diff --git a/uncompyle6/scanner.py b/uncompyle6/scanner.py index 09d5999f..e00531f6 100755 --- a/uncompyle6/scanner.py +++ b/uncompyle6/scanner.py @@ -244,17 +244,57 @@ class Scanner(object): pass return result_offset - def all_instr(self, start, end, instr, target=None, include_beyond_target=False): + def inst_matches(self, start, end, instr, target=None, include_beyond_target=False): """ - Find all in the block from start to end. - is any python bytecode instruction or a list of opcodes - If is an opcode with a target (like a jump), a target + Find all `instr` in the block from start to end. + `instr` is a Python opcode or a list of opcodes + If `instr` is an opcode with a target (like a jump), a target destination can be specified which must match precisely. Return a list with indexes to them or [] if none found. """ + try: + None in instr + except: + instr = [instr] - # FIXME: this is broken on 3.6+. Revise to use instructions self.insts + first = self.offset2inst_index[start] + result = [] + for inst in self.insts[first:]: + if inst.opcode in instr: + if target is None: + result.append(inst.offset) + else: + t = self.get_target(inst.offset) + if include_beyond_target and t >= target: + result.append(inst.offset) + elif t == target: + result.append(inst.offset) + pass + pass + pass + if inst.offset >= end: + break + pass + + # FIXME: put in a test + # check = self.all_instr(start, end, instr, target, include_beyond_target) + # assert result == check + + return result + + + # FIXME: this is broken on 3.6+. Replace remaining (2.x-based) calls + # with inst_matches + def all_instr(self, start, end, instr, target=None, include_beyond_target=False): + """ + Find all `instr` in the block from start to end. + `instr` is any Python opcode or a list of opcodes + If `instr` is an opcode with a target (like a jump), a target + destination can be specified which must match precisely. + + Return a list with indexes to them or [] if none found. + """ code = self.code assert(start >= 0 and end <= len(code)) diff --git a/uncompyle6/scanners/scanner2.py b/uncompyle6/scanners/scanner2.py index ae1f4c13..3bf56628 100644 --- a/uncompyle6/scanners/scanner2.py +++ b/uncompyle6/scanners/scanner2.py @@ -416,7 +416,7 @@ class Scanner2(Scanner): (self.opc.PJIT, self.opc.JUMP_FORWARD), (self.opc.PJIT, self.opc.JUMP_ABSOLUTE)]) - prelim = self.all_instr(start, end, self.stmt_opcodes) + prelim = self.all_instr(start, end, self.statement_opcodes) stmts = self.stmts = set(prelim) pass_stmts = set() diff --git a/uncompyle6/scanners/scanner26.py b/uncompyle6/scanners/scanner26.py index 834fb3db..a494639f 100755 --- a/uncompyle6/scanners/scanner26.py +++ b/uncompyle6/scanners/scanner26.py @@ -40,7 +40,7 @@ JUMP_OPS = opcode_26.JUMP_OPS class Scanner26(scan.Scanner2): def __init__(self, show_asm=False): super(Scanner26, self).__init__(2.6, show_asm) - self.stmt_opcodes = frozenset([ + self.statement_opcodes = frozenset([ self.opc.SETUP_LOOP, self.opc.BREAK_LOOP, self.opc.SETUP_FINALLY, self.opc.END_FINALLY, self.opc.SETUP_EXCEPT, self.opc.POP_BLOCK, diff --git a/uncompyle6/scanners/scanner27.py b/uncompyle6/scanners/scanner27.py index ee571067..0ef2329b 100755 --- a/uncompyle6/scanners/scanner27.py +++ b/uncompyle6/scanners/scanner27.py @@ -25,7 +25,7 @@ class Scanner27(Scanner2): super(Scanner27, self).__init__(2.7, show_asm, is_pypy) # opcodes that start statements - self.stmt_opcodes = frozenset([ + self.statement_opcodes = frozenset([ self.opc.SETUP_LOOP, self.opc.BREAK_LOOP, self.opc.SETUP_FINALLY, self.opc.END_FINALLY, self.opc.SETUP_EXCEPT, diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 7c03618a..2ad67de8 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -428,6 +428,7 @@ class Scanner3(Scanner): .opname == 'FOR_ITER' and self.insts[i+1].opname == 'JUMP_FORWARD') + if (is_continue or (inst.offset in self.stmts and (self.version != 3.0 or (hasattr(inst, 'linestart'))) and @@ -610,7 +611,7 @@ class Scanner3(Scanner): # Compose preliminary list of indices with statements, # using plain statement opcodes - prelim = self.all_instr(start, end, self.statement_opcodes) + prelim = self.inst_matches(start, end, self.statement_opcodes) # Initialize final container with statements with # preliminary data @@ -873,11 +874,12 @@ class Scanner3(Scanner): pass else: fix = None - jump_ifs = self.all_instr(start, self.next_stmt[offset], - self.opc.POP_JUMP_IF_FALSE) + jump_ifs = self.inst_matches(start, self.next_stmt[offset], + self.opc.POP_JUMP_IF_FALSE) last_jump_good = True for j in jump_ifs: if target == self.get_target(j): + # FIXME: remove magic number if self.lines[j].next == j + 3 and last_jump_good: fix = j break @@ -1139,13 +1141,14 @@ class Scanner3(Scanner): assert(start>=0 and end<=len(self.code) and start <= end) # Find all offsets of requested instructions - instr_offsets = self.all_instr(start, end, instr, target, include_beyond_target) + instr_offsets = self.inst_matches(start, end, instr, target, + include_beyond_target) # Get all POP_JUMP_IF_TRUE (or) offsets if self.version == 3.0: jump_true_op = self.opc.JUMP_IF_TRUE else: jump_true_op = self.opc.POP_JUMP_IF_TRUE - pjit_offsets = self.all_instr(start, end, jump_true_op) + pjit_offsets = self.inst_matches(start, end, jump_true_op) filtered = [] for pjit_offset in pjit_offsets: pjit_tgt = self.get_target(pjit_offset) - 3 diff --git a/uncompyle6/scanners/scanner30.py b/uncompyle6/scanners/scanner30.py index 8d8efffb..0d1691a4 100644 --- a/uncompyle6/scanners/scanner30.py +++ b/uncompyle6/scanners/scanner30.py @@ -195,11 +195,12 @@ class Scanner30(Scanner3): pass else: fix = None - jump_ifs = self.all_instr(start, self.next_stmt[offset], - opc.JUMP_IF_FALSE) + jump_ifs = self.inst_matches(start, self.next_stmt[offset], + opc.JUMP_IF_FALSE) last_jump_good = True for j in jump_ifs: if target == self.get_target(j): + # FIXME: remove magic number if self.lines[j].next == j + 3 and last_jump_good: fix = j break