Closure bytecodes?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Closure bytecodes?

jamesl
Hi All,

This list has been amazinly quick and helpful so thank you all.

I'm continuing my adventure through the bytecode and I have a question about
the bytecodes for closures. Below is an example dump of a closure ([])

165     <8F 10 00 1E> closureNumCopied: 1 numArgs: 0 bytes 169 to 198
169         <10> pushTemp: 0
170         <C7> send: class
171         <83 11> send: selectors
173         <83 10> send: asSortedCollection
175         <52> pushLit: WriteStream
176         <53> pushLit: String
177         <CC> send: new
178         <EA> send: on:

The number on the left I will refer to as the line number to make my questions more
clear.

Firstly, on line 165 the closure is reporting num copied 1.  What is the 1 thing that it is copying?

Secondly, the send bytecode on line 171  is different to that on line 175.
Is it because 175 is using a set of known selectors while 171 has to refer to a literal table?

Rgs, James.

_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: Closure bytecodes?

Eliot Miranda-2


2010/8/11 James Ladd <[hidden email]>
Hi All,

This list has been amazinly quick and helpful so thank you all.

I'm continuing my adventure through the bytecode and I have a question about
the bytecodes for closures. Below is an example dump of a closure ([])

165     <8F 10 00 1E> closureNumCopied: 1 numArgs: 0 bytes 169 to 198
169         <10> pushTemp: 0
170         <C7> send: class
171         <83 11> send: selectors
173         <83 10> send: asSortedCollection
175         <52> pushLit: WriteStream
176         <53> pushLit: String
177         <CC> send: new
178         <EA> send: on:

The number on the left I will refer to as the line number to make my questions more
clear.

Firstly, on line 165 the closure is reporting num copied 1.  What is the 1 thing that it is copying?


Secondly, the send bytecode on line 171  is different to that on line 175.
Is it because 175 is using a set of known selectors while 171 has to refer to a literal table?

I think you mean lines 171 & 177 right?  If so, then yes, #new is a special selector (see Smalltalk specialSelectors).

best
Eliot
 

Rgs, James.

_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project


_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: Closure bytecodes?

jamesl
In reply to this post by jamesl
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.

_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
Reply | Threaded
Open this post in threaded view
|

Re: Closure bytecodes?

Eliot Miranda-2
Hi James,

2010/8/11 James Ladd <[hidden email]>
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
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project


_______________________________________________
Pharo-project mailing list
[hidden email]
http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project