@@ -148,7 +148,7 @@ def ingest(self, co, classname=None, code_objects={}, show_asm=None):
148148 """
149149
150150 show_asm = self .show_asm if not show_asm else show_asm
151- # show_asm = 'after '
151+ # show_asm = 'both '
152152 if show_asm in ('both' , 'before' ):
153153 bytecode = Bytecode (co , self .opc )
154154 for instr in bytecode .get_instructions (co ):
@@ -600,7 +600,6 @@ def detect_structure(self, offset, targets):
600600 parent = struct
601601
602602 if op == self .opc .SETUP_LOOP :
603-
604603 # We categorize loop types: 'for', 'while', 'while 1' with
605604 # possibly suffixes '-loop' and '-else'
606605 # Try to find the jump_back instruction of the loop.
@@ -618,20 +617,30 @@ def detect_structure(self, offset, targets):
618617 jump_back = self .last_instr (start , end , self .opc .JUMP_ABSOLUTE ,
619618 next_line_byte , False )
620619
621- if jump_back and jump_back != self .prev_op [end ] and self .is_jump_forward (jump_back + 3 ):
622- if (code [self .prev_op [end ]] == self .opc .RETURN_VALUE
623- or (code [self .prev_op [end ]] == self .opc .POP_BLOCK
624- and code [self .prev_op [self .prev_op [end ]]] == self .opc .RETURN_VALUE )):
620+ jump_forward_offset = jump_back + 3
621+ return_val_offset1 = self .prev [self .prev [end ]]
622+
623+ if (jump_back and jump_back != self .prev_op [end ]
624+ and self .is_jump_forward (jump_forward_offset )):
625+ if (code [self .prev_op [end ]] == self .opc .RETURN_VALUE or
626+ (code [self .prev_op [end ]] == self .opc .POP_BLOCK
627+ and code [return_val_offset1 ] == self .opc .RETURN_VALUE )):
625628 jump_back = None
626- if not jump_back : # loop suite ends in return. wtf right?
629+ if not jump_back :
630+ # loop suite ends in return
627631 jump_back = self .last_instr (start , end , self .opc .RETURN_VALUE ) + 1
628632 if not jump_back :
629633 return
634+
635+ jump_back += 1
636+ if_offset = None
630637 if code [self .prev_op [next_line_byte ]] not in POP_JUMP_TF :
631- loop_type = 'for'
632- else :
638+ if_offset = self . prev [ next_line_byte ]
639+ if if_offset :
633640 loop_type = 'while'
634- self .ignore_if .add (self .prev_op [next_line_byte ])
641+ self .ignore_if .add (if_offset )
642+ else :
643+ loop_type = 'for'
635644 target = next_line_byte
636645 end = jump_back + 3
637646 else :
@@ -645,13 +654,15 @@ def detect_structure(self, offset, targets):
645654 elif target < offset :
646655 self .fixed_jumps [offset ] = jump_back + 4
647656 end = jump_back + 4
657+
648658 target = self .get_target (jump_back )
649659
650660 if code [target ] in (self .opc .FOR_ITER , self .opc .GET_ITER ):
651661 loop_type = 'for'
652662 else :
653663 loop_type = 'while'
654664 test = self .prev_op [next_line_byte ]
665+
655666 if test == offset :
656667 loop_type = 'while 1'
657668 elif self .code [test ] in op3 .hasjabs + op3 .hasjrel :
@@ -764,14 +775,15 @@ def detect_structure(self, offset, targets):
764775 if offset in self .ignore_if :
765776 return
766777
767- if (code [prev_op [rtarget ]] == self .opc .JUMP_ABSOLUTE and
768- prev_op [rtarget ] in self .stmts and
769- prev_op [rtarget ] != offset and
770- prev_op [prev_op [rtarget ]] != offset and
778+ rrtarget = prev_op [rtarget ]
779+ if (code [rrtarget ] == self .opc .JUMP_ABSOLUTE and
780+ rrtarget in self .stmts and
781+ rrtarget != offset and
782+ prev_op [rrtarget ] != offset and
771783 not (code [rtarget ] == self .opc .JUMP_ABSOLUTE and
772784 code [rtarget + 3 ] == self .opc .POP_BLOCK and
773- code [prev_op [prev_op [ rtarget ] ]] != self .opc .JUMP_ABSOLUTE )):
774- rtarget = prev_op [ rtarget ]
785+ code [prev_op [rrtarget ]] != self .opc .JUMP_ABSOLUTE )):
786+ rtarget = rrtarget
775787
776788 # Does the "jump if" jump beyond a jump op?
777789 # That is, we have something like:
@@ -787,8 +799,7 @@ def detect_structure(self, offset, targets):
787799 # There are other contexts we may need to consider
788800 # like whether the target is "END_FINALLY"
789801 # or if the condition jump is to a forward location
790- if self .is_jump_forward (prev_op [rtarget ]):
791- rrtarget = prev_op [rtarget ]
802+ if self .is_jump_forward (rrtarget ):
792803 if_end = self .get_target (rrtarget )
793804
794805 # If the jump target is back, we are looping
@@ -813,7 +824,13 @@ def detect_structure(self, offset, targets):
813824 'start' : rtarget ,
814825 'end' : end })
815826 self .else_start [rtarget ] = end
816- elif code [prev_op [rtarget ]] == self .opc .RETURN_VALUE :
827+ elif self .is_jump_back (rrtarget ):
828+ if_end = rtarget
829+ self .structs .append ({'type' : 'if-then' ,
830+ 'start' : start ,
831+ 'end' : rrtarget })
832+ self .not_continue .add (prev_op [rtarget ])
833+ elif code [rrtarget ] == self .opc .RETURN_VALUE :
817834 self .structs .append ({'type' : 'if-then' ,
818835 'start' : start ,
819836 'end' : rtarget })
@@ -882,6 +899,16 @@ def detect_structure(self, offset, targets):
882899 pass
883900 return
884901
902+ def is_jump_back (self , offset ):
903+ """
904+ Return True if the code at offset is some sort of jump back.
905+ That is, it is ether "JUMP_FORWARD" or an absolute jump that
906+ goes forward.
907+ """
908+ if self .code [offset ] != self .opc .JUMP_ABSOLUTE :
909+ return False
910+ return offset > self .get_target (offset )
911+
885912 def next_except_jump (self , start ):
886913 """
887914 Return the next jump that was generated by an except SomeException:
0 commit comments