Python 3 needs Python2's RETURN_END_IF

Make python2 and python3 scanner look more the same
This commit is contained in:
rocky
2016-06-20 22:05:59 -04:00
parent a6fbe4c636
commit 1a83c849dc
5 changed files with 40 additions and 26 deletions

Binary file not shown.

View File

@@ -115,7 +115,7 @@ class Python3Parser(PythonParser):
return_if_stmts ::= return_if_stmt come_from_opt return_if_stmts ::= return_if_stmt come_from_opt
return_if_stmts ::= _stmts return_if_stmt return_if_stmts ::= _stmts return_if_stmt
return_if_stmt ::= ret_expr RETURN_VALUE return_if_stmt ::= ret_expr RETURN_END_IF
stmt ::= break_stmt stmt ::= break_stmt
break_stmt ::= BREAK_LOOP break_stmt ::= BREAK_LOOP

View File

@@ -272,6 +272,9 @@ class Scanner(object):
target = parent['end'] target = parent['end']
return target return target
def parse_fn_counts(argc):
return ((argc & 0xFF), (argc >> 8) & 0xFF, (argc >> 16) & 0x7FFF)
def get_scanner(version, show_asm=None): def get_scanner(version, show_asm=None):
# Pick up appropriate scanner # Pick up appropriate scanner
if version in PYTHON_VERSIONS: if version in PYTHON_VERSIONS:

View File

