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

Patch by Demur Rumed.
This commit is contained in:
Serhiy Storchaka 2016-05-24 09:15:14 +03:00
parent c35f491a06
commit b0f80b0312
18 changed files with 4747 additions and 5022 deletions

View file

@ -31,9 +31,9 @@ the following command can be used to display the disassembly of
>>> dis.dis(myfunc)
2 0 LOAD_GLOBAL 0 (len)
3 LOAD_FAST 0 (alist)
6 CALL_FUNCTION 1
9 RETURN_VALUE
2 LOAD_FAST 0 (alist)
4 CALL_FUNCTION 1
6 RETURN_VALUE
(The "2" is a line number).
@ -682,8 +682,7 @@ iterations of the loop.
.. XXX explain the WHY stuff!
All of the following opcodes expect arguments. An argument is two bytes, with
the more significant byte last.
All of the following opcodes use their arguments.
.. opcode:: STORE_NAME (namei)

View file

@ -79,9 +79,9 @@ class struct_frozen(Structure):
continue
items.append((entry.name.decode("ascii"), entry.size))
expected = [("__hello__", 161),
("__phello__", -161),
("__phello__.spam", 161),
expected = [("__hello__", 139),
("__phello__", -139),
("__phello__.spam", 139),
]
self.assertEqual(items, expected, "PyImport_FrozenModules example "
"in Doc/library/ctypes.rst may be out of date")

View file

@ -285,7 +285,6 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
"""
labels = findlabels(code)
starts_line = None
free = None
for offset, op, arg in _unpack_opargs(code):
if linestarts is not None:
starts_line = linestarts.get(offset, None)
@ -296,7 +295,7 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
argrepr = ''
if arg is not None:
# 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
# raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
argval = arg
@ -305,7 +304,7 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
elif op in hasname:
argval, argrepr = _get_name_info(arg, names)
elif op in hasjrel:
argval = offset + 3 + arg
argval = offset + 2 + arg
argrepr = "to " + repr(argval)
elif op in haslocal:
argval, argrepr = _get_name_info(arg, varnames)
@ -352,23 +351,15 @@ def _disassemble_str(source, *, file=None):
disco = disassemble # XXX For backwards compatibility
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
n = len(code)
i = 0
while i < n:
for i in range(0, len(code), 2):
op = code[i]
offset = i
i = i+1
arg = None
if op >= HAVE_ARGUMENT:
arg = code[i] + code[i+1]*256 + extended_arg
extended_arg = 0
i = i+2
if op == EXTENDED_ARG:
extended_arg = arg*65536
yield (offset, op, arg)
arg = code[i+1] | extended_arg
extended_arg = (arg << 8) if op == EXTENDED_ARG else 0
else:
arg = None
yield (i, op, arg)
def findlabels(code):
"""Detect all offsets in a byte code which are jump targets.
@ -379,14 +370,14 @@ def findlabels(code):
labels = []
for offset, op, arg in _unpack_opargs(code):
if arg is not None:
label = -1
if op in hasjrel:
label = offset + 3 + arg
label = offset + 2 + arg
elif op in hasjabs:
label = arg
if label >= 0:
if label not in labels:
labels.append(label)
else:
continue
if label not in labels:
labels.append(label)
return labels
def findlinestarts(code):

View file

@ -225,6 +225,7 @@ def _write_atomic(path, data, mode=0o666):
# Python 3.5b2 3350 (add GET_YIELD_FROM_ITER opcode #24400)
# Python 3.6a0 3360 (add FORMAT_VALUE opcode #25483
# 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
# longer be understood by older implementations of the eval loop (usually
@ -233,7 +234,7 @@ def _write_atomic(path, data, mode=0o666):
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# 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
_PYCACHE = '__pycache__'

View file

@ -40,41 +40,41 @@ def cm(cls, x):
dis_c_instance_method = """\
%3d 0 LOAD_FAST 1 (x)
3 LOAD_CONST 1 (1)
6 COMPARE_OP 2 (==)
9 LOAD_FAST 0 (self)
12 STORE_ATTR 0 (x)
15 LOAD_CONST 0 (None)
18 RETURN_VALUE
2 LOAD_CONST 1 (1)
4 COMPARE_OP 2 (==)
6 LOAD_FAST 0 (self)
8 STORE_ATTR 0 (x)
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
""" % (_C.__init__.__code__.co_firstlineno + 1,)
dis_c_instance_method_bytes = """\
0 LOAD_FAST 1 (1)
3 LOAD_CONST 1 (1)
6 COMPARE_OP 2 (==)
9 LOAD_FAST 0 (0)
12 STORE_ATTR 0 (0)
15 LOAD_CONST 0 (0)
18 RETURN_VALUE
2 LOAD_CONST 1 (1)
4 COMPARE_OP 2 (==)
6 LOAD_FAST 0 (0)
8 STORE_ATTR 0 (0)
10 LOAD_CONST 0 (0)
12 RETURN_VALUE
"""
dis_c_class_method = """\
%3d 0 LOAD_FAST 1 (x)
3 LOAD_CONST 1 (1)
6 COMPARE_OP 2 (==)
9 LOAD_FAST 0 (cls)
12 STORE_ATTR 0 (x)
15 LOAD_CONST 0 (None)
18 RETURN_VALUE
2 LOAD_CONST 1 (1)
4 COMPARE_OP 2 (==)
6 LOAD_FAST 0 (cls)
8 STORE_ATTR 0 (x)
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
""" % (_C.cm.__code__.co_firstlineno + 2,)
dis_c_static_method = """\
%3d 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (1)
6 COMPARE_OP 2 (==)
9 STORE_FAST 0 (x)
12 LOAD_CONST 0 (None)
15 RETURN_VALUE
2 LOAD_CONST 1 (1)
4 COMPARE_OP 2 (==)
6 STORE_FAST 0 (x)
8 LOAD_CONST 0 (None)
10 RETURN_VALUE
""" % (_C.sm.__code__.co_firstlineno + 2,)
# Class disassembling info has an extra newline at end.
@ -95,23 +95,23 @@ def _f(a):
dis_f = """\
%3d 0 LOAD_GLOBAL 0 (print)
3 LOAD_FAST 0 (a)
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 POP_TOP
2 LOAD_FAST 0 (a)
4 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
6 POP_TOP
%3d 10 LOAD_CONST 1 (1)
13 RETURN_VALUE
%3d 8 LOAD_CONST 1 (1)
10 RETURN_VALUE
""" % (_f.__code__.co_firstlineno + 1,
_f.__code__.co_firstlineno + 2)
dis_f_co_code = """\
0 LOAD_GLOBAL 0 (0)
3 LOAD_FAST 0 (0)
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 POP_TOP
10 LOAD_CONST 1 (1)
13 RETURN_VALUE
2 LOAD_FAST 0 (0)
4 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
6 POP_TOP
8 LOAD_CONST 1 (1)
10 RETURN_VALUE
"""
@ -121,20 +121,20 @@ def bug708901():
pass
dis_bug708901 = """\
%3d 0 SETUP_LOOP 23 (to 26)
3 LOAD_GLOBAL 0 (range)
6 LOAD_CONST 1 (1)
%3d 0 SETUP_LOOP 18 (to 20)
2 LOAD_GLOBAL 0 (range)
4 LOAD_CONST 1 (1)
%3d 9 LOAD_CONST 2 (10)
12 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
15 GET_ITER
>> 16 FOR_ITER 6 (to 25)
19 STORE_FAST 0 (res)
%3d 6 LOAD_CONST 2 (10)
8 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
10 GET_ITER
>> 12 FOR_ITER 4 (to 18)
14 STORE_FAST 0 (res)
%3d 22 JUMP_ABSOLUTE 16
>> 25 POP_BLOCK
>> 26 LOAD_CONST 0 (None)
29 RETURN_VALUE
%3d 16 JUMP_ABSOLUTE 12
>> 18 POP_BLOCK
>> 20 LOAD_CONST 0 (None)
22 RETURN_VALUE
""" % (bug708901.__code__.co_firstlineno + 1,
bug708901.__code__.co_firstlineno + 2,
bug708901.__code__.co_firstlineno + 3)
@ -147,22 +147,22 @@ def bug1333982(x=[]):
dis_bug1333982 = """\
%3d 0 LOAD_CONST 1 (0)
3 POP_JUMP_IF_TRUE 35
6 LOAD_GLOBAL 0 (AssertionError)
9 LOAD_CONST 2 (<code object <listcomp> at 0x..., file "%s", line %d>)
12 LOAD_CONST 3 ('bug1333982.<locals>.<listcomp>')
15 MAKE_FUNCTION 0
18 LOAD_FAST 0 (x)
21 GET_ITER
2 POP_JUMP_IF_TRUE 26
4 LOAD_GLOBAL 0 (AssertionError)
6 LOAD_CONST 2 (<code object <listcomp> at 0x..., file "%s", line %d>)
8 LOAD_CONST 3 ('bug1333982.<locals>.<listcomp>')
10 MAKE_FUNCTION 0
12 LOAD_FAST 0 (x)
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)
24 RAISE_VARARGS 1
%3d 25 LOAD_CONST 4 (1)
28 BINARY_ADD
29 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
32 RAISE_VARARGS 1
%3d >> 35 LOAD_CONST 0 (None)
38 RETURN_VALUE
%3d >> 26 LOAD_CONST 0 (None)
28 RETURN_VALUE
""" % (bug1333982.__code__.co_firstlineno + 1,
__file__,
bug1333982.__code__.co_firstlineno + 1,
@ -171,19 +171,19 @@ def bug1333982(x=[]):
_BIG_LINENO_FORMAT = """\
%3d 0 LOAD_GLOBAL 0 (spam)
3 POP_TOP
2 POP_TOP
4 LOAD_CONST 0 (None)
7 RETURN_VALUE
6 RETURN_VALUE
"""
dis_module_expected_results = """\
Disassembly of f:
4 0 LOAD_CONST 0 (None)
3 RETURN_VALUE
2 RETURN_VALUE
Disassembly of g:
5 0 LOAD_CONST 0 (None)
3 RETURN_VALUE
2 RETURN_VALUE
"""
@ -191,20 +191,20 @@ def bug1333982(x=[]):
dis_expr_str = """\
1 0 LOAD_NAME 0 (x)
3 LOAD_CONST 0 (1)
6 BINARY_ADD
7 RETURN_VALUE
2 LOAD_CONST 0 (1)
4 BINARY_ADD
6 RETURN_VALUE
"""
simple_stmt_str = "x = x + 1"
dis_simple_stmt_str = """\
1 0 LOAD_NAME 0 (x)
3 LOAD_CONST 0 (1)
6 BINARY_ADD
7 STORE_NAME 0 (x)
10 LOAD_CONST 1 (None)
13 RETURN_VALUE
2 LOAD_CONST 0 (1)
4 BINARY_ADD
6 STORE_NAME 0 (x)
8 LOAD_CONST 1 (None)
10 RETURN_VALUE
"""
compound_stmt_str = """\
@ -215,54 +215,54 @@ def bug1333982(x=[]):
dis_compound_stmt_str = """\
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)
12 LOAD_CONST 1 (1)
15 INPLACE_ADD
16 STORE_NAME 0 (x)
19 JUMP_ABSOLUTE 9
22 POP_BLOCK
>> 23 LOAD_CONST 2 (None)
26 RETURN_VALUE
3 >> 6 LOAD_NAME 0 (x)
8 LOAD_CONST 1 (1)
10 INPLACE_ADD
12 STORE_NAME 0 (x)
14 JUMP_ABSOLUTE 6
16 POP_BLOCK
>> 18 LOAD_CONST 2 (None)
20 RETURN_VALUE
"""
dis_traceback = """\
%3d 0 SETUP_EXCEPT 12 (to 15)
%3d 0 SETUP_EXCEPT 12 (to 14)
%3d 3 LOAD_CONST 1 (1)
6 LOAD_CONST 2 (0)
--> 9 BINARY_TRUE_DIVIDE
10 POP_TOP
11 POP_BLOCK
12 JUMP_FORWARD 46 (to 61)
%3d 2 LOAD_CONST 1 (1)
4 LOAD_CONST 2 (0)
--> 6 BINARY_TRUE_DIVIDE
8 POP_TOP
10 POP_BLOCK
12 JUMP_FORWARD 40 (to 54)
%3d >> 15 DUP_TOP
%3d >> 14 DUP_TOP
16 LOAD_GLOBAL 0 (Exception)
19 COMPARE_OP 10 (exception match)
22 POP_JUMP_IF_FALSE 60
25 POP_TOP
26 STORE_FAST 0 (e)
29 POP_TOP
30 SETUP_FINALLY 14 (to 47)
18 COMPARE_OP 10 (exception match)
20 POP_JUMP_IF_FALSE 52
22 POP_TOP
24 STORE_FAST 0 (e)
26 POP_TOP
28 SETUP_FINALLY 12 (to 42)
%3d 33 LOAD_FAST 0 (e)
36 LOAD_ATTR 1 (__traceback__)
39 STORE_FAST 1 (tb)
42 POP_BLOCK
43 POP_EXCEPT
44 LOAD_CONST 0 (None)
>> 47 LOAD_CONST 0 (None)
50 STORE_FAST 0 (e)
53 DELETE_FAST 0 (e)
56 END_FINALLY
57 JUMP_FORWARD 1 (to 61)
>> 60 END_FINALLY
%3d 30 LOAD_FAST 0 (e)
32 LOAD_ATTR 1 (__traceback__)
34 STORE_FAST 1 (tb)
36 POP_BLOCK
38 POP_EXCEPT
40 LOAD_CONST 0 (None)
>> 42 LOAD_CONST 0 (None)
44 STORE_FAST 0 (e)
46 DELETE_FAST 0 (e)
48 END_FINALLY
50 JUMP_FORWARD 2 (to 54)
>> 52 END_FINALLY
%3d >> 61 LOAD_FAST 1 (tb)
64 RETURN_VALUE
%3d >> 54 LOAD_FAST 1 (tb)
56 RETURN_VALUE
""" % (TRACEBACK_CODE.co_firstlineno + 1,
TRACEBACK_CODE.co_firstlineno + 2,
TRACEBACK_CODE.co_firstlineno + 3,
@ -650,170 +650,170 @@ def jumpy():
Instruction = dis.Instruction
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=2, argval=4, argrepr='4', offset=3, 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=1, argval='b', argrepr='b', offset=9, 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='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=4, argval='outer.<locals>.f', argrepr="'outer.<locals>.f'", offset=18, 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='STORE_FAST', opcode=125, arg=2, argval='f', argrepr='f', offset=24, 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_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=1, argval='b', argrepr='b', offset=33, 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=6, argval=1, argrepr='1', offset=39, 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_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=45, 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='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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=54, 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='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=58, 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=4, 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=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=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=12, 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=16, starts_line=None, 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=20, 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=24, 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=28, 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=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=34, 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=38, starts_line=8, 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 = [
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_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=3, argval='b', argrepr='b', offset=9, 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=1, argval='d', argrepr='d', offset=15, 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='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=4, argval='outer.<locals>.f.<locals>.inner', argrepr="'outer.<locals>.f.<locals>.inner'", offset=24, 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='STORE_FAST', opcode=125, arg=2, argval='inner', argrepr='inner', offset=30, 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_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=3, argval='b', argrepr='b', offset=39, 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=1, argval='d', argrepr='d', offset=45, 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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=51, 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='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=55, 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=4, 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=8, 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=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=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=16, 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=20, starts_line=None, 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=24, 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=28, 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=32, 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=36, starts_line=6, 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 = [
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=1, argval='b', argrepr='b', offset=6, 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=3, argval='d', argrepr='d', offset=12, 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=1, argval='f', argrepr='f', offset=18, 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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=24, 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='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=28, 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=4, 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=8, 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=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=14, 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=18, 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 = [
Instruction(opname='SETUP_LOOP', opcode=120, arg=68, argval=71, argrepr='to 71', 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_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=6, 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='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=12, 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='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=16, 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_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=22, 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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=28, 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_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=32, 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='POP_JUMP_IF_FALSE', opcode=114, arg=44, argval=44, argrepr='', offset=38, 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='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=44, 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='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=50, 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='BREAK_LOOP', opcode=80, arg=None, argval=None, argrepr='', offset=56, 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='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=60, 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_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='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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=70, 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='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=74, 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='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=80, 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='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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=89, 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_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=93, 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='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=97, 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_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=103, 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='POP_JUMP_IF_FALSE', opcode=114, arg=115, argval=115, argrepr='', offset=109, 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='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=115, 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='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=121, 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='BREAK_LOOP', opcode=80, arg=None, argval=None, argrepr='', offset=127, 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='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=131, 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_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='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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=141, 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_EXCEPT', opcode=121, arg=12, argval=160, argrepr='to 160', offset=145, 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=7, argval=0, argrepr='0', offset=151, 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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=155, 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='JUMP_FORWARD', opcode=110, arg=28, argval=188, argrepr='to 188', offset=157, 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='LOAD_GLOBAL', opcode=116, arg=2, argval='ZeroDivisionError', argrepr='ZeroDivisionError', offset=161, 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='POP_JUMP_IF_FALSE', opcode=114, arg=187, argval=187, argrepr='', offset=167, 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=171, 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='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=173, 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='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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=182, 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='JUMP_FORWARD', opcode=110, arg=27, argval=214, argrepr='to 214', offset=184, 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='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=188, 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='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=194, 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_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=200, 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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=206, 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='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=208, 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_FINISH', opcode=82, arg=None, argval=None, argrepr='', offset=212, 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='POP_BLOCK', opcode=87, arg=None, argval=None, argrepr='', offset=214, 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_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=218, 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='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='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=227, 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='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=229, 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='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=2, 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=6, 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=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=12, starts_line=None, 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=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=18, 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=22, starts_line=5, 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=26, 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=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=32, starts_line=7, is_jump_target=True),
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=36, 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=40, starts_line=8, 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=44, starts_line=None, is_jump_target=True),
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=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=50, 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=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=56, starts_line=None, is_jump_target=True),
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=60, starts_line=12, 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=64, 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=68, starts_line=13, 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=72, 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=76, starts_line=14, 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=80, 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=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=86, starts_line=16, is_jump_target=True),
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=90, 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=94, starts_line=17, 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=98, starts_line=None, is_jump_target=True),
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=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=104, 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=70, argval=180, argrepr='to 180', offset=108, starts_line=20, is_jump_target=True),
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=112, starts_line=21, 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=116, 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=120, 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=124, starts_line=22, is_jump_target=True),
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=128, 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=132, 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=136, starts_line=None, 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=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=142, 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=146, 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=150, starts_line=None, 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=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=156, starts_line=None, 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=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=162, 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=166, 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=170, starts_line=None, is_jump_target=True),
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=174, starts_line=None, is_jump_target=False),
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=178, starts_line=None, is_jump_target=False),
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=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=184, 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=188, 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=192, starts_line=None, is_jump_target=False),
]
# One last piece of inspect fodder to check the default line number handling
def simple(): pass
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='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)
]

View file

@ -10,6 +10,9 @@ What's New in Python 3.6.0 alpha 2
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:
() = iterable.

View file

@ -189,7 +189,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno)
memset(blockstack, '\0', sizeof(blockstack));
memset(in_finally, '\0', sizeof(in_finally));
blockstack_top = 0;
for (addr = 0; addr < code_len; addr++) {
for (addr = 0; addr < code_len; addr += 2) {
unsigned char op = code[addr];
switch (op) {
case SETUP_LOOP:
@ -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. */
@ -277,7 +273,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno)
* can tell whether the jump goes into any blocks without coming out
* again - in that case we raise an exception below. */
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];
switch (op) {
case SETUP_LOOP:
@ -294,10 +290,6 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno)
}
min_delta_iblock = Py_MIN(min_delta_iblock, delta_iblock);
if (op >= HAVE_ARGUMENT) {
addr += 2;
}
}
/* Derive the absolute iblock values from the deltas. */

View file

@ -277,7 +277,7 @@ _PyGen_yf(PyGenObject *gen)
PyObject *bytecode = f->f_code->co_code;
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;
yf = f->f_stacktop[-1];
Py_INCREF(yf);
@ -376,7 +376,7 @@ gen_throw(PyGenObject *gen, PyObject *args)
assert(ret == yf);
Py_DECREF(ret);
/* Termination repetition of YIELD_FROM */
gen->gi_frame->f_lasti++;
gen->gi_frame->f_lasti += 2;
if (_PyGen_FetchStopIterationValue(&val) == 0) {
ret = gen_send_ex(gen, val, 0, 0);
Py_DECREF(val);

View file

@ -1089,7 +1089,7 @@ static PYC_MAGIC magic_values[] = {
{ 3190, 3230, L"3.3" },
{ 3250, 3310, L"3.4" },
{ 3320, 3350, L"3.5" },
{ 3360, 3361, L"3.6" },
{ 3360, 3370, L"3.6" },
{ 0 }
};

View file

@ -209,6 +209,7 @@
<ClInclude Include="..\Python\condvar.h" />
<ClInclude Include="..\Python\importdl.h" />
<ClInclude Include="..\Python\thread_nt.h" />
<ClInclude Include="..\Python\wordcode_helpers.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\Modules\_bisectmodule.c" />

View file

@ -420,6 +420,9 @@
<ClInclude Include="..\Python\thread_nt.h">
<Filter>Python</Filter>
</ClInclude>
<ClInclude Include="..\Python\wordcode_helpers.h">
<Filter>Python</Filter>
</ClInclude>
<ClInclude Include="..\Python\condvar.h">
<Filter>Python</Filter>
</ClInclude>

View file

@ -886,24 +886,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
/* Import the static jump table */
#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) \
TARGET_##op: \
opcode = op; \
if (HAS_ARG(op)) \
oparg = NEXTARG(); \
case op:
#define DISPATCH() \
{ \
if (!_Py_atomic_load_relaxed(&eval_breaker)) { \
@ -917,7 +903,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
{ \
if (!lltrace && !_Py_TracingPossible) { \
f->f_lasti = INSTR_OFFSET(); \
goto *opcode_targets[*next_instr++]; \
opcode = NEXTOP(); \
oparg = NEXTARG(); \
goto *opcode_targets[opcode]; \
} \
goto fast_next_opcode; \
}
@ -926,7 +914,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
{ \
if (!_Py_TracingPossible) { \
f->f_lasti = INSTR_OFFSET(); \
goto *opcode_targets[*next_instr++]; \
opcode = NEXTOP(); \
oparg = NEXTARG(); \
goto *opcode_targets[opcode]; \
} \
goto fast_next_opcode; \
}
@ -935,10 +925,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
#else
#define TARGET(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 FAST_DISPATCH() goto fast_next_opcode
#endif
@ -995,9 +982,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
/* Code access macros */
#define INSTR_OFFSET() ((int)(next_instr - first_instr))
#define NEXTOP() (*next_instr++)
#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
#define PEEKARG() ((next_instr[2]<<8) + next_instr[1])
#define NEXTOP() (next_instr+=2, next_instr[-2])
#define NEXTARG() (next_instr[-1])
#define PEEKARG() (next_instr[1])
#define JUMPTO(x) (next_instr = first_instr + (x))
#define JUMPBY(x) (next_instr += (x))
@ -1012,10 +999,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
processor's own internal branch predication has a high likelihood of
success, resulting in a nearly zero-overhead transition to the
next opcode. A successful prediction saves a trip through the eval-loop
including its two unpredictable branches, the HAS_ARG test and the
switch-case. Combined with the processor's internal branch prediction,
a successful PREDICT has the effect of making the two opcodes run as if
they were a single new opcode with the bodies combined.
including its unpredictable switch-case branch. Combined with the
processor's internal branch prediction, a successful PREDICT has the
effect of making the two opcodes run as if they were a single new opcode
with the bodies combined.
If collecting opcode statistics, your choices are to either keep the
predictions turned-on and interpret the results as if some opcodes
@ -1030,13 +1017,18 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
#if defined(DYNAMIC_EXECUTION_PROFILE) || USE_COMPUTED_GOTOS
#define PREDICT(op) if (0) goto PRED_##op
#define PREDICTED(op) PRED_##op:
#define PREDICTED_WITH_ARG(op) PRED_##op:
#else
#define PREDICT(op) if (*next_instr == op) goto PRED_##op
#define PREDICTED(op) PRED_##op: next_instr++
#define PREDICTED_WITH_ARG(op) PRED_##op: oparg = PEEKARG(); next_instr += 3
#define PREDICT(op) \
do{ \
if (*next_instr == op){ \
opcode = op; \
oparg = PEEKARG(); \
next_instr += 2; \
goto PRED_##op; \
} \
} while(0)
#endif
#define PREDICTED(op) PRED_##op:
/* Stack manipulation macros */
@ -1100,7 +1092,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
}
#define UNWIND_EXCEPT_HANDLER(b) \
{ \
do { \
PyObject *type, *value, *traceback; \
assert(STACK_LEVEL() >= (b)->b_level + 3); \
while (STACK_LEVEL() > (b)->b_level + 3) { \
@ -1116,7 +1108,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
Py_XDECREF(type); \
Py_XDECREF(value); \
Py_XDECREF(traceback); \
}
} while(0)
/* Start of code */
@ -1166,15 +1158,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
fastlocals = f->f_localsplus;
freevars = f->f_localsplus + co->co_nlocals;
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,
unless it's -1 in which case next_instr should be first_instr.
f->f_lasti now refers to the index of the last instruction
executed. You might think this was obvious from the name, but
this wasn't always true before 2.3! PyFrame_New now sets
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
YIELD_FROM sets f_lasti to itself, in order to repeatedly yield
multiple values.
When the PREDICT() macros are enabled, some opcode pairs follow in
@ -1183,9 +1171,12 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
were a single new opcode; accordingly,f->f_lasti will point to
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
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;
assert(stack_pointer != NULL);
f->f_stacktop = NULL; /* remains NULL unless yield suspends frame */
@ -1323,10 +1314,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
/* Extract opcode and argument */
opcode = NEXTOP();
oparg = 0; /* allows oparg to be stored in a register because
it doesn't have to be remembered across a full loop */
if (HAS_ARG(opcode))
oparg = NEXTARG();
oparg = NEXTARG();
dispatch_opcode:
#ifdef DYNAMIC_EXECUTION_PROFILE
#ifdef DXPAIRS
@ -1384,7 +1372,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
FAST_DISPATCH();
}
PREDICTED_WITH_ARG(STORE_FAST);
PREDICTED(STORE_FAST);
TARGET(STORE_FAST) {
PyObject *value = POP();
SETLOCAL(oparg, value);
@ -2075,7 +2063,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
f->f_stacktop = stack_pointer;
why = WHY_YIELD;
/* and repeat... */
f->f_lasti--;
f->f_lasti -= 2;
goto fast_yield;
}
@ -2213,7 +2201,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
PREDICTED_WITH_ARG(UNPACK_SEQUENCE);
PREDICTED(UNPACK_SEQUENCE);
TARGET(UNPACK_SEQUENCE) {
PyObject *seq = POP(), *item, **items;
if (PyTuple_CheckExact(seq) &&
@ -2511,9 +2499,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
TARGET_WITH_IMPL(BUILD_TUPLE_UNPACK, _build_list_unpack)
TARGET(BUILD_LIST_UNPACK)
_build_list_unpack: {
TARGET(BUILD_TUPLE_UNPACK)
TARGET(BUILD_LIST_UNPACK) {
int convert_to_tuple = opcode == BUILD_TUPLE_UNPACK;
int i;
PyObject *sum = PyList_New(0);
@ -2610,9 +2597,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
TARGET_WITH_IMPL(BUILD_MAP_UNPACK_WITH_CALL, _build_map_unpack)
TARGET(BUILD_MAP_UNPACK)
_build_map_unpack: {
TARGET(BUILD_MAP_UNPACK_WITH_CALL)
TARGET(BUILD_MAP_UNPACK) {
int with_call = opcode == BUILD_MAP_UNPACK_WITH_CALL;
int num_maps;
int function_location;
@ -2819,7 +2805,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
FAST_DISPATCH();
}
PREDICTED_WITH_ARG(POP_JUMP_IF_FALSE);
PREDICTED(POP_JUMP_IF_FALSE);
TARGET(POP_JUMP_IF_FALSE) {
PyObject *cond = POP();
int err;
@ -2843,7 +2829,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
PREDICTED_WITH_ARG(POP_JUMP_IF_TRUE);
PREDICTED(POP_JUMP_IF_TRUE);
TARGET(POP_JUMP_IF_TRUE) {
PyObject *cond = POP();
int err;
@ -2920,7 +2906,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
PREDICTED_WITH_ARG(JUMP_ABSOLUTE);
PREDICTED(JUMP_ABSOLUTE);
TARGET(JUMP_ABSOLUTE) {
JUMPTO(oparg);
#if FAST_LOOPS
@ -2977,7 +2963,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
PREDICTED_WITH_ARG(FOR_ITER);
PREDICTED(FOR_ITER);
TARGET(FOR_ITER) {
/* before: [iter]; after: [iter, iter()] *or* [] */
PyObject *iter = TOP();
@ -3015,10 +3001,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
goto fast_block_end;
}
TARGET_WITH_IMPL(SETUP_LOOP, _setup_finally)
TARGET_WITH_IMPL(SETUP_EXCEPT, _setup_finally)
TARGET(SETUP_FINALLY)
_setup_finally: {
TARGET(SETUP_LOOP)
TARGET(SETUP_EXCEPT)
TARGET(SETUP_FINALLY) {
/* NOTE: If you add any new block-setup opcodes that
are not try/except/finally handlers, you may need
to update the PyGen_NeedsFinalizing() function.
@ -3213,10 +3198,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
TARGET_WITH_IMPL(CALL_FUNCTION_VAR, _call_function_var_kw)
TARGET_WITH_IMPL(CALL_FUNCTION_KW, _call_function_var_kw)
TARGET(CALL_FUNCTION_VAR_KW)
_call_function_var_kw: {
TARGET(CALL_FUNCTION_VAR)
TARGET(CALL_FUNCTION_KW)
TARGET(CALL_FUNCTION_VAR_KW) {
int na = oparg & 0xff;
int nk = (oparg>>8) & 0xff;
int flags = (opcode - CALL_FUNCTION) & 3;
@ -3258,9 +3242,8 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
TARGET_WITH_IMPL(MAKE_CLOSURE, _make_function)
TARGET(MAKE_FUNCTION)
_make_function: {
TARGET(MAKE_CLOSURE)
TARGET(MAKE_FUNCTION) {
int posdefaults = oparg & 0xff;
int kwdefaults = (oparg>>8) & 0xff;
int num_annotations = (oparg >> 16) & 0x7fff;
@ -3450,7 +3433,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
TARGET(EXTENDED_ARG) {
opcode = NEXTOP();
oparg = oparg<<16 | NEXTARG();
oparg = oparg<<8 | NEXTARG();
goto dispatch_opcode;
}

View file

@ -29,6 +29,7 @@
#include "code.h"
#include "symtable.h"
#include "opcode.h"
#include "wordcode_helpers.h"
#define DEFAULT_BLOCK_SIZE 16
#define DEFAULT_BLOCKS 8
@ -43,7 +44,6 @@
struct instr {
unsigned i_jabs : 1;
unsigned i_jrel : 1;
unsigned i_hasarg : 1;
unsigned char i_opcode;
int i_oparg;
struct basicblock_ *i_target; /* target block (if jump instruction) */
@ -1080,13 +1080,14 @@ compiler_addop(struct compiler *c, int opcode)
basicblock *b;
struct instr *i;
int off;
assert(!HAS_ARG(opcode));
off = compiler_next_instr(c, c->u->u_curblock);
if (off < 0)
return 0;
b = c->u->u_curblock;
i = &b->b_instr[off];
i->i_opcode = opcode;
i->i_hasarg = 0;
i->i_oparg = 0;
if (opcode == RETURN_VALUE)
b->b_return = 1;
compiler_set_lineno(c, off);
@ -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.
The argument of a concrete bytecode instruction is limited to 16-bit.
EXTENDED_ARG is used for 32-bit arguments. */
The argument of a concrete bytecode instruction is limited to 8-bit.
EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */
assert(HAS_ARG(opcode));
assert(0 <= oparg && oparg <= 2147483647);
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)
i = &c->u->u_curblock->b_instr[off];
i->i_opcode = opcode;
i->i_oparg = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int);
i->i_hasarg = 1;
compiler_set_lineno(c, off);
return 1;
}
@ -1189,6 +1190,7 @@ compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute)
struct instr *i;
int off;
assert(HAS_ARG(opcode));
assert(b != NULL);
off = compiler_next_instr(c, c->u->u_curblock);
if (off < 0)
@ -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->i_opcode = opcode;
i->i_target = b;
i->i_hasarg = 1;
if (absolute)
i->i_jabs = 1;
else
@ -4397,18 +4398,6 @@ assemble_free(struct assembler *a)
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
blocksize(basicblock *b)
{
@ -4416,7 +4405,7 @@ blocksize(basicblock *b)
int size = 0;
for (i = 0; i < b->b_iused; i++)
size += instrsize(&b->b_instr[i]);
size += instrsize(b->b_instr[i].i_oparg);
return size;
}
@ -4536,15 +4525,12 @@ assemble_lnotab(struct assembler *a, struct instr *i)
static int
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);
char *code;
size = instrsize(i);
if (i->i_hasarg) {
arg = i->i_oparg;
ext = arg >> 16;
}
arg = i->i_oparg;
size = instrsize(arg);
if (i->i_lineno && !assemble_lnotab(a, i))
return 0;
if (a->a_offset + size >= len) {
@ -4555,19 +4541,7 @@ assemble_emit(struct assembler *a, struct instr *i)
}
code = PyBytes_AS_STRING(a->a_bytecode) + a->a_offset;
a->a_offset += size;
if (size == 6) {
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;
}
write_op_arg((unsigned char*)code, i->i_opcode, arg, size);
return 1;
}
@ -4575,7 +4549,7 @@ static void
assemble_jump_offsets(struct assembler *a, struct compiler *c)
{
basicblock *b;
int bsize, totsize, extended_arg_count = 0, last_extended_arg_count;
int bsize, totsize, extended_arg_recompile;
int i;
/* Compute the size of each block and fixup jump args.
@ -4588,27 +4562,26 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c)
b->b_offset = totsize;
totsize += bsize;
}
last_extended_arg_count = extended_arg_count;
extended_arg_count = 0;
extended_arg_recompile = 0;
for (b = c->u->u_blocks; b != NULL; b = b->b_list) {
bsize = b->b_offset;
for (i = 0; i < b->b_iused; i++) {
struct instr *instr = &b->b_instr[i];
int isize = instrsize(instr->i_oparg);
/* Relative jumps are computed relative to
the instruction pointer after fetching
the jump instruction.
*/
bsize += instrsize(instr);
if (instr->i_jabs)
bsize += isize;
if (instr->i_jabs || instr->i_jrel) {
instr->i_oparg = instr->i_target->b_offset;
else if (instr->i_jrel) {
int delta = instr->i_target->b_offset - bsize;
instr->i_oparg = delta;
if (instr->i_jrel) {
instr->i_oparg -= bsize;
}
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)
The issue is that in the first loop blocksize() is called
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.
So we loop until we stop seeing new EXTENDED_ARGs.
@ -4626,7 +4599,7 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c)
ones in jump instructions. So this should converge
fairly quickly.
*/
} while (last_extended_arg_count != extended_arg_count);
} while (extended_arg_recompile);
}
static PyObject *
@ -4772,9 +4745,9 @@ dump_instr(const struct instr *i)
char arg[128];
*arg = '\0';
if (i->i_hasarg)
if (HAS_ARG(i->i_opcode)) {
sprintf(arg, "arg: %d ", i->i_oparg);
}
fprintf(stderr, "line: %d, opcode: %d %s%s%s\n",
i->i_lineno, i->i_opcode, arg, jabs, jrel);
}

View file

@ -14,17 +14,15 @@
the appropriate bytes from M___main__.c. */
static unsigned char M___hello__[] = {
99,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,
101,2,0,100,0,0,131,1,0,1,100,1,0,83,40,3,
0,0,0,117,12,0,0,0,72,101,108,108,111,32,119,111,
114,108,100,33,78,84,40,3,0,0,0,117,4,0,0,0,
84,114,117,101,117,11,0,0,0,105,110,105,116,105,97,108,
105,122,101,100,117,5,0,0,0,112,114,105,110,116,40,0,
0,0,0,40,0,0,0,0,40,0,0,0,0,117,7,0,
0,0,102,108,97,103,46,112,121,117,8,0,0,0,60,109,
111,100,117,108,101,62,1,0,0,0,115,2,0,0,0,6,
1,
227,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,
0,64,0,0,0,115,16,0,0,0,100,0,90,0,101,1,
100,1,131,1,1,0,100,2,83,0,41,3,84,122,12,72,
101,108,108,111,32,119,111,114,108,100,33,78,41,2,218,11,
105,110,105,116,105,97,108,105,122,101,100,218,5,112,114,105,
110,116,169,0,114,3,0,0,0,114,3,0,0,0,250,22,
46,47,84,111,111,108,115,47,102,114,101,101,122,101,47,102,
108,97,103,46,112,121,218,8,60,109,111,100,117,108,101,62,
1,0,0,0,115,2,0,0,0,4,1,
};
#define SIZE (int)sizeof(M___hello__)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -8,8 +8,8 @@
#include "code.h"
#include "symtable.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 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)
@ -17,22 +17,15 @@
|| op==POP_JUMP_IF_FALSE || op==POP_JUMP_IF_TRUE \
|| 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 GETJUMPTGT(arr, i) (GETARG(arr,i) + (ABSOLUTE_JUMP(arr[i]) ? 0 : i+3))
#define SETARG(arr, i, val) do { \
assert(0 <= val && val <= 0xffff); \
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 GETJUMPTGT(arr, i) (get_arg(arr, i) + (ABSOLUTE_JUMP(arr[i]) ? 0 : i+2))
#define ISBASICBLOCK(blocks, start, end) \
(blocks[start]==blocks[end])
#define CONST_STACK_CREATE() { \
const_stack_size = 256; \
const_stack = PyMem_New(PyObject *, const_stack_size); \
load_const_stack = PyMem_New(Py_ssize_t, const_stack_size); \
if (!const_stack || !load_const_stack) { \
if (!const_stack) { \
PyErr_NoMemory(); \
goto exitError; \
} \
@ -41,27 +34,23 @@
#define CONST_STACK_DELETE() do { \
if (const_stack) \
PyMem_Free(const_stack); \
if (load_const_stack) \
PyMem_Free(load_const_stack); \
} 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 { \
PyObject *_x; \
assert(codestr[i] == LOAD_CONST); \
assert(PyList_GET_SIZE(consts) > GETARG(codestr, i)); \
_x = PyList_GET_ITEM(consts, GETARG(codestr, i)); \
assert(PyList_GET_SIZE(consts) > (Py_ssize_t)get_arg(codestr, i)); \
_x = PyList_GET_ITEM(consts, get_arg(codestr, i)); \
if (++const_stack_top >= const_stack_size) { \
const_stack_size *= 2; \
PyMem_Resize(const_stack, PyObject *, const_stack_size); \
PyMem_Resize(load_const_stack, Py_ssize_t, const_stack_size); \
if (!const_stack || !load_const_stack) { \
if (!const_stack) { \
PyErr_NoMemory(); \
goto exitError; \
} \
} \
load_const_stack[const_stack_top] = i; \
const_stack[const_stack_top] = _x; \
in_consts = 1; \
} while(0)
@ -70,22 +59,108 @@
const_stack_top = -1; \
} while(0)
#define CONST_STACK_TOP() \
const_stack[const_stack_top]
#define CONST_STACK_LASTN(i) \
&const_stack[const_stack_top - i + 1]
&const_stack[CONST_STACK_LEN() - i]
#define CONST_STACK_POP(i) do { \
assert(const_stack_top + 1 >= i); \
assert(CONST_STACK_LEN() >= i); \
const_stack_top -= i; \
} while(0)
#define CONST_STACK_OP_LASTN(i) \
((const_stack_top >= i - 1) ? load_const_stack[const_stack_top - i + 1] : -1)
/* Scans back N consecutive LOAD_CONST instructions, skipping NOPs,
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;
}
/* Replace LOAD_CONST c1. LOAD_CONST c2 ... LOAD_CONST cn BUILD_TUPLE n
/* 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
with LOAD_CONST (c1, c2, ... cn).
The consts table must still be in list form so that the
new constant (c1, c2, ... cn) can be appended.
@ -94,9 +169,10 @@
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.
*/
static int
tuple_of_constants(unsigned char *codestr, Py_ssize_t n,
PyObject *consts, PyObject **objs)
static Py_ssize_t
fold_tuple_on_constants(unsigned char *codestr, Py_ssize_t c_start,
Py_ssize_t opcode_end, unsigned char opcode,
PyObject *consts, PyObject **objs, int n)
{
PyObject *newconst, *constant;
Py_ssize_t i, len_consts;
@ -106,9 +182,9 @@ tuple_of_constants(unsigned char *codestr, Py_ssize_t n,
/* Buildup new tuple of constants */
newconst = PyTuple_New(n);
if (newconst == NULL)
return 0;
len_consts = PyList_GET_SIZE(consts);
if (newconst == NULL) {
return -1;
}
for (i=0 ; i<n ; i++) {
constant = objs[i];
Py_INCREF(constant);
@ -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
PyFrozenSet, and use that as the constant instead: */
if (codestr[0] == BUILD_SET) {
Py_XSETREF(newconst, PyFrozenSet_New(newconst));
if (newconst == NULL)
return 0;
PyFrozenSet, and use that as the constant instead: */
if (opcode == BUILD_SET) {
Py_SETREF(newconst, PyFrozenSet_New(newconst));
if (newconst == NULL) {
return -1;
}
}
/* Append folded constant onto consts */
len_consts = PyList_GET_SIZE(consts);
if (PyList_Append(consts, newconst)) {
Py_DECREF(newconst);
return 0;
return -1;
}
Py_DECREF(newconst);
/* Write NOPs over old LOAD_CONSTS and
add a new LOAD_CONST newconst on top of the BUILD_TUPLE n */
codestr[0] = LOAD_CONST;
SETARG(codestr, 0, len_consts);
return 1;
return copy_op_arg(codestr, c_start, LOAD_CONST, len_consts, opcode_end);
}
/* Replace LOAD_CONST c1. LOAD_CONST c2 BINOP
/* Replace LOAD_CONST c1, LOAD_CONST c2, BINOP
with LOAD_CONST binop(c1,c2)
The consts table must still be in list form so that the
new constant can be appended.
@ -147,20 +221,21 @@ tuple_of_constants(unsigned char *codestr, Py_ssize_t n,
is below a threshold value. That keeps pyc files from
becoming large in the presence of code like: (None,)*1000.
*/
static int
fold_binops_on_constants(unsigned char *codestr, PyObject *consts, PyObject **objs)
static Py_ssize_t
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;
Py_ssize_t len_consts, size;
int opcode;
/* Pre-conditions */
assert(PyList_CheckExact(consts));
len_consts = PyList_GET_SIZE(consts);
/* Create new constant */
v = objs[0];
w = objs[1];
opcode = codestr[0];
switch (opcode) {
case BINARY_POWER:
newconst = PyNumber_Power(v, w, Py_None);
@ -206,50 +281,48 @@ fold_binops_on_constants(unsigned char *codestr, PyObject *consts, PyObject **ob
PyErr_Format(PyExc_SystemError,
"unexpected binary operation %d on a constant",
opcode);
return 0;
return -1;
}
if (newconst == NULL) {
if(!PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
if(!PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
PyErr_Clear();
return 0;
}
return -1;
}
size = PyObject_Size(newconst);
if (size == -1) {
if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
return 0;
if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
return -1;
}
PyErr_Clear();
} else if (size > 20) {
Py_DECREF(newconst);
return 0;
return -1;
}
/* Append folded constant into consts table */
len_consts = PyList_GET_SIZE(consts);
if (PyList_Append(consts, newconst)) {
Py_DECREF(newconst);
return 0;
return -1;
}
Py_DECREF(newconst);
/* Write NOP NOP NOP NOP LOAD_CONST newconst */
codestr[-2] = LOAD_CONST;
SETARG(codestr, -2, len_consts);
return 1;
return copy_op_arg(codestr, c_start, LOAD_CONST, len_consts, opcode_end);
}
static int
fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts, PyObject *v)
static Py_ssize_t
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;
Py_ssize_t len_consts;
int opcode;
/* Pre-conditions */
assert(PyList_CheckExact(consts));
assert(codestr[0] == LOAD_CONST);
len_consts = PyList_GET_SIZE(consts);
/* Create new constant */
opcode = codestr[3];
switch (opcode) {
case UNARY_NEGATIVE:
newconst = PyNumber_Negative(v);
@ -265,35 +338,31 @@ fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts, PyObject *v
PyErr_Format(PyExc_SystemError,
"unexpected unary operation %d on a constant",
opcode);
return 0;
return -1;
}
if (newconst == NULL) {
if(!PyErr_ExceptionMatches(PyExc_KeyboardInterrupt))
if(!PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
PyErr_Clear();
return 0;
}
return -1;
}
/* Append folded constant into consts table */
len_consts = PyList_GET_SIZE(consts);
if (PyList_Append(consts, newconst)) {
Py_DECREF(newconst);
PyErr_Clear();
return 0;
return -1;
}
Py_DECREF(newconst);
/* Write NOP LOAD_CONST newconst */
codestr[0] = NOP;
codestr[1] = LOAD_CONST;
SETARG(codestr, 1, len_consts);
return 1;
return copy_op_arg(codestr, c_start, LOAD_CONST, len_consts, opcode_end);
}
static unsigned int *
markblocks(unsigned char *code, Py_ssize_t len)
{
unsigned int *blocks = PyMem_New(unsigned int, len);
int i,j, opcode, blockcnt = 0;
int i, j, opcode, blockcnt = 0;
if (blocks == NULL) {
PyErr_NoMemory();
@ -302,7 +371,7 @@ markblocks(unsigned char *code, Py_ssize_t len)
memset(blocks, 0, len*sizeof(int));
/* Mark labels in the first pass */
for (i=0 ; i<len ; i+=CODESIZE(opcode)) {
for (i=0 ; i<len ; i+=2) {
opcode = code[i];
switch (opcode) {
case FOR_ITER:
@ -324,7 +393,7 @@ markblocks(unsigned char *code, Py_ssize_t len)
}
}
/* 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 */
blocks[i] = blockcnt;
}
@ -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
to be appended.
To keep the optimizer simple, it bails out (does nothing) for code that
has a length over 32,700, and does not calculate extended arguments.
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.
To keep the optimizer simple, it bails when the lineno table has complex
encoding for gaps >= 255.
Optimizations are restricted to simple transformations occuring within a
single basic block. All transformations keep the code size the same or
smaller. For those that reduce size, the gaps are initially filled with
NOPs. Later those NOPs are removed and the jump addresses retargeted in
a single pass. Code offset is adjusted accordingly. */
a single pass. */
PyObject *
PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
PyObject *lnotab_obj)
{
Py_ssize_t i, j, codelen;
int nops, h, adj;
int tgt, tgttgt, opcode;
Py_ssize_t h, i, nexti, op_start, codelen, tgt;
unsigned int j, nops;
unsigned char opcode, nextop;
unsigned char *codestr = NULL;
unsigned char *lnotab;
int *addrmap = NULL;
int cum_orig_offset, last_offset;
unsigned int cum_orig_offset, last_offset;
Py_ssize_t tabsiz;
PyObject **const_stack = NULL;
Py_ssize_t *load_const_stack = NULL;
Py_ssize_t const_stack_top = -1;
Py_ssize_t const_stack_size = 0;
int in_consts = 0; /* whether we are in a LOAD_CONST sequence */
@ -383,11 +446,9 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
/* Note: -128 and 127 special values for line number delta are ok,
the peephole optimizer doesn't modify line numbers. */
/* Avoid situations where jump retargeting could overflow */
assert(PyBytes_Check(code));
codelen = PyBytes_GET_SIZE(code);
if (codelen > 32700)
goto exitUnchanged;
assert(codelen % 2 == 0);
/* Make a modifiable copy of the code string */
codestr = (unsigned char *)PyMem_Malloc(codelen);
@ -398,21 +459,6 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
codestr = (unsigned char *)memcpy(codestr,
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);
if (blocks == NULL)
goto exitError;
@ -420,9 +466,17 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
CONST_STACK_CREATE();
for (i=0 ; i<codelen ; i += CODESIZE(codestr[i])) {
reoptimize_current:
for (i=find_op(codestr, 0) ; i<codelen ; i=nexti) {
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) {
CONST_STACK_RESET();
@ -433,14 +487,12 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
/* Replace UNARY_NOT POP_JUMP_IF_FALSE
with POP_JUMP_IF_TRUE */
case UNARY_NOT:
if (codestr[i+1] != POP_JUMP_IF_FALSE
|| !ISBASICBLOCK(blocks,i,4))
continue;
j = GETARG(codestr, i+1);
codestr[i] = POP_JUMP_IF_TRUE;
SETARG(codestr, i, j);
codestr[i+3] = NOP;
goto reoptimize_current;
if (nextop != POP_JUMP_IF_FALSE
|| !ISBASICBLOCK(blocks, op_start, i+2))
break;
memset(codestr + op_start, NOP, i - op_start + 2);
codestr[nexti] = POP_JUMP_IF_TRUE;
break;
/* not a is b --> a is not b
not a in b --> a not in b
@ -448,78 +500,79 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
not a not in b --> a in b
*/
case COMPARE_OP:
j = GETARG(codestr, i);
if (j < 6 || j > 9 ||
codestr[i+3] != UNARY_NOT ||
!ISBASICBLOCK(blocks,i,4))
continue;
SETARG(codestr, i, (j^1));
codestr[i+3] = NOP;
j = get_arg(codestr, i);
if (j < 6 || j > 9 ||
nextop != UNARY_NOT ||
!ISBASICBLOCK(blocks, op_start, i + 2))
break;
codestr[i+1] = (j^1);
memset(codestr + i + 2, NOP, nexti - i);
break;
/* Skip over LOAD_CONST trueconst
POP_JUMP_IF_FALSE xx. This improves
"while 1" performance. */
POP_JUMP_IF_FALSE xx. This improves
"while 1" performance. */
case LOAD_CONST:
CONST_STACK_PUSH_OP(i);
j = GETARG(codestr, i);
if (codestr[i+3] != POP_JUMP_IF_FALSE ||
!ISBASICBLOCK(blocks,i,6) ||
!PyObject_IsTrue(PyList_GET_ITEM(consts, j)))
continue;
memset(codestr+i, NOP, 6);
CONST_STACK_RESET();
if (nextop != POP_JUMP_IF_FALSE ||
!ISBASICBLOCK(blocks, op_start, i + 2) ||
!PyObject_IsTrue(PyList_GET_ITEM(consts, get_arg(codestr, i))))
break;
memset(codestr + op_start, NOP, nexti - op_start + 2);
CONST_STACK_POP(1);
break;
/* Try to fold tuples of constants (includes a case for lists and sets
which are only used for "in" and "not in" tests).
/* Try to fold tuples of constants (includes a case for lists
and sets which are only used for "in" and "not in" tests).
Skip over BUILD_SEQN 1 UNPACK_SEQN 1.
Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2.
Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */
case BUILD_TUPLE:
case BUILD_LIST:
case BUILD_SET:
j = GETARG(codestr, i);
if (j == 0)
break;
h = CONST_STACK_OP_LASTN(j);
assert((h >= 0 || CONST_STACK_LEN() < j));
if (h >= 0 && j > 0 && j <= CONST_STACK_LEN() &&
((opcode == BUILD_TUPLE &&
ISBASICBLOCK(blocks, h, i-h+3)) ||
((opcode == BUILD_LIST || opcode == BUILD_SET) &&
codestr[i+3]==COMPARE_OP &&
ISBASICBLOCK(blocks, h, i-h+6) &&
(GETARG(codestr,i+3)==6 ||
GETARG(codestr,i+3)==7))) &&
tuple_of_constants(&codestr[i], j, consts, CONST_STACK_LASTN(j))) {
assert(codestr[i] == LOAD_CONST);
memset(&codestr[h], NOP, i - h);
CONST_STACK_POP(j);
CONST_STACK_PUSH_OP(i);
break;
j = get_arg(codestr, i);
if (j > 0 && CONST_STACK_LEN() >= j) {
h = lastn_const_start(codestr, op_start, j);
if ((opcode == BUILD_TUPLE &&
ISBASICBLOCK(blocks, h, op_start)) ||
((opcode == BUILD_LIST || opcode == BUILD_SET) &&
((nextop==COMPARE_OP &&
(codestr[nexti+1]==6 ||
codestr[nexti+1]==7)) ||
nextop == GET_ITER) && ISBASICBLOCK(blocks, h, i + 2))) {
h = fold_tuple_on_constants(codestr, h, i+2, opcode,
consts, CONST_STACK_LASTN(j), j);
if (h >= 0) {
CONST_STACK_POP(j);
CONST_STACK_PUSH_OP(h);
}
break;
}
}
if (codestr[i+3] != UNPACK_SEQUENCE ||
!ISBASICBLOCK(blocks,i,6) ||
j != GETARG(codestr, i+3) ||
if (nextop != UNPACK_SEQUENCE ||
!ISBASICBLOCK(blocks, op_start, i + 2) ||
j != get_arg(codestr, nexti) ||
opcode == BUILD_SET)
continue;
if (j == 1) {
memset(codestr+i, NOP, 6);
break;
if (j < 2) {
memset(codestr+op_start, NOP, nexti - op_start + 2);
} else if (j == 2) {
codestr[i] = ROT_TWO;
memset(codestr+i+1, NOP, 5);
codestr[op_start] = ROT_TWO;
codestr[op_start + 1] = 0;
memset(codestr + op_start + 2, NOP, nexti - op_start);
CONST_STACK_RESET();
} else if (j == 3) {
codestr[i] = ROT_THREE;
codestr[i+1] = ROT_TWO;
memset(codestr+i+2, NOP, 4);
codestr[op_start] = ROT_THREE;
codestr[op_start + 1] = 0;
codestr[op_start + 2] = ROT_TWO;
codestr[op_start + 3] = 0;
memset(codestr + op_start + 4, NOP, nexti - op_start - 2);
CONST_STACK_RESET();
}
break;
/* 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_MULTIPLY:
case BINARY_TRUE_DIVIDE:
@ -533,35 +586,34 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
case BINARY_AND:
case BINARY_XOR:
case BINARY_OR:
/* NOTE: LOAD_CONST is saved at `i-2` since it has an arg
while BINOP hasn't */
h = CONST_STACK_OP_LASTN(2);
assert((h >= 0 || CONST_STACK_LEN() < 2));
if (h >= 0 &&
ISBASICBLOCK(blocks, h, i-h+1) &&
fold_binops_on_constants(&codestr[i], consts, CONST_STACK_LASTN(2))) {
i -= 2;
memset(&codestr[h], NOP, i - h);
assert(codestr[i] == LOAD_CONST);
CONST_STACK_POP(2);
CONST_STACK_PUSH_OP(i);
if (CONST_STACK_LEN() < 2)
break;
h = lastn_const_start(codestr, op_start, 2);
if (ISBASICBLOCK(blocks, h, op_start)) {
h = fold_binops_on_constants(codestr, h, i+2, opcode,
consts, CONST_STACK_LASTN(2));
if (h >= 0) {
CONST_STACK_POP(2);
CONST_STACK_PUSH_OP(h);
}
}
break;
/* 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_INVERT:
case UNARY_POSITIVE:
h = CONST_STACK_OP_LASTN(1);
assert((h >= 0 || CONST_STACK_LEN() < 1));
if (h >= 0 &&
ISBASICBLOCK(blocks, h, i-h+1) &&
fold_unaryops_on_constants(&codestr[i-3], consts, CONST_STACK_TOP())) {
i -= 2;
assert(codestr[i] == LOAD_CONST);
CONST_STACK_POP(1);
CONST_STACK_PUSH_OP(i);
if (CONST_STACK_LEN() < 1)
break;
h = lastn_const_start(codestr, op_start, 1);
if (ISBASICBLOCK(blocks, h, op_start)) {
h = fold_unaryops_on_constants(codestr, h, i+2, opcode,
consts, *CONST_STACK_LASTN(1));
if (h >= 0) {
CONST_STACK_POP(1);
CONST_STACK_PUSH_OP(h);
}
}
break;
@ -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 z
x:JUMP_IF_FALSE_OR_POP y y:JUMP_IF_TRUE_OR_POP z
--> x:POP_JUMP_IF_FALSE y+3
where y+3 is the instruction following the second test.
--> x:POP_JUMP_IF_FALSE y+2
where y+2 is the instruction following the second test.
*/
case JUMP_IF_FALSE_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];
if (CONDITIONAL_JUMP(j)) {
/* NOTE: all possible jumps here are
absolute! */
if (JUMPS_ON_TRUE(j) == JUMPS_ON_TRUE(opcode)) {
/* The second jump will be
taken iff the first is. */
tgttgt = GETJUMPTGT(codestr, tgt);
/* The current opcode inherits
its target's stack behaviour */
codestr[i] = j;
SETARG(codestr, i, tgttgt);
goto reoptimize_current;
taken iff the first is.
The current opcode inherits
its target's stack effect */
h = set_arg(codestr, i, get_arg(codestr, tgt));
} else {
/* The second jump is not taken
if the first is (so jump past
@ -603,12 +654,15 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
they're not taken (so change
the first jump to pop its
argument when it's taken). */
if (JUMPS_ON_TRUE(opcode))
codestr[i] = POP_JUMP_IF_TRUE;
else
codestr[i] = POP_JUMP_IF_FALSE;
SETARG(codestr, i, (tgt + 3));
goto reoptimize_current;
h = set_arg(codestr, i, tgt + 2);
j = opcode == JUMP_IF_TRUE_OR_POP ?
POP_JUMP_IF_TRUE : POP_JUMP_IF_FALSE;
}
if (h >= 0) {
nexti = h;
codestr[nexti] = j;
break;
}
}
/* Intentional fallthrough */
@ -625,76 +679,73 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
case SETUP_FINALLY:
case SETUP_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 */
if (UNCONDITIONAL_JUMP(opcode) &&
codestr[tgt] == RETURN_VALUE) {
codestr[i] = RETURN_VALUE;
memset(codestr+i+1, NOP, 2);
continue;
codestr[op_start] = RETURN_VALUE;
codestr[op_start + 1] = 0;
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;
/* Replace RETURN LOAD_CONST None RETURN with just RETURN */
/* Remove unreachable JUMPs after RETURN */
/* Remove unreachable ops after RETURN */
case RETURN_VALUE:
if (i+4 >= codelen)
continue;
if (codestr[i+4] == RETURN_VALUE &&
ISBASICBLOCK(blocks,i,5))
memset(codestr+i+1, NOP, 4);
else if (UNCONDITIONAL_JUMP(codestr[i+1]) &&
ISBASICBLOCK(blocks,i,4))
memset(codestr+i+1, NOP, 3);
h = i + 2;
while (h + 2 < codelen && ISBASICBLOCK(blocks, i, h + 2)) {
h += 2;
}
if (h > i + 2) {
memset(codestr + i + 2, NOP, h - i);
nexti = find_op(codestr, h);
}
break;
}
}
/* 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);
/* original code offset => new code offset */
addrmap[i] = (int)(i - nops);
blocks[i] = i - nops;
if (codestr[i] == NOP)
nops++;
nops += 2;
}
cum_orig_offset = 0;
last_offset = 0;
for (i=0 ; i < tabsiz ; i+=2) {
int offset_delta, new_offset;
unsigned int offset_delta, new_offset;
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;
assert(0 <= offset_delta && offset_delta <= 255);
assert(offset_delta <= 255);
lnotab[i] = (unsigned char)offset_delta;
last_offset = new_offset;
}
/* 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];
switch (opcode) {
case NOP:
i++;
continue;
case NOP:continue;
case JUMP_ABSOLUTE:
case CONTINUE_LOOP:
@ -702,8 +753,7 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
case POP_JUMP_IF_TRUE:
case JUMP_IF_FALSE_OR_POP:
case JUMP_IF_TRUE_OR_POP:
j = addrmap[GETARG(codestr, i)];
SETARG(codestr, i, j);
j = blocks[j];
break;
case FOR_ITER:
@ -713,31 +763,31 @@ PyCode_Optimize(PyObject *code, PyObject* consts, PyObject *names,
case SETUP_FINALLY:
case SETUP_WITH:
case SETUP_ASYNC_WITH:
j = addrmap[GETARG(codestr, i) + i + 3] - addrmap[i] - 3;
SETARG(codestr, i, j);
j = blocks[j + i + 2] - blocks[i] - 2;
break;
}
adj = CODESIZE(opcode);
while (adj--)
codestr[h++] = codestr[i++];
nexti = i - op_start + 2;
if (instrsize(j) > nexti)
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();
PyMem_Free(addrmap);
PyMem_Free(codestr);
PyMem_Free(blocks);
code = PyBytes_FromStringAndSize((char *)codestr, h);
PyMem_Free(codestr);
return code;
exitError:
code = NULL;
exitUnchanged:
Py_XINCREF(code);
CONST_STACK_DELETE();
PyMem_Free(blocks);
PyMem_Free(addrmap);
PyMem_Free(codestr);
Py_XINCREF(code);
return code;
}

38
Python/wordcode_helpers.h Normal file
View file

@ -0,0 +1,38 @@
/* 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);
}
}