LocalAllocation

Overview

This topic discusses how to use the JVM local slots to implement the VariableBindings and ClosureAllocation. The intent is to allocate all lexical, non-closure variables to stack-allocated slots. The current references to gensymed symbols that hold values will be dropped in favor of stack allocation. Free variables will be treated as lisp symbols, as they are in the current implementation. However, the current system calls the intern method for every reference, slowing execution significantly. The new implementation allocates a local variable on entry of the enclosing lambda expression, intern s the symbol and puts it in the local variable slot. All other references to the symbol later in the lambda expression refer to the symbol in the local variable.

At every level of binding, the binding allocations are complete before descending into a nested binding environment. The order of allocation is

  • lambda bindings (parameters passed to funcall or apply methods).
  • Non- lambda bindings (let etc)
  • Closures
  • Globally free variables

The order reflects some constraints imposed by the JVM (parameters come first) and the assumption that lexically-bound, non-closed variables are accessed more frequently. The JVM has special instructions for the first 4 stack slots, supporting a minor optimization. Later versions of the compiler may support much more efficient allocation schemes.

References

HyperSpec CLtL
link 1 Link 2

Implementation

Lexical, Non-Closure Variables

These variables have lexical scope within the binding environment and are not part of a closure in that binding environment. For example, in

(lambda (x y)
  ..some code...
  (lambda (z) (+ x z))
  ...more code...
)

The parameter x is closed in the outer binding, and the parameter y is bound but not closed. In this example, x is allocated to a closure structure and all references to x are to the closure. But y is merely a bound variable. It is stack-allocated as a JVM local variable. All references to y are to that local variable.

Free Variables

Variables in CLforJava that are globally free are treated as dynamically-scoped symbols. Such variables may be referenced in many locations within a lambda expression. Free variables may be recognized within let forms, but they are allocated within the nearest enclosing lambda expression (including the current one). The allocation of free variables is determined after the creation of the lambda reference data. All of the free variables are identified in the binding form where they occur. The allocation algorithm determines in which binding form the symbol is allocated and assigned to a JVM local variable.

Notice that the recognition of a globally free variable within a let form forces an :symbol-table entry for that variable in the enclosing lambda expression.

Examples

Lisp Form Lambda Reference Data Augmented Reference Data Pseudo JVM Code
(lambda (x)
  (+ x y))
(%lambda
  (:bindings
    (x :allocation (:parameter . 1)
       :scope :lexical))
  (:symbol-table
    (y :scope :dynamic
       :binding :free))
  (:closure)
  (:parent nil)
)
(%lambda
  (:bindings
    (x :allocation (:parameter . 1)
       :scope :lexical))
  (:symbol-table
    (y :scope :dynamic
       :binding :free
       :allocation (local . 2)))
  (:closure)
  (:parent nil)
)
  1. Code to locate the package for y (if there is one)
  2. Look up the symbol with name "y"
  3. Store symbol into local variable 2
  4. load local variable 1 (x)
  5. Load symbol from local variable 2
  6. invoke getValue method on the symbol
  7. invoke Function2 funcall method on function +
  8. return the result
(lambda (x)
  (let ((z (+ x y)))
    (+ z 5)))
