Commit d490f32b authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #26647: Python interpreter now uses 16-bit wordcode instead of bytecode.

Patch by Demur Rumed.
parent 92ba6865
...@@ -31,9 +31,9 @@ the following command can be used to display the disassembly of ...@@ -31,9 +31,9 @@ the following command can be used to display the disassembly of
>>> dis.dis(myfunc) >>> dis.dis(myfunc)
2 0 LOAD_GLOBAL 0 (len) 2 0 LOAD_GLOBAL 0 (len)
3 LOAD_FAST 0 (alist) 2 LOAD_FAST 0 (alist)
6 CALL_FUNCTION 1 4 CALL_FUNCTION 1
9 RETURN_VALUE 6 RETURN_VALUE
(The "2" is a line number). (The "2" is a line number).
...@@ -682,8 +682,7 @@ iterations of the loop. ...@@ -682,8 +682,7 @@ iterations of the loop.
.. XXX explain the WHY stuff! .. XXX explain the WHY stuff!
All of the following opcodes expect arguments. An argument is two bytes, with All of the following opcodes use their arguments.
the more significant byte last.
.. opcode:: STORE_NAME (namei) .. opcode:: STORE_NAME (namei)
......
...@@ -79,9 +79,9 @@ class PythonValuesTestCase(unittest.TestCase): ...@@ -79,9 +79,9 @@ class PythonValuesTestCase(unittest.TestCase):
continue continue
items.append((entry.name.decode("ascii"), entry.size)) items.append((entry.name.decode("ascii"), entry.size))
expected = [("__hello__", 161), expected = [("__hello__", 139),
("__phello__", -161), ("__phello__", -139),
("__phello__.spam", 161), ("__phello__.spam", 139),
] ]
self.assertEqual(items, expected, "PyImport_FrozenModules example " self.assertEqual(items, expected, "PyImport_FrozenModules example "
"in Doc/library/ctypes.rst may be out of date") "in Doc/library/ctypes.rst may be out of date")
......
...@@ -285,7 +285,6 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None, ...@@ -285,7 +285,6 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
""" """
labels = findlabels(code) labels = findlabels(code)
starts_line = None starts_line = None
free = None
for offset, op, arg in _unpack_opargs(code): for offset, op, arg in _unpack_opargs(code):
if linestarts is not None: if linestarts is not None:
starts_line = linestarts.get(offset, None) starts_line = linestarts.get(offset, None)
...@@ -296,7 +295,7 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None, ...@@ -296,7 +295,7 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
argrepr = '' argrepr = ''
if arg is not None: if arg is not None:
# Set argval to the dereferenced value of the argument when # Set argval to the dereferenced value of the argument when
# availabe, and argrepr to the string representation of argval. # available, and argrepr to the string representation of argval.
# _disassemble_bytes needs the string repr of the # _disassemble_bytes needs the string repr of the
# raw name index for LOAD_GLOBAL, LOAD_CONST, etc. # raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
argval = arg argval = arg
...@@ -305,7 +304,7 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None, ...@@ -305,7 +304,7 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
elif op in hasname: elif op in hasname:
argval, argrepr = _get_name_info(arg, names) argval, argrepr = _get_name_info(arg, names)
elif op in hasjrel: elif op in hasjrel:
argval = offset + 3 + arg argval = offset + 2 + arg
argrepr = "to " + repr(argval) argrepr = "to " + repr(argval)
elif op in haslocal: elif op in haslocal:
argval, argrepr = _get_name_info(arg, varnames) argval, argrepr = _get_name_info(arg, varnames)
...@@ -352,23 +351,15 @@ def _disassemble_str(source, *, file=None): ...@@ -352,23 +351,15 @@ def _disassemble_str(source, *, file=None):
disco = disassemble # XXX For backwards compatibility disco = disassemble # XXX For backwards compatibility
def _unpack_opargs(code): def _unpack_opargs(code):
# enumerate() is not an option, since we sometimes process
# multiple elements on a single pass through the loop
extended_arg = 0 extended_arg = 0
n = len(code) for i in range(0, len(code), 2):
i = 0
while i < n:
op = code[i] op = code[i]
offset = i
i = i+1
arg = None
if op >= HAVE_ARGUMENT: if op >= HAVE_ARGUMENT:
arg = code[i] + code[i+1]*256 + extended_arg arg = code[i+1] | extended_arg
extended_arg = 0 extended_arg = (arg << 8) if op == EXTENDED_ARG else 0
i = i+2 else:
if op == EXTENDED_ARG: arg = None
extended_arg = arg*65536 yield (i, op, arg)
yield (offset, op, arg)
def findlabels(code): def findlabels(code):
"""Detect all offsets in a byte code which are jump targets. """Detect all offsets in a byte code which are jump targets.
...@@ -379,14 +370,14 @@ def findlabels(code): ...@@ -379,14 +370,14 @@ def findlabels(code):
labels = [] labels = []
for offset, op, arg in _unpack_opargs(code): for offset, op, arg in _unpack_opargs(code):
if arg is not None: if arg is not None:
label = -1
if op in hasjrel: if op in hasjrel:
label = offset + 3 + arg label = offset + 2 + arg
elif op in hasjabs: elif op in hasjabs:
label = arg label = arg
if label >= 0: else:
if label not in labels: continue
labels.append(label) if label not in labels:
labels.append(label)
return labels return labels
def findlinestarts(code): def findlinestarts(code):
......
...@@ -225,6 +225,7 @@ _code_type = type(_write_atomic.__code__) ...@@ -225,6 +225,7 @@ _code_type = type(_write_atomic.__code__)
# Python 3.5b2 3350 (add GET_YIELD_FROM_ITER opcode #24400) # Python 3.5b2 3350 (add GET_YIELD_FROM_ITER opcode #24400)
# Python 3.6a0 3360 (add FORMAT_VALUE opcode #25483 # Python 3.6a0 3360 (add FORMAT_VALUE opcode #25483
# Python 3.6a0 3361 (lineno delta of code.co_lnotab becomes signed) # Python 3.6a0 3361 (lineno delta of code.co_lnotab becomes signed)
# Python 3.6a0 3370 (16 bit wordcode)
# #
# MAGIC must change whenever the bytecode emitted by the compiler may no # MAGIC must change whenever the bytecode emitted by the compiler may no
# longer be understood by older implementations of the eval loop (usually # longer be understood by older implementations of the eval loop (usually
...@@ -233,7 +234,7 @@ _code_type = type(_write_atomic.__code__) ...@@ -233,7 +234,7 @@ _code_type = type(_write_atomic.__code__)
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated. # in PC/launcher.c must also be updated.
MAGIC_NUMBER = (3361).to_bytes(2, 'little') + b'\r\n' MAGIC_NUMBER = (3370).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
_PYCACHE = '__pycache__' _PYCACHE = '__pycache__'
......
...@@ -40,41 +40,41 @@ class _C: ...@@ -40,41 +40,41 @@ class _C:
dis_c_instance_method = """\ dis_c_instance_method = """\
%3d 0 LOAD_FAST 1 (x) %3d 0 LOAD_FAST 1 (x)
3 LOAD_CONST 1 (1) 2 LOAD_CONST 1 (1)
6 COMPARE_OP 2 (==) 4 COMPARE_OP 2 (==)
9 LOAD_FAST 0 (self) 6 LOAD_FAST 0 (self)
12 STORE_ATTR 0 (x) 8 STORE_ATTR 0 (x)
15 LOAD_CONST 0 (None) 10 LOAD_CONST 0 (None)
18 RETURN_VALUE 12 RETURN_VALUE
""" % (_C.__init__.__code__.co_firstlineno + 1,) """ % (_C.__init__.__code__.co_firstlineno + 1,)
dis_c_instance_method_bytes = """\ dis_c_instance_method_bytes = """\
0 LOAD_FAST 1 (1) 0 LOAD_FAST 1 (1)
3 LOAD_CONST 1 (1) 2 LOAD_CONST 1 (1)
6 COMPARE_OP 2 (==) 4 COMPARE_OP 2 (==)
9 LOAD_FAST 0 (0) 6 LOAD_FAST 0 (0)
12 STORE_ATTR 0 (0) 8 STORE_ATTR 0 (0)
15 LOAD_CONST 0 (0) 10 LOAD_CONST 0 (0)
18 RETURN_VALUE 12 RETURN_VALUE
""" """
dis_c_class_method = """\ dis_c_class_method = """\
%3d 0 LOAD_FAST 1 (x) %3d 0 LOAD_FAST 1 (x)
3 LOAD_CONST 1 (1) 2 LOAD_CONST 1 (1)
6 COMPARE_OP 2 (==) 4 COMPARE_OP 2 (==)
9 LOAD_FAST 0 (cls) 6 LOAD_FAST 0 (cls)
12 STORE_ATTR 0 (x) 8 STORE_ATTR 0 (x)
15 LOAD_CONST 0 (None) 10 LOAD_CONST 0 (None)
18 RETURN_VALUE 12 RETURN_VALUE
""" % (_C.cm.__code__.co_firstlineno + 2,) """ % (_C.cm.__code__.co_firstlineno + 2,)
dis_c_static_method = """\ dis_c_static_method = """\
%3d 0 LOAD_FAST 0 (x) %3d 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (1) 2 LOAD_CONST 1 (1)
6 COMPARE_OP 2 (==) 4 COMPARE_OP 2 (==)
9 STORE_FAST 0 (x) 6 STORE_FAST 0 (x)
12 LOAD_CONST 0 (None) 8 LOAD_CONST 0 (None)
15 RETURN_VALUE 10 RETURN_VALUE
""" % (_C.sm.__code__.co_firstlineno + 2,) """ % (_C.sm.__code__.co_firstlineno + 2,)
# Class disassembling info has an extra newline at end. # Class disassembling info has an extra newline at end.
...@@ -95,23 +95,23 @@ def _f(a): ...@@ -95,23 +95,23 @@ def _f(a):
dis_f = """\ dis_f = """\
%3d 0 LOAD_GLOBAL 0 (print) %3d 0 LOAD_GLOBAL 0 (print)
3 LOAD_FAST 0 (a) 2 LOAD_FAST 0 (a)
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 4 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 POP_TOP 6 POP_TOP
%3d 10 LOAD_CONST 1 (1) %3d 8 LOAD_CONST 1 (1)
13 RETURN_VALUE 10 RETURN_VALUE
""" % (_f.__code__.co_firstlineno + 1, """ % (_f.__code__.co_firstlineno + 1,
_f.__code__.co_firstlineno + 2) _f.__code__.co_firstlineno + 2)
dis_f_co_code = """\ dis_f_co_code = """\
0 LOAD_GLOBAL 0 (0) 0 LOAD_GLOBAL 0 (0)
3 LOAD_FAST 0 (0) 2 LOAD_FAST 0 (0)
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 4 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 POP_TOP 6 POP_TOP
10 LOAD_CONST 1 (1) 8 LOAD_CONST 1 (1)
13 RETURN_VALUE 10 RETURN_VALUE
""" """
...@@ -121,20 +121,20 @@ def bug708901(): ...@@ -121,20 +121,20 @@ def bug708901():
pass pass
dis_bug708901 = """\ dis_bug708901 = """\
%3d 0 SETUP_LOOP 23 (to 26) %3d 0 SETUP_LOOP 18 (to 20)
3 LOAD_GLOBAL 0 (range) 2 LOAD_GLOBAL 0 (range)
6 LOAD_CONST 1 (1) 4 LOAD_CONST 1 (1)
%3d 9 LOAD_CONST 2 (10) %3d 6 LOAD_CONST 2 (10)
12 CALL_FUNCTION 2 (2 positional, 0 keyword pair) 8 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
15 GET_ITER 10 GET_ITER
>> 16 FOR_ITER 6 (to 25) >> 12 FOR_ITER 4 (to 18)
19 STORE_FAST 0 (res) 14 STORE_FAST 0 (res)
%3d 22 JUMP_ABSOLUTE 16 %3d 16 JUMP_ABSOLUTE 12
>> 25 POP_BLOCK >> 18 POP_BLOCK
>> 26 LOAD_CONST 0 (None) >> 20 LOAD_CONST 0 (None)
29 RETURN_VALUE 22 RETURN_VALUE
""" % (bug708901.__code__.co_firstlineno + 1, """ % (bug708901.__code__.co_firstlineno + 1,
bug708901.__code__.co_firstlineno + 2, bug708901.__code__.co_firstlineno + 2,
bug708901.__code__.co_firstlineno + 3) bug708901.__code__.co_firstlineno + 3)
...@@ -147,22 +147,22 @@ def bug1333982(x=[]): ...@@ -147,22 +147,22 @@ def bug1333982(x=[]):
dis_bug1333982 = """\ dis_bug1333982 = """\
%3d 0 LOAD_CONST 1 (0) %3d 0 LOAD_CONST 1 (0)
3 POP_JUMP_IF_TRUE 35 2 POP_JUMP_IF_TRUE 26
6 LOAD_GLOBAL 0 (AssertionError) 4 LOAD_GLOBAL 0 (AssertionError)
9 LOAD_CONST 2 (<code object <listcomp> at 0x..., file "%s", line %d>) 6 LOAD_CONST 2 (<code object <listcomp> at 0x..., file "%s", line %d>)
12 LOAD_CONST 3 ('bug1333982.<locals>.<listcomp>') 8 LOAD_CONST 3 ('bug1333982.<locals>.<listcomp>')
15 MAKE_FUNCTION 0 10 MAKE_FUNCTION 0
18 LOAD_FAST 0 (x) 12 LOAD_FAST 0 (x)
21 GET_ITER 14 GET_ITER
16 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
%3d 18 LOAD_CONST 4 (1)
20 BINARY_ADD
22 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 22 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
24 RAISE_VARARGS 1
%3d 25 LOAD_CONST 4 (1) %3d >> 26 LOAD_CONST 0 (None)
28 BINARY_ADD 28 RETURN_VALUE
29 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
32 RAISE_VARARGS 1
%3d >> 35 LOAD_CONST 0 (None)
38 RETURN_VALUE
""" % (bug1333982.__code__.co_firstlineno + 1, """ % (bug1333982.__code__.co_firstlineno + 1,
__file__, __file__,
bug1333982.__code__.co_firstlineno + 1, bug1333982.__code__.co_firstlineno + 1,
...@@ -171,19 +171,19 @@ dis_bug1333982 = """\ ...@@ -171,19 +171,19 @@ dis_bug1333982 = """\
_BIG_LINENO_FORMAT = """\ _BIG_LINENO_FORMAT = """\
%3d 0 LOAD_GLOBAL 0 (spam) %3d 0 LOAD_GLOBAL 0 (spam)
3 POP_TOP 2 POP_TOP
4 LOAD_CONST 0 (None) 4 LOAD_CONST 0 (None)
7 RETURN_VALUE 6 RETURN_VALUE
""" """
dis_module_expected_results = """\ dis_module_expected_results = """\
Disassembly of f: Disassembly of f:
4 0 LOAD_CONST 0 (None) 4 0 LOAD_CONST 0 (None)
3 RETURN_VALUE 2 RETURN_VALUE
Disassembly of g: Disassembly of g:
5 0 LOAD_CONST 0 (None) 5 0 LOAD_CONST 0 (None)
3 RETURN_VALUE 2 RETURN_VALUE
""" """
...@@ -191,20 +191,20 @@ expr_str = "x + 1" ...@@ -191,20 +191,20 @@ expr_str = "x + 1"
dis_expr_str = """\ dis_expr_str = """\
1 0 LOAD_NAME 0 (x) 1 0 LOAD_NAME 0 (x)
3 LOAD_CONST 0 (1) 2 LOAD_CONST 0 (1)
6 BINARY_ADD 4 BINARY_ADD
7 RETURN_VALUE 6 RETURN_VALUE
""" """
simple_stmt_str = "x = x + 1" simple_stmt_str = "x = x + 1"
dis_simple_stmt_str = """\ dis_simple_stmt_str = """\
1 0 LOAD_NAME 0 (x) 1 0 LOAD_NAME 0 (x)
3 LOAD_CONST 0 (1) 2 LOAD_CONST 0 (1)
6 BINARY_ADD 4 BINARY_ADD
7 STORE_NAME 0 (x) 6 STORE_NAME 0 (x)
10 LOAD_CONST 1 (None) 8 LOAD_CONST 1 (None)
13 RETURN_VALUE 10 RETURN_VALUE
""" """
compound_stmt_str = """\ compound_stmt_str = """\
...@@ -215,54 +215,54 @@ while 1: ...@@ -215,54 +215,54 @@ while 1:
dis_compound_stmt_str = """\ dis_compound_stmt_str = """\
1 0 LOAD_CONST 0 (0) 1 0 LOAD_CONST 0 (0)
3 STORE_NAME 0 (x) 2 STORE_NAME 0 (x)
2 6 SETUP_LOOP 14 (to 23) 2 4 SETUP_LOOP 12 (to 18)
3 >> 9 LOAD_NAME 0 (x) 3 >> 6 LOAD_NAME 0 (x)
12 LOAD_CONST 1 (1) 8 LOAD_CONST 1 (1)
15 INPLACE_ADD 10 INPLACE_ADD
16 STORE_NAME 0 (x) 12 STORE_NAME 0 (x)
19 JUMP_ABSOLUTE 9 14 JUMP_ABSOLUTE 6
22 POP_BLOCK 16 POP_BLOCK
>> 23 LOAD_CONST 2 (None) >> 18 LOAD_CONST 2 (None)
26 RETURN_VALUE 20 RETURN_VALUE
""" """
dis_traceback = """\ dis_traceback = """\
%3d 0 SETUP_EXCEPT 12 (to 15) %3d 0 SETUP_EXCEPT 12 (to 14)
%3d 3 LOAD_CONST 1 (1) %3d 2 LOAD_CONST 1 (1)
6 LOAD_CONST 2 (0) 4 LOAD_CONST 2 (0)
--> 9 BINARY_TRUE_DIVIDE --> 6 BINARY_TRUE_DIVIDE
10 POP_TOP 8 POP_TOP
11 POP_BLOCK 10 POP_BLOCK
12 JUMP_FORWARD 46 (to 61) 12 JUMP_FORWARD 40 (to 54)
%3d >> 15 DUP_TOP %3d >> 14 DUP_TOP
16 LOAD_GLOBAL 0 (Exception) 16 LOAD_GLOBAL 0 (Exception)
19 COMPARE_OP 10 (exception match) 18 COMPARE_OP 10 (exception match)
22 POP_JUMP_IF_FALSE 60 20 POP_JUMP_IF_FALSE 52
25 POP_TOP 22 POP_TOP
26 STORE_FAST 0 (e) 24 STORE_FAST 0 (e)
29 POP_TOP 26 POP_TOP
30 SETUP_FINALLY 14 (to 47) 28 SETUP_FINALLY 12 (to 42)
%3d 33 LOAD_FAST 0 (e) %3d 30 LOAD_FAST 0 (e)
36 LOAD_ATTR 1 (__traceback__) 32 LOAD_ATTR 1 (__traceback__)
39 STORE_FAST 1 (tb) 34 STORE_FAST 1 (tb)
42 POP_BLOCK 36 POP_BLOCK
43 POP_EXCEPT 38 POP_EXCEPT
44 LOAD_CONST 0 (None) 40 LOAD_CONST 0 (None)
>> 47 LOAD_CONST 0 (None) >> 42 LOAD_CONST 0 (None)
50 STORE_FAST 0 (e) 44 STORE_FAST 0 (e)
53 DELETE_FAST 0 (e) 46 DELETE_FAST 0 (e)
56 END_FINALLY 48 END_FINALLY
57 JUMP_FORWARD 1 (to 61) 50 JUMP_FORWARD 2 (to 54)
>> 60 END_FINALLY >> 52 END_FINALLY
%3d >> 61 LOAD_FAST 1 (tb) %3d >> 54 LOAD_FAST 1 (tb)
64 RETURN_VALUE 56 RETURN_VALUE
""" % (TRACEBACK_CODE.co_firstlineno + 1, """ % (TRACEBACK_CODE.co_firstlineno + 1,
TRACEBACK_CODE.co_firstlineno + 2, TRACEBACK_CODE.co_firstlineno + 2,
TRACEBACK_CODE.co_firstlineno + 3, TRACEBACK_CODE.co_firstlineno + 3,
...@@ -650,170 +650,170 @@ expected_jumpy_line = 1 ...@@ -650,170 +650,170 @@ expected_jumpy_line = 1
Instruction = dis.Instruction Instruction = dis.Instruction
expected_opinfo_outer = [ expected_opinfo_outer = [
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=3, argrepr='3', offset=0, starts_line=2, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=3, argrepr='3', offset=0, starts_line=2, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=3, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=2, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='a', argrepr='a', offset=4, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='b', argrepr='b', offset=9, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='b', argrepr='b', offset=6, starts_line=None, is_jump_target=False),
Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=12, starts_line=None, is_jump_target=False), Instruction(opname='BUILD_TUPLE', opcode=102, arg=2, argval=2, argrepr='', offset=8, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=15, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_f, argrepr=repr(code_object_f), offset=10, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f', argrepr="'outer.<locals>.f'", offset=18, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f', argrepr="'outer.<locals>.f'", offset=12, starts_line=None, is_jump_target=False),
Instruction(opname='MAKE_CLOSURE', opcode=134, arg=2, argval=2, argrepr='', offset=21, starts_line=None, is_jump_target=False), Instruction(opname='MAKE_CLOSURE', opcode=134, arg=2, argval=2, argrepr='', offset=14, starts_line=None, is_jump_target=False),
Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=24, starts_line=None, is_jump_target=False), Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=16, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=27, starts_line=7, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=18, starts_line=7, is_jump_target=False),
Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=30, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=20, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=33, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=22, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval='', argrepr="''", offset=36, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval='', argrepr="''", offset=24, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval=1, argrepr='1', offset=39, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval=1, argrepr='1', offset=26, starts_line=None, is_jump_target=False),
Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=42, starts_line=None, is_jump_target=False), Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=28, starts_line=None, is_jump_target=False),
Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=45, starts_line=None, is_jump_target=False), Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=30, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval='Hello world!', argrepr="'Hello world!'", offset=48, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval='Hello world!', argrepr="'Hello world!'", offset=32, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='7 positional, 0 keyword pair', offset=51, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='7 positional, 0 keyword pair', offset=34, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=54, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=55, starts_line=8, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=38, starts_line=8, is_jump_target=False),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=58, starts_line=None, is_jump_target=False), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=40, starts_line=None, is_jump_target=False),
] ]
expected_opinfo_f = [ expected_opinfo_f = [
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=5, argrepr='5', offset=0, starts_line=3, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=5, argrepr='5', offset=0, starts_line=3, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=6, argrepr='6', offset=3, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=6, argrepr='6', offset=2, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=2, argval='a', argrepr='a', offset=6, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CLOSURE', opcode=135, arg=2, argval='a', argrepr='a', offset=4, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='b', argrepr='b', offset=9, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CLOSURE', opcode=135, arg=3, argval='b', argrepr='b', offset=6, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='c', argrepr='c', offset=12, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CLOSURE', opcode=135, arg=0, argval='c', argrepr='c', offset=8, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='d', argrepr='d', offset=15, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CLOSURE', opcode=135, arg=1, argval='d', argrepr='d', offset=10, starts_line=None, is_jump_target=False),
Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=18, starts_line=None, is_jump_target=False), Instruction(opname='BUILD_TUPLE', opcode=102, arg=4, argval=4, argrepr='', offset=12, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=21, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=code_object_inner, argrepr=repr(code_object_inner), offset=14, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f.<locals>.inner', argrepr="'outer.<locals>.f.<locals>.inner'", offset=24, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='outer.<locals>.f.<locals>.inner', argrepr="'outer.<locals>.f.<locals>.inner'", offset=16, starts_line=None, is_jump_target=False),
Instruction(opname='MAKE_CLOSURE', opcode=134, arg=2, argval=2, argrepr='', offset=27, starts_line=None, is_jump_target=False), Instruction(opname='MAKE_CLOSURE', opcode=134, arg=2, argval=2, argrepr='', offset=18, starts_line=None, is_jump_target=False),
Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=30, starts_line=None, is_jump_target=False), Instruction(opname='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=20, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=33, starts_line=5, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=22, starts_line=5, is_jump_target=False),
Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='a', argrepr='a', offset=36, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='a', argrepr='a', offset=24, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='b', argrepr='b', offset=39, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='b', argrepr='b', offset=26, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='c', argrepr='c', offset=42, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='c', argrepr='c', offset=28, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='d', argrepr='d', offset=45, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='d', argrepr='d', offset=30, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='4 positional, 0 keyword pair', offset=48, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='4 positional, 0 keyword pair', offset=32, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=51, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=34, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=52, starts_line=6, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=36, starts_line=6, is_jump_target=False),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=55, starts_line=None, is_jump_target=False), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=38, starts_line=None, is_jump_target=False),
] ]
expected_opinfo_inner = [ expected_opinfo_inner = [
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=0, starts_line=4, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=0, starts_line=4, is_jump_target=False),
Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=3, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_DEREF', opcode=136, arg=0, argval='a', argrepr='a', offset=2, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=6, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_DEREF', opcode=136, arg=1, argval='b', argrepr='b', offset=4, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='c', argrepr='c', offset=9, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_DEREF', opcode=136, arg=2, argval='c', argrepr='c', offset=6, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='d', argrepr='d', offset=12, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_DEREF', opcode=136, arg=3, argval='d', argrepr='d', offset=8, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=15, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=10, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=18, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=12, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=6, argval=6, argrepr='6 positional, 0 keyword pair', offset=21, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=6, argval=6, argrepr='6 positional, 0 keyword pair', offset=14, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=24, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=16, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=25, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=18, starts_line=None, is_jump_target=False),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=28, starts_line=None, is_jump_target=False), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=20, starts_line=None, is_jump_target=False),
] ]
expected_opinfo_jumpy = [ expected_opinfo_jumpy = [
Instruction(opname='SETUP_LOOP', opcode=120, arg=68, argval=71, argrepr='to 71', offset=0, starts_line=3, is_jump_target=False), Instruction(opname='SETUP_LOOP', opcode=120, arg=52, argval=54, argrepr='to 54', offset=0, starts_line=3, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='range', argrepr='range', offset=3, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='range', argrepr='range', offset=2, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=6, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=4, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=9, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=6, starts_line=None, is_jump_target=False),
Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=12, starts_line=None, is_jump_target=False), Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=8, starts_line=None, is_jump_target=False),
Instruction(opname='FOR_ITER', opcode=93, arg=44, argval=60, argrepr='to 60', offset=13, starts_line=None, is_jump_target=True), Instruction(opname='FOR_ITER', opcode=93, arg=32, argval=44, argrepr='to 44', offset=10, starts_line=None, is_jump_target=True),
Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=16, starts_line=None, is_jump_target=False), Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=12, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=19, starts_line=4, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=14, starts_line=4, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=22, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=16, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=25, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=18, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=28, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=20, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=29, starts_line=5, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=22, starts_line=5, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=32, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=24, starts_line=None, is_jump_target=False),
Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=35, starts_line=None, is_jump_target=False), Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=26, starts_line=None, is_jump_target=False),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=44, argval=44, argrepr='', offset=38, starts_line=None, is_jump_target=False), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=32, argval=32, argrepr='', offset=28, starts_line=None, is_jump_target=False),
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=13, argval=13, argrepr='', offset=41, starts_line=6, is_jump_target=False), Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=10, argval=10, argrepr='', offset=30, starts_line=6, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=44, starts_line=7, is_jump_target=True), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=32, starts_line=7, is_jump_target=True),
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=47, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=34, starts_line=None, is_jump_target=False),
Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=50, starts_line=None, is_jump_target=False), Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=36, starts_line=None, is_jump_target=False),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=13, argval=13, argrepr='', offset=53, starts_line=None, is_jump_target=False), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=10, argval=10, argrepr='', offset=38, starts_line=None, is_jump_target=False),
Instruction(opname='BREAK_LOOP', opcode=80, arg=None, argval=None, argrepr='', offset=56, starts_line=8, is_jump_target=False), Instruction(opname='BREAK_LOOP', opcode=80, arg=None, argval=None, argrepr='', offset=40, starts_line=8, is_jump_target=False),
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=13, argval=13, argrepr='', offset=57, starts_line=None, is_jump_target=False), Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=10, argval=10, argrepr='', offset=42, starts_line=None, is_jump_target=False),
Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=60, starts_line=None, is_jump_target=True), Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=44, starts_line=None, is_jump_target=True),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=61, starts_line=10, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=46, starts_line=10, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=64, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=48, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=67, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=50, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=70, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=52, starts_line=None, is_jump_target=False),
Instruction(opname='SETUP_LOOP', opcode=120, arg=68, argval=142, argrepr='to 142', offset=71, starts_line=11, is_jump_target=True), Instruction(opname='SETUP_LOOP', opcode=120, arg=52, argval=108, argrepr='to 108', offset=54, starts_line=11, is_jump_target=True),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=74, starts_line=None, is_jump_target=True), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=56, starts_line=None, is_jump_target=True),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=131, argval=131, argrepr='', offset=77, starts_line=None, is_jump_target=False), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=98, argval=98, argrepr='', offset=58, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=80, starts_line=12, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=60, starts_line=12, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=83, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=62, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=86, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=64, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=89, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=66, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=90, starts_line=13, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=68, starts_line=13, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=93, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=70, starts_line=None, is_jump_target=False),
Instruction(opname='INPLACE_SUBTRACT', opcode=56, arg=None, argval=None, argrepr='', offset=96, starts_line=None, is_jump_target=False), Instruction(opname='INPLACE_SUBTRACT', opcode=56, arg=None, argval=None, argrepr='', offset=72, starts_line=None, is_jump_target=False),
Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=97, starts_line=None, is_jump_target=False), Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=74, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=100, starts_line=14, is_jump_target=False), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=76, starts_line=14, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=103, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=78, starts_line=None, is_jump_target=False),
Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=106, starts_line=None, is_jump_target=False), Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=80, starts_line=None, is_jump_target=False),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=115, argval=115, argrepr='', offset=109, starts_line=None, is_jump_target=False), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=86, argval=86, argrepr='', offset=82, starts_line=None, is_jump_target=False),
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=74, argval=74, argrepr='', offset=112, starts_line=15, is_jump_target=False), Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=56, argval=56, argrepr='', offset=84, starts_line=15, is_jump_target=False),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=115, starts_line=16, is_jump_target=True), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=86, starts_line=16, is_jump_target=True),
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=118, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=88, starts_line=None, is_jump_target=False),
Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=121, starts_line=None, is_jump_target=False), Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=90, starts_line=None, is_jump_target=False),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=74, argval=74, argrepr='', offset=124, starts_line=None, is_jump_target=False), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=56, argval=56, argrepr='', offset=92, starts_line=None, is_jump_target=False),
Instruction(opname='BREAK_LOOP', opcode=80, arg=None, argval=None, argrepr='', offset=127, starts_line=17, is_jump_target=False), Instruction(opname='BREAK_LOOP', opcode=80, arg=None, argval=None, argrepr='', offset=94, starts_line=17, is_jump_target=False),
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=74, argval=74, argrepr='', offset=128, starts_line=None, is_jump_target=False), Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=56, argval=56, argrepr='', offset=96, starts_line=None, is_jump_target=False),
Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=131, starts_line=None, is_jump_target=True), Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=98, starts_line=None, is_jump_target=True),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=132, starts_line=19, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=100, starts_line=19, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=135, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=102, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=138, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=104, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=141, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=106, starts_line=None, is_jump_target=False),
Instruction(opname='SETUP_FINALLY', opcode=122, arg=73, argval=218, argrepr='to 218', offset=142, starts_line=20, is_jump_target=True), Instruction(opname='SETUP_FINALLY', opcode=122, arg=70, argval=180, argrepr='to 180', offset=108, starts_line=20, is_jump_target=True),
Instruction(opname='SETUP_EXCEPT', opcode=121, arg=12, argval=160, argrepr='to 160', offset=145, starts_line=None, is_jump_target=False), Instruction(opname='SETUP_EXCEPT', opcode=121, arg=12, argval=124, argrepr='to 124', offset=110, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=148, starts_line=21, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=112, starts_line=21, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=151, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=7, argval=0, argrepr='0', offset=114, starts_line=None, is_jump_target=False),
Instruction(opname='BINARY_TRUE_DIVIDE', opcode=27, arg=None, argval=None, argrepr='', offset=154, starts_line=None, is_jump_target=False), Instruction(opname='BINARY_TRUE_DIVIDE', opcode=27, arg=None, argval=None, argrepr='', offset=116, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=155, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=118, starts_line=None, is_jump_target=False),
Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=156, starts_line=None, is_jump_target=False), Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=120, starts_line=None, is_jump_target=False),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=28, argval=188, argrepr='to 188', offset=157, starts_line=None, is_jump_target=False), Instruction(opname='JUMP_FORWARD', opcode=110, arg=28, argval=152, argrepr='to 152', offset=122, starts_line=None, is_jump_target=False),
Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=160, starts_line=22, is_jump_target=True), Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=124, starts_line=22, is_jump_target=True),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=161, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=126, starts_line=None, is_jump_target=False),
Instruction(opname='COMPARE_OP', opcode=107, arg=10, argval='exception match', argrepr='exception match', offset=164, starts_line=None, is_jump_target=False), Instruction(opname='COMPARE_OP', opcode=107, arg=10, argval='exception match', argrepr='exception match', offset=128, starts_line=None, is_jump_target=False),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=187, argval=187, argrepr='', offset=167, starts_line=None, is_jump_target=False), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=150, argval=150, argrepr='', offset=130, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=170, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=132, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=171, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=134, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=172, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=136, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=173, starts_line=23, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=138, starts_line=23, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=176, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=140, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=179, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=142, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=182, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=144, starts_line=None, is_jump_target=False),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=183, starts_line=None, is_jump_target=False), Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=146, starts_line=None, is_jump_target=False),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=27, argval=214, argrepr='to 214', offset=184, starts_line=None, is_jump_target=False), Instruction(opname='JUMP_FORWARD', opcode=110, arg=26, argval=176, argrepr='to 176', offset=148, starts_line=None, is_jump_target=False),
Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=187, starts_line=None, is_jump_target=True), Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=150, starts_line=None, is_jump_target=True),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=188, starts_line=25, is_jump_target=True), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=152, starts_line=25, is_jump_target=True),
Instruction(opname='SETUP_WITH', opcode=143, arg=17, argval=211, argrepr='to 211', offset=191, starts_line=None, is_jump_target=False), Instruction(opname='SETUP_WITH', opcode=143, arg=14, argval=170, argrepr='to 170', offset=154, starts_line=None, is_jump_target=False),
Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=194, starts_line=None, is_jump_target=False), Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=156, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=197, starts_line=26, is_jump_target=False), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=158, starts_line=26, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=200, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=160, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=203, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=162, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=206, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=164, starts_line=None, is_jump_target=False),
Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=207, starts_line=None, is_jump_target=False), Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=166, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=208, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=168, starts_line=None, is_jump_target=False),
Instruction(opname='WITH_CLEANUP_START', opcode=81, arg=None, argval=None, argrepr='', offset=211, starts_line=None, is_jump_target=True), Instruction(opname='WITH_CLEANUP_START', opcode=81, arg=None, argval=None, argrepr='', offset=170, starts_line=None, is_jump_target=True),
Instruction(opname='WITH_CLEANUP_FINISH', opcode=82, arg=None, argval=None, argrepr='', offset=212, starts_line=None, is_jump_target=False), Instruction(opname='WITH_CLEANUP_FINISH', opcode=82, arg=None, argval=None, argrepr='', offset=172, starts_line=None, is_jump_target=False),
Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=213, starts_line=None, is_jump_target=False), Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=174, starts_line=None, is_jump_target=False),
Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=214, starts_line=None, is_jump_target=True), Instruction(opname='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=176, starts_line=None, is_jump_target=True),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=215, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=178, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=218, starts_line=28, is_jump_target=True), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=180, starts_line=28, is_jump_target=True),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=221, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=182, starts_line=None, is_jump_target=False),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=224, starts_line=None, is_jump_target=False), Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=184, starts_line=None, is_jump_target=False),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=227, starts_line=None, is_jump_target=False), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=186, starts_line=None, is_jump_target=False),
Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=228, starts_line=None, is_jump_target=False), Instruction(opname='END_FINALLY', opcode=88, arg=None, argval=None, argrepr='', offset=188, starts_line=None, is_jump_target=False),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=229, starts_line=None, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=190, starts_line=None, is_jump_target=False),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=232, starts_line=None, is_jump_target=False), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=192, starts_line=None, is_jump_target=False),
] ]
# One last piece of inspect fodder to check the default line number handling # One last piece of inspect fodder to check the default line number handling
def simple(): pass def simple(): pass
expected_opinfo_simple = [ expected_opinfo_simple = [
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=0, starts_line=simple.__code__.co_firstlineno, is_jump_target=False), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=0, starts_line=simple.__code__.co_firstlineno, is_jump_target=False),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=3, starts_line=None, is_jump_target=False) Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=2, starts_line=None, is_jump_target=False)
] ]
......
...@@ -10,6 +10,9 @@ What's New in Python 3.6.0 alpha 2 ...@@ -10,6 +10,9 @@ What's New in Python 3.6.0 alpha 2
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #26647: Python interpreter now uses 16-bit wordcode instead of bytecode.
Patch by Demur Rumed.
- Issue #23275: Allow assigning to an empty target list in round brackets: - Issue #23275: Allow assigning to an empty target list in round brackets:
() = iterable. () = iterable.
......
...@@ -189,7 +189,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) ...@@ -189,7 +189,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno)
memset(blockstack, '\0', sizeof(blockstack)); memset(blockstack, '\0', sizeof(blockstack));
memset(in_finally, '\0', sizeof(in_finally)); memset(in_finally, '\0', sizeof(in_finally));
blockstack_top = 0; blockstack_top = 0;
for (addr = 0; addr < code_len; addr++) { for (addr = 0; addr < code_len; addr += 2) {
unsigned char op = code[addr]; unsigned char op = code[addr];
switch (op) { switch (op) {
case SETUP_LOOP: case SETUP_LOOP:
...@@ -251,10 +251,6 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) ...@@ -251,10 +251,6 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno)
} }
} }
} }
if (op >= HAVE_ARGUMENT) {
addr += 2;
}
} }
/* Verify that the blockstack tracking code didn't get lost. */ /* Verify that the blockstack tracking code didn't get lost. */
...@@ -277,7 +273,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) ...@@ -277,7 +273,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno)
* can tell whether the jump goes into any blocks without coming out * can tell whether the jump goes into any blocks without coming out
* again - in that case we raise an exception below. */ * again - in that case we raise an exception below. */
delta_iblock = 0; delta_iblock = 0;
for (addr = min_addr; addr < max_addr; addr++) { for (addr = min_addr; addr < max_addr; addr += 2) {
unsigned char op = code[addr]; unsigned char op = code[addr];
switch (op) { switch (op) {
case SETUP_LOOP: case SETUP_LOOP:
...@@ -294,10 +290,6 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) ...@@ -294,10 +290,6 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno)
} }
min_delta_iblock = Py_MIN(min_delta_iblock, delta_iblock); min_delta_iblock = Py_MIN(min_delta_iblock, delta_iblock);
if (op >= HAVE_ARGUMENT) {
addr += 2;
}
} }
/* Derive the absolute iblock values from the deltas. */ /* Derive the absolute iblock values from the deltas. */
......
...@@ -277,7 +277,7 @@ _PyGen_yf(PyGenObject *gen) ...@@ -277,7 +277,7 @@ _PyGen_yf(PyGenObject *gen)
PyObject *bytecode = f->f_code->co_code; PyObject *bytecode = f->f_code->co_code;
unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode); unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode);
if (code[f->f_lasti + 1] != YIELD_FROM) if (code[f->f_lasti + 2] != YIELD_FROM)
return NULL; return NULL;
yf = f->f_stacktop[-1]; yf = f->f_stacktop[-1];
Py_INCREF(yf); Py_INCREF(yf);
...@@ -376,7 +376,7 @@ gen_throw(PyGenObject *gen, PyObject *args) ...@@ -376,7 +376,7 @@ gen_throw(PyGenObject *gen, PyObject *args)
assert(ret == yf); assert(ret == yf);
Py_DECREF(ret); Py_DECREF(ret);
/* Termination repetition of YIELD_FROM */ /* Termination repetition of YIELD_FROM */
gen->gi_frame->f_lasti++; gen->gi_frame->f_lasti += 2;
if (_PyGen_FetchStopIterationValue(&val) == 0) { if (_PyGen_FetchStopIterationValue(&val) == 0) {
ret = gen_send_ex(gen, val, 0, 0); ret = gen_send_ex(gen, val, 0, 0);
Py_DECREF(val); Py_DECREF(val);
......
...@@ -1089,7 +1089,7 @@ static PYC_MAGIC magic_values[] = { ...@@ -1089,7 +1089,7 @@ static PYC_MAGIC magic_values[] = {
{ 3190, 3230, L"3.3" }, { 3190, 3230, L"3.3" },
{ 3250, 3310, L"3.4" }, { 3250, 3310, L"3.4" },
{ 3320, 3350, L"3.5" }, { 3320, 3350, L"3.5" },
{ 3360, 3361, L"3.6" }, { 3360, 3370, L"3.6" },
{ 0 } { 0 }
}; };
......
...@@ -209,6 +209,7 @@ ...@@ -209,6 +209,7 @@
<ClInclude Include="..\Python\condvar.h" /> <ClInclude Include="..\Python\condvar.h" />
<ClInclude Include="..\Python\importdl.h" /> <ClInclude Include="..\Python\importdl.h" />
<ClInclude Include="..\Python\thread_nt.h" /> <ClInclude Include="..\Python\thread_nt.h" />
<ClInclude Include="..\Python\wordcode_helpers.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\Modules\_bisectmodule.c" /> <ClCompile Include="..\Modules\_bisectmodule.c" />
......
...@@ -420,6 +420,9 @@ ...@@ -420,6 +420,9 @@
<ClInclude Include="..\Python\thread_nt.h"> <ClInclude Include="..\Python\thread_nt.h">
<Filter>Python</Filter> <Filter>Python</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Python\wordcode_helpers.h">
<Filter>Python</Filter>
</ClInclude>
<ClInclude Include="..\Python\condvar.h"> <ClInclude Include="..\Python\condvar.h">
<Filter>Python</Filter> <Filter>Python</Filter>
</ClInclude> </ClInclude>
......
...@@ -886,24 +886,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -886,24 +886,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
/* Import the static jump table */ /* Import the static jump table */
#include "opcode_targets.h" #include "opcode_targets.h"
/* This macro is used when several opcodes defer to the same implementation
(e.g. SETUP_LOOP, SETUP_FINALLY) */
#define TARGET_WITH_IMPL(op, impl) \
TARGET_##op: \
opcode = op; \
if (HAS_ARG(op)) \
oparg = NEXTARG(); \
case op: \
goto impl; \
#define TARGET(op) \ #define TARGET(op) \
TARGET_##op: \ TARGET_##op: \
opcode = op; \
if (HAS_ARG(op)) \
oparg = NEXTARG(); \
case op: case op:
#define DISPATCH() \ #define DISPATCH() \
{ \ { \
if (!_Py_atomic_load_relaxed(&eval_breaker)) { \ if (!_Py_atomic_load_relaxed(&eval_breaker)) { \
...@@ -917,7 +903,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -917,7 +903,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
{ \ { \
if (!lltrace && !_Py_TracingPossible) { \ if (!lltrace && !_Py_TracingPossible) { \
f->f_lasti = INSTR_OFFSET(); \ f->f_lasti = INSTR_OFFSET(); \
goto *opcode_targets[*next_instr++]; \ opcode = NEXTOP(); \
oparg = NEXTARG(); \
goto *opcode_targets[opcode]; \
} \ } \
goto fast_next_opcode; \ goto fast_next_opcode; \
} }
...@@ -926,7 +914,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -926,7 +914,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
{ \ { \
if (!_Py_TracingPossible) { \ if (!_Py_TracingPossible) { \
f->f_lasti = INSTR_OFFSET(); \ f->f_lasti = INSTR_OFFSET(); \
goto *opcode_targets[*next_instr++]; \ opcode = NEXTOP(); \
oparg = NEXTARG(); \
goto *opcode_targets[opcode]; \
} \ } \
goto fast_next_opcode; \ goto fast_next_opcode; \
} }
...@@ -935,10 +925,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -935,10 +925,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
#else #else
#define TARGET(op) \ #define TARGET(op) \
case op: case op:
#define TARGET_WITH_IMPL(op, impl) \
/* silence compiler warnings about `impl` unused */ \
if (0) goto impl; \
case op:
#define DISPATCH() continue #define DISPATCH() continue
#define FAST_DISPATCH() goto fast_next_opcode #define FAST_DISPATCH() goto fast_next_opcode
#endif #endif
...@@ -995,9 +982,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -995,9 +982,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
/* Code access macros */ /* Code access macros */
#define INSTR_OFFSET() ((int)(next_instr - first_instr)) #define INSTR_OFFSET() ((int)(next_instr - first_instr))
#define NEXTOP() (*next_instr++) #define NEXTOP() (next_instr+=2, next_instr[-2])
#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2]) #define NEXTARG() (next_instr[-1])
#define PEEKARG() ((next_instr[2]<<8) + next_instr[1]) #define PEEKARG() (next_instr[1])
#define JUMPTO(x) (next_instr = first_instr + (x)) #define JUMPTO(x) (next_instr = first_instr + (x))
#define JUMPBY(x) (next_instr += (x)) #define JUMPBY(x) (next_instr += (x))
...@@ -1012,10 +999,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -1012,10 +999,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
processor's own internal branch predication has a high likelihood of processor's own internal branch predication has a high likelihood of
success, resulting in a nearly zero-overhead transition to the success, resulting in a nearly zero-overhead transition to the
next opcode. A successful prediction saves a trip through the eval-loop next opcode. A successful prediction saves a trip through the eval-loop
including its two unpredictable branches, the HAS_ARG test and the including its unpredictable switch-case branch. Combined with the
switch-case. Combined with the processor's internal branch prediction, processor's internal branch prediction, a successful PREDICT has the
a successful PREDICT has the effect of making the two opcodes run as if effect of making the two opcodes run as if they were a single new opcode
they were a single new opcode with the bodies combined. with the bodies combined.
If collecting opcode statistics, your choices are to either keep the If collecting opcode statistics, your choices are to either keep the
predictions turned-on and interpret the results as if some opcodes predictions turned-on and interpret the results as if some opcodes
...@@ -1030,13 +1017,18 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -1030,13 +1017,18 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
#if defined(DYNAMIC_EXECUTION_PROFILE) || USE_COMPUTED_GOTOS #if defined(DYNAMIC_EXECUTION_PROFILE) || USE_COMPUTED_GOTOS
#define PREDICT(op) if (0) goto PRED_##op #define PREDICT(op) if (0) goto PRED_##op
#define PREDICTED(op) PRED_##op:
#define PREDICTED_WITH_ARG(op) PRED_##op:
#else #else
#define PREDICT(op) if (*next_instr == op) goto PRED_##op #define PREDICT(op) \
#define PREDICTED(op) PRED_##op: next_instr++ do{ \
#define PREDICTED_WITH_ARG(op) PRED_##op: oparg = PEEKARG(); next_instr += 3 if (*next_instr == op){ \
opcode = op; \
oparg = PEEKARG(); \
next_instr += 2; \
goto PRED_##op; \
} \
} while(0)
#endif #endif
#define PREDICTED(op) PRED_##op:
/* Stack manipulation macros */ /* Stack manipulation macros */
...@@ -1100,7 +1092,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -1100,7 +1092,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
} }
#define UNWIND_EXCEPT_HANDLER(b) \ #define UNWIND_EXCEPT_HANDLER(b) \
{ \ do { \
PyObject *type, *value, *traceback; \ PyObject *type, *value, *traceback; \
assert(STACK_LEVEL() >= (b)->b_level + 3); \ assert(STACK_LEVEL() >= (b)->b_level + 3); \
while (STACK_LEVEL() > (b)->b_level + 3) { \ while (STACK_LEVEL() > (b)->b_level + 3) { \
...@@ -1116,7 +1108,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -1116,7 +1108,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
Py_XDECREF(type); \ Py_XDECREF(type); \
Py_XDECREF(value); \ Py_XDECREF(value); \
Py_XDECREF(traceback); \ Py_XDECREF(traceback); \
} } while(0)
/* Start of code */ /* Start of code */
...@@ -1166,15 +1158,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -1166,15 +1158,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
fastlocals = f->f_localsplus; fastlocals = f->f_localsplus;
freevars = f->f_localsplus + co->co_nlocals; freevars = f->f_localsplus + co->co_nlocals;
first_instr = (unsigned char*) PyBytes_AS_STRING(co->co_code); first_instr = (unsigned char*) PyBytes_AS_STRING(co->co_code);
/* An explanation is in order for the next line. /*
f->f_lasti refers to the index of the last instruction,
f->f_lasti now refers to the index of the last instruction unless it's -1 in which case next_instr should be first_instr.
executed. You might think this was obvious from the name, but
this wasn't always true before 2.3! PyFrame_New now sets YIELD_FROM sets f_lasti to itself, in order to repeatedly yield
f->f_lasti to -1 (i.e. the index *before* the first instruction)
and YIELD_VALUE doesn't fiddle with f_lasti any more. So this
does work. Promise.
YIELD_FROM sets f_lasti to itself, in order to repeated yield
multiple values. multiple values.
When the PREDICT() macros are enabled, some opcode pairs follow in When the PREDICT() macros are enabled, some opcode pairs follow in
...@@ -1183,9 +1171,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -1183,9 +1171,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
were a single new opcode; accordingly,f->f_lasti will point to were a single new opcode; accordingly,f->f_lasti will point to
the first code in the pair (for instance, GET_ITER followed by the first code in the pair (for instance, GET_ITER followed by
FOR_ITER is effectively a single opcode and f->f_lasti will point FOR_ITER is effectively a single opcode and f->f_lasti will point
at to the beginning of the combined pair.) to the beginning of the combined pair.)
*/ */
next_instr = first_instr + f->f_lasti + 1; next_instr = first_instr;
if (f->f_lasti >= 0) {
next_instr += f->f_lasti + 2;
}
stack_pointer = f->f_stacktop; stack_pointer = f->f_stacktop;
assert(stack_pointer != NULL); assert(stack_pointer != NULL);
f->f_stacktop = NULL; /* remains NULL unless yield suspends frame */ f->f_stacktop = NULL; /* remains NULL unless yield suspends frame */
...@@ -1323,10 +1314,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -1323,10 +1314,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
/* Extract opcode and argument */ /* Extract opcode and argument */
opcode = NEXTOP(); opcode = NEXTOP();
oparg = 0; /* allows oparg to be stored in a register because oparg = NEXTARG();
it doesn't have to be remembered across a full loop */
if (HAS_ARG(opcode))
oparg = NEXTARG();
dispatch_opcode: dispatch_opcode:
#ifdef DYNAMIC_EXECUTION_PROFILE #ifdef DYNAMIC_EXECUTION_PROFILE
#ifdef DXPAIRS #ifdef DXPAIRS
...@@ -1384,7 +1372,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -1384,7 +1372,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
FAST_DISPATCH(); FAST_DISPATCH();
} }
PREDICTED_WITH_ARG(STORE_FAST); PREDICTED(STORE_FAST);
TARGET(STORE_FAST) { TARGET(STORE_FAST) {
PyObject *value = POP(); PyObject *value = POP();
SETLOCAL(oparg, value); SETLOCAL(oparg, value);
...@@ -2075,7 +2063,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -2075,7 +2063,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
f->f_stacktop = stack_pointer; f->f_stacktop = stack_pointer;
why = WHY_YIELD; why = WHY_YIELD;
/* and repeat... */ /* and repeat... */
f->f_lasti--; f->f_lasti -= 2;
goto fast_yield; goto fast_yield;
} }
...@@ -2213,7 +2201,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -2213,7 +2201,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH(); DISPATCH();
} }
PREDICTED_WITH_ARG(UNPACK_SEQUENCE); PREDICTED(UNPACK_SEQUENCE);
TARGET(UNPACK_SEQUENCE) { TARGET(UNPACK_SEQUENCE) {
PyObject *seq = POP(), *item, **items; PyObject *seq = POP(), *item, **items;
if (PyTuple_CheckExact(seq) && if (PyTuple_CheckExact(seq) &&
...@@ -2511,9 +2499,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -2511,9 +2499,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH(); DISPATCH();
} }
TARGET_WITH_IMPL(BUILD_TUPLE_UNPACK, _build_list_unpack) TARGET(BUILD_TUPLE_UNPACK)
TARGET(BUILD_LIST_UNPACK) TARGET(BUILD_LIST_UNPACK) {
_build_list_unpack: {
int convert_to_tuple = opcode == BUILD_TUPLE_UNPACK; int convert_to_tuple = opcode == BUILD_TUPLE_UNPACK;
int i; int i;
PyObject *sum = PyList_New(0); PyObject *sum = PyList_New(0);
...@@ -2610,9 +2597,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -2610,9 +2597,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH(); DISPATCH();
} }
TARGET_WITH_IMPL(BUILD_MAP_UNPACK_WITH_CALL, _build_map_unpack) TARGET(BUILD_MAP_UNPACK_WITH_CALL)
TARGET(BUILD_MAP_UNPACK) TARGET(BUILD_MAP_UNPACK) {
_build_map_unpack: {
int with_call = opcode == BUILD_MAP_UNPACK_WITH_CALL; int with_call = opcode == BUILD_MAP_UNPACK_WITH_CALL;
int num_maps; int num_maps;
int function_location; int function_location;
...@@ -2819,7 +2805,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -2819,7 +2805,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
FAST_DISPATCH(); FAST_DISPATCH();
} }
PREDICTED_WITH_ARG(POP_JUMP_IF_FALSE); PREDICTED(POP_JUMP_IF_FALSE);
TARGET(POP_JUMP_IF_FALSE) { TARGET(POP_JUMP_IF_FALSE) {
PyObject *cond = POP(); PyObject *cond = POP();
int err; int err;
...@@ -2843,7 +2829,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -2843,7 +2829,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH(); DISPATCH();
} }
PREDICTED_WITH_ARG(POP_JUMP_IF_TRUE); PREDICTED(POP_JUMP_IF_TRUE);
TARGET(POP_JUMP_IF_TRUE) { TARGET(POP_JUMP_IF_TRUE) {
PyObject *cond = POP(); PyObject *cond = POP();
int err; int err;
...@@ -2920,7 +2906,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -2920,7 +2906,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH(); DISPATCH();
} }
PREDICTED_WITH_ARG(JUMP_ABSOLUTE); PREDICTED(JUMP_ABSOLUTE);
TARGET(JUMP_ABSOLUTE) { TARGET(JUMP_ABSOLUTE) {
JUMPTO(oparg); JUMPTO(oparg);
#if FAST_LOOPS #if FAST_LOOPS
...@@ -2977,7 +2963,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -2977,7 +2963,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH(); DISPATCH();
} }
PREDICTED_WITH_ARG(FOR_ITER); PREDICTED(FOR_ITER);
TARGET(FOR_ITER) { TARGET(FOR_ITER) {
/* before: [iter]; after: [iter, iter()] *or* [] */ /* before: [iter]; after: [iter, iter()] *or* [] */
PyObject *iter = TOP(); PyObject *iter = TOP();
...@@ -3015,10 +3001,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -3015,10 +3001,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
goto fast_block_end; goto fast_block_end;
} }
TARGET_WITH_IMPL(SETUP_LOOP, _setup_finally) TARGET(SETUP_LOOP)
TARGET_WITH_IMPL(SETUP_EXCEPT, _setup_finally) TARGET(SETUP_EXCEPT)
TARGET(SETUP_FINALLY) TARGET(SETUP_FINALLY) {
_setup_finally: {
/* NOTE: If you add any new block-setup opcodes that /* NOTE: If you add any new block-setup opcodes that
are not try/except/finally handlers, you may need are not try/except/finally handlers, you may need
to update the PyGen_NeedsFinalizing() function. to update the PyGen_NeedsFinalizing() function.
...@@ -3213,10 +3198,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -3213,10 +3198,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH(); DISPATCH();
} }
TARGET_WITH_IMPL(CALL_FUNCTION_VAR, _call_function_var_kw) TARGET(CALL_FUNCTION_VAR)
TARGET_WITH_IMPL(CALL_FUNCTION_KW, _call_function_var_kw) TARGET(CALL_FUNCTION_KW)
TARGET(CALL_FUNCTION_VAR_KW) TARGET(CALL_FUNCTION_VAR_KW) {
_call_function_var_kw: {
int na = oparg & 0xff; int na = oparg & 0xff;
int nk = (oparg>>8) & 0xff; int nk = (oparg>>8) & 0xff;
int flags = (opcode - CALL_FUNCTION) & 3; int flags = (opcode - CALL_FUNCTION) & 3;
...@@ -3258,9 +3242,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -3258,9 +3242,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH(); DISPATCH();
} }
TARGET_WITH_IMPL(MAKE_CLOSURE, _make_function) TARGET(MAKE_CLOSURE)
TARGET(MAKE_FUNCTION) TARGET(MAKE_FUNCTION) {
_make_function: {
int posdefaults = oparg & 0xff; int posdefaults = oparg & 0xff;
int kwdefaults = (oparg>>8) & 0xff; int kwdefaults = (oparg>>8) & 0xff;
int num_annotations = (oparg >> 16) & 0x7fff; int num_annotations = (oparg >> 16) & 0x7fff;
...@@ -3450,7 +3433,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) ...@@ -3450,7 +3433,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
TARGET(EXTENDED_ARG) { TARGET(EXTENDED_ARG) {
opcode = NEXTOP(); opcode = NEXTOP();
oparg = oparg<<16 | NEXTARG(); oparg = oparg<<8 | NEXTARG();
goto dispatch_opcode; goto dispatch_opcode;
} }
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "code.h" #include "code.h"
#include "symtable.h" #include "symtable.h"
#include "opcode.h" #include "opcode.h"
#include "wordcode_helpers.h"
#define DEFAULT_BLOCK_SIZE 16 #define DEFAULT_BLOCK_SIZE 16
#define DEFAULT_BLOCKS 8 #define DEFAULT_BLOCKS 8
...@@ -43,7 +44,6 @@ ...@@ -43,7 +44,6 @@
struct instr { struct instr {
unsigned i_jabs : 1; unsigned i_jabs : 1;
unsigned i_jrel : 1; unsigned i_jrel : 1;
unsigned i_hasarg : 1;
unsigned char i_opcode; unsigned char i_opcode;
int i_oparg; int i_oparg;
struct basicblock_ *i_target; /* target block (if jump instruction) */ struct basicblock_ *i_target; /* target block (if jump instruction) */
...@@ -1080,13 +1080,14 @@ compiler_addop(struct compiler *c, int opcode) ...@@ -1080,13 +1080,14 @@ compiler_addop(struct compiler *c, int opcode)
basicblock *b; basicblock *b;
struct instr *i; struct instr *i;
int off; int off;
assert(!HAS_ARG(opcode));
off = compiler_next_instr(c, c->u->u_curblock); off = compiler_next_instr(c, c->u->u_curblock);
if (off < 0) if (off < 0)
return 0; return 0;
b = c->u->u_curblock; b = c->u->u_curblock;
i = &b->b_instr[off]; i = &b->b_instr[off];
i->i_opcode = opcode; i->i_opcode = opcode;
i->i_hasarg = 0; i->i_oparg = 0;
if (opcode == RETURN_VALUE) if (opcode == RETURN_VALUE)
b->b_return = 1; b->b_return = 1;
compiler_set_lineno(c, off); compiler_set_lineno(c, off);
...@@ -1168,8 +1169,9 @@ compiler_addop_i(struct compiler *c, int opcode, Py_ssize_t oparg) ...@@ -1168,8 +1169,9 @@ compiler_addop_i(struct compiler *c, int opcode, Py_ssize_t oparg)
Limit to 32-bit signed C int (rather than INT_MAX) for portability. Limit to 32-bit signed C int (rather than INT_MAX) for portability.
The argument of a concrete bytecode instruction is limited to 16-bit. The argument of a concrete bytecode instruction is limited to 8-bit.
EXTENDED_ARG is used for 32-bit arguments. */ EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */
assert(HAS_ARG(opcode));
assert(0 <= oparg && oparg <= 2147483647); assert(0 <= oparg && oparg <= 2147483647);
off = compiler_next_instr(c, c->u->u_curblock); off = compiler_next_instr(c, c->u->u_curblock);
...@@ -1178,7 +1180,6 @@ compiler_addop_i(struct compiler *c, int opcode, Py_ssize_t oparg) ...@@ -1178,7 +1180,6 @@ compiler_addop_i(struct compiler *c, int opcode, Py_ssize_t oparg)
i = &c->u->u_curblock->b_instr[off]; i = &c->u->u_curblock->b_instr[off];
i->i_opcode = opcode; i->i_opcode = opcode;
i->i_oparg = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int); i->i_oparg = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int);
i->i_hasarg = 1;
compiler_set_lineno(c, off); compiler_set_lineno(c, off);
return 1; return 1;
} }
...@@ -1189,6 +1190,7 @@ compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute) ...@@ -1189,6 +1190,7 @@ compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute)
struct instr *i; struct instr *i;
int off; int off;
assert(HAS_ARG(opcode));
assert(b != NULL); assert(b != NULL);
off = compiler_next_instr(c, c->u->u_curblock); off = compiler_next_instr(c, c->u->u_curblock);
if (off < 0) if (off < 0)
...@@ -1196,7 +1198,6 @@ compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute) ...@@ -1196,7 +1198,6 @@ compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute)
i = &c->u->u_curblock->b_instr[off]; i = &c->u->u_curblock->b_instr[off];
i->i_opcode = opcode; i->i_opcode = opcode;
i->i_target = b; i->i_target = b;
i->i_hasarg = 1;
if (absolute) if (absolute)
i->i_jabs = 1; i->i_jabs = 1;
else else
...@@ -4397,18 +4398,6 @@ assemble_free(struct assembler *a) ...@@ -4397,18 +4398,6 @@ assemble_free(struct assembler *a)
PyObject_Free(a->a_postorder); PyObject_Free(a->a_postorder);
} }
/* Return the size of a basic block in bytes. */
static int
instrsize(struct instr *instr)
{
if (!instr->i_hasarg)
return 1; /* 1 byte for the opcode*/
if (instr->i_oparg > 0xffff)
return 6; /* 1 (opcode) + 1 (EXTENDED_ARG opcode) + 2 (oparg) + 2(oparg extended) */
return 3; /* 1 (opcode) + 2 (oparg) */
}
static int static int
blocksize(basicblock *b) blocksize(basicblock *b)
{ {
...@@ -4416,7 +4405,7 @@ blocksize(basicblock *b) ...@@ -4416,7 +4405,7 @@ blocksize(basicblock *b)
int size = 0; int size = 0;
for (i = 0; i < b->b_iused; i++) for (i = 0; i < b->b_iused; i++)
size += instrsize(&b->b_instr[i]); size += instrsize(b->b_instr[i].i_oparg);
return size; return size;
} }
...@@ -4536,15 +4525,12 @@ assemble_lnotab(struct assembler *a, struct instr *i) ...@@ -4536,15 +4525,12 @@ assemble_lnotab(struct assembler *a, struct instr *i)
static int static int
assemble_emit(struct assembler *a, struct instr *i) assemble_emit(struct assembler *a, struct instr *i)
{ {
int size, arg = 0, ext = 0; int size, arg = 0;
Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode); Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode);
char *code; char *code;
size = instrsize(i); arg = i->i_oparg;
if (i->i_hasarg) { size = instrsize(arg);
arg = i->i_oparg;
ext = arg >> 16;
}
if (i->i_lineno && !assemble_lnotab(a, i)) if (i->i_lineno && !assemble_lnotab(a, i))
return 0; return 0;
if (a->a_offset + size >= len) { if (a->a_offset + size >= len) {
...@@ -4555,19 +4541,7 @@ assemble_emit(struct assembler *a, struct instr *i) ...@@ -4555,19 +4541,7 @@ assemble_emit(struct assembler *a, struct instr *i)
} }
code = PyBytes_AS_STRING(a->a_bytecode) + a->a_offset; code = PyBytes_AS_STRING(a->a_bytecode) + a->a_offset;
a->a_offset += size; a->a_offset += size;
if (size == 6) { write_op_arg((unsigned char*)code, i->i_opcode, arg, size);
assert(i->i_hasarg);
*code++ = (char)EXTENDED_ARG;
*code++ = ext & 0xff;
*code++ = ext >> 8;
arg &= 0xffff;
}
*code++ = i->i_opcode;
if (i->i_hasarg) {
assert(size == 3 || size == 6);
*code++ = arg & 0xff;
*code++ = arg >> 8;
}
return 1; return 1;
} }
...@@ -4575,7 +4549,7 @@ static void ...@@ -4575,7 +4549,7 @@ static void
assemble_jump_offsets(struct assembler *a, struct compiler *c) assemble_jump_offsets(struct assembler *a, struct compiler *c)
{ {
basicblock *b; basicblock *b;
int bsize, totsize, extended_arg_count = 0, last_extended_arg_count; int bsize, totsize, extended_arg_recompile;
int i; int i;
/* Compute the size of each block and fixup jump args. /* Compute the size of each block and fixup jump args.
...@@ -4588,27 +4562,26 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c) ...@@ -4588,27 +4562,26 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c)
b->b_offset = totsize; b->b_offset = totsize;
totsize += bsize; totsize += bsize;
} }
last_extended_arg_count = extended_arg_count; extended_arg_recompile = 0;
extended_arg_count = 0;
for (b = c->u->u_blocks; b != NULL; b = b->b_list) { for (b = c->u->u_blocks; b != NULL; b = b->b_list) {
bsize = b->b_offset; bsize = b->b_offset;
for (i = 0; i < b->b_iused; i++) { for (i = 0; i < b->b_iused; i++) {
struct instr *instr = &b->b_instr[i]; struct instr *instr = &b->b_instr[i];
int isize = instrsize(instr->i_oparg);
/* Relative jumps are computed relative to /* Relative jumps are computed relative to
the instruction pointer after fetching the instruction pointer after fetching
the jump instruction. the jump instruction.
*/ */
bsize += instrsize(instr); bsize += isize;
if (instr->i_jabs) if (instr->i_jabs || instr->i_jrel) {
instr->i_oparg = instr->i_target->b_offset; instr->i_oparg = instr->i_target->b_offset;
else if (instr->i_jrel) { if (instr->i_jrel) {
int delta = instr->i_target->b_offset - bsize; instr->i_oparg -= bsize;
instr->i_oparg = delta; }
if (instrsize(instr->i_oparg) != isize) {
extended_arg_recompile = 1;
}
} }
else
continue;
if (instr->i_oparg > 0xffff)
extended_arg_count++;
} }
} }
...@@ -4618,7 +4591,7 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c) ...@@ -4618,7 +4591,7 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c)
The issue is that in the first loop blocksize() is called The issue is that in the first loop blocksize() is called
which calls instrsize() which requires i_oparg be set which calls instrsize() which requires i_oparg be set
appropriately. There is a bootstrap problem because appropriately. There is a bootstrap problem because
i_oparg is calculated in the second loop above. i_oparg is calculated in the second loop above.
So we loop until we stop seeing new EXTENDED_ARGs. So we loop until we stop seeing new EXTENDED_ARGs.
...@@ -4626,7 +4599,7 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c) ...@@ -4626,7 +4599,7 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c)
ones in jump instructions. So this should converge ones in jump instructions. So this should converge
fairly quickly. fairly quickly.
*/ */
} while (last_extended_arg_count != extended_arg_count); } while (extended_arg_recompile);
} }
static PyObject * static PyObject *
...@@ -4772,9 +4745,9 @@ dump_instr(const struct instr *i) ...@@ -4772,9 +4745,9 @@ dump_instr(const struct instr *i)
char arg[128]; char arg[128];
*arg = '\0'; *arg = '\0';
if (i->i_hasarg) if (HAS_ARG(i->i_opcode)) {
sprintf(arg, "arg: %d ", i->i_oparg); sprintf(arg, "arg: %d ", i->i_oparg);
}
fprintf(stderr, "line: %d, opcode: %d %s%s%s\n", fprintf(stderr, "line: %d, opcode: %d %s%s%s\n",
i->i_lineno, i->i_opcode, arg, jabs, jrel); i->i_lineno, i->i_opcode, arg, jabs, jrel);
} }
......
...@@ -14,17 +14,15 @@ ...@@ -14,17 +14,15 @@
the appropriate bytes from M___main__.c. */ the appropriate bytes from M___main__.c. */
static unsigned char M___hello__[] = { static unsigned char M___hello__[] = {
99,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0, 227,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,
0,64,0,0,0,115,20,0,0,0,100,2,0,90,1,0, 0,64,0,0,0,115,16,0,0,0,100,0,90,0,101,1,
101,2,0,100,0,0,131,1,0,1,100,1,0,83,40,3, 100,1,131,1,1,0,100,2,83,0,41,3,84,122,12,72,
0,0,0,117,12,0,0,0,72,101,108,108,111,32,119,111, 101,108,108,111,32,119,111,114,108,100,33,78,41,2,218,11,
114,108,100,33,78,84,40,3,0,0,0,117,4,0,0,0, 105,110,105,116,105,97,108,105,122,101,100,218,5,112,114,105,
84,114,117,101,117,11,0,0,0,105,110,105,116,105,97,108, 110,116,169,0,114,3,0,0,0,114,3,0,0,0,250,22,
105,122,101,100,117,5,0,0,0,112,114,105,110,116,40,0, 46,47,84,111,111,108,115,47,102,114,101,101,122,101,47,102,
0,0,0,40,0,0,0,0,40,0,0,0,0,117,7,0, 108,97,103,46,112,121,218,8,60,109,111,100,117,108,101,62,
0,0,102,108,97,103,46,112,121,117,8,0,0,0,60,109, 1,0,0,0,115,2,0,0,0,4,1,
111,100,117,108,101,62,1,0,0,0,115,2,0,0,0,6,
1,
}; };
#define SIZE (int)sizeof(M___hello__) #define SIZE (int)sizeof(M___hello__)
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
#include "code.h" #include "code.h"
#include "symtable.h" #include "symtable.h"
#include "opcode.h" #include "opcode.h"
#include "wordcode_helpers.h"
#define GETARG(arr, i) ((int)((arr[i+2]<<8) + arr[i+1]))
#define UNCONDITIONAL_JUMP(op) (op==JUMP_ABSOLUTE || op==JUMP_FORWARD) #define UNCONDITIONAL_JUMP(op) (op==JUMP_ABSOLUTE || op==JUMP_FORWARD)
#define CONDITIONAL_JUMP(op) (op==POP_JUMP_IF_FALSE || op==POP_JUMP_IF_TRUE \ #define CONDITIONAL_JUMP(op) (op==POP_JUMP_IF_FALSE || op==POP_JUMP_IF_TRUE \
|| op==JUMP_IF_FALSE_OR_POP || op==JUMP_IF_TRUE_OR_POP) || op==JUMP_IF_FALSE_OR_POP || op==JUMP_IF_TRUE_OR_POP)
...@@ -17,22 +17,15 @@ ...@@ -17,22 +17,15 @@
|| op==POP_JUMP_IF_FALSE || op==POP_JUMP_IF_TRUE \ || op==POP_JUMP_IF_FALSE || op==POP_JUMP_IF_TRUE \
|| op==JUMP_IF_FALSE_OR_POP || op==JUMP_IF_TRUE_OR_POP) || op==JUMP_IF_FALSE_OR_POP || op==JUMP_IF_TRUE_OR_POP)
#define JUMPS_ON_TRUE(op) (op==POP_JUMP_IF_TRUE || op==JUMP_IF_TRUE_OR_POP) #define JUMPS_ON_TRUE(op) (op==POP_JUMP_IF_TRUE || op==JUMP_IF_TRUE_OR_POP)
#define GETJUMPTGT(arr, i) (GETARG(arr,i) + (ABSOLUTE_JUMP(arr[i]) ? 0 : i+3)) #define GETJUMPTGT(arr, i) (get_arg(arr, i) + (ABSOLUTE_JUMP(arr[i]) ? 0 : i+2))
#define SETARG(arr, i, val) do { \ #define ISBASICBLOCK(blocks, start, end) \
assert(0 <= val && val <= 0xffff); \ (blocks[start]==blocks[end])
arr[i+2] = (unsigned char)(((unsigned int)val)>>8); \
arr[i+1] = (unsigned char)(((unsigned int)val) & 255); \
} while(0)
#define CODESIZE(op) (HAS_ARG(op) ? 3 : 1)
#define ISBASICBLOCK(blocks, start, bytes) \
(blocks[start]==blocks[start+bytes-1])
#define CONST_STACK_CREATE() { \ #define CONST_STACK_CREATE() { \
const_stack_size = 256; \ const_stack_size = 256; \
const_stack = PyMem_New(PyObject *, const_stack_size); \ const_stack = PyMem_New(PyObject *, const_stack_size); \
load_const_stack = PyMem_New(Py_ssize_t, const_stack_size); \ if (!const_stack) { \
if (!const_stack || !load_const_stack) { \
PyErr_NoMemory(); \ PyErr_NoMemory(); \
goto exitError; \ goto exitError; \
} \ } \
...@@ -41,27 +34,23 @@ ...@@ -41,27 +34,23 @@
#define CONST_STACK_DELETE() do { \ #define CONST_STACK_DELETE() do { \
if (const_stack) \ if (const_stack) \
PyMem_Free(const_stack); \ PyMem_Free(const_stack); \
if (load_const_stack) \
PyMem_Free(load_const_stack); \
} while(0) } while(0)
#define CONST_STACK_LEN() (const_stack_top + 1) #define CONST_STACK_LEN() ((unsigned)(const_stack_top + 1))
#define CONST_STACK_PUSH_OP(i) do { \ #define CONST_STACK_PUSH_OP(i) do { \
PyObject *_x; \ PyObject *_x; \
assert(codestr[i] == LOAD_CONST); \ assert(codestr[i] == LOAD_CONST); \
assert(PyList_GET_SIZE(consts) > GETARG(codestr, i)); \ assert(PyList_GET_SIZE(consts) > (Py_ssize_t)get_arg(codestr, i)); \
_x = PyList_GET_ITEM(consts, GETARG(codestr, i)); \ _x = PyList_GET_ITEM(consts, get_arg(codestr, i)); \
if (++const_stack_top >= const_stack_size) { \ if (++const_stack_top >= const_stack_size) { \
const_stack_size *= 2; \ const_stack_size *= 2; \
PyMem_Resize(const_stack, PyObject *, const_stack_size); \ PyMem_Resize(const_stack, PyObject *, const_stack_size); \
PyMem_Resize(load_const_stack, Py_ssize_t, const_stack_size); \ if (!const_stack) { \
if (!const_stack || !load_const_stack) { \
PyErr_NoMemory(); \ PyErr_NoMemory(); \
goto exitError; \ goto exitError; \
} \ } \
} \ } \
load_const_stack[const_stack_top] = i; \
const_stack[const_stack_top] = _x; \ const_stack[const_stack_top] = _x; \
in_consts = 1; \ in_consts = 1; \
} while(0) } while(0)
...@@ -70,22 +59,108 @@ ...@@ -70,22 +59,108 @@
const_stack_top = -1; \ const_stack_top = -1; \
} while(0) } while(0)
#define CONST_STACK_TOP() \
const_stack[const_stack_top]
#define CONST_STACK_LASTN(i) \ #define CONST_STACK_LASTN(i) \
&const_stack[const_stack_top - i + 1] &const_stack[CONST_STACK_LEN() - i]
#define CONST_STACK_POP(i) do { \ #define CONST_STACK_POP(i) do { \
assert(const_stack_top + 1 >= i); \ assert(CONST_STACK_LEN() >= i); \
const_stack_top -= i; \ const_stack_top -= i; \
} while(0) } while(0)
#define CONST_STACK_OP_LASTN(i) \ /* Scans back N consecutive LOAD_CONST instructions, skipping NOPs,
((const_stack_top >= i - 1) ? load_const_stack[const_stack_top - i + 1] : -1) returns index of the Nth last's LOAD_CONST's EXTENDED_ARG prefix.
Callers are responsible to check CONST_STACK_LEN beforehand.
*/
static Py_ssize_t
lastn_const_start(unsigned char *codestr, Py_ssize_t i, Py_ssize_t n)
{
assert(n > 0 && (i&1) == 0);
for (;;) {
i -= 2;
assert(i >= 0);
if (codestr[i] == LOAD_CONST) {
if (!--n) {
while (i > 0 && codestr[i-2] == EXTENDED_ARG) {
i -= 2;
}
return i;
}
}
else {
assert(codestr[i] == NOP || codestr[i] == EXTENDED_ARG);
}
}
}
/* Scans through EXTENDED ARGs, seeking the index of the effective opcode */
static Py_ssize_t
find_op(unsigned char *codestr, Py_ssize_t i)
{
assert((i&1) == 0);
while (codestr[i] == EXTENDED_ARG) {
i += 2;
}
return i;
}
/* Given the index of the effective opcode,
scan back to construct the oparg with EXTENDED_ARG */
static unsigned int
get_arg(unsigned char *codestr, Py_ssize_t i)
{
unsigned int oparg = codestr[i+1];
assert((i&1) == 0);
if (i >= 2 && codestr[i-2] == EXTENDED_ARG) {
oparg |= codestr[i-1] << 8;
if (i >= 4 && codestr[i-4] == EXTENDED_ARG) {
oparg |= codestr[i-3] << 16;
if (i >= 6 && codestr[i-6] == EXTENDED_ARG) {
oparg |= codestr[i-5] << 24;
}
}
}
return oparg;
}
/* Given the index of the effective opcode,
attempt to replace the argument, taking into account EXTENDED_ARG.
Returns -1 on failure, or the new op index on success */
static Py_ssize_t
set_arg(unsigned char *codestr, Py_ssize_t i, unsigned int oparg)
{
unsigned int curarg = get_arg(codestr, i);
int curilen, newilen;
if (curarg == oparg)
return i;
curilen = instrsize(curarg);
newilen = instrsize(oparg);
if (curilen < newilen) {
return -1;
}
write_op_arg(codestr + i + 2 - curilen, codestr[i], oparg, newilen);
memset(codestr + i + 2 - curilen + newilen, NOP, curilen - newilen);
return i-curilen+newilen;
}
/* Attempt to write op/arg at end of specified region of memory.
Preceding memory in the region is overwritten with NOPs.
Returns -1 on failure, op index on success */
static Py_ssize_t
copy_op_arg(unsigned char *codestr, Py_ssize_t i, unsigned char op,
unsigned int oparg, Py_ssize_t maxi)
{
int ilen = instrsize(oparg);
assert((i&1) == 0);
if (i + ilen > maxi) {
return -1;
}
write_op_arg(codestr + maxi - ilen, op, oparg, ilen);
memset(codestr + i, NOP, maxi - i - ilen);
return maxi - 2;
}
/* Replace LOAD_CONST c1. LOAD_CONST c2 ... LOAD_CONST cn BUILD_TUPLE n /* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n
with LOAD_CONST (c1, c2, ... cn). with LOAD_CONST (c1, c2, ... cn).
The consts table must still be in list form so that the The consts table must still be in list form so that the
new constant (c1, c2, ... cn) can be appended. new constant (c1, c2, ... cn) can be appended.
...@@ -94,9 +169,10 @@ ...@@ -94,9 +169,10 @@
Also works for BUILD_LIST and BUILT_SET when followed by an "in" or "not in" Also works for BUILD_LIST and BUILT_SET when followed by an "in" or "not in"
test; for BUILD_SET it assembles a frozenset rather than a tuple. test; for BUILD_SET it assembles a frozenset rather than a tuple.
*/ */
static int static Py_ssize_t
tuple_of_constants(unsigned char *codestr, Py_ssize_t n, fold_tuple_on_constants(unsigned char *codestr, Py_ssize_t c_start,
PyObject *consts, PyObject **objs) Py_ssize_t opcode_end, unsigned char opcode,
PyObject *consts, PyObject **objs, int n)
{ {
PyObject *newconst, *constant; PyObject *newconst, *constant;
Py_ssize_t i, len_consts; Py_ssize_t i, len_consts;
...@@ -106,9 +182,9 @@ tuple_of_constants(unsigned char *codestr, Py_ssize_t n, ...@@ -106,9 +182,9 @@ tuple_of_constants(unsigned char *codestr, Py_ssize_t n,
/* Buildup new tuple of constants */ /* Buildup new tuple of constants */
newconst = PyTuple_New(n); newconst = PyTuple_New(n);
if (newconst == NULL) if (newconst == NULL) {
return 0; return -1;
len_consts = PyList_GET_SIZE(consts); }
for (i=0 ; i<n ; i++) { for (i=0 ; i<n ; i++) {
constant = objs[i]; constant = objs[i];
Py_INCREF(constant); Py_INCREF(constant);
...@@ -116,28 +192,26 @@ tuple_of_constants(unsigned char *codestr, Py_ssize_t n, ...@@ -116,28 +192,26 @@ tuple_of_constants(unsigned char *codestr, Py_ssize_t n,
} }
/* If it's a BUILD_SET, use the PyTuple we just built to create a /* If it's a BUILD_SET, use the PyTuple we just built to create a
PyFrozenSet, and use that as the constant instead: */ PyFrozenSet, and use that as the constant instead: */
if (codestr[0] == BUILD_SET) { if (opcode == BUILD_SET) {
Py_XSETREF(newconst, PyFrozenSet_New(newconst)); Py_SETREF(newconst, PyFrozenSet_New(newconst));
if (newconst == NULL) if (newconst == NULL) {
return 0; return -1;
}
} }
/* Append folded constant onto consts */ /* Append folded constant onto consts */
len_consts = PyList_GET_SIZE(consts);
if (PyList_Append(consts, newconst)) { if (PyList_Append(consts, newconst)) {
Py_DECREF(newconst); Py_DECREF(newconst);
return 0; return -1;
} }
Py_DECREF(newconst); Py_DECREF(newconst);
/* Write NOPs over old LOAD_CONSTS and return copy_op_arg(codestr, c_start, LOAD_CONST, len_consts, opcode_end);
add a new LOAD_CONST newconst on top of the BUILD_TUPLE n */
codestr[0] = LOAD_CONST;
SETARG(codestr, 0, len_consts);
return 1;
} }
/* Replace LOAD_CONST c1. LOAD_CONST c2 BINOP /* Replace LOAD_CONST c1, LOAD_CONST c2, BINOP
with LOAD_CONST binop(c1,c2) with LOAD_CONST binop(c1,c2)
The consts table must still be in list form so that the The consts table must still be in list form so that the
new constant can be appended. new constant can be appended.
...@@ -147,20 +221,21 @@ tuple_of_constants(unsigned char *codestr, Py_ssize_t n, ...@@ -147,20 +221,21 @@ tuple_of_constants(unsigned char *codestr, Py_ssize_t n,
is below a threshold value. That keeps pyc files from is below a threshold value. That keeps pyc files from
becoming large in the presence of code like: (None,)*1000. becoming large in the presence of code like: (None,)*1000.
*/ */
static int static Py_ssize_t
fold_binops_on_constants(unsigned char *codestr, PyObject *consts, PyObject **objs) fold_binops_on_constants(unsigned char *codestr, Py_ssize_t c_start,
Py_ssize_t opcode_end, unsigned char opcode,
PyObject *consts, PyObject **objs)
{ {
PyObject *newconst, *v, *w; PyObject *newconst, *v, *w;
Py_ssize_t len_consts, size; Py_ssize_t len_consts, size;
int opcode;
/* Pre-conditions */ /* Pre-conditions */
assert(PyList_CheckExact(consts)); assert(PyList_CheckExact(consts));
len_consts = PyList_GET_SIZE(consts);
/* Create new constant */ /* Create new constant */
v = objs[0]; v = objs[0];
w = objs[1]; w = objs[1];
opcode = codestr[0];
switch (opcode) { switch (opcode) {
case BINARY_POWER: case BINARY_POWER:
newconst = PyNumber_Power(v, w, Py_None); newconst = PyNumber_Power(v, w, Py_None);
...@@ -206,50 +281,48 @@ fold_binops_on_constants(unsigned char *codestr, PyObject *consts, PyObject **ob ...@@ -206,50 +281,48 @@ fold_binops_on_constants(unsigned char *codestr, PyObject *consts, PyObject **ob
PyErr_Format(PyExc_SystemError, PyErr_Format(PyExc_SystemError,
"unexpected binary operation %d on a constant", "unexpected binary operation %d on a constant",
opcode); opcode);
return 0; return -1;
} }
if (newconst == NULL) { if (newconst == NULL) {
if(!PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) if(!PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
PyErr_Clear(); PyErr_Clear();
return 0; }
return -1;
} }
size = PyObject_Size(newconst); size = PyObject_Size(newconst);
if (size == -1) { if (size == -1) {
if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
return 0; return -1;
}
PyErr_Clear(); PyErr_Clear();
} else if (size > 20) { } else if (size > 20) {
Py_DECREF(newconst); Py_DECREF(newconst);
return 0; return -1;
} }
/* Append folded constant into consts table */ /* Append folded constant into consts table */
len_consts = PyList_GET_SIZE(consts);
if (PyList_Append(consts, newconst)) { if (PyList_Append(consts, newconst)) {
Py_DECREF(newconst); Py_DECREF(newconst);
return 0; return -1;
} }
Py_DECREF(newconst); Py_DECREF(newconst);
/* Write NOP NOP NOP NOP LOAD_CONST newconst */ return copy_op_arg(codestr, c_start, LOAD_CONST, len_consts, opcode_end);
codestr[-2] = LOAD_CONST;
SETARG(codestr, -2, len_consts);
return 1;
} }
static int static Py_ssize_t
fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts, PyObject *v) fold_unaryops_on_constants(unsigned char *codestr, Py_ssize_t c_start,
Py_ssize_t opcode_end, unsigned char opcode,
PyObject *consts, PyObject *v)
{ {
PyObject *newconst; PyObject *newconst;
Py_ssize_t len_consts; Py_ssize_t len_consts;
int opcode;
/* Pre-conditions */ /* Pre-conditions */
assert(PyList_CheckExact(consts)); assert(PyList_CheckExact(consts));
assert(codestr[0] == LOAD_CONST); len_consts = PyList_GET_SIZE(consts);
/* Create new constant */ /* Create new constant */
opcode = codestr[3];
switch (opcode) { switch (opcode) {
case UNARY_NEGATIVE: case UNARY_NEGATIVE:
newconst = PyNumber_Negative(v); newconst = PyNumber_Negative(v);
...@@ -265,35 +338,31 @@ fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts, PyObject *v ...@@ -265,35 +338,31 @@ fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts, PyObject *v
PyErr_Format(PyExc_SystemError, PyErr_Format(PyExc_SystemError,
"unexpected unary operation %d on a constant", "unexpected unary operation %d on a constant",
opcode); opcode);
return 0; return -1;
} }
if (newconst == NULL) { if (newconst == NULL) {
if(!PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) if(!PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
PyErr_Clear(); PyErr_Clear();
return 0; }
return -1;
} }
/* Append folded constant into consts table */ /* Append folded constant into consts table */
len_consts = PyList_GET_SIZE(consts);
if (PyList_Append(consts, newconst)) { if (PyList_Append(consts, newconst)) {
Py_DECREF(newconst); Py_DECREF(newconst);
PyErr_Clear(); PyErr_Clear();
return 0; return -1;
} }
Py_DECREF(newconst); Py_DECREF(newconst);
/* Write NOP LOAD_CONST newconst */ return copy_op_arg(codestr, c_start, LOAD_CONST, len_consts, opcode_end);
codestr[0] = NOP;
codestr[1] = LOAD_CONST;
SETARG(codestr, 1, len_consts);
return 1;
} }
static unsigned int * static unsigned int *
markblocks(unsigned char *code, Py_ssize_t len) markblocks(unsigned char *code, Py_ssize_t len)
{ {
unsigned int *blocks = PyMem_New(unsigned int, len); unsigned int *blocks = PyMem_New(unsigned int, len);
int i,j, opcode, blockcnt = 0; int i, j, opcode, blockcnt = 0;
if (blocks == NULL) { if (blocks == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
...@@ -302,7 +371,7 @@ markblocks(unsigned char *code, Py_ssize_t len) ...@@ -302,7 +371,7 @@ markblocks(unsigned char *code, Py_ssize_t len)
memset(blocks, 0, len*sizeof(int)); memset(blocks, 0, len*sizeof(int));
/* Mark labels in the first pass */ /* Mark labels in the first pass */
for (i=0 ; i<len ; i+=CODESIZE(opcode)) { for (i=0 ; i<len ; i+=2) {
opcode = code[i]; opcode = code[i];
switch (opcode) { switch (opcode) {
case FOR_ITER: case FOR_ITER:
...@@ -324,7 +393,7 @@ markblocks(unsigned char *code, Py_ssize_t len) ...@@ -324,7 +393,7 @@ markblocks(unsigned char *code, Py_ssize_t len)
} }
} }
/* Build block numbers in the second pass */ /* Build block numbers in the second pass */
for (i=0 ; i<len ; i++) { for (i=0 ; i<len ; i+=2) {
blockcnt += blocks[i]; /* increment blockcnt over labels */ blockcnt += blocks[i]; /* increment blockcnt over labels */
blocks[i] = blockcnt; blocks[i] = blockcnt;
} }
...@@ -335,33 +404,27 @@ markblocks(unsigned char *code, Py_ssize_t len) ...@@ -335,33 +404,27 @@ markblocks(unsigned char *code, Py_ssize_t len)
The consts object should still be in list form to allow new constants The consts object should still be in list form to allow new constants
to be appended. to be appended.
To keep the optimizer simple, it bails out (does nothing) for code that To keep the optimizer simple, it bails when the lineno table has complex
has a length over 32,700, and does not calculate extended arguments. encoding for gaps >= 255.
That allows us to avoid overflow and sign issues. Likewise, it bails when
the lineno table has complex encoding for gaps >= 255. EXTENDED_ARG can
appear before MAKE_FUNCTION; in this case both opcodes are skipped.
EXTENDED_ARG preceding any other opcode causes the optimizer to bail.
Optimizations are restricted to simple transformations occuring within a Optimizations are restricted to simple transformations occuring within a
single basic block. All transformations keep the code size the same or single basic block. All transformations keep the code size the same or
smaller. For those that reduce size, the gaps are initially filled with smaller. For those that reduce size, the gaps are initially filled with
NOPs. Later those NOPs are removed and the jump addresses retargeted in NOPs. Later those NOPs are removed and the jump addresses retargeted in
a single pass. Code offset is adjusted accordingly. */ a single pass. */
PyObject * PyObject *
PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
PyObject *lnotab_obj) PyObject *lnotab_obj)
{ {
Py_ssize_t i, j, codelen; Py_ssize_t h, i, nexti, op_start, codelen, tgt;
int nops, h, adj; unsigned int j, nops;
int tgt, tgttgt, opcode; unsigned char opcode, nextop;
unsigned char *codestr = NULL; unsigned char *codestr = NULL;
unsigned char *lnotab; unsigned char *lnotab;
int *addrmap = NULL; unsigned int cum_orig_offset, last_offset;
int cum_orig_offset, last_offset;
Py_ssize_t tabsiz; Py_ssize_t tabsiz;
PyObject **const_stack = NULL; PyObject **const_stack = NULL;
Py_ssize_t *load_const_stack = NULL;
Py_ssize_t const_stack_top = -1; Py_ssize_t const_stack_top = -1;
Py_ssize_t const_stack_size = 0; Py_ssize_t const_stack_size = 0;
int in_consts = 0; /* whether we are in a LOAD_CONST sequence */ int in_consts = 0; /* whether we are in a LOAD_CONST sequence */
...@@ -383,11 +446,9 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, ...@@ -383,11 +446,9 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
/* Note: -128 and 127 special values for line number delta are ok, /* Note: -128 and 127 special values for line number delta are ok,
the peephole optimizer doesn't modify line numbers. */ the peephole optimizer doesn't modify line numbers. */
/* Avoid situations where jump retargeting could overflow */
assert(PyBytes_Check(code)); assert(PyBytes_Check(code));
codelen = PyBytes_GET_SIZE(code); codelen = PyBytes_GET_SIZE(code);
if (codelen > 32700) assert(codelen % 2 == 0);
goto exitUnchanged;
/* Make a modifiable copy of the code string */ /* Make a modifiable copy of the code string */
codestr = (unsigned char *)PyMem_Malloc(codelen); codestr = (unsigned char *)PyMem_Malloc(codelen);
...@@ -398,21 +459,6 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, ...@@ -398,21 +459,6 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
codestr = (unsigned char *)memcpy(codestr, codestr = (unsigned char *)memcpy(codestr,
PyBytes_AS_STRING(code), codelen); PyBytes_AS_STRING(code), codelen);
/* Verify that RETURN_VALUE terminates the codestring. This allows
the various transformation patterns to look ahead several
instructions without additional checks to make sure they are not
looking beyond the end of the code string.
*/
if (codestr[codelen-1] != RETURN_VALUE)
goto exitUnchanged;
/* Mapping to new jump targets after NOPs are removed */
addrmap = PyMem_New(int, codelen);
if (addrmap == NULL) {
PyErr_NoMemory();
goto exitError;
}
blocks = markblocks(codestr, codelen); blocks = markblocks(codestr, codelen);
if (blocks == NULL) if (blocks == NULL)
goto exitError; goto exitError;
...@@ -420,9 +466,17 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, ...@@ -420,9 +466,17 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
CONST_STACK_CREATE(); CONST_STACK_CREATE();
for (i=0 ; i<codelen ; i += CODESIZE(codestr[i])) { for (i=find_op(codestr, 0) ; i<codelen ; i=nexti) {
reoptimize_current:
opcode = codestr[i]; opcode = codestr[i];
op_start = i;
while (op_start >= 2 && codestr[op_start-2] == EXTENDED_ARG) {
op_start -= 2;
}
nexti = i + 2;
while (nexti < codelen && codestr[nexti] == EXTENDED_ARG)
nexti += 2;
nextop = nexti < codelen ? codestr[nexti] : 0;
if (!in_consts) { if (!in_consts) {
CONST_STACK_RESET(); CONST_STACK_RESET();
...@@ -433,14 +487,12 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, ...@@ -433,14 +487,12 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
/* Replace UNARY_NOT POP_JUMP_IF_FALSE /* Replace UNARY_NOT POP_JUMP_IF_FALSE
with POP_JUMP_IF_TRUE */ with POP_JUMP_IF_TRUE */
case UNARY_NOT: case UNARY_NOT:
if (codestr[i+1] != POP_JUMP_IF_FALSE if (nextop != POP_JUMP_IF_FALSE
|| !ISBASICBLOCK(blocks,i,4)) || !ISBASICBLOCK(blocks, op_start, i+2))
continue; break;
j = GETARG(codestr, i+1); memset(codestr + op_start, NOP, i - op_start + 2);
codestr[i] = POP_JUMP_IF_TRUE; codestr[nexti] = POP_JUMP_IF_TRUE;
SETARG(codestr, i, j); break;
codestr[i+3] = NOP;
goto reoptimize_current;
/* not a is b --> a is not b /* not a is b --> a is not b
not a in b --> a not in b not a in b --> a not in b
...@@ -448,78 +500,79 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, ...@@ -448,78 +500,79 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
not a not in b --> a in b not a not in b --> a in b
*/ */
case COMPARE_OP: case COMPARE_OP:
j = GETARG(codestr, i); j = get_arg(codestr, i);
if (j < 6 || j > 9 || if (j < 6 || j > 9 ||
codestr[i+3] != UNARY_NOT || nextop != UNARY_NOT ||
!ISBASICBLOCK(blocks,i,4)) !ISBASICBLOCK(blocks, op_start, i + 2))
continue; break;
SETARG(codestr, i, (j^1)); codestr[i+1] = (j^1);
codestr[i+3] = NOP; memset(codestr + i + 2, NOP, nexti - i);
break; break;
/* Skip over LOAD_CONST trueconst /* Skip over LOAD_CONST trueconst
POP_JUMP_IF_FALSE xx. This improves POP_JUMP_IF_FALSE xx. This improves
"while 1" performance. */ "while 1" performance. */
case LOAD_CONST: case LOAD_CONST:
CONST_STACK_PUSH_OP(i); CONST_STACK_PUSH_OP(i);
j = GETARG(codestr, i); if (nextop != POP_JUMP_IF_FALSE ||
if (codestr[i+3] != POP_JUMP_IF_FALSE || !ISBASICBLOCK(blocks, op_start, i + 2) ||
!ISBASICBLOCK(blocks,i,6) || !PyObject_IsTrue(PyList_GET_ITEM(consts, get_arg(codestr, i))))
!PyObject_IsTrue(PyList_GET_ITEM(consts, j))) break;
continue; memset(codestr + op_start, NOP, nexti - op_start + 2);
memset(codestr+i, NOP, 6); CONST_STACK_POP(1);
CONST_STACK_RESET();
break; break;
/* Try to fold tuples of constants (includes a case for lists and sets /* Try to fold tuples of constants (includes a case for lists
which are only used for "in" and "not in" tests). and sets which are only used for "in" and "not in" tests).
Skip over BUILD_SEQN 1 UNPACK_SEQN 1. Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2. Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2.
Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */ Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */
case BUILD_TUPLE: case BUILD_TUPLE:
case BUILD_LIST: case BUILD_LIST:
case BUILD_SET: case BUILD_SET:
j = GETARG(codestr, i); j = get_arg(codestr, i);
if (j == 0) if (j > 0 && CONST_STACK_LEN() >= j) {
break; h = lastn_const_start(codestr, op_start, j);
h = CONST_STACK_OP_LASTN(j); if ((opcode == BUILD_TUPLE &&
assert((h >= 0 || CONST_STACK_LEN() < j)); ISBASICBLOCK(blocks, h, op_start)) ||
if (h >= 0 && j > 0 && j <= CONST_STACK_LEN() && ((opcode == BUILD_LIST || opcode == BUILD_SET) &&
((opcode == BUILD_TUPLE && ((nextop==COMPARE_OP &&
ISBASICBLOCK(blocks, h, i-h+3)) || (codestr[nexti+1]==6 ||
((opcode == BUILD_LIST || opcode == BUILD_SET) && codestr[nexti+1]==7)) ||
codestr[i+3]==COMPARE_OP && nextop == GET_ITER) && ISBASICBLOCK(blocks, h, i + 2))) {
ISBASICBLOCK(blocks, h, i-h+6) && h = fold_tuple_on_constants(codestr, h, i+2, opcode,
(GETARG(codestr,i+3)==6 || consts, CONST_STACK_LASTN(j), j);
GETARG(codestr,i+3)==7))) && if (h >= 0) {
tuple_of_constants(&codestr[i], j, consts, CONST_STACK_LASTN(j))) { CONST_STACK_POP(j);
assert(codestr[i] == LOAD_CONST); CONST_STACK_PUSH_OP(h);
memset(&codestr[h], NOP, i - h); }
CONST_STACK_POP(j); break;
CONST_STACK_PUSH_OP(i); }
break;
} }
if (codestr[i+3] != UNPACK_SEQUENCE || if (nextop != UNPACK_SEQUENCE ||
!ISBASICBLOCK(blocks,i,6) || !ISBASICBLOCK(blocks, op_start, i + 2) ||
j != GETARG(codestr, i+3) || j != get_arg(codestr, nexti) ||
opcode == BUILD_SET) opcode == BUILD_SET)
continue; break;
if (j == 1) { if (j < 2) {
memset(codestr+i, NOP, 6); memset(codestr+op_start, NOP, nexti - op_start + 2);
} else if (j == 2) { } else if (j == 2) {
codestr[i] = ROT_TWO; codestr[op_start] = ROT_TWO;
memset(codestr+i+1, NOP, 5); codestr[op_start + 1] = 0;
memset(codestr + op_start + 2, NOP, nexti - op_start);
CONST_STACK_RESET(); CONST_STACK_RESET();
} else if (j == 3) { } else if (j == 3) {
codestr[i] = ROT_THREE; codestr[op_start] = ROT_THREE;
codestr[i+1] = ROT_TWO; codestr[op_start + 1] = 0;
memset(codestr+i+2, NOP, 4); codestr[op_start + 2] = ROT_TWO;
codestr[op_start + 3] = 0;
memset(codestr + op_start + 4, NOP, nexti - op_start - 2);
CONST_STACK_RESET(); CONST_STACK_RESET();
} }
break; break;
/* Fold binary ops on constants. /* Fold binary ops on constants.
LOAD_CONST c1 LOAD_CONST c2 BINOP --> LOAD_CONST binop(c1,c2) */ LOAD_CONST c1 LOAD_CONST c2 BINOP --> LOAD_CONST binop(c1,c2) */
case BINARY_POWER: case BINARY_POWER:
case BINARY_MULTIPLY: case BINARY_MULTIPLY:
case BINARY_TRUE_DIVIDE: case BINARY_TRUE_DIVIDE:
...@@ -533,35 +586,34 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, ...@@ -533,35 +586,34 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
case BINARY_AND: case BINARY_AND:
case BINARY_XOR: case BINARY_XOR:
case BINARY_OR: case BINARY_OR:
/* NOTE: LOAD_CONST is saved at `i-2` since it has an arg if (CONST_STACK_LEN() < 2)
while BINOP hasn't */ break;
h = CONST_STACK_OP_LASTN(2); h = lastn_const_start(codestr, op_start, 2);
assert((h >= 0 || CONST_STACK_LEN() < 2)); if (ISBASICBLOCK(blocks, h, op_start)) {
if (h >= 0 && h = fold_binops_on_constants(codestr, h, i+2, opcode,
ISBASICBLOCK(blocks, h, i-h+1) && consts, CONST_STACK_LASTN(2));
fold_binops_on_constants(&codestr[i], consts, CONST_STACK_LASTN(2))) { if (h >= 0) {
i -= 2; CONST_STACK_POP(2);
memset(&codestr[h], NOP, i - h); CONST_STACK_PUSH_OP(h);
assert(codestr[i] == LOAD_CONST); }
CONST_STACK_POP(2);
CONST_STACK_PUSH_OP(i);
} }
break; break;
/* Fold unary ops on constants. /* Fold unary ops on constants.
LOAD_CONST c1 UNARY_OP --> LOAD_CONST unary_op(c) */ LOAD_CONST c1 UNARY_OP --> LOAD_CONST unary_op(c) */
case UNARY_NEGATIVE: case UNARY_NEGATIVE:
case UNARY_INVERT: case UNARY_INVERT:
case UNARY_POSITIVE: case UNARY_POSITIVE:
h = CONST_STACK_OP_LASTN(1); if (CONST_STACK_LEN() < 1)
assert((h >= 0 || CONST_STACK_LEN() < 1)); break;
if (h >= 0 && h = lastn_const_start(codestr, op_start, 1);
ISBASICBLOCK(blocks, h, i-h+1) && if (ISBASICBLOCK(blocks, h, op_start)) {
fold_unaryops_on_constants(&codestr[i-3], consts, CONST_STACK_TOP())) { h = fold_unaryops_on_constants(codestr, h, i+2, opcode,
i -= 2; consts, *CONST_STACK_LASTN(1));
assert(codestr[i] == LOAD_CONST); if (h >= 0) {
CONST_STACK_POP(1); CONST_STACK_POP(1);
CONST_STACK_PUSH_OP(i); CONST_STACK_PUSH_OP(h);
}
} }
break; break;
...@@ -576,25 +628,24 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, ...@@ -576,25 +628,24 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_FALSE_OR_POP z x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_FALSE_OR_POP z
--> x:JUMP_IF_FALSE_OR_POP z --> x:JUMP_IF_FALSE_OR_POP z
x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_TRUE_OR_POP z x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_TRUE_OR_POP z
--> x:POP_JUMP_IF_FALSE y+3 --> x:POP_JUMP_IF_FALSE y+2
where y+3 is the instruction following the second test. where y+2 is the instruction following the second test.
*/ */
case JUMP_IF_FALSE_OR_POP: case JUMP_IF_FALSE_OR_POP:
case JUMP_IF_TRUE_OR_POP: case JUMP_IF_TRUE_OR_POP:
tgt = GETJUMPTGT(codestr, i); h = get_arg(codestr, i);
tgt = find_op(codestr, h);
j = codestr[tgt]; j = codestr[tgt];
if (CONDITIONAL_JUMP(j)) { if (CONDITIONAL_JUMP(j)) {
/* NOTE: all possible jumps here are /* NOTE: all possible jumps here are
absolute! */ absolute! */
if (JUMPS_ON_TRUE(j) == JUMPS_ON_TRUE(opcode)) { if (JUMPS_ON_TRUE(j) == JUMPS_ON_TRUE(opcode)) {
/* The second jump will be /* The second jump will be
taken iff the first is. */ taken iff the first is.
tgttgt = GETJUMPTGT(codestr, tgt); The current opcode inherits
/* The current opcode inherits its target's stack effect */
its target's stack behaviour */ h = set_arg(codestr, i, get_arg(codestr, tgt));
codestr[i] = j;
SETARG(codestr, i, tgttgt);
goto reoptimize_current;
} else { } else {
/* The second jump is not taken /* The second jump is not taken
if the first is (so jump past if the first is (so jump past
...@@ -603,12 +654,15 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, ...@@ -603,12 +654,15 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
they're not taken (so change they're not taken (so change
the first jump to pop its the first jump to pop its
argument when it's taken). */ argument when it's taken). */
if (JUMPS_ON_TRUE(opcode)) h = set_arg(codestr, i, tgt + 2);
codestr[i] = POP_JUMP_IF_TRUE; j = opcode == JUMP_IF_TRUE_OR_POP ?
else POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE;
codestr[i] = POP_JUMP_IF_FALSE; }
SETARG(codestr, i, (tgt + 3));
goto reoptimize_current; if (h >= 0) {
nexti = h;
codestr[nexti] = j;
break;
} }
} }
/* Intentional fallthrough */ /* Intentional fallthrough */
...@@ -625,76 +679,73 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, ...@@ -625,76 +679,73 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
case SETUP_FINALLY: case SETUP_FINALLY:
case SETUP_WITH: case SETUP_WITH:
case SETUP_ASYNC_WITH: case SETUP_ASYNC_WITH:
tgt = GETJUMPTGT(codestr, i); h = GETJUMPTGT(codestr, i);
tgt = find_op(codestr, h);
/* Replace JUMP_* to a RETURN into just a RETURN */ /* Replace JUMP_* to a RETURN into just a RETURN */
if (UNCONDITIONAL_JUMP(opcode) && if (UNCONDITIONAL_JUMP(opcode) &&
codestr[tgt] == RETURN_VALUE) { codestr[tgt] == RETURN_VALUE) {
codestr[i] = RETURN_VALUE; codestr[op_start] = RETURN_VALUE;
memset(codestr+i+1, NOP, 2); codestr[op_start + 1] = 0;
continue; memset(codestr + op_start + 2, NOP, i - op_start);
} else if (UNCONDITIONAL_JUMP(codestr[tgt])) {
j = GETJUMPTGT(codestr, tgt);
if (opcode == JUMP_FORWARD) { /* JMP_ABS can go backwards */
opcode = JUMP_ABSOLUTE;
} else if (!ABSOLUTE_JUMP(opcode)) {
if ((Py_ssize_t)j < i + 2) {
break; /* No backward relative jumps */
}
j -= i + 2; /* Calc relative jump addr */
}
copy_op_arg(codestr, op_start, opcode, j, i+2);
} }
if (!UNCONDITIONAL_JUMP(codestr[tgt]))
continue;
tgttgt = GETJUMPTGT(codestr, tgt);
if (opcode == JUMP_FORWARD) /* JMP_ABS can go backwards */
opcode = JUMP_ABSOLUTE;
if (!ABSOLUTE_JUMP(opcode))
tgttgt -= i + 3; /* Calc relative jump addr */
if (tgttgt < 0) /* No backward relative jumps */
continue;
codestr[i] = opcode;
SETARG(codestr, i, tgttgt);
break;
case EXTENDED_ARG:
if (codestr[i+3] != MAKE_FUNCTION)
goto exitUnchanged;
/* don't visit MAKE_FUNCTION as GETARG will be wrong */
i += 3;
break; break;
/* Replace RETURN LOAD_CONST None RETURN with just RETURN */ /* Remove unreachable ops after RETURN */
/* Remove unreachable JUMPs after RETURN */
case RETURN_VALUE: case RETURN_VALUE:
if (i+4 >= codelen) h = i + 2;
continue; while (h + 2 < codelen && ISBASICBLOCK(blocks, i, h + 2)) {
if (codestr[i+4] == RETURN_VALUE && h += 2;
ISBASICBLOCK(blocks,i,5)) }
memset(codestr+i+1, NOP, 4); if (h > i + 2) {
else if (UNCONDITIONAL_JUMP(codestr[i+1]) && memset(codestr + i + 2, NOP, h - i);
ISBASICBLOCK(blocks,i,4)) nexti = find_op(codestr, h);
memset(codestr+i+1, NOP, 3); }
break; break;
} }
} }
/* Fixup lnotab */ /* Fixup lnotab */
for (i=0, nops=0 ; i<codelen ; i += CODESIZE(codestr[i])) { for (i=0, nops=0 ; i<codelen ; i += 2) {
assert(i - nops <= INT_MAX); assert(i - nops <= INT_MAX);
/* original code offset => new code offset */ /* original code offset => new code offset */
addrmap[i] = (int)(i - nops); blocks[i] = i - nops;
if (codestr[i] == NOP) if (codestr[i] == NOP)
nops++; nops += 2;
} }
cum_orig_offset = 0; cum_orig_offset = 0;
last_offset = 0; last_offset = 0;
for (i=0 ; i < tabsiz ; i+=2) { for (i=0 ; i < tabsiz ; i+=2) {
int offset_delta, new_offset; unsigned int offset_delta, new_offset;
cum_orig_offset += lnotab[i]; cum_orig_offset += lnotab[i];
new_offset = addrmap[cum_orig_offset]; assert((cum_orig_offset & 1) == 0);
new_offset = blocks[cum_orig_offset];
offset_delta = new_offset - last_offset; offset_delta = new_offset - last_offset;
assert(0 <= offset_delta && offset_delta <= 255); assert(offset_delta <= 255);
lnotab[i] = (unsigned char)offset_delta; lnotab[i] = (unsigned char)offset_delta;
last_offset = new_offset; last_offset = new_offset;
} }
/* Remove NOPs and fixup jump targets */ /* Remove NOPs and fixup jump targets */
for (i=0, h=0 ; i<codelen ; ) { for (op_start=0, i=0, h=0 ; i<codelen ; i+=2, op_start=i) {
j = codestr[i+1];
while (codestr[i] == EXTENDED_ARG) {
i += 2;
j = j<<8 | codestr[i+1];
}
opcode = codestr[i]; opcode = codestr[i];
switch (opcode) { switch (opcode) {
case NOP: case NOP:continue;
i++;
continue;
case JUMP_ABSOLUTE: case JUMP_ABSOLUTE:
case CONTINUE_LOOP: case CONTINUE_LOOP:
...@@ -702,8 +753,7 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, ...@@ -702,8 +753,7 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
case POP_JUMP_IF_TRUE: case POP_JUMP_IF_TRUE:
case JUMP_IF_FALSE_OR_POP: case JUMP_IF_FALSE_OR_POP:
case JUMP_IF_TRUE_OR_POP: case JUMP_IF_TRUE_OR_POP:
j = addrmap[GETARG(codestr, i)]; j = blocks[j];
SETARG(codestr, i, j);
break; break;
case FOR_ITER: case FOR_ITER:
...@@ -713,31 +763,31 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names, ...@@ -713,31 +763,31 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
case SETUP_FINALLY: case SETUP_FINALLY:
case SETUP_WITH: case SETUP_WITH:
case SETUP_ASYNC_WITH: case SETUP_ASYNC_WITH:
j = addrmap[GETARG(codestr, i) + i + 3] - addrmap[i] - 3; j = blocks[j + i + 2] - blocks[i] - 2;
SETARG(codestr, i, j);
break; break;
} }
adj = CODESIZE(opcode); nexti = i - op_start + 2;
while (adj--) if (instrsize(j) > nexti)
codestr[h++] = codestr[i++]; goto exitUnchanged;
/* If instrsize(j) < nexti, we'll emit EXTENDED_ARG 0 */
write_op_arg(codestr + h, opcode, j, nexti);
h += nexti;
} }
assert(h + nops == codelen); assert(h + (Py_ssize_t)nops == codelen);
code = PyBytes_FromStringAndSize((char *)codestr, h);
CONST_STACK_DELETE(); CONST_STACK_DELETE();
PyMem_Free(addrmap);
PyMem_Free(codestr);
PyMem_Free(blocks); PyMem_Free(blocks);
code = PyBytes_FromStringAndSize((char *)codestr, h);
PyMem_Free(codestr);
return code; return code;
exitError: exitError:
code = NULL; code = NULL;
exitUnchanged: exitUnchanged:
Py_XINCREF(code);
CONST_STACK_DELETE(); CONST_STACK_DELETE();
PyMem_Free(blocks); PyMem_Free(blocks);
PyMem_Free(addrmap);
PyMem_Free(codestr); PyMem_Free(codestr);
Py_XINCREF(code);
return code; return code;
} }
/* This file contains code shared by the compiler and the peephole
optimizer.
*/
/* Minimum number of bytes necessary to encode instruction with EXTENDED_ARGs */
static int
instrsize(unsigned int oparg)
{
return oparg <= 0xff ? 2 :
oparg <= 0xffff ? 4 :
oparg <= 0xffffff ? 6 :
8;
}
/* Spits out op/oparg pair using ilen bytes. codestr should be pointed at the
desired location of the first EXTENDED_ARG */
static void
write_op_arg(unsigned char *codestr, unsigned char opcode,
unsigned int oparg, int ilen)
{
switch (ilen) {
case 8:
*codestr++ = EXTENDED_ARG;
*codestr++ = (oparg >> 24) & 0xff;
case 6:
*codestr++ = EXTENDED_ARG;
*codestr++ = (oparg >> 16) & 0xff;
case 4:
*codestr++ = EXTENDED_ARG;
*codestr++ = (oparg >> 8) & 0xff;
case 2:
*codestr++ = opcode;
*codestr++ = oparg & 0xff;
break;
default:
assert(0);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment