2014-08-22 22:50 GMT+02:00 Nicolas Cellier < [email protected]>:
> > > > 2014-08-21 9:09 GMT+02:00 Nicolai Hess <[email protected]>: > > 2014-08-21 7:14 GMT+02:00 Eliot Miranda <[email protected]>: >> >> >>> >>> >>> On Wed, Aug 20, 2014 at 10:15 PM, Nicolai Hess <[email protected]> >>> wrote: >>> >>>> >>>> 2014-08-19 19:02 GMT+02:00 Eliot Miranda <[email protected]>: >>>> >>>> Hi Nicolai, >>>>> >>>>> >>>>> On Aug 19, 2014, at 11:58 AM, Nicolai Hess <[email protected]> wrote: >>>>> >>>>> Thank you eliot, >>>>> >>>>> >>>>> 2014-08-19 7:29 GMT+02:00 Eliot Miranda <[email protected]>: >>>>> >>>>>> 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). >>> >> >> >> No optimization, the bytecode is: >> >> 13 <76> pushConstant: 1 >> 14 <68> popIntoTemp: 0 >> 15 <76> pushConstant: 1 >> 16 <69> popIntoTemp: 1 >> 17 <8F 00 00 0A> closureNumCopied: 0 numArgs: 0 bytes 21 to 30 >> 21 <73> pushConstant: nil >> 22 <73> pushConstant: nil >> 23 <76> pushConstant: 1 >> 24 <68> popIntoTemp: 0 >> 25 <76> pushConstant: 1 >> 26 <69> popIntoTemp: 1 >> 27 <10> pushTemp: 0 >> 28 <11> pushTemp: 1 >> 29 <B0> send: + >> 30 <7D> blockReturn >> 31 <7C> returnTop >> >> >> > The pushConstant: nil are here to initialize the local temps, so they > should be followed by a popIntoTemp: 0 (resp. 1) > If those pop have been optimized away, so should the push, otherwise this > makes a depth 6 necessary (2 temps + 4 push), and an imbalanced stack - > probably harmless, the blockReturn unwind correctly (?). > > No, as far as I understand block local temps the "pushConstant: nil" *are* the temp vars. stack stack stack <- method stack pointer stack <- block temp 0 (initialized with pushConstant: nil) stack <- block temp 1 (initialized with pushConstant: nil) stack <- block stack pointer stack .... > > >> >>> >>> >>> >>>> Nicolai >>>> >>>> >>>> >>>>> >>>>> >>>>> >>>>> >>>>>> >>>>>> On Aug 18, 2014, at 11:32 PM, Nicolai Hess <[email protected]> >>>>>> 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 >>> >> >> >
