You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
Remove erroneously checked-in files
This commit is contained in:
@@ -1,219 +0,0 @@
|
|||||||
# Copyright (c) 2020 Rocky Bernstein
|
|
||||||
|
|
||||||
from uncompyle6.scanners.tok import Token
|
|
||||||
|
|
||||||
IFELSE_STMT_RULES = frozenset(
|
|
||||||
[
|
|
||||||
(
|
|
||||||
"ifelsestmt",
|
|
||||||
(
|
|
||||||
"testexpr",
|
|
||||||
"c_stmts_opt",
|
|
||||||
"jump_forward_else",
|
|
||||||
"else_suite",
|
|
||||||
"_come_froms",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"ifelsestmt",
|
|
||||||
(
|
|
||||||
"testexpr",
|
|
||||||
"c_stmts_opt",
|
|
||||||
"jump_forward_else",
|
|
||||||
"else_suite",
|
|
||||||
"\\e__come_froms",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"ifelsestmtl",
|
|
||||||
(
|
|
||||||
"testexpr",
|
|
||||||
"c_stmts_opt",
|
|
||||||
"jump_forward_else",
|
|
||||||
"else_suitec",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"ifelsestmtc",
|
|
||||||
(
|
|
||||||
"testexpr",
|
|
||||||
"c_stmts_opt",
|
|
||||||
"jump_forward_else",
|
|
||||||
"else_suitec",
|
|
||||||
"\\e__come_froms",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"ifelsestmtc",
|
|
||||||
(
|
|
||||||
"testexpr",
|
|
||||||
"c_stmts_opt",
|
|
||||||
"jump_absolute_else",
|
|
||||||
"else_suitec",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"ifelsestmt",
|
|
||||||
(
|
|
||||||
"testexpr",
|
|
||||||
"c_stmts_opt",
|
|
||||||
"jf_cfs",
|
|
||||||
"else_suite",
|
|
||||||
"\\e_opt_come_from_except",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"ifelsestmt",
|
|
||||||
(
|
|
||||||
"testexpr",
|
|
||||||
"c_stmts_opt",
|
|
||||||
"JUMP_FORWARD",
|
|
||||||
"else_suite",
|
|
||||||
"come_froms",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"ifelsestmt",
|
|
||||||
("testexpr", "c_stmts", "come_froms", "else_suite", "come_froms",),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"ifelsestmt",
|
|
||||||
(
|
|
||||||
"testexpr",
|
|
||||||
"c_stmts_opt",
|
|
||||||
"jf_cfs",
|
|
||||||
"else_suite",
|
|
||||||
"opt_come_from_except",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"ifelsestmt",
|
|
||||||
(
|
|
||||||
"testexpr",
|
|
||||||
"c_stmts_opt",
|
|
||||||
"jf_cf_pop",
|
|
||||||
"else_suite",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
])
|
|
||||||
|
|
||||||
def ifelsestmt(self, lhs, n, rule, ast, tokens, first, last):
|
|
||||||
|
|
||||||
if (last + 1) < n and tokens[last + 1] == "COME_FROM_LOOP" and lhs != "ifelsestmtc":
|
|
||||||
# ifelsestmt jumped outside of loop. No good.
|
|
||||||
return True
|
|
||||||
|
|
||||||
if not (rule[1][0] == "testexpr_then") and rule not in IFELSE_STMT_RULES:
|
|
||||||
# print("XXX", rule)
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Avoid if/else where the "then" is a "raise_stmt1" for an
|
|
||||||
# assert statemetn. Parse this as an "assert" instead.
|
|
||||||
stmts = ast[1]
|
|
||||||
if stmts in ("c_stmts",) and len(stmts) == 1:
|
|
||||||
raise_stmt1 = stmts[0]
|
|
||||||
if (
|
|
||||||
raise_stmt1 == "raise_stmt1" and
|
|
||||||
raise_stmt1[0] in ("LOAD_ASSERT",)
|
|
||||||
):
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Make sure all of the "come froms" offset at the
|
|
||||||
# end of the "if" come from somewhere inside the "if".
|
|
||||||
# Since the come_froms are ordered so that lowest
|
|
||||||
# offset COME_FROM is last, it is sufficient to test
|
|
||||||
# just the last one.
|
|
||||||
if len(ast) == 5:
|
|
||||||
end_come_froms = ast[-1]
|
|
||||||
if end_come_froms.kind != "else_suite" and self.version >= 3.0:
|
|
||||||
if end_come_froms == "opt_come_from_except" and len(end_come_froms) > 0:
|
|
||||||
end_come_froms = end_come_froms[0]
|
|
||||||
if not isinstance(end_come_froms, Token):
|
|
||||||
if len(end_come_froms):
|
|
||||||
return tokens[first].offset > end_come_froms[-1].attr
|
|
||||||
elif tokens[first].offset > end_come_froms.attr:
|
|
||||||
return True
|
|
||||||
|
|
||||||
# FIXME: There is weirdness in the grammar we need to work around.
|
|
||||||
# we need to clean up the grammar.
|
|
||||||
if self.version < 3.0:
|
|
||||||
last_token = ast[-1]
|
|
||||||
else:
|
|
||||||
last_token = tokens[last]
|
|
||||||
if last_token == "COME_FROM" and tokens[first].offset > last_token.attr:
|
|
||||||
if self.version < 3.0 and self.insts[self.offset2inst_index[last_token.attr]].opname != "SETUP_LOOP":
|
|
||||||
return True
|
|
||||||
|
|
||||||
testexpr = ast[0]
|
|
||||||
|
|
||||||
if rule[1][0] == "testexpr_then":
|
|
||||||
from trepan.api import debug; debug()
|
|
||||||
|
|
||||||
if_condition = testexpr[0]
|
|
||||||
# Check that the condition portion of the "if"
|
|
||||||
# jumps to the "else" part.
|
|
||||||
if if_condition in ("testtrue", "testfalse", "testfalse_then"):
|
|
||||||
|
|
||||||
else_suite = ast[3]
|
|
||||||
assert else_suite.kind.startswith("else_suite")
|
|
||||||
|
|
||||||
if len(if_condition) > 1 and if_condition[1].kind.startswith("jmp_"):
|
|
||||||
if last == n:
|
|
||||||
last -= 1
|
|
||||||
jmp = if_condition[1]
|
|
||||||
if self.version > 2.6:
|
|
||||||
jmp_target = jmp[0].attr
|
|
||||||
else:
|
|
||||||
jmp_target = int(jmp[0].pattr)
|
|
||||||
|
|
||||||
|
|
||||||
# Below we check that jmp_target is jumping to a feasible
|
|
||||||
# location. It should be to the transition after the "then"
|
|
||||||
# block and to the beginning of the "else" block.
|
|
||||||
# However the "if/else" is inside a loop the false test can be
|
|
||||||
# back to the loop.
|
|
||||||
|
|
||||||
# FIXME: the below logic for jf_cfs could probably be
|
|
||||||
# simplified.
|
|
||||||
jump_else_end = ast[2]
|
|
||||||
if jump_else_end == "filler":
|
|
||||||
jump_else_end = ast[3]
|
|
||||||
if jump_else_end == "jf_cf_pop":
|
|
||||||
jump_else_end = jump_else_end[0]
|
|
||||||
|
|
||||||
jump_to_jump = False
|
|
||||||
if jump_else_end == "JUMP_FORWARD":
|
|
||||||
jump_to_jump = True
|
|
||||||
endif_target = int(jump_else_end.pattr)
|
|
||||||
last_offset = tokens[last].off2int()
|
|
||||||
if endif_target != last_offset:
|
|
||||||
return True
|
|
||||||
last_offset = tokens[last].off2int(prefer_last=False)
|
|
||||||
if jmp_target == last_offset:
|
|
||||||
# jmp_target should be jumping to the end of the if/then/else
|
|
||||||
# but is it jumping to the beginning of the "else"
|
|
||||||
return True
|
|
||||||
if (
|
|
||||||
jump_else_end in ("jf_cfs", "jump_forward_else")
|
|
||||||
and jump_else_end[0] == "JUMP_FORWARD"
|
|
||||||
):
|
|
||||||
# If the "else" jump jumps before the end of the the "if .. else end", then this
|
|
||||||
# is not this kind of "ifelsestmt".
|
|
||||||
jump_else_forward = jump_else_end[0]
|
|
||||||
jump_else_forward_target = jump_else_forward.attr
|
|
||||||
if jump_else_forward_target < last_offset:
|
|
||||||
return True
|
|
||||||
pass
|
|
||||||
if (
|
|
||||||
jump_else_end in ("jb_elsec", "jb_elsel", "jf_cfs", "jb_cfs")
|
|
||||||
and jump_else_end[-1] == "COME_FROM"
|
|
||||||
):
|
|
||||||
if jump_else_end[-1].off2int() != jmp_target:
|
|
||||||
return True
|
|
||||||
|
|
||||||
if tokens[first].off2int() > jmp_target:
|
|
||||||
return True
|
|
||||||
|
|
||||||
return (jmp_target > last_offset) and tokens[last] != "JUMP_FORWARD"
|
|
||||||
|
|
||||||
return False
|
|
File diff suppressed because it is too large
Load Diff
@@ -1,454 +0,0 @@
|
|||||||
# Copyright (c) 2016, 2017 by Rocky Bernstein
|
|
||||||
"""
|
|
||||||
Python 3.0 bytecode scanner/deparser
|
|
||||||
|
|
||||||
This sets up opcodes Python's 3.0 and calls a generalized
|
|
||||||
scanner routine for Python 3.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
# bytecode verification, verify(), uses JUMP_OPs from here
|
|
||||||
from xdis.opcodes import opcode_30 as opc
|
|
||||||
from xdis.bytecode import instruction_size, next_offset
|
|
||||||
import xdis
|
|
||||||
|
|
||||||
JUMP_TF = frozenset([opc.JUMP_IF_FALSE, opc.JUMP_IF_TRUE])
|
|
||||||
|
|
||||||
from uncompyle6.scanners.scanner3 import Scanner3
|
|
||||||
class Scanner30(Scanner3):
|
|
||||||
|
|
||||||
def __init__(self, show_asm=None, is_pypy=False):
|
|
||||||
Scanner3.__init__(self, 3.0, show_asm, is_pypy)
|
|
||||||
self.thens = {} # JUMP_IF's that separate the 'then' part of an 'if'
|
|
||||||
return
|
|
||||||
pass
|
|
||||||
|
|
||||||
def detect_control_flow(self, offset, targets, inst_index):
|
|
||||||
"""
|
|
||||||
Detect structures and their boundaries to fix optimized jumps
|
|
||||||
Python 3.0 is more like Python 2.6 than it is Python 3.x.
|
|
||||||
So we have a special routine here.
|
|
||||||
"""
|
|
||||||
|
|
||||||
code = self.code
|
|
||||||
op = code[offset]
|
|
||||||
|
|
||||||
# Detect parent structure
|
|
||||||
parent = self.structs[0]
|
|
||||||
start = parent['start']
|
|
||||||
end = parent['end']
|
|
||||||
|
|
||||||
# Pick inner-most parent for our offset
|
|
||||||
for struct in self.structs:
|
|
||||||
current_start = struct['start']
|
|
||||||
current_end = struct['end']
|
|
||||||
if ((current_start <= offset < current_end)
|
|
||||||
and (current_start >= start and current_end <= end)):
|
|
||||||
start = current_start
|
|
||||||
end = current_end
|
|
||||||
parent = struct
|
|
||||||
|
|
||||||
if op == self.opc.SETUP_LOOP:
|
|
||||||
# We categorize loop types: 'for', 'while', 'while 1' with
|
|
||||||
# possibly suffixes '-loop' and '-else'
|
|
||||||
# Try to find the jump_back instruction of the loop.
|
|
||||||
# It could be a return instruction.
|
|
||||||
|
|
||||||
start += instruction_size(op, self.opc)
|
|
||||||
target = self.get_target(offset)
|
|
||||||
end = self.restrict_to_parent(target, parent)
|
|
||||||
self.setup_loop_targets[offset] = target
|
|
||||||
self.setup_loops[target] = offset
|
|
||||||
|
|
||||||
if target != end:
|
|
||||||
self.fixed_jumps[offset] = end
|
|
||||||
|
|
||||||
(line_no, next_line_byte) = self.lines[offset]
|
|
||||||
jump_back = self.last_instr(start, end, self.opc.JUMP_ABSOLUTE,
|
|
||||||
next_line_byte, False)
|
|
||||||
|
|
||||||
if jump_back:
|
|
||||||
jump_forward_offset = next_offset(code[jump_back], self.opc, jump_back)
|
|
||||||
else:
|
|
||||||
jump_forward_offset = None
|
|
||||||
|
|
||||||
return_val_offset1 = self.prev[self.prev[end]]
|
|
||||||
|
|
||||||
if (jump_back and jump_back != self.prev_op[end]
|
|
||||||
and self.is_jump_forward(jump_forward_offset)):
|
|
||||||
if (code[self.prev_op[end]] == self.opc.RETURN_VALUE or
|
|
||||||
(code[self.prev_op[end]] == self.opc.POP_BLOCK
|
|
||||||
and code[return_val_offset1] == self.opc.RETURN_VALUE)):
|
|
||||||
jump_back = None
|
|
||||||
if not jump_back:
|
|
||||||
# loop suite ends in return
|
|
||||||
jump_back = self.last_instr(start, end, self.opc.RETURN_VALUE)
|
|
||||||
if not jump_back:
|
|
||||||
return
|
|
||||||
|
|
||||||
jump_back += 2
|
|
||||||
if_offset = None
|
|
||||||
if code[self.prev_op[next_line_byte]] not in JUMP_TF:
|
|
||||||
if_offset = self.prev[next_line_byte]
|
|
||||||
if if_offset:
|
|
||||||
loop_type = 'while'
|
|
||||||
self.ignore_if.add(if_offset)
|
|
||||||
else:
|
|
||||||
loop_type = 'for'
|
|
||||||
target = next_line_byte
|
|
||||||
end = jump_back + 3
|
|
||||||
else:
|
|
||||||
if self.get_target(jump_back, 0) >= next_line_byte:
|
|
||||||
jump_back = self.last_instr(start, end, self.opc.JUMP_ABSOLUTE, start, False)
|
|
||||||
if end > jump_back+4 and self.is_jump_forward(end):
|
|
||||||
if self.is_jump_forward(jump_back+4):
|
|
||||||
if self.get_target(jump_back+4) == self.get_target(end):
|
|
||||||
self.fixed_jumps[offset] = jump_back+4
|
|
||||||
end = jump_back+4
|
|
||||||
elif target < offset:
|
|
||||||
self.fixed_jumps[offset] = jump_back+4
|
|
||||||
end = jump_back+4
|
|
||||||
|
|
||||||
target = self.get_target(jump_back, 0)
|
|
||||||
|
|
||||||
if code[target] in (self.opc.FOR_ITER, self.opc.GET_ITER):
|
|
||||||
loop_type = 'for'
|
|
||||||
else:
|
|
||||||
loop_type = 'while'
|
|
||||||
test = self.prev_op[next_line_byte]
|
|
||||||
|
|
||||||
if test == offset:
|
|
||||||
loop_type = 'while 1'
|
|
||||||
elif self.code[test] in self.opc.JUMP_OPs:
|
|
||||||
self.ignore_if.add(test)
|
|
||||||
test_target = self.get_target(test)
|
|
||||||
if test_target > (jump_back+3):
|
|
||||||
jump_back = test_target
|
|
||||||
self.not_continue.add(jump_back)
|
|
||||||
self.loops.append(target)
|
|
||||||
self.structs.append({'type': loop_type + '-loop',
|
|
||||||
'start': target,
|
|
||||||
'end': jump_back})
|
|
||||||
after_jump_offset = xdis.next_offset(code[jump_back], self.opc, jump_back)
|
|
||||||
if after_jump_offset != end:
|
|
||||||
self.structs.append({'type': loop_type + '-else',
|
|
||||||
'start': after_jump_offset,
|
|
||||||
'end': end})
|
|
||||||
elif op in self.pop_jump_tf:
|
|
||||||
start = offset + instruction_size(op, self.opc)
|
|
||||||
target = self.get_target(offset)
|
|
||||||
rtarget = self.restrict_to_parent(target, parent)
|
|
||||||
prev_op = self.prev_op
|
|
||||||
|
|
||||||
# Do not let jump to go out of parent struct bounds
|
|
||||||
if target != rtarget and parent['type'] == 'and/or':
|
|
||||||
self.fixed_jumps[offset] = rtarget
|
|
||||||
return
|
|
||||||
|
|
||||||
# Does this jump to right after another conditional 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[prev_op[target]] in self.pop_jump_if_pop) and
|
|
||||||
(target > offset) and prev_op[target] != offset):
|
|
||||||
self.fixed_jumps[offset] = prev_op[target]
|
|
||||||
self.structs.append({'type': 'and/or',
|
|
||||||
'start': start,
|
|
||||||
'end': prev_op[target]})
|
|
||||||
return
|
|
||||||
|
|
||||||
# The op offset just before the target jump offset is important
|
|
||||||
# in making a determination of what we have. Save that.
|
|
||||||
pre_rtarget = prev_op[rtarget]
|
|
||||||
|
|
||||||
# Is it an "and" inside an "if" or "while" block
|
|
||||||
if op == opc.JUMP_IF_FALSE:
|
|
||||||
|
|
||||||
# Search for another 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[offset],
|
|
||||||
opc.JUMP_IF_FALSE, target)
|
|
||||||
|
|
||||||
# If we still have any offsets in set, start working on it
|
|
||||||
if match:
|
|
||||||
is_jump_forward = self.is_jump_forward(pre_rtarget)
|
|
||||||
if (is_jump_forward and pre_rtarget not in self.stmts and
|
|
||||||
self.restrict_to_parent(self.get_target(pre_rtarget), parent) == rtarget):
|
|
||||||
if (code[prev_op[pre_rtarget]] == self.opc.JUMP_ABSOLUTE
|
|
||||||
and self.remove_mid_line_ifs([offset]) and
|
|
||||||
target == self.get_target(prev_op[pre_rtarget]) and
|
|
||||||
(prev_op[pre_rtarget] not in self.stmts or
|
|
||||||
self.get_target(prev_op[pre_rtarget]) > prev_op[pre_rtarget]) and
|
|
||||||
1 == len(self.remove_mid_line_ifs(self.rem_or(start, prev_op[pre_rtarget], JUMP_TF, target)))):
|
|
||||||
pass
|
|
||||||
elif (code[prev_op[pre_rtarget]] == self.opc.RETURN_VALUE
|
|
||||||
and self.remove_mid_line_ifs([offset]) and
|
|
||||||
1 == (len(set(self.remove_mid_line_ifs(self.rem_or(start, prev_op[pre_rtarget],
|
|
||||||
JUMP_TF, target))) |
|
|
||||||
set(self.remove_mid_line_ifs(self.rem_or(start, prev_op[pre_rtarget],
|
|
||||||
(opc.JUMP_IF_FALSE,
|
|
||||||
opc.JUMP_IF_TRUE,
|
|
||||||
opc.JUMP_ABSOLUTE),
|
|
||||||
pre_rtarget, True)))))):
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
fix = None
|
|
||||||
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
|
|
||||||
else:
|
|
||||||
last_jump_good = False
|
|
||||||
self.fixed_jumps[offset] = fix or match[-1]
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
self.fixed_jumps[offset] = match[-1]
|
|
||||||
return
|
|
||||||
# op == JUMP_IF_TRUE
|
|
||||||
else:
|
|
||||||
next = self.next_stmt[offset]
|
|
||||||
if prev_op[next] == offset:
|
|
||||||
pass
|
|
||||||
elif self.is_jump_forward(next) and target == self.get_target(next):
|
|
||||||
if code[prev_op[next]] == opc.JUMP_IF_FALSE:
|
|
||||||
if (code[next] == self.opc.JUMP_FORWARD
|
|
||||||
or target != rtarget
|
|
||||||
or code[prev_op[pre_rtarget]] not in
|
|
||||||
(self.opc.JUMP_ABSOLUTE, self.opc.RETURN_VALUE)):
|
|
||||||
self.fixed_jumps[offset] = prev_op[next]
|
|
||||||
return
|
|
||||||
elif (code[next] == self.opc.JUMP_ABSOLUTE and self.is_jump_forward(target) and
|
|
||||||
self.get_target(target) == self.get_target(next)):
|
|
||||||
self.fixed_jumps[offset] = prev_op[next]
|
|
||||||
return
|
|
||||||
|
|
||||||
# Don't add a struct for a while test, it's already taken care of
|
|
||||||
if offset in self.ignore_if:
|
|
||||||
return
|
|
||||||
|
|
||||||
if (code[pre_rtarget] == self.opc.JUMP_ABSOLUTE and
|
|
||||||
pre_rtarget in self.stmts and
|
|
||||||
pre_rtarget != offset and
|
|
||||||
prev_op[pre_rtarget] != offset and
|
|
||||||
not (code[rtarget] == self.opc.JUMP_ABSOLUTE and
|
|
||||||
code[rtarget+3] == self.opc.POP_BLOCK and
|
|
||||||
code[prev_op[pre_rtarget]] != self.opc.JUMP_ABSOLUTE)):
|
|
||||||
rtarget = pre_rtarget
|
|
||||||
|
|
||||||
# Does the "jump if" jump beyond a jump op?
|
|
||||||
# That is, we have something like:
|
|
||||||
# JUMP_IF_FALSE HERE
|
|
||||||
# ...
|
|
||||||
# JUMP_FORWARD
|
|
||||||
# HERE:
|
|
||||||
#
|
|
||||||
# If so, this can be block inside an "if" statement
|
|
||||||
# or a conditional assignment like:
|
|
||||||
# x = 1 if x else 2
|
|
||||||
#
|
|
||||||
# There are other contexts we may need to consider
|
|
||||||
# like whether the target is "END_FINALLY"
|
|
||||||
# or if the condition jump is to a forward location
|
|
||||||
if self.is_jump_forward(pre_rtarget):
|
|
||||||
if_end = self.get_target(pre_rtarget, 0)
|
|
||||||
|
|
||||||
# If the jump target is back, we are looping
|
|
||||||
if (if_end < pre_rtarget and
|
|
||||||
(code[prev_op[if_end]] == self.opc.SETUP_LOOP)):
|
|
||||||
if (if_end > start):
|
|
||||||
return
|
|
||||||
|
|
||||||
end = self.restrict_to_parent(if_end, parent)
|
|
||||||
|
|
||||||
if_then_maybe = None
|
|
||||||
from trepan.api import debug; debug()
|
|
||||||
|
|
||||||
if self.version == 3.0:
|
|
||||||
# Take the JUMP_IF target. In an "if/then", it will be
|
|
||||||
# a POP_TOP instruction and the instruction before it
|
|
||||||
# will be a JUMP_FORWARD to just after the POP_TOP.
|
|
||||||
# For example:
|
|
||||||
# Good:
|
|
||||||
# 3 JUMP_IF_FALSE 33 'to 39'
|
|
||||||
# ..
|
|
||||||
# 36 JUMP_FORWARD 1 'to 40'
|
|
||||||
# 39 POP_TOP
|
|
||||||
# 40 ...
|
|
||||||
# example:
|
|
||||||
|
|
||||||
# BAD (is an "and"):
|
|
||||||
# 28 JUMP_IF_FALSE 4 'to 35'
|
|
||||||
# ...
|
|
||||||
# 32 JUMP_ABSOLUTE 40 'to 40' # should be 36 or there should
|
|
||||||
# # be a COME_FROM at the pop top
|
|
||||||
# # before 40 to 35
|
|
||||||
# 35 POP_TOP
|
|
||||||
# 36 ...
|
|
||||||
# 39 POP_TOP
|
|
||||||
# 39_0 COME_FROM 3
|
|
||||||
# 40 ...
|
|
||||||
|
|
||||||
jump_if_offset = offset
|
|
||||||
if self.opname_for_offset(jump_if_offset).startswith('JUMP_IF'):
|
|
||||||
jump_if_target = code[jump_if_offset+1]
|
|
||||||
if self.opname_for_offset(jump_if_target + jump_if_offset + 3) == 'POP_TOP':
|
|
||||||
jump_inst = jump_if_target + jump_if_offset
|
|
||||||
jump_offset = code[jump_inst+1]
|
|
||||||
jump_op = self.opname_for_offset(jump_inst)
|
|
||||||
if (jump_op == 'JUMP_FORWARD' and jump_offset == 1):
|
|
||||||
self.structs.append({'type': 'if-then',
|
|
||||||
'start': start-3,
|
|
||||||
'end': pre_rtarget})
|
|
||||||
self.thens[start] = end
|
|
||||||
elif jump_op == 'JUMP_ABSOLUTE':
|
|
||||||
if_then_maybe = {'type': 'if-then',
|
|
||||||
'start': start-3,
|
|
||||||
'end': pre_rtarget}
|
|
||||||
|
|
||||||
self.structs.append({'type': 'if-then',
|
|
||||||
'start': start,
|
|
||||||
'end': pre_rtarget})
|
|
||||||
self.not_continue.add(pre_rtarget)
|
|
||||||
|
|
||||||
if rtarget < end:
|
|
||||||
# We have an "else" block of some kind.
|
|
||||||
# Is it associated with "if_then_maybe" seen above?
|
|
||||||
# These will be linked in this funny way:
|
|
||||||
|
|
||||||
# 198 JUMP_IF_FALSE 18 'to 219'
|
|
||||||
# 201 POP_TOP
|
|
||||||
# ...
|
|
||||||
# 216 JUMP_ABSOLUTE 256 'to 256'
|
|
||||||
# 219 POP_TOP
|
|
||||||
# ...
|
|
||||||
# 252 JUMP_FORWARD 1 'to 256'
|
|
||||||
# 255 POP_TOP
|
|
||||||
# 256
|
|
||||||
if if_then_maybe and jump_op == 'JUMP_ABSOLUTE':
|
|
||||||
jump_target = self.get_target(jump_inst, code[jump_inst])
|
|
||||||
if self.opname_for_offset(end) == 'JUMP_FORWARD':
|
|
||||||
end_target = self.get_target(end, code[end])
|
|
||||||
if jump_target == end_target:
|
|
||||||
self.structs.append(if_then_maybe)
|
|
||||||
self.thens[start] = end
|
|
||||||
|
|
||||||
self.structs.append({'type': 'else',
|
|
||||||
'start': rtarget,
|
|
||||||
'end': end})
|
|
||||||
|
|
||||||
elif self.is_jump_back(pre_rtarget, 0):
|
|
||||||
if_end = rtarget
|
|
||||||
self.structs.append({'type': 'if-then',
|
|
||||||
'start': start,
|
|
||||||
'end': pre_rtarget})
|
|
||||||
self.not_continue.add(pre_rtarget)
|
|
||||||
elif code[pre_rtarget] in (self.opc.RETURN_VALUE,
|
|
||||||
self.opc.BREAK_LOOP):
|
|
||||||
self.structs.append({'type': 'if-then',
|
|
||||||
'start': start,
|
|
||||||
'end': rtarget})
|
|
||||||
# It is important to distingish if this return is inside some sort
|
|
||||||
# except block return
|
|
||||||
jump_prev = prev_op[offset]
|
|
||||||
if self.is_pypy and code[jump_prev] == self.opc.COMPARE_OP:
|
|
||||||
if self.opc.cmp_op[code[jump_prev+1]] == 'exception-match':
|
|
||||||
return
|
|
||||||
if self.version >= 3.5:
|
|
||||||
# Python 3.5 may remove as dead code a JUMP
|
|
||||||
# instruction after a RETURN_VALUE. So we check
|
|
||||||
# based on seeing SETUP_EXCEPT various places.
|
|
||||||
if code[rtarget] == self.opc.SETUP_EXCEPT:
|
|
||||||
return
|
|
||||||
# Check that next instruction after pops and jump is
|
|
||||||
# not from SETUP_EXCEPT
|
|
||||||
next_op = rtarget
|
|
||||||
if code[next_op] == self.opc.POP_BLOCK:
|
|
||||||
next_op += instruction_size(self.code[next_op], self.opc)
|
|
||||||
if code[next_op] == self.opc.JUMP_ABSOLUTE:
|
|
||||||
next_op += instruction_size(self.code[next_op], self.opc)
|
|
||||||
if next_op in targets:
|
|
||||||
for try_op in targets[next_op]:
|
|
||||||
come_from_op = code[try_op]
|
|
||||||
if come_from_op == self.opc.SETUP_EXCEPT:
|
|
||||||
return
|
|
||||||
pass
|
|
||||||
pass
|
|
||||||
if code[pre_rtarget] == self.opc.RETURN_VALUE:
|
|
||||||
if self.version == 3.0:
|
|
||||||
next_op = rtarget
|
|
||||||
if code[next_op] == self.opc.POP_TOP:
|
|
||||||
next_op = rtarget
|
|
||||||
next_op += instruction_size(self.code[next_op], self.opc)
|
|
||||||
if code[next_op] == self.opc.POP_BLOCK:
|
|
||||||
return
|
|
||||||
self.return_end_ifs.add(pre_rtarget)
|
|
||||||
else:
|
|
||||||
self.fixed_jumps[offset] = rtarget
|
|
||||||
self.not_continue.add(pre_rtarget)
|
|
||||||
|
|
||||||
|
|
||||||
elif op == self.opc.SETUP_EXCEPT:
|
|
||||||
target = self.get_target(offset)
|
|
||||||
end = self.restrict_to_parent(target, parent)
|
|
||||||
self.fixed_jumps[offset] = end
|
|
||||||
elif op == self.opc.SETUP_FINALLY:
|
|
||||||
target = self.get_target(offset)
|
|
||||||
end = self.restrict_to_parent(target, parent)
|
|
||||||
self.fixed_jumps[offset] = end
|
|
||||||
elif op in self.jump_if_pop:
|
|
||||||
target = self.get_target(offset)
|
|
||||||
if target > offset:
|
|
||||||
unop_target = self.last_instr(offset, target, self.opc.JUMP_FORWARD, target)
|
|
||||||
if unop_target and code[unop_target+3] != self.opc.ROT_TWO:
|
|
||||||
self.fixed_jumps[offset] = unop_target
|
|
||||||
else:
|
|
||||||
self.fixed_jumps[offset] = self.restrict_to_parent(target, parent)
|
|
||||||
pass
|
|
||||||
pass
|
|
||||||
elif self.version >= 3.5:
|
|
||||||
# 3.5+ has Jump optimization which too often causes RETURN_VALUE to get
|
|
||||||
# misclassified as RETURN_END_IF. Handle that here.
|
|
||||||
# In RETURN_VALUE, JUMP_ABSOLUTE, RETURN_VALUE is never RETURN_END_IF
|
|
||||||
if op == self.opc.RETURN_VALUE:
|
|
||||||
if (offset+1 < len(code) and code[offset+1] == self.opc.JUMP_ABSOLUTE and
|
|
||||||
offset in self.return_end_ifs):
|
|
||||||
self.return_end_ifs.remove(offset)
|
|
||||||
pass
|
|
||||||
pass
|
|
||||||
elif op == self.opc.JUMP_FORWARD:
|
|
||||||
# If we have:
|
|
||||||
# JUMP_FORWARD x, [non-jump, insns], RETURN_VALUE, x:
|
|
||||||
# then RETURN_VALUE is not RETURN_END_IF
|
|
||||||
rtarget = self.get_target(offset)
|
|
||||||
rtarget_prev = self.prev[rtarget]
|
|
||||||
if (code[rtarget_prev] == self.opc.RETURN_VALUE and
|
|
||||||
rtarget_prev in self.return_end_ifs):
|
|
||||||
i = rtarget_prev
|
|
||||||
while i != offset:
|
|
||||||
if code[i] in [opc.JUMP_FORWARD, opc.JUMP_ABSOLUTE]:
|
|
||||||
return
|
|
||||||
i = self.prev[i]
|
|
||||||
self.return_end_ifs.remove(rtarget_prev)
|
|
||||||
pass
|
|
||||||
return
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
from uncompyle6 import PYTHON_VERSION
|
|
||||||
if PYTHON_VERSION == 3.0:
|
|
||||||
import inspect
|
|
||||||
co = inspect.currentframe().f_code
|
|
||||||
tokens, customize = Scanner30().ingest(co)
|
|
||||||
for t in tokens:
|
|
||||||
print(t)
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
print("Need to be Python 3.0 to demo; I am %s." %
|
|
||||||
PYTHON_VERSION)
|
|
Reference in New Issue
Block a user