Add self.offset2inst_index and document more

This commit is contained in:
rocky
2018-02-04 09:13:49 -05:00
parent ca2c06ca87
commit 296fcd89ce
3 changed files with 64 additions and 40 deletions

View File

@@ -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 == [

View File

@@ -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

View File

@@ -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