On Wed, Aug 20, 2014 at 10:15 PM, Nicolai Hess <nicolaihess@web.de> wrote:
2014-08-19 19:02 GMT+02:00 Eliot Miranda <eliot.miranda@gmail.com>:
Hi Nicolai,
On Aug 19, 2014, at 11:58 AM, Nicolai Hess <nicolaihess@web.de> wrote:
Thank you eliot,
2014-08-19 7:29 GMT+02:00 Eliot Miranda <eliot.miranda@gmail.com>:
Hi Nicolai,
the stack starts as deep as the method's number of temporaries,
ok,
which is the sum of the number of arguments
ok,
plus the number of temporary variables that can exist in the stack
ok (what does "can exist in the stack" mean? They always do?)
Not necessarily. The closure implementation moves temps that need it into an indirect temp vector. See eg my blog on the closure compiler.
http://www.mirandabanda.org/cogblog/2008/06/07/closures-part-i/
plus one if there are any closed-over temporary variables that need to
be in an indirection vector. Then as execution proceeds the receiver and arguments are pushed on the stack, and are replaced by intermediate results by sends it by the create array bytecode.
So, for a method with no blocks, the stack is just the number of temporaries plus the number of args for the message send with the maximum number of args?
No. What about this:
^Point x: 1 y: (self a: 1 b: 2 c: 3)
Before sending a:b:c: the stack is
Point 1 self 1 2 3
Any blocks within the method start with the sum of their number of
arguments, their number of copied values (temp values they access read-only) plus their local temporaries.
But this is not just added to the stack size, right? I have a method with 9 local temporaris and a block in this method with 8 local temporaries and the frameSize is still 16, (with the old compiler/ 56 with the new compiler). So, method and block local temporaries not just sum up? I tried different variations - numberOfMethod temps smaller/equal/greater numberOfBlockTemp - no/some/all method temporaries are accessed in the block closure.
But I can not see a pattern :)
May be a bug in the old compiler. The stack size is the max of the separate sizes in the method and each block.
In the method and each block scope stack depth is the hence the sum of the number of temporaries plus the max execution depth. And the method's depth is the max of the method and that of any blocks within it.
What is the execution depth of a method ? The number of "nested blocks"?
No, it is how many things it pushes in the stack at the deepest point. See my example above.
Then if that depth is 17 or greater it gets the LargeFrame flag set which means the VM allocates a 56 slot context, the compiler raising an error if the depth is greater than 56.
HTH Eliot (phone)
Here are two carefully handcrafted methods :)
fooSmall |t1 t2 t3 t4 t5 t6 t7 t8| t1:=1. t2:=2. t3:=3. t4:=4. t5:=5. t6:=6. t7:=7. t8:= 8. t1:=[:i | |b1 b2 b3 b4 c1 c2 c3 c4 x| b1:=1. b2:=2. b3:=3. b4:=4. c1:=1. c2:=2. c3:=3. c4:=4. x:=1. x+t1 + b1+b2+b3+b4 + c1 + c2 + c3 + c4] value:1. ^ t1 + t2 + t3 + t4 + t5 + t6 + t7 + t8
fooLarge |t1 t2 t3 t4 t5 t6 t7| t1:=1. t2:=2. t3:=3. t4:=4. t5:=5. t6:=6. t7:=7. t1:=[:i | |b1 b2 b3 b4 c1 c2 c3 c4 x| b1:=1. b2:=2. b3:=3. b4:=4. c1:=1. c2:=2. c3:=3. c4:=4. x:=1. x+t1 +t2 + t3 + t4 + t5+ b1+b2+b3+b4 + c1 + c2 + c3 + c4] value:1. ^ t1 + t2 + t3 + t4 + t5 + t6 + t7
They differ only in the number of tempraries (t1-t8 / t1-t7) and the number of copied values for the block closure (1 / 5).
with the old compiler: fooSmall frameSize -> 16 fooLarge frameSize -> 56
the opal compiler computes the opposite sizes fooSmall frameSize -> 56 fooLarge frameSize -> 16
Looks like a bug in the Opal compiler :-). Well found.
I am confused.
No you're not. You've found a bug. Now find its cause....
No, I am still confused :)
Maybe you can help me with, how the old compiler computes the stack frame in this examples:
I changed CompiledMethod>>#needsFrameSize: to write the value for self numTemps and newFrameSize to the Transcript and compiled some simple functions:
foo |a b| a:=1. b:=1. ^ a+b
numTemps:2 frameSize: 2
ok, two temps and two pushes on the stack
foo ^ [ 1+1 ]
numTemps:0 frameSize: 2
ok, no temps and two pushs (push constant:1/push constant:1) on the stack
foo ^ [|a b| a:=1. b:=1. a+b ]
numTemps:0 frameSize: 4
ok, no (method) temps, why is the stackframe 4? Two block local temps and two pushs.
|x y| x:=1. y:=1. ^ [|a b| a:=1. b:=1. a+b ]
numTemps:2 frameSize: 2
Now what? Adding method temps enlarges the number of temps, ok. But the stackframe decreases?
Looks like a bug. The stack size needed in |x y| x:=1. y:=1. ^ [|a b| a:=1. b:=1. a+b ] is 4, unless the compiler is optimizing away the a+b and is replacing the block with [1] ? The stack size of the outer method is 3 (2 temps + 1 for the push of either 1 or the block).
Nicolai
On Aug 18, 2014, at 11:32 PM, Nicolai Hess <nicolaihess@web.de> wrote:
Hi,
on what depends the stack size for a compiled method? I try to figure out, why the old compiler and the opal compile generate different compiled method headers. I think this comes from a wrong stack size computed by opal, but I can not figure out how the stack size is computed.
Old Compiler PolygonMorph>>#lineSegmentsDo: header -> "primitive: 0 numArgs: 1 numTemps: 3 numLiterals: 23 frameSize: 56"
Opal compiler: PolygonMorph>>#lineSegmentsDo: header -> "primitive: 0 numArgs: 1 numTemps: 3 numLiterals: 23 frameSize: 16"
Eliot (phone)
-- best, Eliot