You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Add self.offset2inst_index and document more
This commit is contained in:
@@ -30,6 +30,9 @@ def test_if_in_for():
|
|||||||
bytecode = Bytecode(code, scan.opc)
|
bytecode = Bytecode(code, scan.opc)
|
||||||
scan.build_lines_data(code, n)
|
scan.build_lines_data(code, n)
|
||||||
scan.insts = list(bytecode)
|
scan.insts = list(bytecode)
|
||||||
|
scan.offset2inst_index = {}
|
||||||
|
for i, inst in enumerate(scan.insts):
|
||||||
|
scan.offset2inst_index[inst.offset] = i
|
||||||
scan.build_prev_op(n)
|
scan.build_prev_op(n)
|
||||||
fjt = scan.find_jump_targets(False)
|
fjt = scan.find_jump_targets(False)
|
||||||
|
|
||||||
@@ -46,8 +49,13 @@ def test_if_in_for():
|
|||||||
|
|
||||||
code = bug_loop.__code__
|
code = bug_loop.__code__
|
||||||
n = scan.setup_code(code)
|
n = scan.setup_code(code)
|
||||||
|
bytecode = Bytecode(code, scan.opc)
|
||||||
scan.build_lines_data(code, n)
|
scan.build_lines_data(code, n)
|
||||||
|
scan.insts = list(bytecode)
|
||||||
scan.build_prev_op(n)
|
scan.build_prev_op(n)
|
||||||
|
scan.offset2inst_index = {}
|
||||||
|
for i, inst in enumerate(scan.insts):
|
||||||
|
scan.offset2inst_index[inst.offset] = i
|
||||||
fjt = scan.find_jump_targets(False)
|
fjt = scan.find_jump_targets(False)
|
||||||
assert{64: [42], 67: [42, 42], 42: [16, 41], 19: [6]} == fjt
|
assert{64: [42], 67: [42, 42], 42: [16, 41], 19: [6]} == fjt
|
||||||
assert scan.structs == [
|
assert scan.structs == [
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2015-2017 by Rocky Bernstein
|
# Copyright (c) 2015-2018 by Rocky Bernstein
|
||||||
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
|
||||||
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
|
||||||
"""
|
"""
|
||||||
@@ -109,7 +109,11 @@ class Scanner2(Scanner):
|
|||||||
|
|
||||||
self.build_lines_data(co, codelen)
|
self.build_lines_data(co, codelen)
|
||||||
self.build_prev_op(codelen)
|
self.build_prev_op(codelen)
|
||||||
|
|
||||||
self.insts = list(bytecode)
|
self.insts = list(bytecode)
|
||||||
|
self.offset2inst_index = {}
|
||||||
|
for i, inst in enumerate(self.insts):
|
||||||
|
self.offset2inst_index[inst.offset] = i
|
||||||
|
|
||||||
free, names, varnames = self.unmangle_code_names(co, classname)
|
free, names, varnames = self.unmangle_code_names(co, classname)
|
||||||
self.names = names
|
self.names = names
|
||||||
@@ -506,17 +510,18 @@ class Scanner2(Scanner):
|
|||||||
# Try to find the jump_back instruction of the loop.
|
# Try to find the jump_back instruction of the loop.
|
||||||
# It could be a return instruction.
|
# It could be a return instruction.
|
||||||
|
|
||||||
|
inst = self.insts[self.offset2inst_index[offset]]
|
||||||
start += instruction_size(op, self.opc)
|
start += instruction_size(op, self.opc)
|
||||||
target = self.get_target(offset) + extended_arg
|
target = inst.argval
|
||||||
end = self.restrict_to_parent(target, parent)
|
end_offset = self.restrict_to_parent(target, parent)
|
||||||
self.setup_loop_targets[offset] = target
|
self.setup_loop_targets[offset] = target
|
||||||
self.setup_loops[target] = offset
|
self.setup_loops[target] = offset
|
||||||
|
|
||||||
if target != end:
|
if target != end_offset:
|
||||||
self.fixed_jumps[offset] = end
|
self.fixed_jumps[offset] = end_offset
|
||||||
|
|
||||||
(line_no, next_line_byte) = self.lines[offset]
|
(line_no, next_line_byte) = self.lines[offset]
|
||||||
jump_back = self.last_instr(start, end, self.opc.JUMP_ABSOLUTE,
|
jump_back = self.last_instr(start, end_offset, self.opc.JUMP_ABSOLUTE,
|
||||||
next_line_byte, False)
|
next_line_byte, False)
|
||||||
|
|
||||||
if jump_back:
|
if jump_back:
|
||||||
@@ -525,7 +530,7 @@ class Scanner2(Scanner):
|
|||||||
# construct
|
# construct
|
||||||
if self.version < 2.7:
|
if self.version < 2.7:
|
||||||
jump_forward_offset = jump_back+4
|
jump_forward_offset = jump_back+4
|
||||||
return_val_offset1 = self.prev[self.prev[self.prev[end]]]
|
return_val_offset1 = self.prev[self.prev[self.prev[end_offset]]]
|
||||||
# Is jump back really "back"?
|
# Is jump back really "back"?
|
||||||
jump_target = self.get_target(jump_back, code[jump_back])
|
jump_target = self.get_target(jump_back, code[jump_back])
|
||||||
if (jump_target > jump_back or
|
if (jump_target > jump_back or
|
||||||
@@ -534,19 +539,19 @@ class Scanner2(Scanner):
|
|||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
jump_forward_offset = jump_back+3
|
jump_forward_offset = jump_back+3
|
||||||
return_val_offset1 = self.prev[self.prev[end]]
|
return_val_offset1 = self.prev[self.prev[end_offset]]
|
||||||
|
|
||||||
if (jump_back and jump_back != self.prev[end]
|
if (jump_back and jump_back != self.prev[end_offset]
|
||||||
and code[jump_forward_offset] in self.jump_forward):
|
and code[jump_forward_offset] in self.jump_forward):
|
||||||
if (code[self.prev[end]] == self.opc.RETURN_VALUE or
|
if (code[self.prev[end_offset]] == self.opc.RETURN_VALUE or
|
||||||
(code[self.prev[end]] == self.opc.POP_BLOCK
|
(code[self.prev[end_offset]] == self.opc.POP_BLOCK
|
||||||
and code[return_val_offset1] == self.opc.RETURN_VALUE)):
|
and code[return_val_offset1] == self.opc.RETURN_VALUE)):
|
||||||
jump_back = None
|
jump_back = None
|
||||||
if not jump_back:
|
if not jump_back:
|
||||||
# loop suite ends in return
|
# loop suite ends in return
|
||||||
# scanner26 of wbiti had:
|
# scanner26 of wbiti had:
|
||||||
# jump_back = self.last_instr(start, end, self.opc.JUMP_ABSOLUTE, start, False)
|
# jump_back = self.last_instr(start, end_offset, self.opc.JUMP_ABSOLUTE, start, False)
|
||||||
jump_back = self.last_instr(start, end, self.opc.RETURN_VALUE)
|
jump_back = self.last_instr(start, end_offset, self.opc.RETURN_VALUE)
|
||||||
if not jump_back:
|
if not jump_back:
|
||||||
return
|
return
|
||||||
jump_back += 1
|
jump_back += 1
|
||||||
@@ -572,18 +577,18 @@ class Scanner2(Scanner):
|
|||||||
else:
|
else:
|
||||||
loop_type = 'for'
|
loop_type = 'for'
|
||||||
target = next_line_byte
|
target = next_line_byte
|
||||||
end = jump_back + 3
|
end_offset = jump_back + 3
|
||||||
else:
|
else:
|
||||||
if self.get_target(jump_back) >= next_line_byte:
|
if self.get_target(jump_back) >= next_line_byte:
|
||||||
jump_back = self.last_instr(start, end, self.opc.JUMP_ABSOLUTE, start, False)
|
jump_back = self.last_instr(start, end_offset, self.opc.JUMP_ABSOLUTE, start, False)
|
||||||
if end > jump_back+4 and code[end] in self.jump_forward:
|
if end_offset > jump_back+4 and code[end_offset] in self.jump_forward:
|
||||||
if code[jump_back+4] in self.jump_forward:
|
if code[jump_back+4] in self.jump_forward:
|
||||||
if self.get_target(jump_back+4) == self.get_target(end):
|
if self.get_target(jump_back+4) == self.get_target(end_offset):
|
||||||
self.fixed_jumps[offset] = jump_back+4
|
self.fixed_jumps[offset] = jump_back+4
|
||||||
end = jump_back+4
|
end_offset = jump_back+4
|
||||||
elif target < offset:
|
elif target < offset:
|
||||||
self.fixed_jumps[offset] = jump_back+4
|
self.fixed_jumps[offset] = jump_back+4
|
||||||
end = jump_back+4
|
end_offset = jump_back+4
|
||||||
|
|
||||||
target = self.get_target(jump_back, self.opc.JUMP_ABSOLUTE)
|
target = self.get_target(jump_back, self.opc.JUMP_ABSOLUTE)
|
||||||
|
|
||||||
@@ -610,26 +615,26 @@ class Scanner2(Scanner):
|
|||||||
self.structs.append({'type': loop_type + '-loop',
|
self.structs.append({'type': loop_type + '-loop',
|
||||||
'start': target,
|
'start': target,
|
||||||
'end': jump_back})
|
'end': jump_back})
|
||||||
if jump_back+3 != end:
|
if jump_back+3 != end_offset:
|
||||||
self.structs.append({'type': loop_type + '-else',
|
self.structs.append({'type': loop_type + '-else',
|
||||||
'start': jump_back+3,
|
'start': jump_back+3,
|
||||||
'end': end})
|
'end': end_offset})
|
||||||
elif op == self.opc.SETUP_EXCEPT:
|
elif op == self.opc.SETUP_EXCEPT:
|
||||||
start = offset + op_size(op, self.opc)
|
start = offset + op_size(op, self.opc)
|
||||||
target = self.get_target(offset, op)
|
target = self.get_target(offset, op)
|
||||||
end = self.restrict_to_parent(target, parent)
|
end_offset = self.restrict_to_parent(target, parent)
|
||||||
if target != end:
|
if target != end_offset:
|
||||||
self.fixed_jumps[offset] = end
|
self.fixed_jumps[offset] = end_offset
|
||||||
# print target, end, parent
|
# print target, end, parent
|
||||||
# Add the try block
|
# Add the try block
|
||||||
self.structs.append({'type': 'try',
|
self.structs.append({'type': 'try',
|
||||||
'start': start-3,
|
'start': start-3,
|
||||||
'end': end-4})
|
'end': end_offset-4})
|
||||||
# Now isolate the except and else blocks
|
# Now isolate the except and else blocks
|
||||||
end_else = start_else = self.get_target(self.prev[end])
|
end_else = start_else = self.get_target(self.prev[end_offset])
|
||||||
|
|
||||||
|
|
||||||
end_finally_offset = end
|
end_finally_offset = end_offset
|
||||||
setup_except_nest = 0
|
setup_except_nest = 0
|
||||||
while end_finally_offset < len(self.code):
|
while end_finally_offset < len(self.code):
|
||||||
if self.code[end_finally_offset] == self.opc.END_FINALLY:
|
if self.code[end_finally_offset] == self.opc.END_FINALLY:
|
||||||
@@ -643,7 +648,7 @@ class Scanner2(Scanner):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
# Add the except blocks
|
# Add the except blocks
|
||||||
i = end
|
i = end_offset
|
||||||
while i < len(self.code) and i < end_finally_offset:
|
while i < len(self.code) and i < end_finally_offset:
|
||||||
jmp = self.next_except_jump(i)
|
jmp = self.next_except_jump(i)
|
||||||
if jmp is None: # check
|
if jmp is None: # check
|
||||||
@@ -701,7 +706,7 @@ class Scanner2(Scanner):
|
|||||||
|
|
||||||
test_target = target
|
test_target = target
|
||||||
if self.version < 2.7:
|
if self.version < 2.7:
|
||||||
# Before 2.6 we have to deal with the fact that there is an extra
|
# Before 2.7 we have to deal with the fact that there is an extra
|
||||||
# POP_TOP that is logically associated with the JUMP_IF's (even though
|
# POP_TOP that is logically associated with the JUMP_IF's (even though
|
||||||
# the instance set is called "self.pop_jump_if")
|
# the instance set is called "self.pop_jump_if")
|
||||||
if code[pre[test_target]] == self.opc.POP_TOP:
|
if code[pre[test_target]] == self.opc.POP_TOP:
|
||||||
@@ -711,22 +716,29 @@ class Scanner2(Scanner):
|
|||||||
test_set = self.pop_jump_if_or_pop | self.pop_jump_if
|
test_set = self.pop_jump_if_or_pop | self.pop_jump_if
|
||||||
|
|
||||||
if ( code[pre[test_target]] in test_set and target > offset ):
|
if ( code[pre[test_target]] in test_set and target > offset ):
|
||||||
|
# We have POP_JUMP_IF... target
|
||||||
|
# ...
|
||||||
|
# pre: POP_JUMP_IF ...
|
||||||
|
# target: ...
|
||||||
|
#
|
||||||
|
# We will take that as either as "and" or "or".
|
||||||
self.fixed_jumps[offset] = pre[target]
|
self.fixed_jumps[offset] = pre[target]
|
||||||
self.structs.append({'type': 'and/or',
|
self.structs.append({'type': 'and/or',
|
||||||
'start': start,
|
'start': start,
|
||||||
'end': pre[target]})
|
'end': pre[target]})
|
||||||
return
|
return
|
||||||
|
|
||||||
# The op offset just before the target jump offset is important
|
# The instruction offset just before the target jump offset is important
|
||||||
# in making a determination of what we have. Save that.
|
# in making a determination of what we have. Save that.
|
||||||
pre_rtarget = pre[rtarget]
|
pre_rtarget = pre[rtarget]
|
||||||
|
|
||||||
# Is it an "and" inside an "if" or "while" block
|
# Is it an "and" inside an "if" or "while" block
|
||||||
if op == self.opc.PJIF:
|
if op == self.opc.PJIF:
|
||||||
|
|
||||||
# Search for other POP_JUMP_IF_FALSE targetting the same op,
|
# Search for other POP_JUMP_IF_...'s targetting the
|
||||||
# in current statement, starting from current offset, and filter
|
# same target, of the current POP_JUMP_... instruction,
|
||||||
# everything inside inner 'or' jumps and midline ifs
|
# starting from current offset, and filter everything inside inner 'or'
|
||||||
|
# jumps and mid-line ifs
|
||||||
match = self.rem_or(start, self.next_stmt[offset], self.opc.PJIF, target)
|
match = self.rem_or(start, self.next_stmt[offset], self.opc.PJIF, target)
|
||||||
|
|
||||||
# If we still have any offsets in set, start working on it
|
# If we still have any offsets in set, start working on it
|
||||||
@@ -856,7 +868,7 @@ class Scanner2(Scanner):
|
|||||||
self.fixed_jumps[jump_if_offset] = jump_target
|
self.fixed_jumps[jump_if_offset] = jump_target
|
||||||
return
|
return
|
||||||
|
|
||||||
end = self.restrict_to_parent(if_end, parent)
|
end_offset = self.restrict_to_parent(if_end, parent)
|
||||||
|
|
||||||
if_then_maybe = None
|
if_then_maybe = None
|
||||||
|
|
||||||
@@ -895,7 +907,7 @@ class Scanner2(Scanner):
|
|||||||
self.structs.append({'type': 'if-then',
|
self.structs.append({'type': 'if-then',
|
||||||
'start': start-3,
|
'start': start-3,
|
||||||
'end': pre_rtarget})
|
'end': pre_rtarget})
|
||||||
self.thens[start] = end
|
self.thens[start] = end_offset
|
||||||
elif jump_op == 'JUMP_ABSOLUTE':
|
elif jump_op == 'JUMP_ABSOLUTE':
|
||||||
if_then_maybe = {'type': 'if-then',
|
if_then_maybe = {'type': 'if-then',
|
||||||
'start': start-3,
|
'start': start-3,
|
||||||
@@ -910,7 +922,7 @@ class Scanner2(Scanner):
|
|||||||
if pre_rtarget not in self.linestartoffsets or self.version < 2.7:
|
if pre_rtarget not in self.linestartoffsets or self.version < 2.7:
|
||||||
self.not_continue.add(pre_rtarget)
|
self.not_continue.add(pre_rtarget)
|
||||||
|
|
||||||
if rtarget < end:
|
if rtarget < end_offset:
|
||||||
# We have an "else" block of some kind.
|
# We have an "else" block of some kind.
|
||||||
# Is it associated with "if_then_maybe" seen above?
|
# Is it associated with "if_then_maybe" seen above?
|
||||||
# These will be linked in this funny way:
|
# These will be linked in this funny way:
|
||||||
@@ -926,15 +938,15 @@ class Scanner2(Scanner):
|
|||||||
# 256
|
# 256
|
||||||
if if_then_maybe and jump_op == 'JUMP_ABSOLUTE':
|
if if_then_maybe and jump_op == 'JUMP_ABSOLUTE':
|
||||||
jump_target = self.get_target(jump_inst, code[jump_inst])
|
jump_target = self.get_target(jump_inst, code[jump_inst])
|
||||||
if self.opname_for_offset(end) == 'JUMP_FORWARD':
|
if self.opname_for_offset(end_offset) == 'JUMP_FORWARD':
|
||||||
end_target = self.get_target(end, code[end])
|
end_target = self.get_target(end_offset, code[end_offset])
|
||||||
if jump_target == end_target:
|
if jump_target == end_target:
|
||||||
self.structs.append(if_then_maybe)
|
self.structs.append(if_then_maybe)
|
||||||
self.thens[start] = end
|
self.thens[start] = end_offset
|
||||||
|
|
||||||
self.structs.append({'type': 'else',
|
self.structs.append({'type': 'else',
|
||||||
'start': rtarget,
|
'start': rtarget,
|
||||||
'end': end})
|
'end': end_offset})
|
||||||
elif code_pre_rtarget == self.opc.RETURN_VALUE:
|
elif code_pre_rtarget == self.opc.RETURN_VALUE:
|
||||||
if self.version == 2.7 or pre_rtarget not in self.ignore_if:
|
if self.version == 2.7 or pre_rtarget not in self.ignore_if:
|
||||||
# 10 is exception-match. If there is an exception match in the
|
# 10 is exception-match. If there is an exception match in the
|
||||||
|
@@ -110,7 +110,11 @@ class Scanner26(scan.Scanner2):
|
|||||||
|
|
||||||
self.build_lines_data(co, codelen)
|
self.build_lines_data(co, codelen)
|
||||||
self.build_prev_op(codelen)
|
self.build_prev_op(codelen)
|
||||||
|
|
||||||
self.insts = list(bytecode)
|
self.insts = list(bytecode)
|
||||||
|
self.offset2inst_index = {}
|
||||||
|
for i, inst in enumerate(self.insts):
|
||||||
|
self.offset2inst_index[inst.offset] = i
|
||||||
|
|
||||||
free, names, varnames = self.unmangle_code_names(co, classname)
|
free, names, varnames = self.unmangle_code_names(co, classname)
|
||||||
self.names = names
|
self.names = names
|
||||||
|
Reference in New Issue
Block a user