<br><br><div class="gmail_quote">On Sun, Apr 22, 2012 at 11:48 AM, stephane ducasse <span dir="ltr"><<a href="mailto:stephane.ducasse@gmail.com">stephane.ducasse@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Hi eliot<br>
<br>
I'm rereading your blog. I understand that you create an array so that you are sure that<br>
local of the activation context of the method containing a block are not modified, just the<br>
array elements. so this means in particular that since the array is not allocated on the heap<br>
you guarantee that captured variables of the closure environment outlive the method activation.<br>
I hope I got it correctly.<br></blockquote><div><br></div><div>The array *is* allocated on the heap. I don't guarantee that captured variables of the closure environment outlive the method activation. That depends on whether a reference to the block is captured. If some object takes a reference to the block (stores it in an inst var) then the block can outlive its enclosing method activation. If this happens, if the variables closed-over by the block live on the stack of the method activation then the method activation must persist too. And that's a problem if the activation has been mapped to a stack ftrame, because we've exited the stack frame on returning from the method activation and so must update the state of the context from the stack frame at return time, and that's what we're trying to avoid. So instead any shared closed-over variables (variables that can't be copied) get allocated in a heap-allocated indirection vector (the array).</div>
<div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Now I have a question about the following snippet representing what the compiler is doing.<br>
Where indirectTempsCopy is initialized and to what?<br>
<br>
inject: thisValue into: binaryBlock<br>
| indirectTemps |<br>
indirectTemps := Array new: 1.<br>
indirectTemps at: 1 put: thisValue.<br>
self do: (thisContext<br>
closureCopy:<br>
[:each |<br>
| binaryBlockCopy indirectTempsCopy |<br>
indirectTempsCopy<br>
at:1<br>
put: (binaryBlockCopy value: (indirectTempsCopy at: 1) value: each)]<br>
copiedValues: (Array with: binaryBlock with: indirectTemps)).<br>
^indirectTemps at: 1<br>
<br>
I thought that it should be like and I was wondering after if and why the indirectTemps should be copied.<br>
Because we create one context for each<br>
<br>
[:each |<br>
| binaryBlockCopy indirectTempsCopy |<br>
indirectTempsCopy := indirectTemps<br>
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^<br>
indirectTempsCopy<br>
at:1<br>
put: (binaryBlockCopy value: (indirectTempsCopy at: 1) value: each)]<br>
copiedValues: (Array with: binaryBlock with: indirectTemps)).<br>
^indirectTemps at: 1<br></blockquote><div><br></div><div>That's right. But the indirectTempsCopy assignment happens in the block value primitive. The first place the indirection vector ends up is on the stack frame of the method activation:</div>
<div><br></div><div>17 <8A 01> push: (Array new: 1)</div><div>19 <6A> popIntoTemp: 2</div><div><br></div><div>The second place it ends up is in the block:</div><div><br></div><div>25 <11> pushTemp: 1 << pushes the binaryBlock argument to inject:into:</div>
<div>26 <12> pushTemp: 2 << pushes the indirection vector</div><div>27 <8F 21 00 0A> closureNumCopied: 2 numArgs: 1 bytes 31 to 40 <<= creates the block within inject:into: that takes a copy of the two arguments on the stack</div>
<div><br></div><div>The third place it sends up is at stack offset 2 in the inner block. In the inner block the argument nextValue is at offset 0, binaryBlock is at offset 1, and the indirection vector is at offset 2. So the line "<span class="Apple-style-span" style="border-collapse:collapse;font-family:arial,sans-serif;font-size:13px">indirectTempsCopy := indirectTemps</span>" is implicit in the value:value: primitive that activates the context.</div>
<div><br></div><div>i.e. in the value:value: primitive you'll see a simulation of this which is disabled (in the false ifTrue: arm):</div><div><br></div><div><div>BlockClosure>>value: firstArg value: secondArg</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span>"Activate the receiver, creating a closure activation (MethodContext)</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> whose closure is the receiver and whose caller is the sender of this</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span> message. Supply the arguments and copied values to the activation</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> as its arguments and copied temps. Primitive. Essential."</div>
<div><span class="Apple-tab-span" style="white-space:pre">        </span><primitive: 203></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>| newContext |</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>numArgs ~= 2 ifTrue:</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>[self numArgsError: 2].</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>false</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>ifTrue: "Old code to simulate the closure value primitive on VMs that lack it."</div>
<div><span class="Apple-tab-span" style="white-space:pre">                        </span>[newContext := <b>self asContextWithSender: thisContext sender</b>.</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span><b>newContext at: 1 put: firstArg.</b></div>
<div><b><span class="Apple-tab-span" style="white-space:pre">                        </span>newContext at: 2 put: secondArg.</b></div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>thisContext privSender: newContext]</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>ifFalse: [self primitiveFailed]</div></div><div> </div><div><div>BlockClosure>>asContextWithSender: aContext</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>"Inner private support method for evaluation. Do not use unless you know what you're doing."</div>
<div><br></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>^((MethodContext newForMethod: outerContext method)</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>setSender: aContext</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>receiver: outerContext receiver</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>method: outerContext method</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>closure: self</div>
<div><span class="Apple-tab-span" style="white-space:pre">                </span>startpc: startpc) <b>privRefresh</b></div></div><div><br></div><div><div>MethodContext>>privRefresh</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>"Reinitialize the receiver so that it is in the state it was at its creation."</div>
<div><br></div><div><span class="Apple-tab-span" style="white-space:pre">        </span><b>closureOrNil</b></div><div><span class="Apple-tab-span" style="white-space:pre">                </span>ifNotNil:</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>[pc := closureOrNil startpc.</div>
<div><span class="Apple-tab-span" style="white-space:pre">                        </span>self stackp: <b>closureOrNil numArgs + closureOrNil numCopiedValues</b>.</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span><b>1 to: closureOrNil numCopiedValues</b> do:</div>
<div><span class="Apple-tab-span" style="white-space:pre">                                </span>[:i | self tempAt: <b>closureOrNil numArgs + i</b> put: (closureOrNil at: i)]]</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>ifNil:</div>
<div><span class="Apple-tab-span" style="white-space:pre">                        </span>[pc := method initialPC.</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>self stackp: method numTemps.</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>method numArgs+1 to: method numTemps do:</div>
<div><span class="Apple-tab-span" style="white-space:pre">                                </span>[:i | self tempAt: i put: nil]]</div></div><div><br></div><div>Make sense now?</div></div><div><br></div>-- <br>best,<div>Eliot</div><br>