Comments on Smalltalk block closure designs, part 1

Allen Wirfs-Brock Allen_Wirfs-Brock at Instantiations.com
Thu May 3 06:38:23 UTC 2001


At 09:16 PM 5/2/2001 -0400, Anthony Hannan wrote:
...
>However, references in the block's compiledMethod to variables outside its
>scope will require new bytecodes (pushOuterSharedTemporaryVariable,
>popIntoOuterSharedTemporaryVariable, &
>storeIntoOuterSharedTemporaryVariable).  Likewise, references to these
>shared variables in the home method will require new bytecodes
>(pushLocalSharedTemporaryVariable, popIntoLocalSharedTemporaryVariable, &
>storeIntoLocalSharedTemporaryVariable).  Like Allen said, upon method (or
>block) activation, shared temporary variables are placed in a local
>SharedContext (environment) array on the heap, while other variables can
>live in a StackContext (method/block context) on the stack.

A more general mechanism would be push/pop indirect bytecodes that 
load/store indirectly through any activation record slot. The parameters 
are slot offset and offset within indirect object.  With these basic 
instructions. Your can build any sort of environment structure including 
chaining through multiple lexical levels.



>Summary of classes:
>
>CompiledMethod
>         header - encoding num args, num shared vars, num stack vars, 
> frame size
>needed (large or small), and share-outer-context-with-inner flag.  args
>always go on stack and copied to shared (in first few bytecodes) if
>necessary.
>         literals
>         bytecodes

With a little bit of thought the same class can be used to represent the 
code (and literals) for either a method or a block (of any nesting level). 
There really isn't much, if any, any difference between them from the 
perspective of the execution mechanisms. For debugging purposes it may be 
useful to have a separate class for compiled blocks code to help the 
debugger display the source code as embedded within a method.

>BlockFunction (superclass: CompiledMethod)
>         receiver
>         outerSharedContext

Don't try to combine CompiledMethods and closures into a single 
class.  This is a problematic as combining activation records and closures.

Roughly speaking a Block closure object would be:
         Block (superclass: Object)
                 outerEnvironment
                 method

but there are many ways to elaborate the design to optimize special cases.


>StackContext (replaces BlockContext and MethodContext)
>         sender - implicit if allocated on the stack
>         pc - points to next bytecode instruction
>         stackp - not necessary if using the stack pointer
>         methodLiterals
>         methodBytecodes
>         receiver
>         outerSharedContext
>         localSharedContext - holds local shared vars
>         (indexed vars) - args, stack vars, and local execution stack

See comments above about push/pop indirect bytecodes.  If you use those you 
don't necessarily have to dedicate slots for a sharedContext or even an 
outerSharedContext.  You may find this it is better to link through the 
environment objects rather that the activation records.


>SharedContext (superclass: Array)
>         (indexed vars) - first one may be the outer SharedContext


Allen





More information about the Squeak-dev mailing list