ClosureAllocation

Overview

This topic details the process of defining, allocating, and referencing closures in CLforJava. Closures are allocated at the beginning of a new binding environment as determined by the SemanticAnalyzer and the VariableBindings data. Each closure is an instance of an anonymous class implementing the Closure interface. Just prior to creating the closure, the enclosing class creates an array of the values of the bound variables. The constructor of the Closure instance accesses this array as an access to an enclosing class instance variable. (unless we can find a better way to pass it to the constructor). (or an initialize method defined in the Closure interface)

References

HyperSpec CLtL
link 1 Link 2

Implementation

Instances of the Closure interface contain an array of the values of the bound variables. The SA has defined the ordinal positions of each bound variable in the array. The sequence of operations is

  1. Allocate a new array of size of the :closure list and of the least specific type of the bound variables. Usually this means type lisp.common.type.T.
  2. Copy the references of the bound values to the proper positions in the array.
  3. Create an instance of the Closure passing the array and the parent Closure to the new Closure instance.
  4. Connect the current closure to the new binding environment as a stack-local reference
  5. When the ICG encounters a nested LAMBDA, it creates a new instance of the LAMBDA and passes the current closure to the constructor of the new instance.

Examples

Basic

;;; X is allocated in the closure
(let ((x (some-form-to-eval)))
... some code ...
#'(lambda (y) (+ x y))
)

The resulting JVM peudocode looks like:

;;; Code for the LET form

  1. allocate an array of length 1 (remember the array reference as a stack local)
  2. create an instance of type Closure passing it the new array and a NIL reference to the parent Closure (no parent)
  3. make the new Closure the current one
  4. evaluate the (some-form-to-eval) and store the result in the 0th slot in the closure array
  5. ...some code... executed, referencing the 0th slot in the closure array for the value of X
  6. create an instance of the lambda expression passing the current Closure to its constructor

;;; Code for the LAMBDA expression

  1. do the usual setup for a LAMBDA expression
  2. push the value of the parameter Y
  3. fetch the Closure instance (implies that the constructor stores the Closure as an instance variable)
  4. call its getBindingAt method using 0 for the index for X and 0 for the index of the current closure
  5. call the + function

Simple Multiple Closures

;;; X is allocated to an outer closure
(let ((x (some-form-to-eval)))
... some code ...
;;; Y is allocated to an inner closure
(let ((y (some-fn x)))
....some inner code ...
#'(lambda (z) (+ x y z))
)

The resulting JVM peudocode looks like:

;;; Code for the outer LET form

  1. allocate an array of length 1 (remember the array reference as a stack local)
  2. create an instance of type Closure passing it the new array and a NIL reference to the parent Closure
  3. make the new Closure the current one
  4. evaluate the (some-form-to-eval) and store the result in the 0th slot in the closure array
  5. ...some code... executed, referencing the 0th slot in the closure array for the value of X
  6. start the nested LET

;;; Code for the nested LET expression

  1. allocate an array of length 1 (remember the array reference as a stack local)
  2. create an instance of type Closure passing it the new array and a reference to the parent (current) Closure
  3. make the new Closure the current one
  4. call the getBindingAt method of the current Closure using 0 for the index for X and 1 for the index of the enclosing closure
  5. the value of X is on the stack
  6. evaluate the (some-fn ) and store the result in the 0th slot in the closure array
  7. create an instance of the lambda expression passing the current Closure to its constructor

;;; Code for the LAMBDA expression

  1. do the usual setup for a LAMBDA expression
  2. push the value of the parameter Z
  3. fetch the Closure instance (implies that the constructor stores the Closure as an instance variable)
  4. call its getBindingAt method using 0 for the index for Y and 0 for the index of the current closure
  5. push the value on the stack
  6. call the Closure's getBindingAt method using 0 for the index for X and 1 for the index of the enclosing closure
  7. push the value on the stack
  8. call the + function

Core Java Classes Javadoc Links

Illustrations

Current Status of ClosureAllocation

Status:

Release Level:

Open bug count:

Test Suites

Links to JUnit results

-- JerryBoetje - 12 Jul 2003

Topic revision: r5 - 2009-02-10 - 21:14:13 - RobertGoodrich
 
Home
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback