You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 00:45:53 +08:00
Fix 3.5 misclassifying RETURN_VALUE
We use location of SETUP_EXCEPT instructions to disambiguate.
This commit is contained in:
@@ -40,8 +40,6 @@ class Python35Parser(Python3Parser):
|
|||||||
# RETURN_END_IF vs RETURN_VALUE
|
# RETURN_END_IF vs RETURN_VALUE
|
||||||
|
|
||||||
ifelsestmtc ::= testexpr c_stmts_opt JUMP_FORWARD else_suitec
|
ifelsestmtc ::= testexpr c_stmts_opt JUMP_FORWARD else_suitec
|
||||||
return_stmt ::= ret_expr RETURN_END_IF
|
|
||||||
|
|
||||||
|
|
||||||
# Python 3.3+ also has yield from. 3.5 does it
|
# Python 3.3+ also has yield from. 3.5 does it
|
||||||
# differently than 3.3, 3.4
|
# differently than 3.3, 3.4
|
||||||
|
@@ -251,6 +251,8 @@ class Scanner(object):
|
|||||||
self.Token = tokenClass
|
self.Token = tokenClass
|
||||||
return self.Token
|
return self.Token
|
||||||
|
|
||||||
|
def op_has_argument(op, opc):
|
||||||
|
return op >= opc.HAVE_ARGUMENT
|
||||||
|
|
||||||
def parse_fn_counts(argc):
|
def parse_fn_counts(argc):
|
||||||
return ((argc & 0xFF), (argc >> 8) & 0xFF, (argc >> 16) & 0x7FFF)
|
return ((argc & 0xFF), (argc >> 8) & 0xFF, (argc >> 16) & 0x7FFF)
|
||||||
|
@@ -25,6 +25,7 @@ from __future__ import print_function
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from array import array
|
from array import array
|
||||||
|
|
||||||
|
from uncompyle6.scanner import Scanner, op_has_argument
|
||||||
from xdis.code import iscode
|
from xdis.code import iscode
|
||||||
from xdis.bytecode import Bytecode
|
from xdis.bytecode import Bytecode
|
||||||
from uncompyle6.scanner import Token, parse_fn_counts
|
from uncompyle6.scanner import Token, parse_fn_counts
|
||||||
@@ -42,9 +43,7 @@ globals().update(op3.opmap)
|
|||||||
# POP_JUMP_IF is used by verify
|
# POP_JUMP_IF is used by verify
|
||||||
POP_JUMP_TF = (POP_JUMP_IF_TRUE, POP_JUMP_IF_FALSE)
|
POP_JUMP_TF = (POP_JUMP_IF_TRUE, POP_JUMP_IF_FALSE)
|
||||||
|
|
||||||
import uncompyle6.scanner as scan
|
class Scanner3(Scanner):
|
||||||
|
|
||||||
class Scanner3(scan.Scanner):
|
|
||||||
|
|
||||||
def __init__(self, version, show_asm=None, is_pypy=False):
|
def __init__(self, version, show_asm=None, is_pypy=False):
|
||||||
super(Scanner3, self).__init__(version, show_asm, is_pypy)
|
super(Scanner3, self).__init__(version, show_asm, is_pypy)
|
||||||
@@ -234,7 +233,7 @@ class Scanner3(scan.Scanner):
|
|||||||
offset = inst.offset,
|
offset = inst.offset,
|
||||||
linestart = inst.starts_line,
|
linestart = inst.starts_line,
|
||||||
op = op,
|
op = op,
|
||||||
has_arg = (op >= op3.HAVE_ARGUMENT),
|
has_arg = op_has_argument(op, op3),
|
||||||
opc = self.opc
|
opc = self.opc
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -403,7 +402,7 @@ class Scanner3(scan.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_structure(offset)
|
self.detect_structure(offset, targets)
|
||||||
|
|
||||||
has_arg = (op >= op3.HAVE_ARGUMENT)
|
has_arg = (op >= op3.HAVE_ARGUMENT)
|
||||||
if has_arg:
|
if has_arg:
|
||||||
@@ -517,7 +516,7 @@ class Scanner3(scan.Scanner):
|
|||||||
target += offset + 3
|
target += offset + 3
|
||||||
return target
|
return target
|
||||||
|
|
||||||
def detect_structure(self, offset):
|
def detect_structure(self, offset, targets):
|
||||||
"""
|
"""
|
||||||
Detect structures and their boundaries to fix optimized jumps
|
Detect structures and their boundaries to fix optimized jumps
|
||||||
in python2.3+
|
in python2.3+
|
||||||
@@ -735,10 +734,33 @@ class Scanner3(scan.Scanner):
|
|||||||
self.structs.append({'type': 'if-then',
|
self.structs.append({'type': 'if-then',
|
||||||
'start': start,
|
'start': start,
|
||||||
'end': rtarget})
|
'end': rtarget})
|
||||||
|
# It is important to distingish if this return is inside some sort
|
||||||
|
# except block return
|
||||||
jump_prev = prev_op[offset]
|
jump_prev = prev_op[offset]
|
||||||
if self.is_pypy and code[jump_prev] == self.opc.COMPARE_OP:
|
if self.is_pypy and code[jump_prev] == self.opc.COMPARE_OP:
|
||||||
if self.opc.cmp_op[code[jump_prev+1]] == 'exception match':
|
if self.opc.cmp_op[code[jump_prev+1]] == 'exception match':
|
||||||
return
|
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 += self.op_size(self.code[next_op])
|
||||||
|
if code[next_op] == self.opc.JUMP_ABSOLUTE:
|
||||||
|
next_op += self.op_size(self.code[next_op])
|
||||||
|
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
|
||||||
|
pass
|
||||||
self.return_end_ifs.add(prev_op[rtarget])
|
self.return_end_ifs.add(prev_op[rtarget])
|
||||||
|
|
||||||
elif op in self.jump_if_pop:
|
elif op in self.jump_if_pop:
|
||||||
|
@@ -739,11 +739,6 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
if self.return_none or node != AST('return_stmt', [AST('ret_expr', [NONE]), Token('RETURN_VALUE')]):
|
if self.return_none or node != AST('return_stmt', [AST('ret_expr', [NONE]), Token('RETURN_VALUE')]):
|
||||||
self.write(' ')
|
self.write(' ')
|
||||||
self.preorder(node[0])
|
self.preorder(node[0])
|
||||||
# 3.5 does jump optimization. The RETURN_END_IF in the return
|
|
||||||
# statement means to dedent. Earlier versions will just have
|
|
||||||
# RETURN_VALUE it is done by a nonterminal in the grammar.
|
|
||||||
if self.version >= 3.5 and node[-1] == 'RETURN_END_IF':
|
|
||||||
self.indentLess()
|
|
||||||
self.println()
|
self.println()
|
||||||
self.prune() # stop recursing
|
self.prune() # stop recursing
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user