[Pharo-dev] Stack size for compiled methods (issue 13854 Crash/hang on array access)

Nicolai Hess nicolaihess at web.de
Wed Aug 20 17:15:38 EDT 2014


2014-08-19 19:02 GMT+02:00 Eliot Miranda <eliot.miranda at gmail.com>:

> Hi Nicolai,
>
>
> On Aug 19, 2014, at 11:58 AM, Nicolai Hess <nicolaihess at web.de> wrote:
>
> Thank you eliot,
>
>
> 2014-08-19 7:29 GMT+02:00 Eliot Miranda <eliot.miranda at 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?





Nicolai



>
>
>
>
>>
>> On Aug 18, 2014, at 11:32 PM, Nicolai Hess <nicolaihess at 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)
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.pharo.org/pipermail/pharo-dev_lists.pharo.org/attachments/20140820/715cb6e2/attachment-0002.html>


More information about the Pharo-dev mailing list