You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
Handle PyPy CALL_METHOD op more correctly
Start testing pypy2.7 and 3.2 bytecodes
This commit is contained in:
@@ -37,7 +37,7 @@ entry_points={
|
|||||||
]}
|
]}
|
||||||
ftp_url = None
|
ftp_url = None
|
||||||
install_requires = ['spark-parser >= 1.4.0',
|
install_requires = ['spark-parser >= 1.4.0',
|
||||||
'xdis >= 2.0.1']
|
'xdis >= 2.0.2']
|
||||||
license = 'MIT'
|
license = 'MIT'
|
||||||
mailing_list = 'python-debugger@googlegroups.com'
|
mailing_list = 'python-debugger@googlegroups.com'
|
||||||
modname = 'uncompyle6'
|
modname = 'uncompyle6'
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
spark-parser >= 1.2.1
|
spark-parser >= 1.2.1
|
||||||
xdis >= 2.0.1
|
xdis >= 2.0.2
|
||||||
|
@@ -112,7 +112,15 @@ check-3.4-ok:
|
|||||||
|
|
||||||
#: PyPy of some sort. E.g. [PyPy 5.0.1 with GCC 4.8.4]
|
#: PyPy of some sort. E.g. [PyPy 5.0.1 with GCC 4.8.4]
|
||||||
# Skip for now
|
# Skip for now
|
||||||
2.4 2.6 5.0:
|
2.6:
|
||||||
|
|
||||||
|
#: PyPy 5.0.x with ...
|
||||||
|
5.0:
|
||||||
|
$(PYTHON) test_pythonlib.py --bytecode-pypy2.7 --verify
|
||||||
|
|
||||||
|
#: PyPy 2.4.x with ...
|
||||||
|
2.4:
|
||||||
|
$(PYTHON) test_pythonlib.py --bytecode-pypy3.2 --verify
|
||||||
|
|
||||||
clean: clean-py-dis clean-dis clean-unverified
|
clean: clean-py-dis clean-dis clean-unverified
|
||||||
|
|
||||||
|
BIN
test/bytecode_pypy2.7/01_fns.pyc
Normal file
BIN
test/bytecode_pypy2.7/01_fns.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_pypy2.7/02_closure.pyc
Normal file
BIN
test/bytecode_pypy2.7/02_closure.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_pypy2.7/02_complex.pyc
Normal file
BIN
test/bytecode_pypy2.7/02_complex.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_pypy2.7/02_def.pyc
Normal file
BIN
test/bytecode_pypy2.7/02_def.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_pypy2.7/02_slice.pyc
Normal file
BIN
test/bytecode_pypy2.7/02_slice.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_pypy2.7/05_setattr.pyc
Normal file
BIN
test/bytecode_pypy2.7/05_setattr.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_pypy3.2/05_setattr.pyc
Normal file
BIN
test/bytecode_pypy3.2/05_setattr.pyc
Normal file
Binary file not shown.
BIN
test/bytecode_pypy3.2/06_setif_comprehension.pyc
Normal file
BIN
test/bytecode_pypy3.2/06_setif_comprehension.pyc
Normal file
Binary file not shown.
9
test/simple_source/bug27+/05_setattr.py
Normal file
9
test/simple_source/bug27+/05_setattr.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Ensure PyPy handling of:
|
||||||
|
# key, value in slotstate.items().
|
||||||
|
# PyPy uses LOOKUP_METHOD and CALL_METHOD instead
|
||||||
|
# of LOAD_ATTR and CALL_FUNCTION
|
||||||
|
def bug(state, slotstate):
|
||||||
|
if state:
|
||||||
|
if slotstate is not None:
|
||||||
|
for key, value in slotstate.items():
|
||||||
|
setattr(state, key, 2)
|
@@ -266,14 +266,12 @@ class Python2Parser(PythonParser):
|
|||||||
self.seen1024 = True
|
self.seen1024 = True
|
||||||
rule = ('build_list ::= ' + 'expr1024 '*thousands +
|
rule = ('build_list ::= ' + 'expr1024 '*thousands +
|
||||||
'expr32 '*thirty32s + 'expr '*(v%32) + opname)
|
'expr32 '*thirty32s + 'expr '*(v%32) + opname)
|
||||||
elif opname == 'CALL_METHOD':
|
elif opname == 'LOOKUP_METHOD':
|
||||||
# A PyPy speciality
|
# A PyPy speciality - DRY with parse3
|
||||||
self.add_unique_rule("load_attr ::= LOAD_FAST LOOKUP_METHOD",
|
self.add_unique_rule("load_attr ::= LOAD_FAST LOOKUP_METHOD",
|
||||||
opname_base, v, customize)
|
opname, v, customize)
|
||||||
self.add_unique_rule("load_attr ::= LOAD_NAME LOOKUP_METHOD",
|
self.add_unique_rule("load_attr ::= LOAD_NAME LOOKUP_METHOD",
|
||||||
opname_base, v, customize)
|
opname, v, customize)
|
||||||
self.add_unique_rule("call_function ::= expr CALL_METHOD",
|
|
||||||
opname_base, v, customize)
|
|
||||||
continue
|
continue
|
||||||
elif opname == 'JUMP_IF_NOT_DEBUG':
|
elif opname == 'JUMP_IF_NOT_DEBUG':
|
||||||
self.add_unique_rule(
|
self.add_unique_rule(
|
||||||
@@ -314,11 +312,19 @@ class Python2Parser(PythonParser):
|
|||||||
# rule = 'mkfunc ::= %s closure_list LOAD_CONST %s' % ('expr '*v, opname)
|
# rule = 'mkfunc ::= %s closure_list LOAD_CONST %s' % ('expr '*v, opname)
|
||||||
elif opname_base in ('CALL_FUNCTION', 'CALL_FUNCTION_VAR',
|
elif opname_base in ('CALL_FUNCTION', 'CALL_FUNCTION_VAR',
|
||||||
'CALL_FUNCTION_VAR_KW', 'CALL_FUNCTION_KW'):
|
'CALL_FUNCTION_VAR_KW', 'CALL_FUNCTION_KW'):
|
||||||
na = (v & 0xff) # positional parameters
|
args_pos = (v & 0xff) # positional parameters
|
||||||
nk = (v >> 8) & 0xff # keyword parameters
|
args_kw = (v >> 8) & 0xff # keyword parameters
|
||||||
# number of apply equiv arguments:
|
# number of apply equiv arguments:
|
||||||
nak = ( len(opname_base)-len('CALL_FUNCTION') ) // 3
|
nak = ( len(opname_base)-len('CALL_FUNCTION') ) // 3
|
||||||
rule = 'call_function ::= expr ' + 'expr '*na + 'kwarg '*nk \
|
rule = 'call_function ::= expr ' + 'expr '*args_pos + 'kwarg '*args_kw \
|
||||||
|
+ 'expr ' * nak + opname
|
||||||
|
elif opname_base == 'CALL_METHOD':
|
||||||
|
# PyPy only - DRY with parse3
|
||||||
|
args_pos = (v & 0xff) # positional parameters
|
||||||
|
args_kw = (v >> 8) & 0xff # keyword parameters
|
||||||
|
# number of apply equiv arguments:
|
||||||
|
nak = ( len(opname_base)-len('CALL_METHOD') ) // 3
|
||||||
|
rule = 'call_function ::= expr ' + 'expr '*args_pos + 'kwarg '*args_kw \
|
||||||
+ 'expr ' * nak + opname
|
+ 'expr ' * nak + opname
|
||||||
else:
|
else:
|
||||||
raise Exception('unknown customize token %s' % opname)
|
raise Exception('unknown customize token %s' % opname)
|
||||||
|
@@ -462,14 +462,12 @@ class Python3Parser(PythonParser):
|
|||||||
if opname_base == 'BUILD_TUPLE':
|
if opname_base == 'BUILD_TUPLE':
|
||||||
rule = ('load_closure ::= %s%s' % (('LOAD_CLOSURE ' * v), opname))
|
rule = ('load_closure ::= %s%s' % (('LOAD_CLOSURE ' * v), opname))
|
||||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
elif opname == 'CALL_METHOD':
|
elif opname == 'LOOKUP_METHOD':
|
||||||
# A PyPy speciality
|
# A PyPy speciality - DRY with parse2
|
||||||
self.add_unique_rule("load_attr ::= LOAD_FAST LOOKUP_METHOD",
|
self.add_unique_rule("load_attr ::= LOAD_FAST LOOKUP_METHOD",
|
||||||
opname, token.attr, customize)
|
opname, token.attr, customize)
|
||||||
self.add_unique_rule("load_attr ::= LOAD_NAME LOOKUP_METHOD",
|
self.add_unique_rule("load_attr ::= LOAD_NAME LOOKUP_METHOD",
|
||||||
opname, token.attr, customize)
|
opname, token.attr, customize)
|
||||||
self.add_unique_rule("call_function ::= expr CALL_METHOD",
|
|
||||||
opname, token.attr, customize)
|
|
||||||
continue
|
continue
|
||||||
elif opname == 'JUMP_IF_NOT_DEBUG':
|
elif opname == 'JUMP_IF_NOT_DEBUG':
|
||||||
self.add_unique_rule(
|
self.add_unique_rule(
|
||||||
@@ -526,6 +524,17 @@ class Python3Parser(PythonParser):
|
|||||||
rule = ('mkfunc ::= kwargs %sexpr %s' %
|
rule = ('mkfunc ::= kwargs %sexpr %s' %
|
||||||
('pos_arg ' * args_pos, opname))
|
('pos_arg ' * args_pos, opname))
|
||||||
self.add_unique_rule(rule, opname, token.attr, customize)
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
|
elif opname_base == 'CALL_METHOD':
|
||||||
|
# PyPy only - DRY with parse2
|
||||||
|
args_pos = (token.attr & 0xff) # positional parameters
|
||||||
|
args_kw = (token.attr >> 8) & 0xff # keyword parameters
|
||||||
|
# number of apply equiv arguments:
|
||||||
|
nak = ( len(opname_base)-len('CALL_METHOD') ) // 3
|
||||||
|
rule = ('call_function ::= expr '
|
||||||
|
+ ('pos_arg ' * args_pos)
|
||||||
|
+ ('kwarg ' * args_kw)
|
||||||
|
+ 'expr ' * nak + token.type)
|
||||||
|
self.add_unique_rule(rule, opname, token.attr, customize)
|
||||||
elif opname.startswith('MAKE_CLOSURE'):
|
elif opname.startswith('MAKE_CLOSURE'):
|
||||||
# DRY with MAKE_FUNCTION
|
# DRY with MAKE_FUNCTION
|
||||||
# Note: this probably doesn't handle kwargs proprerly
|
# Note: this probably doesn't handle kwargs proprerly
|
||||||
|
@@ -192,8 +192,11 @@ class Scanner2(scan.Scanner):
|
|||||||
opname = '%s_%d' % (opname, oparg)
|
opname = '%s_%d' % (opname, oparg)
|
||||||
if op != self.opc.BUILD_SLICE:
|
if op != self.opc.BUILD_SLICE:
|
||||||
customize[opname] = oparg
|
customize[opname] = oparg
|
||||||
elif self.is_pypy and opname in ('CALL_METHOD', 'JUMP_IF_NOT_DEBUG'):
|
elif self.is_pypy and opname in ('LOOKUP_METHOD', 'JUMP_IF_NOT_DEBUG'):
|
||||||
customize[opname] = oparg
|
# The value in the dict is used in rule uniquness key.
|
||||||
|
# These ops need only be done once. Hence we use arbitrary constant
|
||||||
|
# 0.
|
||||||
|
customize[opname] = 0
|
||||||
elif op == self.opc.JUMP_ABSOLUTE:
|
elif op == self.opc.JUMP_ABSOLUTE:
|
||||||
target = self.get_target(offset)
|
target = self.get_target(offset)
|
||||||
if target < offset:
|
if target < offset:
|
||||||
|
@@ -52,7 +52,7 @@ class Scanner27(Scanner2):
|
|||||||
# opcodes with expect a variable number pushed values whose
|
# opcodes with expect a variable number pushed values whose
|
||||||
# count is in the opcode. For parsing we generally change the
|
# count is in the opcode. For parsing we generally change the
|
||||||
# opcode name to include that number.
|
# opcode name to include that number.
|
||||||
self.varargs_ops = frozenset([
|
varargs_ops = set([
|
||||||
self.opc.BUILD_LIST, self.opc.BUILD_TUPLE,
|
self.opc.BUILD_LIST, self.opc.BUILD_TUPLE,
|
||||||
self.opc.BUILD_SLICE, self.opc.UNPACK_SEQUENCE,
|
self.opc.BUILD_SLICE, self.opc.UNPACK_SEQUENCE,
|
||||||
self.opc.MAKE_FUNCTION, self.opc.CALL_FUNCTION,
|
self.opc.MAKE_FUNCTION, self.opc.CALL_FUNCTION,
|
||||||
@@ -62,6 +62,10 @@ class Scanner27(Scanner2):
|
|||||||
# New in Python 2.7
|
# New in Python 2.7
|
||||||
self.opc.BUILD_SET, self.opc.BUILD_MAP])
|
self.opc.BUILD_SET, self.opc.BUILD_MAP])
|
||||||
|
|
||||||
|
if is_pypy:
|
||||||
|
varargs_ops.add(self.opc.CALL_METHOD)
|
||||||
|
self.varargs_ops = frozenset(varargs_ops)
|
||||||
|
|
||||||
# "setup" opcodes
|
# "setup" opcodes
|
||||||
self.setup_ops = frozenset([
|
self.setup_ops = frozenset([
|
||||||
self.opc.SETUP_EXCEPT, self.opc.SETUP_FINALLY,
|
self.opc.SETUP_EXCEPT, self.opc.SETUP_FINALLY,
|
||||||
|
@@ -89,14 +89,16 @@ class Scanner3(scan.Scanner):
|
|||||||
|
|
||||||
# Opcodes that take a variable number of arguments
|
# Opcodes that take a variable number of arguments
|
||||||
# (expr's)
|
# (expr's)
|
||||||
self.varargs = frozenset([self.opc.BUILD_LIST,
|
varargs_ops = set([
|
||||||
self.opc.BUILD_TUPLE,
|
self.opc.BUILD_LIST, self.opc.BUILD_TUPLE,
|
||||||
self.opc.BUILD_SET,
|
self.opc.BUILD_SET, self.opc.BUILD_SLICE,
|
||||||
self.opc.BUILD_SLICE,
|
self.opc.BUILD_MAP, self.opc.UNPACK_SEQUENCE,
|
||||||
self.opc.BUILD_MAP,
|
|
||||||
self.opc.UNPACK_SEQUENCE,
|
|
||||||
self.opc.RAISE_VARARGS])
|
self.opc.RAISE_VARARGS])
|
||||||
|
|
||||||
|
if is_pypy:
|
||||||
|
varargs_ops.add(self.opc.CALL_METHOD)
|
||||||
|
self.varargs_ops = frozenset(varargs_ops)
|
||||||
|
|
||||||
# Not really a set, but still clasification-like
|
# Not really a set, but still clasification-like
|
||||||
self.statement_opcode_sequences = [
|
self.statement_opcode_sequences = [
|
||||||
(self.opc.POP_JUMP_IF_FALSE, self.opc.JUMP_FORWARD),
|
(self.opc.POP_JUMP_IF_FALSE, self.opc.JUMP_FORWARD),
|
||||||
@@ -234,7 +236,7 @@ class Scanner3(scan.Scanner):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
elif op in self.varargs:
|
elif op in self.varargs_ops:
|
||||||
pos_args = inst.argval
|
pos_args = inst.argval
|
||||||
opname = '%s_%d' % (opname, pos_args)
|
opname = '%s_%d' % (opname, pos_args)
|
||||||
elif self.is_pypy and opname in ('CALL_METHOD', 'JUMP_IF_NOT_DEBUG'):
|
elif self.is_pypy and opname in ('CALL_METHOD', 'JUMP_IF_NOT_DEBUG'):
|
||||||
|
Reference in New Issue
Block a user