@@ -99,7 +99,6 @@ func Compile(str, filename, mode string, flags int, dont_inherit bool) py.Object
99
99
fmt .Println (ast .Dump (Ast ))
100
100
code := & py.Code {
101
101
Filename : filename ,
102
- Stacksize : 1 , // FIXME
103
102
Firstlineno : 1 , // FIXME
104
103
Name : "<module>" , // FIXME
105
104
Flags : 64 , // FIXME
@@ -121,6 +120,7 @@ func Compile(str, filename, mode string, flags int, dont_inherit bool) py.Object
121
120
}
122
121
c .Op (vm .RETURN_VALUE )
123
122
code .Code = c .OpCodes .Assemble ()
123
+ code .Stacksize = int32 (c .OpCodes .StackDepth ())
124
124
return code
125
125
}
126
126
@@ -496,16 +496,16 @@ func (is *Instructions) Add(i Instruction) {
496
496
func (is Instructions ) Pass (pass int ) bool {
497
497
addr := uint32 (0 )
498
498
changed := false
499
- for _ , i := range is {
500
- posChanged := i .SetPos (addr )
499
+ for i , instr := range is {
500
+ posChanged := instr .SetPos (i , addr )
501
501
changed = changed || posChanged
502
502
if pass > 0 {
503
503
// Only resolve addresses on 2nd pass
504
- if resolver , ok := i .(Resolver ); ok {
504
+ if resolver , ok := instr .(Resolver ); ok {
505
505
resolver .Resolve ()
506
506
}
507
507
}
508
- addr += i .Size ()
508
+ addr += instr .Size ()
509
509
}
510
510
return changed
511
511
}
@@ -527,31 +527,271 @@ done:
527
527
return string (out )
528
528
}
529
529
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
+
530
760
type Instruction interface {
531
761
Pos () uint32
532
- SetPos (uint32 ) bool
762
+ Number () int
763
+ SetPos (int , uint32 ) bool
533
764
Size () uint32
534
765
Output () []byte
766
+ StackEffect () int
535
767
}
536
768
537
769
type Resolver interface {
538
770
Resolve ()
539
771
}
540
772
541
773
// 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
+ }
543
783
544
784
// Read position
545
785
func (p * pos ) Pos () uint32 {
546
- return uint32 ( * p )
786
+ return p . p
547
787
}
548
788
549
789
// 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
555
795
}
556
796
557
797
// A plain opcode
@@ -570,6 +810,11 @@ func (o *Op) Output() []byte {
570
810
return []byte {byte (o .Op )}
571
811
}
572
812
813
+ // StackEffect
814
+ func (o * Op ) StackEffect () int {
815
+ return opcodeStackEffect (o .Op , 0 )
816
+ }
817
+
573
818
// An opcode with argument
574
819
type OpArg struct {
575
820
pos
@@ -595,6 +840,11 @@ func (o *OpArg) Output() []byte {
595
840
return out
596
841
}
597
842
843
+ // StackEffect
844
+ func (o * OpArg ) StackEffect () int {
845
+ return opcodeStackEffect (o .Op , o .Arg )
846
+ }
847
+
598
848
// A label
599
849
type Label struct {
600
850
pos
@@ -610,6 +860,11 @@ func (o Label) Output() []byte {
610
860
return []byte {}
611
861
}
612
862
863
+ // StackEffect
864
+ func (o * Label ) StackEffect () int {
865
+ return 0
866
+ }
867
+
613
868
// An absolute JUMP with destination label
614
869
type JumpAbs struct {
615
870
pos
0 commit comments