@@ -99,7 +99,6 @@ func Compile(str, filename, mode string, flags int, dont_inherit bool) py.Object
9999 fmt .Println (ast .Dump (Ast ))
100100 code := & py.Code {
101101 Filename : filename ,
102- Stacksize : 1 , // FIXME
103102 Firstlineno : 1 , // FIXME
104103 Name : "<module>" , // FIXME
105104 Flags : 64 , // FIXME
@@ -121,6 +120,7 @@ func Compile(str, filename, mode string, flags int, dont_inherit bool) py.Object
121120 }
122121 c .Op (vm .RETURN_VALUE )
123122 code .Code = c .OpCodes .Assemble ()
123+ code .Stacksize = int32 (c .OpCodes .StackDepth ())
124124 return code
125125}
126126
@@ -496,16 +496,16 @@ func (is *Instructions) Add(i Instruction) {
496496func (is Instructions ) Pass (pass int ) bool {
497497 addr := uint32 (0 )
498498 changed := false
499- for _ , i := range is {
500- posChanged := i .SetPos (addr )
499+ for i , instr := range is {
500+ posChanged := instr .SetPos (i , addr )
501501 changed = changed || posChanged
502502 if pass > 0 {
503503 // Only resolve addresses on 2nd pass
504- if resolver , ok := i .(Resolver ); ok {
504+ if resolver , ok := instr .(Resolver ); ok {
505505 resolver .Resolve ()
506506 }
507507 }
508- addr += i .Size ()
508+ addr += instr .Size ()
509509 }
510510 return changed
511511}
@@ -527,31 +527,271 @@ done:
527527 return string (out )
528528}
529529
530+ // Calculate number of arguments for CALL_FUNCTION etc
531+ func nArgs (o uint32 ) int {
532+ return (int (o ) & 0xFF ) + 2 * ((int (o )>> 8 )& 0xFF )
533+ }
534+
535+ // Effect the opcode has on the stack
536+ func opcodeStackEffect (opcode byte , oparg uint32 ) int {
537+ switch opcode {
538+ case vm .POP_TOP :
539+ return - 1
540+ case vm .ROT_TWO , vm .ROT_THREE :
541+ return 0
542+ case vm .DUP_TOP :
543+ return 1
544+ case vm .DUP_TOP_TWO :
545+ return 2
546+ case vm .UNARY_POSITIVE , vm .UNARY_NEGATIVE , vm .UNARY_NOT , vm .UNARY_INVERT :
547+ return 0
548+ case vm .SET_ADD , vm .LIST_APPEND :
549+ return - 1
550+ case vm .MAP_ADD :
551+ return - 2
552+ case vm .BINARY_POWER , vm .BINARY_MULTIPLY , vm .BINARY_MODULO , vm .BINARY_ADD , vm .BINARY_SUBTRACT , vm .BINARY_SUBSCR , vm .BINARY_FLOOR_DIVIDE , vm .BINARY_TRUE_DIVIDE :
553+ return - 1
554+ case vm .INPLACE_FLOOR_DIVIDE , vm .INPLACE_TRUE_DIVIDE :
555+ return - 1
556+ case vm .INPLACE_ADD , vm .INPLACE_SUBTRACT , vm .INPLACE_MULTIPLY , vm .INPLACE_MODULO :
557+ return - 1
558+ case vm .STORE_SUBSCR :
559+ return - 3
560+ case vm .STORE_MAP :
561+ return - 2
562+ case vm .DELETE_SUBSCR :
563+ return - 2
564+ case vm .BINARY_LSHIFT , vm .BINARY_RSHIFT , vm .BINARY_AND , vm .BINARY_XOR , vm .BINARY_OR :
565+ return - 1
566+ case vm .INPLACE_POWER :
567+ return - 1
568+ case vm .GET_ITER :
569+ return 0
570+ case vm .PRINT_EXPR :
571+ return - 1
572+ case vm .LOAD_BUILD_CLASS :
573+ return 1
574+ case vm .INPLACE_LSHIFT , vm .INPLACE_RSHIFT , vm .INPLACE_AND , vm .INPLACE_XOR , vm .INPLACE_OR :
575+ return - 1
576+ case vm .BREAK_LOOP :
577+ return 0
578+ case vm .SETUP_WITH :
579+ return 7
580+ case vm .WITH_CLEANUP :
581+ return - 1 /* XXX Sometimes more */
582+ case vm .RETURN_VALUE :
583+ return - 1
584+ case vm .IMPORT_STAR :
585+ return - 1
586+ case vm .YIELD_VALUE :
587+ return 0
588+ case vm .YIELD_FROM :
589+ return - 1
590+ case vm .POP_BLOCK :
591+ return 0
592+ case vm .POP_EXCEPT :
593+ return 0 /* -3 except if bad bytecode */
594+ case vm .END_FINALLY :
595+ return - 1 /* or -2 or -3 if exception occurred */
596+ case vm .STORE_NAME :
597+ return - 1
598+ case vm .DELETE_NAME :
599+ return 0
600+ case vm .UNPACK_SEQUENCE :
601+ return int (oparg ) - 1
602+ case vm .UNPACK_EX :
603+ return (int (oparg ) & 0xFF ) + (int (oparg ) >> 8 )
604+ case vm .FOR_ITER :
605+ return 1 /* or -1, at end of iterator */
606+ case vm .STORE_ATTR :
607+ return - 2
608+ case vm .DELETE_ATTR :
609+ return - 1
610+ case vm .STORE_GLOBAL :
611+ return - 1
612+ case vm .DELETE_GLOBAL :
613+ return 0
614+ case vm .LOAD_CONST :
615+ return 1
616+ case vm .LOAD_NAME :
617+ return 1
618+ case vm .BUILD_TUPLE , vm .BUILD_LIST , vm .BUILD_SET :
619+ return 1 - int (oparg )
620+ case vm .BUILD_MAP :
621+ return 1
622+ case vm .LOAD_ATTR :
623+ return 0
624+ case vm .COMPARE_OP :
625+ return - 1
626+ case vm .IMPORT_NAME :
627+ return - 1
628+ case vm .IMPORT_FROM :
629+ return 1
630+ case vm .JUMP_FORWARD , vm .JUMP_ABSOLUTE :
631+ return 0
632+ case vm .JUMP_IF_TRUE_OR_POP : /* -1 if jump not taken */
633+ return 0
634+ case vm .JUMP_IF_FALSE_OR_POP : /* "" */
635+ return 0
636+ case vm .POP_JUMP_IF_FALSE , vm .POP_JUMP_IF_TRUE :
637+ return - 1
638+ case vm .LOAD_GLOBAL :
639+ return 1
640+ case vm .CONTINUE_LOOP :
641+ return 0
642+ case vm .SETUP_LOOP :
643+ return 0
644+ case vm .SETUP_EXCEPT , vm .SETUP_FINALLY :
645+ // can push 3 values for the new exception
646+ // + 3 others for the previous exception state
647+ return 6
648+ case vm .LOAD_FAST :
649+ return 1
650+ case vm .STORE_FAST :
651+ return - 1
652+ case vm .DELETE_FAST :
653+ return 0
654+
655+ case vm .RAISE_VARARGS :
656+ return - int (oparg )
657+ case vm .CALL_FUNCTION :
658+ return - nArgs (oparg )
659+ case vm .CALL_FUNCTION_VAR , vm .CALL_FUNCTION_KW :
660+ return - nArgs (oparg ) - 1
661+ case vm .CALL_FUNCTION_VAR_KW :
662+ return - nArgs (oparg ) - 2
663+ case vm .MAKE_FUNCTION :
664+ return - 1 - nArgs (oparg ) - ((int (oparg ) >> 16 ) & 0xffff )
665+ case vm .MAKE_CLOSURE :
666+ return - 2 - nArgs (oparg ) - ((int (oparg ) >> 16 ) & 0xffff )
667+ case vm .BUILD_SLICE :
668+ if oparg == 3 {
669+ return - 2
670+ } else {
671+ return - 1
672+ }
673+ case vm .LOAD_CLOSURE :
674+ return 1
675+ case vm .LOAD_DEREF , vm .LOAD_CLASSDEREF :
676+ return 1
677+ case vm .STORE_DEREF :
678+ return - 1
679+ case vm .DELETE_DEREF :
680+ return 0
681+ default :
682+ panic ("Unknown opcode in StackEffect" )
683+ }
684+ }
685+
686+ // Recursive instruction walker to find max stack depth
687+ func (is Instructions ) stackDepthWalk (baseIs Instructions , seen map [int ]bool , startDepth map [int ]int , depth int , maxdepth int ) int {
688+ // var i, target_depth, effect int
689+ // var instr *struct instr
690+ // if b.b_seen || b.b_startdepth >= depth {
691+ // return maxdepth
692+ // }
693+ // b.b_seen = 1
694+ // b.b_startdepth = depth
695+ if len (is ) == 0 {
696+ return maxdepth
697+ }
698+ start := is [0 ].Number ()
699+ if seen [start ] {
700+ // We are processing this block already
701+ return maxdepth
702+ }
703+ if d , ok := startDepth [start ]; ok && d >= depth {
704+ // We've processed this block with a larger depth already
705+ return maxdepth
706+ }
707+ seen [start ] = true
708+ startDepth [start ] = depth
709+ for _ , instr := range is {
710+ depth += instr .StackEffect ()
711+ if depth > maxdepth {
712+ maxdepth = depth
713+ }
714+ if depth < 0 {
715+ panic ("Stack depth negative" )
716+ }
717+ jrel , isJrel := instr .(* JumpRel )
718+ jabs , isJabs := instr .(* JumpAbs )
719+ if isJrel || isJabs {
720+ var oparg * OpArg
721+ var dest * Label
722+ if isJrel {
723+ oparg = & jrel .OpArg
724+ dest = jrel .Dest
725+ } else {
726+ oparg = & jabs .OpArg
727+ dest = jabs .Dest
728+ }
729+ opcode := oparg .Op
730+ target_depth := depth
731+ if opcode == vm .FOR_ITER {
732+ target_depth = depth - 2
733+ } else if opcode == vm .SETUP_FINALLY || opcode == vm .SETUP_EXCEPT {
734+ target_depth = depth + 3
735+ if target_depth > maxdepth {
736+ maxdepth = target_depth
737+ }
738+ } else if opcode == vm .JUMP_IF_TRUE_OR_POP || opcode == vm .JUMP_IF_FALSE_OR_POP {
739+ depth = depth - 1
740+ }
741+ isTarget := baseIs [dest .Number ():]
742+ maxdepth = isTarget .stackDepthWalk (baseIs , seen , startDepth , target_depth , maxdepth )
743+ if opcode == vm .JUMP_ABSOLUTE ||
744+ opcode == vm .JUMP_FORWARD {
745+ goto out // remaining code is dead
746+ }
747+ }
748+ }
749+ out:
750+ seen [start ] = false
751+ return maxdepth
752+ }
753+
754+ // Find the flow path that needs the largest stack. We assume that
755+ // cycles in the flow graph have no net effect on the stack depth.
756+ func (is Instructions ) StackDepth () int {
757+ return is .stackDepthWalk (is , make (map [int ]bool ), make (map [int ]int ), 0 , 0 )
758+ }
759+
530760type Instruction interface {
531761 Pos () uint32
532- SetPos (uint32 ) bool
762+ Number () int
763+ SetPos (int , uint32 ) bool
533764 Size () uint32
534765 Output () []byte
766+ StackEffect () int
535767}
536768
537769type Resolver interface {
538770 Resolve ()
539771}
540772
541773// Position
542- type pos uint32
774+ type pos struct {
775+ n uint32
776+ p uint32
777+ }
778+
779+ // Read instruction number
780+ func (p * pos ) Number () int {
781+ return int (p .n )
782+ }
543783
544784// Read position
545785func (p * pos ) Pos () uint32 {
546- return uint32 ( * p )
786+ return p . p
547787}
548788
549789// Set Position - returns changed
550- func (p * pos ) SetPos (newPos uint32 ) bool {
551- oldP := * p
552- newP := pos ( newPos )
553- * p = newP
554- return oldP != newP
790+ func (p * pos ) SetPos (number int , newPos uint32 ) bool {
791+ p . n = uint32 ( number )
792+ oldPos := p . p
793+ p . p = newPos
794+ return oldPos != newPos
555795}
556796
557797// A plain opcode
@@ -570,6 +810,11 @@ func (o *Op) Output() []byte {
570810 return []byte {byte (o .Op )}
571811}
572812
813+ // StackEffect
814+ func (o * Op ) StackEffect () int {
815+ return opcodeStackEffect (o .Op , 0 )
816+ }
817+
573818// An opcode with argument
574819type OpArg struct {
575820 pos
@@ -595,6 +840,11 @@ func (o *OpArg) Output() []byte {
595840 return out
596841}
597842
843+ // StackEffect
844+ func (o * OpArg ) StackEffect () int {
845+ return opcodeStackEffect (o .Op , o .Arg )
846+ }
847+
598848// A label
599849type Label struct {
600850 pos
@@ -610,6 +860,11 @@ func (o Label) Output() []byte {
610860 return []byte {}
611861}
612862
863+ // StackEffect
864+ func (o * Label ) StackEffect () int {
865+ return 0
866+ }
867+
613868// An absolute JUMP with destination label
614869type JumpAbs struct {
615870 pos
0 commit comments