@@ -127,7 +127,7 @@ class Scanner2(scan.Scanner):
k += 1 k += 1
op = self.code[offset] op = self.code[offset]
op_name = self.opc.opname[op] opname = self.opc.opname[op]
oparg = None; pattr = None oparg = None; pattr = None
if op >= self.opc.HAVE_ARGUMENT: if op >= self.opc.HAVE_ARGUMENT:
@@ -141,14 +141,14 @@ class Scanner2(scan.Scanner):
if iscode(const): if iscode(const):
oparg = const oparg = const
if const.co_name == '<lambda>': if const.co_name == '<lambda>':
assert op_name == 'LOAD_CONST' assert opname == 'LOAD_CONST'
op_name = 'LOAD_LAMBDA' opname = 'LOAD_LAMBDA'
elif const.co_name == '<genexpr>': elif const.co_name == '<genexpr>':
op_name = 'LOAD_GENEXPR' opname = 'LOAD_GENEXPR'
elif const.co_name == '<dictcomp>': elif const.co_name == '<dictcomp>':
op_name = 'LOAD_DICTCOMP' opname = 'LOAD_DICTCOMP'
elif const.co_name == '<setcomp>': elif const.co_name == '<setcomp>':
op_name = 'LOAD_SETCOMP' opname = 'LOAD_SETCOMP'
# verify() uses 'pattr' for comparison, since 'attr' # verify() uses 'pattr' for comparison, since 'attr'
# now holds Code(const) and thus can not be used # now holds Code(const) and thus can not be used
# for comparison (todo: think about changing this) # for comparison (todo: think about changing this)
@@ -178,24 +178,24 @@ class Scanner2(scan.Scanner):
self.code[self.prev[offset]] == self.opc.LOAD_CLOSURE: self.code[self.prev[offset]] == self.opc.LOAD_CLOSURE:
continue continue
else: else:
op_name = '%s_%d' % (op_name, oparg) opname = '%s_%d' % (opname, oparg)
if op != self.opc.BUILD_SLICE: if op != self.opc.BUILD_SLICE:
customize[op_name] = oparg customize[opname] = oparg
elif op == self.opc.JA: elif op == self.opc.JA:
target = self.get_target(offset) target = self.get_target(offset)
if target < offset: if target < offset:
if offset in self.stmts and self.code[offset+3] not in (self.opc.END_FINALLY, self.opc.POP_BLOCK) \ if offset in self.stmts and self.code[offset+3] not in (self.opc.END_FINALLY, self.opc.POP_BLOCK) \
and offset not in self.not_continue: and offset not in self.not_continue:
op_name = 'CONTINUE' opname = 'CONTINUE'
else: else:
op_name = 'JUMP_BACK' opname = 'JUMP_BACK'
elif op == self.opc.LOAD_GLOBAL: elif op == self.opc.LOAD_GLOBAL:
if offset in self.load_asserts: if offset in self.load_asserts:
op_name = 'LOAD_ASSERT' opname = 'LOAD_ASSERT'
elif op == self.opc.RETURN_VALUE: elif op == self.opc.RETURN_VALUE:
if offset in self.return_end_ifs: if offset in self.return_end_ifs:
op_name = 'RETURN_END_IF' opname = 'RETURN_END_IF'
if offset in self.linestartoffsets: if offset in self.linestartoffsets:
linestart = self.linestartoffsets[offset] linestart = self.linestartoffsets[offset]
@@ -203,7 +203,7 @@ class Scanner2(scan.Scanner):
linestart = None linestart = None
if offset not in replace: if offset not in replace:
tokens.append(Token(op_name, oparg, pattr, offset, linestart)) tokens.append(Token(opname, oparg, pattr, offset, linestart))
else: else:
tokens.append(Token(replace[offset], oparg, pattr, offset, linestart)) tokens.append(Token(replace[offset], oparg, pattr, offset, linestart))
pass pass
@@ -507,11 +507,15 @@ class Scanner2(scan.Scanner):
rtarget = self.restrict_to_parent(target, parent) rtarget = self.restrict_to_parent(target, parent)
pre = self.prev pre = self.prev
# Do not let jump to go out of parent struct bounds
if target != rtarget and parent['type'] == 'and/or': if target != rtarget and parent['type'] == 'and/or':
self.fixed_jumps[pos] = rtarget self.fixed_jumps[pos] = rtarget
return return
# does this jump to right after another cond jump?
# if so, it's part of a larger conditional # Does this jump to right after another cond jump that is
# not myself? If so, it's part of a larger conditional.
# rocky: if we have a conditional jump to the next instruction, then
# possibly I am "skipping over" a "pass" or null statement.
if (code[pre[target]] in (self.opc.JUMP_IF_FALSE_OR_POP, if (code[pre[target]] in (self.opc.JUMP_IF_FALSE_OR_POP,
self.opc.JUMP_IF_TRUE_OR_POP, self.opc.JUMP_IF_TRUE_OR_POP,
self.opc.PJIF, self.opc.PJIT)) and (target > pos): self.opc.PJIF, self.opc.PJIT)) and (target > pos):
@@ -521,11 +525,15 @@ class Scanner2(scan.Scanner):
'end': pre[target]}) 'end': pre[target]})
return return
# is this an if and # Is it an "and" inside an "if" block
if op == self.opc.PJIF: if op == self.opc.PJIF:
# Search for other POP_JUMP_IF_FALSE targetting the same op,
# in current statement, starting from current offset, and filter
# everything inside inner 'or' jumps and midline ifs
match = self.rem_or(start, self.next_stmt[pos], self.opc.PJIF, target) match = self.rem_or(start, self.next_stmt[pos], self.opc.PJIF, target)
match = self.remove_mid_line_ifs(match) match = self.remove_mid_line_ifs(match)
# If we still have any offsets in set, start working on it
if match: if match:
if code[pre[rtarget]] in self.jump_forward \ if code[pre[rtarget]] in self.jump_forward \
and pre[rtarget] not in self.stmts \ and pre[rtarget] not in self.stmts \
@@ -598,11 +606,12 @@ class Scanner2(scan.Scanner):
rtarget = pre[rtarget] rtarget = pre[rtarget]
else: else:
rtarget = pre[rtarget] rtarget = pre[rtarget]
# does the if jump just beyond a jump op, then this is probably an if statement
# Does the "if" jump just beyond a jump op, then this is probably an if statement
if code[pre[rtarget]] in self.jump_forward: if code[pre[rtarget]] in self.jump_forward:
if_end = self.get_target(pre[rtarget]) if_end = self.get_target(pre[rtarget])
# is this a loop not an if? # Is this a loop and not an "if" statment?
if (if_end < pre[rtarget]) and (code[pre[if_end]] == self.opc.SETUP_LOOP): if (if_end < pre[rtarget]) and (code[pre[if_end]] == self.opc.SETUP_LOOP):
if(if_end > start): if(if_end > start):
return return

View File

