55import types
66import sys
77
8- from typing import Any
8+ from typing import Any , List
99from compiler import misc
1010from compiler .consts \
1111 import CO_OPTIMIZED , CO_NEWLOCALS , CO_VARARGS , CO_VARKEYWORDS
@@ -375,9 +375,8 @@ def dump(self, io=None):
375375 if io :
376376 sys .stdout = save
377377
378- def stackdepth_walk (self , block , depth , maxdepth ):
378+ def stackdepth_walk (self , block , depth = 0 , maxdepth = 0 ):
379379 assert block is not None
380-
381380 if block .seen or block .startdepth >= depth :
382381 return maxdepth
383382 block .seen = True
@@ -428,7 +427,7 @@ def computeStackDepth(self):
428427 for block in self .getBlocksInOrder ():
429428 # We need to get to the first block which actually has instructions
430429 if block .getInstructions ():
431- self .stacksize = self .stackdepth_walk (block , 0 , 0 )
430+ self .stacksize = self .stackdepth_walk (block )
432431 break
433432
434433 def flattenGraph (self ):
@@ -664,6 +663,79 @@ def getConsts(self):
664663 return tuple (const [1 ] for const in self .consts )
665664
666665
666+ class PyFlowGraph37 (PyFlowGraph ):
667+ def push_block (self , worklist : List [Block ], block : Block , depth : int ):
668+ assert block .startdepth < 0 or block .startdepth >= depth , f"{ block !r} : { block .startdepth } vs { depth } "
669+ if block .startdepth < depth :
670+ block .startdepth = depth
671+ worklist .append (block )
672+
673+ def stackdepth_walk (self , block ):
674+ maxdepth = 0
675+ worklist = []
676+ self .push_block (worklist , block , 0 )
677+ while worklist :
678+ block = worklist .pop ()
679+ next = block .next
680+ depth = block .startdepth
681+ assert depth >= 0
682+
683+ for instr in block .getInstructions ():
684+ if instr .opname == "SET_LINENO" :
685+ continue
686+
687+ effect = STACK_EFFECTS_37 .get (instr .opname )
688+ if effect is None :
689+ raise ValueError (f"Error, opcode { instr .opname } was not found, please update STACK_EFFECTS" )
690+ if isinstance (effect , int ):
691+ delta = effect
692+ else :
693+ delta = effect (instr .oparg , 0 )
694+
695+ new_depth = depth + delta
696+ if new_depth > maxdepth :
697+ maxdepth = new_depth
698+
699+ assert depth >= 0
700+
701+ opcode = OPMAP [instr .opname ]
702+ if opcode in dis .hasjabs or opcode in dis .hasjrel :
703+ if isinstance (effect , int ):
704+ delta = effect
705+ else :
706+ delta = effect (instr .oparg , 1 )
707+
708+ target_depth = depth + delta
709+ if target_depth > maxdepth :
710+ maxdepth = target_depth
711+
712+ assert target_depth >= 0
713+ if instr .opname == "CONTINUE_LOOP" :
714+ # Pops a variable number of values from the stack,
715+ # but the target should be already proceeding.
716+ assert instr .target .startdepth >= 0
717+ assert instr .target .startdepth <= depth
718+ # remaining code is dead
719+ next = None
720+ break
721+
722+ self .push_block (worklist , instr .target , target_depth )
723+
724+ depth = new_depth
725+
726+ if instr .opname in ("JUMP_ABSOLUTE" , "JUMP_FORWARD" , "RETURN_VALUE" , "RAISE_VARARGS" , "BREAK_LOOP" ):
727+ # Remaining code is dead
728+ next = None
729+ break
730+
731+ # TODO(dinoviehland): we could save the delta we came up with here and
732+ # reapply it on subsequent walks rather than having to walk all of the
733+ # instructions again.
734+ if next :
735+ self .push_block (worklist , next , depth )
736+
737+ return maxdepth
738+
667739class LineAddrTable :
668740 """lnotab
669741
@@ -808,8 +880,8 @@ def getTable(self):
808880
809881 STORE_NAME = - 1 ,
810882 DELETE_NAME = 0 ,
811- UNPACK_SEQUENCE = lambda oparg : oparg - 1 ,
812- UNPACK_EX = lambda oparg : (oparg & 0xFF ) + (oparg >> 8 ),
883+ UNPACK_SEQUENCE = lambda oparg , jmp = 0 : oparg - 1 ,
884+ UNPACK_EX = lambda oparg , jmp = 0 : (oparg & 0xFF ) + (oparg >> 8 ),
813885 FOR_ITER = 1 , # or -1, at end of iterator
814886
815887 STORE_ATTR = - 2 ,
@@ -819,20 +891,20 @@ def getTable(self):
819891 LOAD_CONST = 1 ,
820892 LOAD_NAME = 1 ,
821893
822- BUILD_TUPLE = lambda oparg : 1 - oparg ,
823- BUILD_LIST = lambda oparg : 1 - oparg ,
824- BUILD_SET = lambda oparg : 1 - oparg ,
825- BUILD_STRING = lambda oparg : 1 - oparg ,
894+ BUILD_TUPLE = lambda oparg , jmp = 0 : 1 - oparg ,
895+ BUILD_LIST = lambda oparg , jmp = 0 : 1 - oparg ,
896+ BUILD_SET = lambda oparg , jmp = 0 : 1 - oparg ,
897+ BUILD_STRING = lambda oparg , jmp = 0 : 1 - oparg ,
826898
827- BUILD_LIST_UNPACK = lambda oparg : 1 - oparg ,
828- BUILD_TUPLE_UNPACK = lambda oparg : 1 - oparg ,
829- BUILD_TUPLE_UNPACK_WITH_CALL = lambda oparg : 1 - oparg ,
830- BUILD_SET_UNPACK = lambda oparg : 1 - oparg ,
831- BUILD_MAP_UNPACK = lambda oparg : 1 - oparg ,
832- BUILD_MAP_UNPACK_WITH_CALL = lambda oparg : 1 - oparg ,
899+ BUILD_LIST_UNPACK = lambda oparg , jmp = 0 : 1 - oparg ,
900+ BUILD_TUPLE_UNPACK = lambda oparg , jmp = 0 : 1 - oparg ,
901+ BUILD_TUPLE_UNPACK_WITH_CALL = lambda oparg , jmp = 0 : 1 - oparg ,
902+ BUILD_SET_UNPACK = lambda oparg , jmp = 0 : 1 - oparg ,
903+ BUILD_MAP_UNPACK = lambda oparg , jmp = 0 : 1 - oparg ,
904+ BUILD_MAP_UNPACK_WITH_CALL = lambda oparg , jmp = 0 : 1 - oparg ,
833905
834- BUILD_MAP = lambda oparg : 1 - 2 * oparg ,
835- BUILD_CONST_KEY_MAP = lambda oparg : - oparg ,
906+ BUILD_MAP = lambda oparg , jmp = 0 : 1 - 2 * oparg ,
907+ BUILD_CONST_KEY_MAP = lambda oparg , jmp = 0 : - oparg ,
836908 LOAD_ATTR = 0 ,
837909 COMPARE_OP = - 1 ,
838910 IMPORT_NAME = - 1 ,
@@ -860,12 +932,12 @@ def getTable(self):
860932 DELETE_FAST = 0 ,
861933 STORE_ANNOTATION = - 1 ,
862934
863- RAISE_VARARGS = lambda oparg : - oparg ,
864- CALL_FUNCTION = lambda oparg : - oparg ,
865- CALL_FUNCTION_KW = lambda oparg : - oparg - 1 ,
866- CALL_FUNCTION_EX = lambda oparg : - 1 - ((oparg & 0x01 ) != 0 ),
867- MAKE_FUNCTION = lambda oparg : - 1 - ((oparg & 0x01 ) != 0 ) - ((oparg & 0x02 ) != 0 ) - ((oparg & 0x04 ) != 0 ) - ((oparg & 0x08 ) != 0 ),
868- BUILD_SLICE = lambda oparg : - 2 if oparg == 3 else - 1 ,
935+ RAISE_VARARGS = lambda oparg , jmp = 0 : - oparg ,
936+ CALL_FUNCTION = lambda oparg , jmp = 0 : - oparg ,
937+ CALL_FUNCTION_KW = lambda oparg , jmp = 0 : - oparg - 1 ,
938+ CALL_FUNCTION_EX = lambda oparg , jmp = 0 : - 1 - ((oparg & 0x01 ) != 0 ),
939+ MAKE_FUNCTION = lambda oparg , jmp = 0 : - 1 - ((oparg & 0x01 ) != 0 ) - ((oparg & 0x02 ) != 0 ) - ((oparg & 0x04 ) != 0 ) - ((oparg & 0x08 ) != 0 ),
940+ BUILD_SLICE = lambda oparg , jmp = 0 : - 2 if oparg == 3 else - 1 ,
869941
870942 LOAD_CLOSURE = 1 ,
871943 LOAD_DEREF = 1 ,
@@ -880,8 +952,25 @@ def getTable(self):
880952 GET_YIELD_FROM_ITER = 0 ,
881953 # If there's a fmt_spec on the stack, we go from 2->1,
882954 # else 1->1.
883- FORMAT_VALUE = lambda oparg : - 1 if (oparg & FVS_MASK ) == FVS_HAVE_SPEC else 0 ,
955+ FORMAT_VALUE = lambda oparg , jmp = 0 : - 1 if (oparg & FVS_MASK ) == FVS_HAVE_SPEC else 0 ,
884956 SET_LINENO = 0 ,
885957 LOAD_METHOD = 1 ,
886- CALL_METHOD = lambda oparg : - oparg - 1 ,
958+ CALL_METHOD = lambda oparg , jmp = 0 : - oparg - 1 ,
959+ )
960+
961+ STACK_EFFECTS_37 = dict (
962+ STACK_EFFECTS ,
963+ SETUP_WITH = lambda oparg , jmp = 0 : 6 if jmp else 1 ,
964+ WITH_CLEANUP_START = 2 , # or 1, depending on TOS
965+ WITH_CLEANUP_FINISH = - 3 ,
966+ POP_EXCEPT = - 3 ,
967+ END_FINALLY = - 6 ,
968+ FOR_ITER = lambda oparg , jmp = 0 : - 1 if jmp > 0 else 1 ,
969+ JUMP_IF_TRUE_OR_POP = lambda oparg , jmp = 0 : 0 if jmp else - 1 ,
970+ JUMP_IF_FALSE_OR_POP = lambda oparg , jmp = 0 : 0 if jmp else - 1 ,
971+ SETUP_EXCEPT = lambda oparg , jmp : 6 if jmp else 0 ,
972+ SETUP_FINALLY = lambda oparg , jmp : 6 if jmp else 0 ,
973+ CALL_METHOD = lambda oparg , jmp : - oparg - 1 ,
974+ SETUP_ASYNC_WITH = lambda oparg , jmp : (- 1 + 6 ) if jmp else 0 ,
975+ LOAD_METHOD = 1 ,
887976)
0 commit comments