Skip to content

Commit 0b49683

Browse files
committed
Handle EXTENDED_ARGS and wordcode too..
while we are at it. Use xdis to help out here.
1 parent 68518e2 commit 0b49683

File tree

2 files changed

+67
-58
lines changed

2 files changed

+67
-58
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
*.egg-info
22
*.pyc
3+
*~
34
.coverage
45
.tox
56
/*~

xpython/pyvm2.py

Lines changed: 66 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
import six
1212
from six.moves import reprlib
1313

14-
from xdis import PYTHON3, PYTHON_VERSION
14+
from xdis import PYTHON3, PYTHON_VERSION, instruction_size, op_has_argument
15+
from xdis.util import code2num
1516
from xdis.op_imports import get_opcode_module
1617

1718
from xpython.pyobj import Frame, Block, Function, Generator
@@ -56,6 +57,7 @@ def __init__(self, python_version=PYTHON_VERSION):
5657
int_vers = int(python_version * 10)
5758
version_info = (int_vers // 10, int_vers % 10)
5859
self.opc = get_opcode_module(version_info)
60+
self.extended_arg_size = instruction_size(self.opc.EXTENDED_ARG, self.opc)
5961
if int_vers < 30:
6062
if int_vers == 27:
6163
from xpython.byteop.byteop27 import ByteOp27
@@ -64,36 +66,20 @@ def __init__(self, python_version=PYTHON_VERSION):
6466
from xpython.byteop.byteop26 import ByteOp26
6567
self.byteop = ByteOp26(self)
6668
pass
67-
elif int_vers == 25:
68-
from xpython.byteop.byteop25 import ByteOp25
69-
self.byteop = ByteOp25(self)
70-
pass
71-
else:
72-
raise RuntimeError("Version %s not supported yet" % python_version)
7369
pass
7470
else:
7571
# 3.0 or greater
76-
if int_vers >= 34:
77-
if int_vers == 34:
78-
from xpython.byteop.byteop34 import ByteOp34
79-
self.byteop = ByteOp34(self)
80-
elif int_vers == 35:
81-
from xpython.byteop.byteop35 import ByteOp35
82-
self.byteop = ByteOp35(self)
83-
pass
84-
else:
85-
raise RuntimeError("Version %s not supported yet" % python_version)
86-
pass
72+
if int_vers == 33:
73+
from xpython.byteop.byteop33 import ByteOp33
74+
self.byteop = ByteOp33(self)
75+
elif int_vers == 34:
76+
from xpython.byteop.byteop34 import ByteOp34
77+
self.byteop = ByteOp34(self)
78+
elif int_vers == 35:
79+
from xpython.byteop.byteop35 import ByteOp35
80+
self.byteop = ByteOp35(self)
8781
else:
88-
if int_vers == 32:
89-
from xpython.byteop.byteop32 import ByteOp32
90-
self.byteop = ByteOp32(self)
91-
elif int_vers == 33:
92-
from xpython.byteop.byteop33 import ByteOp33
93-
self.byteop = ByteOp33(self)
94-
else:
95-
raise RuntimeError("Version %s not supported yet" % python_version)
96-
82+
self.byteop = None
9783

9884
def top(self):
9985
"""Return the value at the top of the stack, with no changes."""
@@ -216,39 +202,61 @@ def unwind_block(self, block):
216202
def parse_byte_and_args(self):
217203
""" Parse 1 - 3 bytes of bytecode into
218204
an instruction and optionally arguments."""
205+
219206
f = self.frame
220-
opoffset = f.f_lasti
221-
line_number = self.linestarts.get(opoffset, None)
222207
f_code = f.f_code
223208
co_code = f_code.co_code
224-
byteCode = byteint(co_code[opoffset])
225-
f.f_lasti += 1
226-
byteName = self.opc.opname[byteCode]
227-
arg = None
228-
arguments = []
229-
if byteCode >= self.opc.HAVE_ARGUMENT:
230-
arg = co_code[f.f_lasti : f.f_lasti + 2]
231-
f.f_lasti += 2
232-
intArg = byteint(arg[0]) + (byteint(arg[1]) << 8)
233-
if byteCode in self.opc.CONST_OPS:
234-
arg = f_code.co_consts[intArg]
235-
elif byteCode in self.opc.FREE_OPS:
236-
if intArg < len(f_code.co_cellvars):
237-
arg = f_code.co_cellvars[intArg]
209+
extended_arg = 0
210+
211+
while True:
212+
opoffset = f.f_lasti
213+
line_number = self.linestarts.get(opoffset, None)
214+
byteCode = byteint(co_code[opoffset])
215+
byteName = self.opc.opname[byteCode]
216+
f.f_lasti += 1
217+
arg = None
218+
arguments = []
219+
if op_has_argument(byteCode, self.opc):
220+
if PYTHON_VERSION >= 3.6:
221+
intArg = code2num(co_code, f.f_lasti) | extended_arg
222+
# Note: Python 3.6.0a1 is 2, for 3.6.a3 and beyond we have 1
223+
f.f_lasti += 1
224+
if byteCode == self.opc.EXTENDED_ARG:
225+
extended_arg = (intArg << 8)
226+
continue
227+
else:
228+
extended_arg = 0
238229
else:
239-
var_idx = intArg - len(f.f_code.co_cellvars)
240-
arg = f_code.co_freevars[var_idx]
241-
elif byteCode in self.opc.NAME_OPS:
242-
arg = f_code.co_names[intArg]
243-
elif byteCode in self.opc.JREL_OPS:
244-
arg = f.f_lasti + intArg
245-
elif byteCode in self.opc.JABS_OPS:
246-
arg = intArg
247-
elif byteCode in self.opc.LOCAL_OPS:
248-
arg = f_code.co_varnames[intArg]
249-
else:
250-
arg = intArg
251-
arguments = [arg]
230+
intArg = code2num(co_code, f.f_lasti) + code2num(co_code, f.f_lasti+1)*256 + extended_arg
231+
f.f_lasti += 2
232+
if byteCode == self.opc.EXTENDED_ARG:
233+
extended_arg = intArg*65536
234+
continue
235+
else:
236+
extended_arg = 0
237+
238+
if byteCode in self.opc.CONST_OPS:
239+
arg = f_code.co_consts[intArg]
240+
elif byteCode in self.opc.FREE_OPS:
241+
if intArg < len(f_code.co_cellvars):
242+
arg = f_code.co_cellvars[intArg]
243+
else:
244+
var_idx = intArg - len(f.f_code.co_cellvars)
245+
arg = f_code.co_freevars[var_idx]
246+
elif byteCode in self.opc.NAME_OPS:
247+
arg = f_code.co_names[intArg]
248+
elif byteCode in self.opc.JREL_OPS:
249+
arg = f.f_lasti + intArg
250+
elif byteCode in self.opc.JABS_OPS:
251+
arg = intArg
252+
elif byteCode in self.opc.LOCAL_OPS:
253+
arg = f_code.co_varnames[intArg]
254+
else:
255+
arg = intArg
256+
arguments = [arg]
257+
elif PYTHON_VERSION >= 3.6:
258+
f.f_lasti += 1
259+
break
252260

253261
return byteName, arguments, opoffset, line_number
254262

@@ -420,7 +428,7 @@ def run_frame(self, frame):
420428
self.pop_frame()
421429

422430
if why == "exception":
423-
if self.last_exception:
431+
if self.last_exception and self.last_exception[0]:
424432
six.reraise(*self.last_exception)
425433
else:
426434
raise VirtualMachineError("Borked exception recording")
@@ -716,7 +724,7 @@ def byte_SETUP_WITH(self, dest):
716724
## Functions
717725

718726
def byte_MAKE_CLOSURE(self, argc):
719-
if PYTHON_VERSION >= 3.3:
727+
if PYTHON3:
720728
# TODO: the py3 docs don't mention this change.
721729
name = self.pop()
722730
else:

0 commit comments

Comments
 (0)