Implementing closures (was: Re: 3.9 vs. 3.10 : Closures, fixTemps)

Mathieu Suen mathk.sue at gmail.com
Thu Dec 20 14:23:49 UTC 2007


Your idea is quite the same than the one from the NewCompiler.
In your idea #tempsAt: will fetch temps inside an array of an instance  
variable of the BlockContext.
In the NewCompiler we have the same and we call this array a  
ClosureEnvironment.

As you said storing or pushing from temp is prim candidate. I have  
implement 2 bytecodes pushing and storing in ClosureEnvironment.
I also have implement some primitive for createBlock: and stuff like  
that.
The benchmark I have made show that it run 2 time slower but some  
other optimization could be done.

We also don't share the bytecode with the home context. instead we  
create a compiled method that we put in the literal array.

Note that we only create this method when it is needed. For example if  
the block do not reference a outer temp we use the old block context.

Cheers,

On Dec 20, 2007, at 5:19 AM, Andreas Raab wrote:

> Mathieu Suen wrote:
>> Well so propose us your solution.
>
> Okay, I promised not to invent a solution but it's one of "those"  
> problems that I've thought about for a while in the past so let's  
> see. Here is how I would address the problem of implementing full  
> closures in Squeak:
>
> 1) First, I would fix the "attempt to evaluate a block that is  
> already evaluated" problem. That's about ten lines of code in the VM  
> - if you look at primitiveValue[withArgs] you'll find that we fail  
> if the CallerIndex is non-nil. Instead of failing, I'd clone the  
> original context and continue as usual.
>
> At this point you'd be able to execute code like:
>
>  | v |
>  fac := [v > 0 ifTrue:[1] ifFalse:[v := v-1. fac value * (v+1)]].
>  fac value: 10.
>
> which allows recursive evaluation but without block args (since they  
> get hacked in some terrible ways).
>
> 2) Next, I'd deal with block variables (temps and args). Instead of  
> sharing the method contexts, blocks would store their own temps and  
> access them via tempAt:. So that for example code like here:
>
>  self do:[:v| | v2 | v2 := v squared. v2].
>
> would be compiled into to:
>
>  self do:[:v|
>    thisContext push: nil. "allocate v2"
>    thisContext tempAt: 2 "v2" put: (thisContext tempAt: 1 "v")  
> squared.
>    thisContext tempAt: 2.
>  ].
>
> This would be slower than what we have today but obviously, the  
> pattern "thisContext tempAt:" is a prime candidate for optimization.  
> At this point we'd be able to run the following correctly:
>
> fac [:v| v = 0 ifTrue:[1] ifFalse:[ v * (fac value: v-1)].
>
> The implementation would be pretty straightforward too, since all  
> you'd have to do is to add BlockVariableNode that generates tempAt:  
> messages (plus some initialization). Very, very straightforward.
>
> 3) Next, I would deal with "outer" state like here:
>
>  self do:[:x|
>    x do:[:y| x * y]
>  ].
>
> This is probably the hardest part since dealing with "non-method  
> closed-over state" can be tricky due to life-time issues. Anyway,  
> for starters I would just add a hidden temporary "outerContext" for  
> all blocks that is just a temp like any other such that the compiler  
> can generate code like:
>
>  self do:[:x|
>    x do:[:y|
>      ((thisContext tempAt: 1) "outerContext" tempAt: 1 "x") *
>        (thisContext tempAt: 2) "y"
>    ].
>  ].
>
> At this point (I think - please correct me if I'm missing something)  
> we have *complete* closure semantics in a straightforward way. What  
> remains is optimization.
>
> 4) Lastly, optimization. I would start with the obvious push/ 
> popBlockTemp bytecodes which would bring all of the above up to par  
> with current Squeak (except (3) which could still be slower).  
> Finally, one might look at the life-time of closed-over state - it  
> is certainly not necessary to preserve the entire outer context so  
> there may be other things that could be done to fix it.
>
> In any case, the above looks pretty simple and straightforward.  
> Wouldn't you agree?
>
> Cheers,
>  - Andreas
>

	Mth






More information about the Squeak-dev mailing list