(%lambda
  (:bindings
    (x :allocation (:parameter . 1)
       :scope :lexical))
  (:symbol-table
    (y :scope :dynamic
       :binding :free))
  (:closure)
  (:parent nil)
)
(%let
  (:bindings
    (z :allocation (:local . 2)
       :init-form (+ x y)
       :scope :lexical))
  (:symbol-table)
  (:closure)
  (:parent #ref-1#)
)
(%lambda
  (:bindings
    (x :allocation (:parameter . 1)
       :scope :lexical))
  (:symbol-table
    (y :scope :dynamic
       :binding :free
       :allocation (local . 3)))
  (:closure)
  (:parent nil)
)
(%let
  (:bindings
    (z :allocation (:local . 2)
       :init-form (+ x y)
       :scope :lexical))
  (:symbol-table)
  (:closure)
  (:parent #ref-1#)
)
  1. Code to locate the package for y (if there is one)
  2. Look up the symbol with name "y"
  3. Store symbol into local variable 3
  4. load local variable 1 (x)
  5. Load symbol from local variable 2
  6. invoke getValue method on the symbol
  7. invoke Function2 funcall method on function +
  8. Store the result into local variable 2 (z)
  9. fetch the value in variable 2 onto the stack
  10. push the constant 5 on the stack
  11. invoke Function2 funcall method on function +
  12. return the result
(lambda (x)
  (let ((z (+ x 5)))
    (+ z y)))
(%lambda
  (:bindings
    (x :allocation (:parameter . 1)
       :scope :lexical))
  (:symbol-table)
  (:closure)
  (:parent nil)
(%let
  (:bindings
    (z :allocation (:local . 2)
       :init-form (+ x 5)
       :scope :lexical))
  (:symbol-table
    (y :scope :dynamic
       :binding :free))
  (:closure)
  (:parent #ref-1#)
)
(%lambda
  (:bindings
    (x :allocation (:parameter . 1)
       :scope :lexical))
  (:symbol-table
    (y :scope :dynamic
       :binding :free
       :allocation (local . 3)))
  (:closure)
  (:parent nil)
(%let
  (:bindings
    (z :allocation (:local . 2)
       :init-form (+ x 5)
       :scope :lexical))
  (:symbol-table
    (y :scope :dynamic
       :binding :free
       :allocation #ref-1#))
  (:closure)
  (:parent #ref-1#)
)
  1. Code to locate the package for y (if there is one)
  2. Look up the symbol with name "y"
  3. Store symbol into local variable 3
  4. load local variable 1 (x)
  5. Push integer 5
  6. invoke Function2 funcall method on function +
  7. Store into variable 2 (z)
  8. Load integer from local variable 2
  9. Load Symbol from local variable 3
  10. invoke getValue method on the symbol
  11. invoke Function2 funcall method on function +
  12. return the result
(lambda ()
  ((lambda (x)
    (let ((z (+ x 5)))
      (+ z y)))
   *radix*))
(%lambda
  (:bindings)
  (:symbol-table
    (radix :scope :dynamic
           :binding :free)))
  (:closure)
  (:parent nil)
(%lambda
  (:bindings
    (x :allocation (:parameter . 1)
       :scope :lexical))
  (:symbol-table)
  (:closure)
  (:parent #ref-1#))
(%let
  (:bindings
    (z :allocation (:local . 2)
       :init-form (+ x 5)
       :scope :lexical))
  (:symbol-table
    (y :scope :dynamic
       :binding :free))
  (:closure)
  (:parent #ref-2#)
)
(%lambda
  (:bindings
    (x :allocation (:parameter . 1)
       :scope :lexical))
  (:symbol-table
    (y :scope :dynamic
       :binding :free
       :allocation (local . 3)))
  (:closure)
  (:parent nil)
(%let
  (:bindings
    (z :allocation (:local . 2)
       :init-form (+ x 5)
       :scope :lexical))
  (:symbol-table
    (y :scope :dynamic
       :binding :free
       :allocation #ref-1#))
  (:closure)
  (:parent #ref-1#)
)
This example deals with analyzing a lambda expression
in the function position and how its bindings
are handled with the (possibly implied) outer lambda.
(lambda (x)
  (let ((a ((lambda (y)
              (+ y 5))
            x)))
    (print a)))
first pass of lambda in fn position second pass commentary

Algorithm

For each free variable, the SemanticAnalyzer locates the nearest enclosing lambda expression

Closure Reference

The reference to a closure in any binding environment is allocated to the next available local variable after all parameter and lexically-bound but not closed variables. It precedes the allocation of globally free variables.

Core Java Classes Javadoc Links

Discussions

Links to Blog issues

Current Status of LocalAllocation

Status:

Release Level:

Open bug count:

Test Suites

Links to JUnit results

-- JerryBoetje - 12 Jul 2003

Topic revision: r9 - 2009-02-11 - 03:19:32 - MeganLusher
 
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