@@ -27,7 +27,7 @@ from array import array
from xdis.code import iscode from xdis.code import iscode
from xdis.bytecode import Bytecode, findlinestarts from xdis.bytecode import Bytecode, findlinestarts
from uncompyle6.scanner import Token from uncompyle6.scanner import Token, parse_fn_counts
# Get all the opcodes into globals # Get all the opcodes into globals
import xdis.opcodes.opcode_33 as op3 import xdis.opcodes.opcode_33 as op3
@@ -129,9 +129,7 @@ class Scanner3(scan.Scanner):
pattr = const pattr = const
pass pass
elif opname in ('MAKE_FUNCTION', 'MAKE_CLOSURE'): elif opname in ('MAKE_FUNCTION', 'MAKE_CLOSURE'):
argc = inst.argval pos_args, name_pair_args, annotate_args = parse_fn_counts(inst.argval)
attr = ((argc & 0xFF), (argc >> 8) & 0xFF, (argc >> 16) & 0x7FFF)
pos_args, name_pair_args, annotate_args = attr
if name_pair_args > 0: if name_pair_args > 0:
opname = '%s_N%d' % (opname, name_pair_args) opname = '%s_N%d' % (opname, name_pair_args)
pass pass
@@ -176,6 +174,9 @@ class Scanner3(scan.Scanner):
else: else:
opname = 'JUMP_BACK' opname = 'JUMP_BACK'
elif opname == 'RETURN_VALUE':
if inst.offset in self.return_end_ifs:
opname = 'RETURN_END_IF'
elif inst.offset in self.load_asserts: elif inst.offset in self.load_asserts:
opname = 'LOAD_ASSERT' opname = 'LOAD_ASSERT'
@@ -517,13 +518,14 @@ class Scanner3(scan.Scanner):
'end': prev_op[target]}) 'end': prev_op[target]})
return return
# Is it an and inside if block # Is it an "and" inside an "if" block
if op == POP_JUMP_IF_FALSE: if op == POP_JUMP_IF_FALSE:
# Search for other POP_JUMP_IF_FALSE targetting the same op, # Search for other POP_JUMP_IF_FALSE targetting the same op,
# in current statement, starting from current offset, and filter # in current statement, starting from current offset, and filter
# everything inside inner 'or' jumps and midline ifs # everything inside inner 'or' jumps and midline ifs
match = self.rem_or(start, self.next_stmt[offset], POP_JUMP_IF_FALSE, target) match = self.rem_or(start, self.next_stmt[offset], POP_JUMP_IF_FALSE, target)
match = self.remove_mid_line_ifs(match) match = self.remove_mid_line_ifs(match)
# If we still have any offsets in set, start working on it # If we still have any offsets in set, start working on it
if match: if match:
if (code[prev_op[rtarget]] in (JUMP_FORWARD, JUMP_ABSOLUTE) and prev_op[rtarget] not in self.stmts and if (code[prev_op[rtarget]] in (JUMP_FORWARD, JUMP_ABSOLUTE) and prev_op[rtarget] not in self.stmts and
@@ -580,11 +582,11 @@ class Scanner3(scan.Scanner):
not (code[rtarget] == JUMP_ABSOLUTE and code[rtarget+3] == POP_BLOCK and code[prev_op[prev_op[rtarget]]] != JUMP_ABSOLUTE)): not (code[rtarget] == JUMP_ABSOLUTE and code[rtarget+3] == POP_BLOCK and code[prev_op[prev_op[rtarget]]] != JUMP_ABSOLUTE)):
rtarget = prev_op[rtarget] rtarget = prev_op[rtarget]
# Does the if jump just beyond a jump op, then this is probably an if statement # Does the "if" jump just beyond a jump op, then this is probably an if statement
if code[prev_op[rtarget]] in (JUMP_ABSOLUTE, JUMP_FORWARD): if code[prev_op[rtarget]] in (JUMP_ABSOLUTE, JUMP_FORWARD):
if_end = self.get_target(prev_op[rtarget]) if_end = self.get_target(prev_op[rtarget])
# Is this a loop not an if? # Is this a loop and not an "if" statement?
if (if_end < prev_op[rtarget]) and (code[prev_op[if_end]] == SETUP_LOOP): if (if_end < prev_op[rtarget]) and (code[prev_op[if_end]] == SETUP_LOOP):
if(if_end > start): if(if_end > start):
return return