Re: [Pharo-project] Closure bytecodes?
Hi Eliot, That is a very nice blog you linked me to. Lots for me to read there. I read this ... The final bytecode is more interesting. 143 10001111 llllkkkk jjjjjjjj iiiiiiii Push Closure Num Copied llll Num Args kkkk BlockSize jjjjjjjjiiiiiiii This creates a closure, initializing it from the arguments and the current context. I'm missing something, is "num copied llll" the number of temps copied from the containing method? Rgs, James.
Hi James, 2010/8/11 James Ladd <james_ladd@hotmail.com>
Hi Eliot,
That is a very nice blog you linked me to. Lots for me to read there.
I read this ...
The final bytecode is more interesting. 143 10001111 llllkkkk jjjjjjjj iiiiiiii Push Closure Num Copied llll Num Args kkkk BlockSize jjjjjjjjiiiiiiii This creates a closure, initializing it from the arguments and the current context.
I'm missing something, is "num copied llll" the number of temps copied from the containing method?
It is the number of values copied from the stack that become locals of the closure. In Collection>>inject: thisValue into: binaryBlock "Accumulate a running value associated with evaluating the argument, binaryBlock, with the current value of the argument, thisValue, and the receiver as block arguments. For instance, to sum the numeric elements of a collection, aCollection inject: 0 into: [:subTotal :next | subTotal + next]." | nextValue | nextValue := thisValue. self do: [:each | nextValue := binaryBlock value: nextValue value: each]. ^nextValue the closure [:each | nextValue := binaryBlock value: nextValue value: each] accesses two non-local variables binaryBlock & nextValue. Because binaryBlock is not modified its value can be copied directly but because nextValue is modified it cannot be copied and a shared location must be used to hold the value. So the compiler arranges to create an (in this case one-element) array (an indirection vector) to hold nextValue. The hidden variable holding the indirection vector is not modified so its value (the indirection vector) can be copied. Hence [:each | nextValue := binaryBlock value: nextValue value: each] has two copied values, one the value of binaryBlock and another a hidden Array that holds nextValue. Hence the bytecode: push: (Array new: 1) # create the indirection vector popIntoTemp: 2 # store it as the 3rd temp (after firstValue & binaryBlock) pushTemp: 0 # push firstValue popIntoTemp: 0 inVectorAt: 2 # initialize nextValue with firstValue self # push the receiver of #do: pushTemp: 1 # push the first copied value binaryBlock pushTemp: 2 # push the second copied value, the indirection vector holding nextValue closureNumCopied: 2 numArgs: 1 bytes 31 to 40 # create the closure with 1 arg and 2 copied values pushTemp: 1 # push binaryBlock (the 1st copied value, the 2nd temp after each) pushTemp: 0 inVectorAt: 2 # push nextValue, the 1st slot in the indirection vector which is the 3rd temp pushTemp: 0 # push each send: #value:value: (2 args) # evaluate binaryBlock value: nextValue value: each storeIntoTemp: 0 inVectorAt: 2 # store the result into nextValue (1st slot in indirection vector) blockReturn # return nextValue as the result of the block send: #do: (1 arg) # evaluate self do: [:each|...] pop # discard the result of elf do: [:each|...] pushTemp: 0 inVectorAt: 2 # push nextValue returnTop # return nextValue as the result of inject:into: If this still doesn't make sense look at the version in the first blog post that uses an explicit array and compare it with the above. HTH Eliot
Rgs, James.
_______________________________________________ Pharo-project mailing list Pharo-project@lists.gforge.inria.fr http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
participants (2)
-
Eliot Miranda -
James Ladd