Better Python 3 ENDIF detection

If we have

COMPARE_OP exception-match
POP_JUMP_IF...
....
RETURN_VALUE

Then RETURN_VALUE can't be RETURN_END_IF
This commit is contained in:
rocky
2017-11-08 23:05:01 -05:00
parent 0bb793239b
commit e9b60ddbf0
2 changed files with 29 additions and 26 deletions

View File

@@ -359,7 +359,7 @@ class Scanner3(Scanner):
# rule for that. # rule for that.
pattr = argval pattr = argval
# FIXME: 0 isn't always correct # FIXME: 0 isn't always correct
target = self.get_target(inst.offset, 0) target = self.get_target(inst.offset)
if target <= inst.offset: if target <= inst.offset:
next_opname = self.opname[self.code[inst.offset+3]] next_opname = self.opname[self.code[inst.offset+3]]
if (inst.offset in self.stmts and if (inst.offset in self.stmts and
@@ -499,7 +499,7 @@ class Scanner3(Scanner):
# Determine structures and fix jumps in Python versions # Determine structures and fix jumps in Python versions
# since 2.3 # since 2.3
self.detect_control_flow(offset, targets, 0) self.detect_control_flow(offset, targets, i)
if inst.has_arg: if inst.has_arg:
label = self.fixed_jumps.get(offset) label = self.fixed_jumps.get(offset)
@@ -579,7 +579,7 @@ class Scanner3(Scanner):
# If absolute jump occurs in forward direction or it takes off from the # If absolute jump occurs in forward direction or it takes off from the
# same line as previous statement, this is not a statement # same line as previous statement, this is not a statement
# FIXME: 0 isn't always correct # FIXME: 0 isn't always correct
target = self.get_target(stmt_offset, 0) target = self.get_target(stmt_offset)
if target > stmt_offset or self.lines[last_stmt_offset].l_no == self.lines[stmt_offset].l_no: if target > stmt_offset or self.lines[last_stmt_offset].l_no == self.lines[stmt_offset].l_no:
stmts.remove(stmt_offset) stmts.remove(stmt_offset)
continue continue
@@ -613,7 +613,7 @@ class Scanner3(Scanner):
# Finish filling the list for last statement # Finish filling the list for last statement
slist += [codelen] * (codelen-len(slist)) slist += [codelen] * (codelen-len(slist))
def get_target(self, offset, extended_arg): def get_target(self, offset, extended_arg=0):
""" """
Get target offset for op located at given <offset>. Get target offset for op located at given <offset>.
""" """
@@ -634,7 +634,7 @@ class Scanner3(Scanner):
return target return target
def detect_control_flow(self, offset, targets, extended_arg): def detect_control_flow(self, offset, targets, inst_index):
""" """
Detect structures and their boundaries to fix optimized jumps Detect structures and their boundaries to fix optimized jumps
in python2.3+ in python2.3+
@@ -667,7 +667,7 @@ class Scanner3(Scanner):
# It could be a return instruction. # It could be a return instruction.
start += instruction_size(op, self.opc) start += instruction_size(op, self.opc)
target = self.get_target(offset, extended_arg) target = self.get_target(offset, 0)
end = self.restrict_to_parent(target, parent) end = self.restrict_to_parent(target, parent)
self.setup_loops[target] = offset self.setup_loops[target] = offset
@@ -712,7 +712,7 @@ class Scanner3(Scanner):
jump_back = self.last_instr(start, end, self.opc.JUMP_ABSOLUTE, start, False) 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 end > jump_back+4 and self.is_jump_forward(end):
if self.is_jump_forward(jump_back+4): if self.is_jump_forward(jump_back+4):
if self.get_target(jump_back+4, extended_arg) == self.get_target(end, extended_arg): if self.get_target(jump_back+4) == self.get_target(end):
self.fixed_jumps[offset] = jump_back+4 self.fixed_jumps[offset] = jump_back+4
end = jump_back+4 end = jump_back+4
elif target < offset: elif target < offset:
@@ -721,7 +721,7 @@ class Scanner3(Scanner):
# I think 0 right because jump_back has been adjusted for any EXTENDED_ARG # I think 0 right because jump_back has been adjusted for any EXTENDED_ARG
# it encounters # it encounters
target = self.get_target(jump_back, 0) target = self.get_target(jump_back)
if code[target] in (self.opc.FOR_ITER, self.opc.GET_ITER): if code[target] in (self.opc.FOR_ITER, self.opc.GET_ITER):
loop_type = 'for' loop_type = 'for'
@@ -733,7 +733,7 @@ class Scanner3(Scanner):
loop_type = 'while 1' loop_type = 'while 1'
elif self.code[test] in self.opc.JUMP_OPs: elif self.code[test] in self.opc.JUMP_OPs:
self.ignore_if.add(test) self.ignore_if.add(test)
test_target = self.get_target(test, extended_arg) test_target = self.get_target(test)
if test_target > (jump_back+3): if test_target > (jump_back+3):
jump_back = test_target jump_back = test_target
self.not_continue.add(jump_back) self.not_continue.add(jump_back)
@@ -748,7 +748,7 @@ class Scanner3(Scanner):
'end': end}) 'end': end})
elif op in self.pop_jump_tf: elif op in self.pop_jump_tf:
start = offset + instruction_size(op, self.opc) start = offset + instruction_size(op, self.opc)
target = self.get_target(offset, extended_arg) target = self.get_target(offset)
rtarget = self.restrict_to_parent(target, parent) rtarget = self.restrict_to_parent(target, parent)
prev_op = self.prev_op prev_op = self.prev_op
@@ -791,12 +791,12 @@ class Scanner3(Scanner):
if match: if match:
is_jump_forward = self.is_jump_forward(pre_rtarget) is_jump_forward = self.is_jump_forward(pre_rtarget)
if (is_jump_forward and pre_rtarget not in self.stmts and if (is_jump_forward and pre_rtarget not in self.stmts and
self.restrict_to_parent(self.get_target(pre_rtarget, extended_arg), parent) == rtarget): self.restrict_to_parent(self.get_target(pre_rtarget), parent) == rtarget):
if (code[prev_op[pre_rtarget]] == self.opc.JUMP_ABSOLUTE if (code[prev_op[pre_rtarget]] == self.opc.JUMP_ABSOLUTE
and self.remove_mid_line_ifs([offset]) and and self.remove_mid_line_ifs([offset]) and
target == self.get_target(prev_op[pre_rtarget], extended_arg) and target == self.get_target(prev_op[pre_rtarget]) and
(prev_op[pre_rtarget] not in self.stmts or (prev_op[pre_rtarget] not in self.stmts or
self.get_target(prev_op[pre_rtarget], extended_arg) > prev_op[pre_rtarget]) and 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], self.pop_jump_tf, target)))): 1 == len(self.remove_mid_line_ifs(self.rem_or(start, prev_op[pre_rtarget], self.pop_jump_tf, target)))):
pass pass
elif (code[prev_op[pre_rtarget]] == self.opc.RETURN_VALUE elif (code[prev_op[pre_rtarget]] == self.opc.RETURN_VALUE
@@ -815,7 +815,7 @@ class Scanner3(Scanner):
self.opc.POP_JUMP_IF_FALSE) self.opc.POP_JUMP_IF_FALSE)
last_jump_good = True last_jump_good = True
for j in jump_ifs: for j in jump_ifs:
if target == self.get_target(j, extended_arg): if target == self.get_target(j):
if self.lines[j].next == j + 3 and last_jump_good: if self.lines[j].next == j + 3 and last_jump_good:
fix = j fix = j
break break
@@ -831,7 +831,7 @@ class Scanner3(Scanner):
next = self.next_stmt[offset] next = self.next_stmt[offset]
if prev_op[next] == offset: if prev_op[next] == offset:
pass pass
elif self.is_jump_forward(next) and target == self.get_target(next, extended_arg): elif self.is_jump_forward(next) and target == self.get_target(next):
if code[prev_op[next]] == self.opc.POP_JUMP_IF_FALSE: if code[prev_op[next]] == self.opc.POP_JUMP_IF_FALSE:
if (code[next] == self.opc.JUMP_FORWARD if (code[next] == self.opc.JUMP_FORWARD
or target != rtarget or target != rtarget
@@ -840,7 +840,7 @@ class Scanner3(Scanner):
self.fixed_jumps[offset] = prev_op[next] self.fixed_jumps[offset] = prev_op[next]
return return
elif (code[next] == self.opc.JUMP_ABSOLUTE and self.is_jump_forward(target) and elif (code[next] == self.opc.JUMP_ABSOLUTE and self.is_jump_forward(target) and
self.get_target(target, extended_arg) == self.get_target(next, extended_arg)): self.get_target(target) == self.get_target(next)):
self.fixed_jumps[offset] = prev_op[next] self.fixed_jumps[offset] = prev_op[next]
return return
@@ -937,7 +937,10 @@ class Scanner3(Scanner):
pass pass
pass pass
if code[pre_rtarget] == self.opc.RETURN_VALUE: if code[pre_rtarget] == self.opc.RETURN_VALUE:
self.return_end_ifs.add(pre_rtarget) # If we are at some sort of POP_JUMP_IF and the instruction before was
# COMPARE_OP exception-match, then pre_rtarget is not an end_if
if not (inst_index > 0 and self.insts[inst_index-1].argval == 'exception-match'):
self.return_end_ifs.add(pre_rtarget)
else: else:
self.fixed_jumps[offset] = rtarget self.fixed_jumps[offset] = rtarget
self.not_continue.add(pre_rtarget) self.not_continue.add(pre_rtarget)
@@ -955,12 +958,12 @@ class Scanner3(Scanner):
self.fixed_jumps[offset] = rtarget self.fixed_jumps[offset] = rtarget
elif op == self.opc.SETUP_EXCEPT: elif op == self.opc.SETUP_EXCEPT:
target = self.get_target(offset, extended_arg) target = self.get_target(offset)
end = self.restrict_to_parent(target, parent) end = self.restrict_to_parent(target, parent)
self.fixed_jumps[offset] = end self.fixed_jumps[offset] = end
elif op == self.opc.POP_EXCEPT: elif op == self.opc.POP_EXCEPT:
next_offset = xdis.next_offset(op, self.opc, offset) next_offset = xdis.next_offset(op, self.opc, offset)
target = self.get_target(next_offset, extended_arg) target = self.get_target(next_offset)
if target > next_offset: if target > next_offset:
next_op = code[next_offset] next_op = code[next_offset]
if (self.opc.JUMP_ABSOLUTE == next_op and if (self.opc.JUMP_ABSOLUTE == next_op and
@@ -969,11 +972,11 @@ class Scanner3(Scanner):
self.except_targets[target] = next_offset self.except_targets[target] = next_offset
elif op == self.opc.SETUP_FINALLY: elif op == self.opc.SETUP_FINALLY:
target = self.get_target(offset, extended_arg) target = self.get_target(offset)
end = self.restrict_to_parent(target, parent) end = self.restrict_to_parent(target, parent)
self.fixed_jumps[offset] = end self.fixed_jumps[offset] = end
elif op in self.jump_if_pop: elif op in self.jump_if_pop:
target = self.get_target(offset, extended_arg) target = self.get_target(offset)
if target > offset: if target > offset:
unop_target = self.last_instr(offset, target, self.opc.JUMP_FORWARD, target) unop_target = self.last_instr(offset, target, self.opc.JUMP_FORWARD, target)
if unop_target and code[unop_target+3] != self.opc.ROT_TWO: if unop_target and code[unop_target+3] != self.opc.ROT_TWO:
@@ -997,7 +1000,7 @@ class Scanner3(Scanner):
# If we have: # If we have:
# JUMP_FORWARD x, [non-jump, insns], RETURN_VALUE, x: # JUMP_FORWARD x, [non-jump, insns], RETURN_VALUE, x:
# then RETURN_VALUE is not RETURN_END_IF # then RETURN_VALUE is not RETURN_END_IF
rtarget = self.get_target(offset, extended_arg) rtarget = self.get_target(offset)
rtarget_prev = self.prev[rtarget] rtarget_prev = self.prev[rtarget]
if (code[rtarget_prev] == self.opc.RETURN_VALUE and if (code[rtarget_prev] == self.opc.RETURN_VALUE and
rtarget_prev in self.return_end_ifs): rtarget_prev in self.return_end_ifs):

View File

@@ -23,7 +23,7 @@ class Scanner30(Scanner3):
return return
pass pass
def detect_control_flow(self, offset, targets, extended_arg): def detect_control_flow(self, offset, targets, inst_index):
""" """
Detect structures and their boundaries to fix optimized jumps Detect structures and their boundaries to fix optimized jumps
Python 3.0 is more like Python 2.6 than it is Python 3.x. Python 3.0 is more like Python 2.6 than it is Python 3.x.
@@ -55,7 +55,7 @@ class Scanner30(Scanner3):
# It could be a return instruction. # It could be a return instruction.
start += instruction_size(op, self.opc) start += instruction_size(op, self.opc)
target = self.get_target(offset, extended_arg) target = self.get_target(offset)
end = self.restrict_to_parent(target, parent) end = 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
@@ -136,7 +136,7 @@ class Scanner30(Scanner3):
'end': end}) 'end': end})
elif op in self.pop_jump_tf: elif op in self.pop_jump_tf:
start = offset + instruction_size(op, self.opc) start = offset + instruction_size(op, self.opc)
target = self.get_target(offset, extended_arg) target = self.get_target(offset)
rtarget = self.restrict_to_parent(target, parent) rtarget = self.restrict_to_parent(target, parent)
prev_op = self.prev_op prev_op = self.prev_op
@@ -329,7 +329,7 @@ class Scanner30(Scanner3):
end = self.restrict_to_parent(target, parent) end = self.restrict_to_parent(target, parent)
self.fixed_jumps[offset] = end self.fixed_jumps[offset] = end
elif op == self.opc.SETUP_FINALLY: elif op == self.opc.SETUP_FINALLY:
target = self.get_target(offset, extended_arg) target = self.get_target(offset)
end = self.restrict_to_parent(target, parent) end = self.restrict_to_parent(target, parent)
self.fixed_jumps[offset] = end self.fixed_jumps[offset] = end
elif op in self.jump_if_pop: elif op in self.jump_if_pop: