gh-148871: extend and improve LOAD_COMMON_CONSTANT (GH-148971)

This commit is contained in:
Neko Asakura
2026-05-03 02:59:51 +08:00
committed by GitHub
parent a65611e7f5
commit 7c9ad27dd1
15 changed files with 362 additions and 184 deletions
+6 -1
View File
@@ -75,7 +75,12 @@ extern "C" {
#define CONSTANT_BUILTIN_ANY 4
#define CONSTANT_BUILTIN_LIST 5
#define CONSTANT_BUILTIN_SET 6
#define NUM_COMMON_CONSTANTS 7
#define CONSTANT_NONE 7
#define CONSTANT_EMPTY_STR 8
#define CONSTANT_TRUE 9
#define CONSTANT_FALSE 10
#define CONSTANT_MINUS_ONE 11
#define NUM_COMMON_CONSTANTS 12
/* Values used in the oparg for RESUME */
#define RESUME_AT_FUNC_START 0
+10 -3
View File
@@ -643,6 +643,7 @@ class ArgResolver:
argrepr = _intrinsic_2_descs[arg]
elif deop == LOAD_COMMON_CONSTANT:
obj = _common_constants[arg]
argval = obj
if isinstance(obj, type):
argrepr = obj.__name__
else:
@@ -692,10 +693,15 @@ def _get_const_value(op, arg, co_consts):
Otherwise (if it is a LOAD_CONST and co_consts is not
provided) returns the dis.UNKNOWN sentinel.
"""
assert op in hasconst or op == LOAD_SMALL_INT
assert op in hasconst or op == LOAD_SMALL_INT or op == LOAD_COMMON_CONSTANT
if op == LOAD_SMALL_INT:
return arg
if op == LOAD_COMMON_CONSTANT:
# Opargs 0-6 are callables; 7-11 are literal values.
if 7 <= arg <= 11:
return _common_constants[arg]
return UNKNOWN
argval = UNKNOWN
if co_consts is not None:
argval = co_consts[arg]
@@ -1015,8 +1021,9 @@ def _find_imports(co):
if op == IMPORT_NAME and i >= 2:
from_op = opargs[i-1]
level_op = opargs[i-2]
if (from_op[0] in hasconst and
(level_op[0] in hasconst or level_op[0] == LOAD_SMALL_INT)):
if ((from_op[0] in hasconst or from_op[0] == LOAD_COMMON_CONSTANT) and
(level_op[0] in hasconst or level_op[0] == LOAD_SMALL_INT or
level_op[0] == LOAD_COMMON_CONSTANT)):
level = _get_const_value(level_op[0], level_op[1], consts)
fromlist = _get_const_value(from_op[0], from_op[1], consts)
# IMPORT_NAME encodes lazy/eager flags in bits 0-1,
+4 -1
View File
@@ -41,7 +41,10 @@ _intrinsic_2_descs = _opcode.get_intrinsic2_descs()
_special_method_names = _opcode.get_special_method_names()
_common_constants = [builtins.AssertionError, builtins.NotImplementedError,
builtins.tuple, builtins.all, builtins.any, builtins.list,
builtins.set]
builtins.set,
# Append-only — must match CONSTANT_* in
# Include/internal/pycore_opcode_utils.h.
None, "", True, False, -1]
_nb_ops = _opcode.get_nb_ops()
hascompare = [opmap["COMPARE_OP"]]
+3 -2
View File
@@ -2685,11 +2685,12 @@ class ConstantTests(unittest.TestCase):
def get_load_const(self, tree):
# Compile to bytecode, disassemble and get parameter of LOAD_CONST
# instructions
# and LOAD_COMMON_CONSTANT instructions
co = compile(tree, '<string>', 'exec')
consts = []
for instr in dis.get_instructions(co):
if instr.opcode in dis.hasconst:
if instr.opcode in dis.hasconst or \
instr.opname == 'LOAD_COMMON_CONSTANT':
consts.append(instr.argval)
return consts
+21
View File
@@ -3446,6 +3446,27 @@ class TestUopsOptimization(unittest.TestCase):
self.assertIn("_BUILD_LIST", uops)
self.assertNotIn("_LOAD_COMMON_CONSTANT", uops)
def test_load_common_constant_new_literals(self):
def testfunc(n):
x = None
s = ""
t = True
f = False
m = -1
for _ in range(n):
x = None
s = ""
t = True
f = False
m = -1
return x, s, t, f, m
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
self.assertEqual(res, (None, "", True, False, -1))
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertNotIn("_LOAD_COMMON_CONSTANT", uops)
self.assertIn("_LOAD_CONST_INLINE_BORROW", uops)
def test_load_small_int(self):
def testfunc(n):
x = 0
+3 -3
View File
@@ -87,7 +87,7 @@ cellvars: ()
freevars: ()
nlocals: 0
flags: 67108867
consts: ("'doc string'", 'None')
consts: ("'doc string'",)
>>> def keywordonly_args(a,b,*,k1):
... return a,b,k1
@@ -161,7 +161,7 @@ cellvars: ()
freevars: ()
nlocals: 3
flags: 67108995
consts: ("'This is a docstring from async function'", 'None')
consts: ("'This is a docstring from async function'",)
>>> def no_docstring(x, y, z):
... return x + "hello" + y + z + "world"
@@ -532,7 +532,7 @@ class CodeTest(unittest.TestCase):
],
[
("PUSH_EXC_INFO", None),
("LOAD_CONST", None), # artificial 'None'
("LOAD_COMMON_CONSTANT", None), # artificial 'None'
("STORE_NAME", "e"), # XX: we know the location for this
("DELETE_NAME", "e"),
("RERAISE", 1),
+3 -2
View File
@@ -2485,12 +2485,13 @@ class TestSourcePositions(unittest.TestCase):
start_line, end_line, _, _ = instr.positions
self.assertEqual(start_line, end_line)
# Expect four `LOAD_CONST None` instructions:
# Expect four `None`-loading instructions:
# three for the no-exception __exit__ call, and one for the return.
# They should all have the locations of the context manager ('xyz').
load_none = [instr for instr in dis.get_instructions(f) if
instr.opname == 'LOAD_CONST' and instr.argval is None]
instr.opname in ('LOAD_CONST', 'LOAD_COMMON_CONSTANT')
and instr.argval is None]
return_value = [instr for instr in dis.get_instructions(f) if
instr.opname == 'RETURN_VALUE']
+53 -56
View File
@@ -56,7 +56,7 @@ dis_c_instance_method = """\
COMPARE_OP 72 (==)
LOAD_FAST_BORROW 0 (self)
STORE_ATTR 0 (x)
LOAD_CONST 1 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
""" % (_C.__init__.__code__.co_firstlineno, _C.__init__.__code__.co_firstlineno + 1,)
@@ -67,7 +67,7 @@ dis_c_instance_method_bytes = """\
COMPARE_OP 72 (==)
LOAD_FAST_BORROW 0
STORE_ATTR 0
LOAD_CONST 1
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
"""
@@ -79,7 +79,7 @@ dis_c_class_method = """\
COMPARE_OP 72 (==)
LOAD_FAST_BORROW 0 (cls)
STORE_ATTR 0 (x)
LOAD_CONST 1 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
""" % (_C.cm.__code__.co_firstlineno, _C.cm.__code__.co_firstlineno + 2,)
@@ -90,7 +90,7 @@ dis_c_static_method = """\
LOAD_SMALL_INT 1
COMPARE_OP 72 (==)
STORE_FAST 0 (x)
LOAD_CONST 1 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
""" % (_C.sm.__code__.co_firstlineno, _C.sm.__code__.co_firstlineno + 2,)
@@ -182,7 +182,7 @@ dis_bug708901 = """\
%3d L2: END_FOR
POP_ITER
LOAD_CONST 1 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
""" % (bug708901.__code__.co_firstlineno,
bug708901.__code__.co_firstlineno + 1,
@@ -229,7 +229,7 @@ bug42562.__code__ = bug42562.__code__.replace(co_linetable=b'\xf8')
dis_bug42562 = """\
RESUME 0
LOAD_CONST 0 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
"""
@@ -282,7 +282,7 @@ dis_kw_names = """\
LOAD_CONST 1 (('c',))
CALL_KW 3
POP_TOP
LOAD_CONST 2 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
""" % (wrap_func_w_kwargs.__code__.co_firstlineno,
wrap_func_w_kwargs.__code__.co_firstlineno + 1)
@@ -295,7 +295,7 @@ dis_intrinsic_1_2 = """\
IMPORT_NAME 2 (math + eager)
CALL_INTRINSIC_1 2 (INTRINSIC_IMPORT_STAR)
POP_TOP
LOAD_CONST 2 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
"""
@@ -322,7 +322,7 @@ _BIG_LINENO_FORMAT = """\
%3d LOAD_GLOBAL 0 (spam)
POP_TOP
LOAD_CONST 0 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
"""
@@ -331,19 +331,19 @@ _BIG_LINENO_FORMAT2 = """\
%4d LOAD_GLOBAL 0 (spam)
POP_TOP
LOAD_CONST 0 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
"""
dis_module_expected_results = """\
Disassembly of f:
4 RESUME 0
LOAD_CONST 0 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
Disassembly of g:
5 RESUME 0
LOAD_CONST 0 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
"""
@@ -368,7 +368,7 @@ dis_simple_stmt_str = """\
LOAD_SMALL_INT 1
BINARY_OP 0 (+)
STORE_NAME 0 (x)
LOAD_CONST 1 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
"""
@@ -409,7 +409,7 @@ dis_annot_stmt_str = """\
LOAD_SMALL_INT 0
CALL 1
STORE_SUBSCR
LOAD_CONST 2 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
"""
@@ -427,7 +427,7 @@ dis_fn_with_annotate_str = """\
MAKE_FUNCTION
SET_FUNCTION_ATTRIBUTE 16 (annotate)
STORE_NAME 0 (foo)
LOAD_CONST 2 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
"""
@@ -477,14 +477,14 @@ dis_traceback = """\
LOAD_ATTR 2 (__traceback__)
STORE_FAST 1 (tb)
L7: POP_EXCEPT
LOAD_CONST 1 (None)
LOAD_COMMON_CONSTANT 7 (None)
STORE_FAST 0 (e)
DELETE_FAST 0 (e)
%4d LOAD_FAST 1 (tb)
RETURN_VALUE
-- L8: LOAD_CONST 1 (None)
-- L8: LOAD_COMMON_CONSTANT 7 (None)
STORE_FAST 0 (e)
DELETE_FAST 0 (e)
RERAISE 1
@@ -554,15 +554,15 @@ dis_with = """\
%4d LOAD_SMALL_INT 1
STORE_FAST 1 (x)
%4d L2: LOAD_CONST 1 (None)
LOAD_CONST 1 (None)
LOAD_CONST 1 (None)
%4d L2: LOAD_COMMON_CONSTANT 7 (None)
LOAD_COMMON_CONSTANT 7 (None)
LOAD_COMMON_CONSTANT 7 (None)
CALL 3
POP_TOP
%4d LOAD_SMALL_INT 2
STORE_FAST 2 (y)
LOAD_CONST 1 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
%4d L3: PUSH_EXC_INFO
@@ -579,7 +579,7 @@ dis_with = """\
%4d LOAD_SMALL_INT 2
STORE_FAST 2 (y)
LOAD_CONST 1 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
-- L8: COPY 3
@@ -617,7 +617,7 @@ dis_asyncwith = """\
CALL 0
GET_AWAITABLE 1
PUSH_NULL
LOAD_CONST 0 (None)
LOAD_COMMON_CONSTANT 7 (None)
L2: SEND 4 (to L5)
L3: YIELD_VALUE 1
L4: RESUME 3
@@ -628,13 +628,13 @@ dis_asyncwith = """\
%4d LOAD_SMALL_INT 1
STORE_FAST 1 (x)
%4d L7: LOAD_CONST 0 (None)
LOAD_CONST 0 (None)
LOAD_CONST 0 (None)
%4d L7: LOAD_COMMON_CONSTANT 7 (None)
LOAD_COMMON_CONSTANT 7 (None)
LOAD_COMMON_CONSTANT 7 (None)
CALL 3
GET_AWAITABLE 2
PUSH_NULL
LOAD_CONST 0 (None)
LOAD_COMMON_CONSTANT 7 (None)
L8: SEND 4 (to L11)
L9: YIELD_VALUE 1
L10: RESUME 3
@@ -644,7 +644,7 @@ dis_asyncwith = """\
%4d LOAD_SMALL_INT 2
STORE_FAST 2 (y)
LOAD_CONST 0 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
%4d L12: CLEANUP_THROW
@@ -655,7 +655,7 @@ dis_asyncwith = """\
WITH_EXCEPT_START
GET_AWAITABLE 2
PUSH_NULL
LOAD_CONST 0 (None)
LOAD_COMMON_CONSTANT 7 (None)
L17: SEND 5 (to L21)
L18: YIELD_VALUE 1
L19: RESUME 3
@@ -674,7 +674,7 @@ dis_asyncwith = """\
%4d LOAD_SMALL_INT 2
STORE_FAST 2 (y)
LOAD_CONST 0 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
-- L26: COPY 3
@@ -895,7 +895,7 @@ Disassembly of <code object <genexpr> at 0x..., file "%s", line %d>:
JUMP_BACKWARD 17 (to L2)
L3: END_FOR
POP_ITER
LOAD_CONST 0 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
-- L4: CALL_INTRINSIC_1 3 (INTRINSIC_STOPITERATION_ERROR)
@@ -933,7 +933,7 @@ dis_loop_test_quickened_code = """\
%3d RESUME_CHECK{: <6} 0
%3d BUILD_LIST 0
LOAD_CONST 2 ((1, 2, 3))
LOAD_CONST 1 ((1, 2, 3))
LIST_EXTEND 1
LOAD_SMALL_INT 3
BINARY_OP 5 (*)
@@ -949,7 +949,7 @@ dis_loop_test_quickened_code = """\
%3d L2: END_FOR
POP_ITER
LOAD_CONST 1 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
""" % (loop_test.__code__.co_firstlineno,
loop_test.__code__.co_firstlineno + 1,
@@ -967,7 +967,7 @@ dis_extended_arg_quick_code = """\
UNPACK_EX 256
POP_TOP
STORE_FAST 0 (_)
LOAD_CONST 1 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
"""% (extended_arg_quick.__code__.co_firstlineno,
extended_arg_quick.__code__.co_firstlineno + 1,)
@@ -1084,7 +1084,7 @@ class DisTests(DisTestBase):
'',
'2:3-3:15 NOP',
'',
'3:11-3:15 LOAD_CONST 0 (None)',
'3:11-3:15 LOAD_COMMON_CONSTANT 7 (None)',
'3:11-3:15 RETURN_VALUE',
'',
' -- L1: PUSH_EXC_INFO',
@@ -1115,7 +1115,7 @@ class DisTests(DisTestBase):
'',
'2:5-2:6 LOAD_SMALL_INT 1',
'2:?-2:? STORE_FAST 0 (x)',
'2:?-2:? LOAD_CONST 1 (None)',
'2:?-2:? LOAD_COMMON_CONSTANT 7 (None)',
'2:?-2:? RETURN_VALUE',
'',
])
@@ -1128,7 +1128,7 @@ class DisTests(DisTestBase):
f.__code__ = f.__code__.replace(co_linetable=b'')
expect = '\n'.join([
' RESUME 0',
' LOAD_CONST 0 (None)',
' LOAD_COMMON_CONSTANT 7 (None)',
' RETURN_VALUE',
'',
])
@@ -1533,7 +1533,6 @@ Stack size: \\d+
Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR
Constants:
0: <code object f at (.*), file "(.*)", line (.*)>
1: None
Variable names:
0: a
1: b
@@ -1605,7 +1604,6 @@ Stack size: \\d+
Flags: 0x0
Constants:
0: 1
1: None
Names:
0: x"""
@@ -1640,7 +1638,6 @@ Stack size: \\d+
Flags: OPTIMIZED, NEWLOCALS, COROUTINE
Constants:
0: 1
1: None
Names:
0: b
1: c
@@ -1790,7 +1787,7 @@ expected_opinfo_outer = [
make_inst(opname='MAKE_CELL', arg=0, argval='a', argrepr='a', offset=0, start_offset=0, starts_line=True, line_number=None),
make_inst(opname='MAKE_CELL', arg=1, argval='b', argrepr='b', offset=2, start_offset=2, starts_line=False, line_number=None),
make_inst(opname='RESUME', arg=0, argval=0, argrepr='', offset=4, start_offset=4, starts_line=True, line_number=1, cache_info=[('counter', 1, b'\x00\x00')]),
make_inst(opname='LOAD_CONST', arg=4, argval=(3, 4), argrepr='(3, 4)', offset=8, start_offset=8, starts_line=True, line_number=2),
make_inst(opname='LOAD_CONST', arg=3, argval=(3, 4), argrepr='(3, 4)', offset=8, start_offset=8, starts_line=True, line_number=2),
make_inst(opname='LOAD_FAST_BORROW', arg=0, argval='a', argrepr='a', offset=10, start_offset=10, starts_line=False, line_number=2),
make_inst(opname='LOAD_FAST_BORROW', arg=1, argval='b', argrepr='b', offset=12, start_offset=12, starts_line=False, line_number=2),
make_inst(opname='BUILD_TUPLE', arg=2, argval=2, argrepr='', offset=14, start_offset=14, starts_line=False, line_number=2),
@@ -1802,11 +1799,11 @@ expected_opinfo_outer = [
make_inst(opname='LOAD_GLOBAL', arg=1, argval='print', argrepr='print + NULL', offset=26, start_offset=26, starts_line=True, line_number=7, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]),
make_inst(opname='LOAD_DEREF', arg=0, argval='a', argrepr='a', offset=36, start_offset=36, starts_line=False, line_number=7),
make_inst(opname='LOAD_DEREF', arg=1, argval='b', argrepr='b', offset=38, start_offset=38, starts_line=False, line_number=7),
make_inst(opname='LOAD_CONST', arg=2, argval='', argrepr="''", offset=40, start_offset=40, starts_line=False, line_number=7),
make_inst(opname='LOAD_COMMON_CONSTANT', arg=8, argval='', argrepr="''", offset=40, start_offset=40, starts_line=False, line_number=7),
make_inst(opname='LOAD_SMALL_INT', arg=1, argval=1, argrepr='', offset=42, start_offset=42, starts_line=False, line_number=7),
make_inst(opname='BUILD_LIST', arg=0, argval=0, argrepr='', offset=44, start_offset=44, starts_line=False, line_number=7),
make_inst(opname='BUILD_MAP', arg=0, argval=0, argrepr='', offset=46, start_offset=46, starts_line=False, line_number=7),
make_inst(opname='LOAD_CONST', arg=3, argval='Hello world!', argrepr="'Hello world!'", offset=48, start_offset=48, starts_line=False, line_number=7),
make_inst(opname='LOAD_CONST', arg=2, argval='Hello world!', argrepr="'Hello world!'", offset=48, start_offset=48, starts_line=False, line_number=7),
make_inst(opname='CALL', arg=7, argval=7, argrepr='', offset=50, start_offset=50, starts_line=False, line_number=7, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=58, start_offset=58, starts_line=False, line_number=7),
make_inst(opname='LOAD_FAST_BORROW', arg=2, argval='f', argrepr='f', offset=60, start_offset=60, starts_line=True, line_number=8),
@@ -1851,7 +1848,7 @@ expected_opinfo_inner = [
make_inst(opname='LOAD_FAST_BORROW_LOAD_FAST_BORROW', arg=1, argval=('e', 'f'), argrepr='e, f', offset=24, start_offset=24, starts_line=False, line_number=4),
make_inst(opname='CALL', arg=6, argval=6, argrepr='', offset=26, start_offset=26, starts_line=False, line_number=4, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=34, start_offset=34, starts_line=False, line_number=4),
make_inst(opname='LOAD_CONST', arg=0, argval=None, argrepr='None', offset=36, start_offset=36, starts_line=False, line_number=4),
make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', offset=36, start_offset=36, starts_line=False, line_number=4),
make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', offset=38, start_offset=38, starts_line=False, line_number=4),
]
@@ -1934,16 +1931,16 @@ expected_opinfo_jumpy = [
make_inst(opname='LOAD_CONST', arg=3, argval='Never reach this', argrepr="'Never reach this'", offset=292, start_offset=292, starts_line=False, line_number=26),
make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=294, start_offset=294, starts_line=False, line_number=26, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=302, start_offset=302, starts_line=False, line_number=26),
make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', offset=304, start_offset=304, starts_line=True, line_number=25),
make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', offset=306, start_offset=306, starts_line=False, line_number=25),
make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', offset=308, start_offset=308, starts_line=False, line_number=25),
make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', offset=304, start_offset=304, starts_line=True, line_number=25),
make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', offset=306, start_offset=306, starts_line=False, line_number=25),
make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', offset=308, start_offset=308, starts_line=False, line_number=25),
make_inst(opname='CALL', arg=3, argval=3, argrepr='', offset=310, start_offset=310, starts_line=False, line_number=25, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=318, start_offset=318, starts_line=False, line_number=25),
make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=320, start_offset=320, starts_line=True, line_number=28, label=10, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]),
make_inst(opname='LOAD_CONST', arg=6, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=330, start_offset=330, starts_line=False, line_number=28),
make_inst(opname='LOAD_CONST', arg=5, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=330, start_offset=330, starts_line=False, line_number=28),
make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=332, start_offset=332, starts_line=False, line_number=28, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=340, start_offset=340, starts_line=False, line_number=28),
make_inst(opname='LOAD_CONST', arg=4, argval=None, argrepr='None', offset=342, start_offset=342, starts_line=False, line_number=28),
make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', offset=342, start_offset=342, starts_line=False, line_number=28),
make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', offset=344, start_offset=344, starts_line=False, line_number=28),
make_inst(opname='PUSH_EXC_INFO', arg=None, argval=None, argrepr='', offset=346, start_offset=346, starts_line=True, line_number=25),
make_inst(opname='WITH_EXCEPT_START', arg=None, argval=None, argrepr='', offset=348, start_offset=348, starts_line=False, line_number=25),
@@ -1967,7 +1964,7 @@ expected_opinfo_jumpy = [
make_inst(opname='NOT_TAKEN', arg=None, argval=None, argrepr='', offset=402, start_offset=402, starts_line=False, line_number=22),
make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=404, start_offset=404, starts_line=False, line_number=22),
make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=406, start_offset=406, starts_line=True, line_number=23, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]),
make_inst(opname='LOAD_CONST', arg=5, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=416, start_offset=416, starts_line=False, line_number=23),
make_inst(opname='LOAD_CONST', arg=4, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=416, start_offset=416, starts_line=False, line_number=23),
make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=418, start_offset=418, starts_line=False, line_number=23, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=426, start_offset=426, starts_line=False, line_number=23),
make_inst(opname='POP_EXCEPT', arg=None, argval=None, argrepr='', offset=428, start_offset=428, starts_line=False, line_number=23),
@@ -1978,7 +1975,7 @@ expected_opinfo_jumpy = [
make_inst(opname='RERAISE', arg=1, argval=1, argrepr='', offset=438, start_offset=438, starts_line=False, line_number=None),
make_inst(opname='PUSH_EXC_INFO', arg=None, argval=None, argrepr='', offset=440, start_offset=440, starts_line=False, line_number=None),
make_inst(opname='LOAD_GLOBAL', arg=3, argval='print', argrepr='print + NULL', offset=442, start_offset=442, starts_line=True, line_number=28, cache_info=[('counter', 1, b'\x00\x00'), ('index', 1, b'\x00\x00'), ('module_keys_version', 1, b'\x00\x00'), ('builtin_keys_version', 1, b'\x00\x00')]),
make_inst(opname='LOAD_CONST', arg=6, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=452, start_offset=452, starts_line=False, line_number=28),
make_inst(opname='LOAD_CONST', arg=5, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=452, start_offset=452, starts_line=False, line_number=28),
make_inst(opname='CALL', arg=1, argval=1, argrepr='', offset=454, start_offset=454, starts_line=False, line_number=28, cache_info=[('counter', 1, b'\x00\x00'), ('func_version', 2, b'\x00\x00\x00\x00')]),
make_inst(opname='POP_TOP', arg=None, argval=None, argrepr='', offset=462, start_offset=462, starts_line=False, line_number=28),
make_inst(opname='RERAISE', arg=0, argval=0, argrepr='', offset=464, start_offset=464, starts_line=False, line_number=28),
@@ -1991,7 +1988,7 @@ expected_opinfo_jumpy = [
def simple(): pass
expected_opinfo_simple = [
make_inst(opname='RESUME', arg=0, argval=0, argrepr='', offset=0, start_offset=0, starts_line=True, line_number=simple.__code__.co_firstlineno),
make_inst(opname='LOAD_CONST', arg=0, argval=None, argrepr='None', offset=4, start_offset=4, starts_line=False, line_number=simple.__code__.co_firstlineno),
make_inst(opname='LOAD_COMMON_CONSTANT', arg=7, argval=None, argrepr='None', offset=4, start_offset=4, starts_line=False, line_number=simple.__code__.co_firstlineno),
make_inst(opname='RETURN_VALUE', arg=None, argval=None, argrepr='', offset=6, start_offset=6, starts_line=False, line_number=simple.__code__.co_firstlineno),
]
@@ -2600,7 +2597,7 @@ class TestDisCLI(unittest.TestCase):
CACHE 0 (func_version: 0)
CACHE 0
POP_TOP
LOAD_CONST 0 (None)
LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
'''
for flag in ['-C', '--show-caches']:
@@ -2612,7 +2609,7 @@ class TestDisCLI(unittest.TestCase):
expect = '''
0 0 RESUME 0
1 4 LOAD_CONST 0 (None)
1 4 LOAD_COMMON_CONSTANT 7 (None)
6 RETURN_VALUE
'''
for flag in ['-O', '--show-offsets']:
@@ -2624,7 +2621,7 @@ class TestDisCLI(unittest.TestCase):
expect = '''
0:0-1:0 RESUME 0
1:0-1:4 LOAD_CONST 0 (None)
1:0-1:4 LOAD_COMMON_CONSTANT 7 (None)
1:0-1:4 RETURN_VALUE
'''
for flag in ['-P', '--show-positions']:
@@ -2636,7 +2633,7 @@ class TestDisCLI(unittest.TestCase):
expect = '''
0 RESUME 0
1 LOAD_CONST 0 (None)
1 LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
'''
for flag in ['-S', '--specialized']:
+114 -35
View File
@@ -106,7 +106,7 @@ class TestTranforms(BytecodeTestCase):
self.check_lnotab(code)
def test_global_as_constant(self):
# LOAD_GLOBAL None/True/False --> LOAD_CONST None/True/False
# LOAD_GLOBAL None/True/False --> LOAD_COMMON_CONSTANT None/True/False
def f():
x = None
x = None
@@ -121,7 +121,7 @@ class TestTranforms(BytecodeTestCase):
for func, elem in ((f, None), (g, True), (h, False)):
with self.subTest(func=func):
self.assertNotInBytecode(func, 'LOAD_GLOBAL')
self.assertInBytecode(func, 'LOAD_CONST', elem)
self.assertInBytecode(func, 'LOAD_COMMON_CONSTANT', elem)
self.check_lnotab(func)
def f():
@@ -129,7 +129,7 @@ class TestTranforms(BytecodeTestCase):
return None
self.assertNotInBytecode(f, 'LOAD_GLOBAL')
self.assertInBytecode(f, 'LOAD_CONST', None)
self.assertInBytecode(f, 'LOAD_COMMON_CONSTANT', None)
self.check_lnotab(f)
def test_while_one(self):
@@ -146,13 +146,14 @@ class TestTranforms(BytecodeTestCase):
def test_pack_unpack(self):
for line, elem in (
('a, = a,', 'LOAD_CONST',),
('a, = a,', None),
('a, b = a, b', 'SWAP',),
('a, b, c = a, b, c', 'SWAP',),
):
with self.subTest(line=line):
code = compile(line,'','single')
self.assertInBytecode(code, elem)
if elem is not None:
self.assertInBytecode(code, elem)
self.assertNotInBytecode(code, 'BUILD_TUPLE')
self.assertNotInBytecode(code, 'UNPACK_SEQUENCE')
self.check_lnotab(code)
@@ -174,10 +175,10 @@ class TestTranforms(BytecodeTestCase):
# Long tuples should be folded too.
code = compile(repr(tuple(range(10000))),'','single')
self.assertNotInBytecode(code, 'BUILD_TUPLE')
# One LOAD_CONST for the tuple, one for the None return value
# One LOAD_CONST for the tuple; None return value uses LOAD_COMMON_CONSTANT
load_consts = [instr for instr in dis.get_instructions(code)
if instr.opname == 'LOAD_CONST']
self.assertEqual(len(load_consts), 2)
self.assertEqual(len(load_consts), 1)
self.check_lnotab(code)
# Bug 1053819: Tuple of constants misidentified when presented with:
@@ -283,11 +284,11 @@ class TestTranforms(BytecodeTestCase):
('-0.0', 'UNARY_NEGATIVE', None, True, 'LOAD_CONST', -0.0),
('-(1.0-1.0)', 'UNARY_NEGATIVE', None, True, 'LOAD_CONST', -0.0),
('-0.5', 'UNARY_NEGATIVE', None, True, 'LOAD_CONST', -0.5),
('---1', 'UNARY_NEGATIVE', None, True, 'LOAD_CONST', -1),
('---1', 'UNARY_NEGATIVE', None, True, 'LOAD_COMMON_CONSTANT', -1),
('---""', 'UNARY_NEGATIVE', None, False, None, None),
('~~~1', 'UNARY_INVERT', None, True, 'LOAD_CONST', -2),
('~~~""', 'UNARY_INVERT', None, False, None, None),
('not not True', 'UNARY_NOT', None, True, 'LOAD_CONST', True),
('not not True', 'UNARY_NOT', None, True, 'LOAD_COMMON_CONSTANT', True),
('not not x', 'UNARY_NOT', None, True, 'LOAD_NAME', 'x'), # this should be optimized regardless of constant or not
('+++1', 'CALL_INTRINSIC_1', intrinsic_positive, True, 'LOAD_SMALL_INT', 1),
('---x', 'UNARY_NEGATIVE', None, False, None, None),
@@ -326,7 +327,7 @@ class TestTranforms(BytecodeTestCase):
('1 + 2', 'NB_ADD', True, 'LOAD_SMALL_INT', 3),
('1 + 2 + 3', 'NB_ADD', True, 'LOAD_SMALL_INT', 6),
('1 + ""', 'NB_ADD', False, None, None),
('1 - 2', 'NB_SUBTRACT', True, 'LOAD_CONST', -1),
('1 - 2', 'NB_SUBTRACT', True, 'LOAD_COMMON_CONSTANT', -1),
('1 - 2 - 3', 'NB_SUBTRACT', True, 'LOAD_CONST', -4),
('1 - ""', 'NB_SUBTRACT', False, None, None),
('2 * 2', 'NB_MULTIPLY', True, 'LOAD_SMALL_INT', 4),
@@ -1539,7 +1540,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase):
end,
('END_FOR', None, 0),
('POP_ITER', None, 0),
('LOAD_CONST', 0, 0),
('LOAD_COMMON_CONSTANT', 7, 0),
('RETURN_VALUE', None, 0),
]
self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None, (1, 2)])
@@ -1572,7 +1573,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase):
end,
('END_FOR', None, 0),
('POP_ITER', None, 0),
('LOAD_CONST', 0, 0),
('LOAD_COMMON_CONSTANT', 7, 0),
('RETURN_VALUE', None, 0),
]
self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None])
@@ -1604,7 +1605,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase):
end,
('END_FOR', None, 0),
('POP_ITER', None, 0),
('LOAD_CONST', 0, 0),
('LOAD_COMMON_CONSTANT', 7, 0),
('RETURN_VALUE', None, 0),
]
self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None, frozenset({1, 2})])
@@ -1626,7 +1627,22 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase):
('LOAD_CONST', 0, 0),
('RETURN_VALUE', None, 0),
]
self.cfg_optimization_test(same, same, consts=[None], expected_consts=[None])
expected = [
('LOAD_SMALL_INT', 1, 0),
('LOAD_NAME', 0, 0),
('BUILD_SET', 2, 0),
('GET_ITER', 0, 0),
start := self.Label(),
('FOR_ITER', end := self.Label(), 0),
('STORE_FAST', 0, 0),
('JUMP', start, 0),
end,
('END_FOR', None, 0),
('POP_ITER', None, 0),
('LOAD_COMMON_CONSTANT', 7, 0),
('RETURN_VALUE', None, 0),
]
self.cfg_optimization_test(same, expected, consts=[None], expected_consts=[None])
def test_optimize_literal_list_contains(self):
# x in [1, 2] ==> x in (1, 2)
@@ -1645,7 +1661,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase):
('LOAD_CONST', 1, 0),
('CONTAINS_OP', 0, 0),
('POP_TOP', None, 0),
('LOAD_CONST', 0, 0),
('LOAD_COMMON_CONSTANT', 7, 0),
('RETURN_VALUE', None, 0),
]
self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None, (1, 2)])
@@ -1668,7 +1684,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase):
('BUILD_TUPLE', 2, 0),
('CONTAINS_OP', 0, 0),
('POP_TOP', None, 0),
('LOAD_CONST', 0, 0),
('LOAD_COMMON_CONSTANT', 7, 0),
('RETURN_VALUE', None, 0),
]
self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None])
@@ -1690,7 +1706,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase):
('LOAD_CONST', 1, 0),
('CONTAINS_OP', 0, 0),
('POP_TOP', None, 0),
('LOAD_CONST', 0, 0),
('LOAD_COMMON_CONSTANT', 7, 0),
('RETURN_VALUE', None, 0),
]
self.cfg_optimization_test(before, after, consts=[None], expected_consts=[None, frozenset({1, 2})])
@@ -1707,7 +1723,17 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase):
('LOAD_CONST', 0, 0),
('RETURN_VALUE', None, 0),
]
self.cfg_optimization_test(same, same, consts=[None], expected_consts=[None])
expected = [
('LOAD_NAME', 0, 0),
('LOAD_SMALL_INT', 1, 0),
('LOAD_NAME', 1, 0),
('BUILD_SET', 2, 0),
('CONTAINS_OP', 0, 0),
('POP_TOP', None, 0),
('LOAD_COMMON_CONSTANT', 7, 0),
('RETURN_VALUE', None, 0),
]
self.cfg_optimization_test(same, expected, consts=[None], expected_consts=[None])
def test_optimize_unary_not(self):
# test folding
@@ -1718,10 +1744,10 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase):
('RETURN_VALUE', None, 0),
]
after = [
('LOAD_CONST', 1, 0),
('LOAD_COMMON_CONSTANT', 10, 0),
('RETURN_VALUE', None, 0),
]
self.cfg_optimization_test(before, after, consts=[], expected_consts=[True, False])
self.cfg_optimization_test(before, after, consts=[], expected_consts=[True])
# test cancel out
before = [
@@ -1769,7 +1795,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase):
('RETURN_VALUE', None, 0),
]
after = [
('LOAD_CONST', 0, 0),
('LOAD_COMMON_CONSTANT', 9, 0),
('RETURN_VALUE', None, 0),
]
self.cfg_optimization_test(before, after, consts=[], expected_consts=[True])
@@ -1785,10 +1811,10 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase):
('RETURN_VALUE', None, 0),
]
after = [
('LOAD_CONST', 1, 0),
('LOAD_COMMON_CONSTANT', 10, 0),
('RETURN_VALUE', None, 0),
]
self.cfg_optimization_test(before, after, consts=[], expected_consts=[True, False])
self.cfg_optimization_test(before, after, consts=[], expected_consts=[True])
# test cancel out & eliminate to bool (to bool stays as we are not iterating to a fixed point)
before = [
@@ -2430,7 +2456,7 @@ class DirectCfgOptimizerTests(CfgOptimizationTestCase):
end,
("END_FOR", None, 11),
("POP_TOP", None, 12),
("LOAD_CONST", 0, 13),
("LOAD_COMMON_CONSTANT", 7, 13),
("RETURN_VALUE", None, 14),
]
self.cfg_optimization_test(insts, expected_insts, consts=[None])
@@ -2454,7 +2480,7 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests):
maxconst = max(maxconst, arg)
consts = [None for _ in range(maxconst + 1)]
return insts + [
("LOAD_CONST", 0, last_loc + 1),
("LOAD_COMMON_CONSTANT", 7, last_loc + 1),
("RETURN_VALUE", None, last_loc + 2),
], consts
@@ -2485,7 +2511,7 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests):
]
expected = [
("LOAD_FAST_BORROW", 0, 1),
("LOAD_CONST", 1, 2),
("LOAD_COMMON_CONSTANT", 7, 2),
("SWAP", 2, 3),
("POP_TOP", None, 4),
]
@@ -2523,7 +2549,13 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests):
("STORE_FAST", 0, 3),
("POP_TOP", None, 4),
]
self.check(insts, insts)
expected = [
("LOAD_FAST", 0, 1),
("LOAD_COMMON_CONSTANT", 7, 2),
("STORE_FAST", 0, 3),
("POP_TOP", None, 4),
]
self.check(insts, expected)
insts = [
("LOAD_FAST", 0, 1),
@@ -2532,7 +2564,14 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests):
("STORE_FAST_STORE_FAST", ((0 << 4) | 1), 4),
("POP_TOP", None, 5),
]
self.check(insts, insts)
expected = [
("LOAD_FAST", 0, 1),
("LOAD_COMMON_CONSTANT", 7, 2),
("LOAD_COMMON_CONSTANT", 7, 3),
("STORE_FAST_STORE_FAST", ((0 << 4) | 1), 4),
("POP_TOP", None, 5),
]
self.check(insts, expected)
insts = [
("LOAD_FAST", 0, 1),
@@ -2553,7 +2592,12 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests):
("LOAD_CONST", 0, 3),
("STORE_FAST_STORE_FAST", ((0 << 4) | 1), 4),
]
self.check(insts, insts)
expected = [
("LOAD_FAST", 0, 1),
("LOAD_COMMON_CONSTANT", 7, 3),
("STORE_FAST_STORE_FAST", ((0 << 4) | 1), 4),
]
self.check(insts, expected)
def test_consume_no_inputs(self):
insts = [
@@ -2598,7 +2642,19 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests):
("LOAD_CONST", 0, 7),
("RETURN_VALUE", None, 8),
]
self.cfg_optimization_test(insts, insts, consts=[None])
expected = [
("LOAD_FAST", 0, 1),
top := self.Label(),
("FOR_ITER", end := self.Label(), 2),
("STORE_FAST", 2, 3),
("JUMP", top, 4),
end,
("END_FOR", None, 5),
("POP_TOP", None, 6),
("LOAD_COMMON_CONSTANT", 7, 7),
("RETURN_VALUE", None, 8),
]
self.cfg_optimization_test(insts, expected, consts=[None])
def test_load_attr(self):
insts = [
@@ -2667,10 +2723,10 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests):
("LOAD_FAST", 0, 1),
("LOAD_FAST_BORROW", 1, 2),
("SEND", end := self.Label(), 3),
("LOAD_CONST", 0, 4),
("LOAD_COMMON_CONSTANT", 7, 4),
("RETURN_VALUE", None, 5),
end,
("LOAD_CONST", 0, 6),
("LOAD_COMMON_CONSTANT", 7, 6),
("RETURN_VALUE", None, 7)
]
self.cfg_optimization_test(insts, expected, consts=[None])
@@ -2708,7 +2764,15 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests):
("LOAD_CONST", 0, 5),
("RETURN_VALUE", None, 6)
]
self.cfg_optimization_test(insts, insts, consts=[None])
expected = [
("LOAD_COMMON_CONSTANT", 7, 1),
("LOAD_FAST", 0, 2),
("SET_FUNCTION_ATTRIBUTE", 2, 3),
("STORE_FAST", 1, 4),
("LOAD_COMMON_CONSTANT", 7, 5),
("RETURN_VALUE", None, 6)
]
self.cfg_optimization_test(insts, expected, consts=[None])
insts = [
("LOAD_CONST", 0, 1),
@@ -2717,7 +2781,7 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests):
("RETURN_VALUE", None, 4)
]
expected = [
("LOAD_CONST", 0, 1),
("LOAD_COMMON_CONSTANT", 7, 1),
("LOAD_FAST_BORROW", 0, 2),
("SET_FUNCTION_ATTRIBUTE", 2, 3),
("RETURN_VALUE", None, 4)
@@ -2740,7 +2804,22 @@ class OptimizeLoadFastTestCase(DirectCfgOptimizerTests):
("LOAD_CONST", 0, 11),
("RETURN_VALUE", None, 12),
]
self.cfg_optimization_test(insts, insts, consts=[None])
expected = [
("LOAD_FAST", 0, 1),
("GET_ITER", 1, 2),
("PUSH_NULL", None, 3),
("LOAD_COMMON_CONSTANT", 7, 4),
send := self.Label(),
("SEND", end := self.Label(), 6),
("YIELD_VALUE", 1, 7),
("RESUME", 2, 8),
("JUMP", send, 9),
end,
("END_SEND", None, 10),
("LOAD_COMMON_CONSTANT", 7, 11),
("RETURN_VALUE", None, 12),
]
self.cfg_optimization_test(insts, expected, consts=[None])
def test_push_exc_info(self):
insts = [
+16 -40
View File
@@ -2128,10 +2128,6 @@ code_returns_only_none(PyCodeObject *co)
int len = (int)Py_SIZE(co);
assert(len > 0);
// The last instruction either returns or raises. We can take advantage
// of that for a quick exit.
_Py_CODEUNIT final = _Py_GetBaseCodeUnit(co, len-1);
// Look up None in co_consts.
Py_ssize_t nconsts = PyTuple_Size(co->co_consts);
int none_index = 0;
@@ -2140,45 +2136,25 @@ code_returns_only_none(PyCodeObject *co)
break;
}
}
if (none_index == nconsts) {
// None wasn't there, which means there was no implicit return,
// "return", or "return None".
// That means there must be
// an explicit return (non-None), or it only raises.
if (IS_RETURN_OPCODE(final.op.code)) {
// It was an explicit return (non-None).
return 0;
/* We don't worry about EXTENDED_ARG for now. */
for (int i = 0; i < len; i += _PyInstruction_GetLength(co, i)) {
_Py_CODEUNIT inst = _Py_GetBaseCodeUnit(co, i);
if (!IS_RETURN_OPCODE(inst.op.code)) {
continue;
}
// It must end with a raise then. We still have to walk the
// bytecode to see if there's any explicit return (non-None).
assert(IS_RAISE_OPCODE(final.op.code));
for (int i = 0; i < len; i += _PyInstruction_GetLength(co, i)) {
_Py_CODEUNIT inst = _Py_GetBaseCodeUnit(co, i);
if (IS_RETURN_OPCODE(inst.op.code)) {
// We alraedy know it isn't returning None.
return 0;
}
assert(i != 0);
_Py_CODEUNIT prev = _Py_GetBaseCodeUnit(co, i-1);
if (prev.op.code == LOAD_COMMON_CONSTANT &&
prev.op.arg == CONSTANT_NONE)
{
continue;
}
// It must only raise.
}
else {
// Walk the bytecode, looking for RETURN_VALUE.
for (int i = 0; i < len; i += _PyInstruction_GetLength(co, i)) {
_Py_CODEUNIT inst = _Py_GetBaseCodeUnit(co, i);
if (IS_RETURN_OPCODE(inst.op.code)) {
assert(i != 0);
// Ignore it if it returns None.
_Py_CODEUNIT prev = _Py_GetBaseCodeUnit(co, i-1);
if (prev.op.code == LOAD_CONST) {
// We don't worry about EXTENDED_ARG for now.
if (prev.op.arg == none_index) {
continue;
}
}
return 0;
}
if (none_index < nconsts && prev.op.code == LOAD_CONST
&& prev.op.arg == none_index)
{
continue;
}
return 0;
}
return 1;
}
+29 -29
View File
@@ -2,38 +2,38 @@
unsigned char M_test_frozenmain[] = {
227,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,
0,0,0,0,0,243,188,0,0,0,128,0,0,0,93,0,
81,1,72,0,115,0,93,0,81,1,72,4,115,1,92,2,
31,0,81,2,50,1,0,0,0,0,0,0,29,0,92,2,
31,0,81,3,92,0,79,6,0,0,0,0,0,0,0,0,
80,7,72,0,115,0,93,0,80,7,72,4,115,1,92,2,
31,0,81,1,50,1,0,0,0,0,0,0,29,0,92,2,
31,0,81,2,92,0,79,6,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,50,2,0,0,0,0,
0,0,29,0,92,1,79,8,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,31,0,50,0,0,0,
0,0,0,0,81,4,42,26,0,0,0,0,0,0,0,0,
0,0,115,5,81,7,70,0,0,0,68,24,0,0,115,6,
92,2,31,0,81,5,92,6,12,0,81,6,92,5,92,6,
0,0,0,0,81,3,42,26,0,0,0,0,0,0,0,0,
0,0,115,5,81,6,70,0,0,0,68,24,0,0,115,6,
92,2,31,0,81,4,92,6,12,0,81,5,92,5,92,6,
42,26,0,0,0,0,0,0,0,0,0,0,12,0,48,4,
50,1,0,0,0,0,0,0,29,0,74,26,0,0,9,0,
28,0,81,1,33,0,41,8,233,0,0,0,0,78,122,18,
70,114,111,122,101,110,32,72,101,108,108,111,32,87,111,114,
108,100,122,8,115,121,115,46,97,114,103,118,218,6,99,111,
110,102,105,103,122,7,99,111,110,102,105,103,32,122,2,58,
32,41,5,218,12,112,114,111,103,114,97,109,95,110,97,109,
101,218,10,101,120,101,99,117,116,97,98,108,101,218,15,117,
115,101,95,101,110,118,105,114,111,110,109,101,110,116,218,17,
99,111,110,102,105,103,117,114,101,95,99,95,115,116,100,105,
111,218,14,98,117,102,102,101,114,101,100,95,115,116,100,105,
111,41,7,218,3,115,121,115,218,17,95,116,101,115,116,105,
110,116,101,114,110,97,108,99,97,112,105,218,5,112,114,105,
110,116,218,4,97,114,103,118,218,11,103,101,116,95,99,111,
110,102,105,103,115,114,3,0,0,0,218,3,107,101,121,169,
0,243,0,0,0,0,218,18,116,101,115,116,95,102,114,111,
122,101,110,109,97,105,110,46,112,121,218,8,60,109,111,100,
117,108,101,62,114,18,0,0,0,1,0,0,0,115,94,0,
0,0,241,3,1,1,1,243,8,0,1,11,219,0,24,225,
0,5,208,6,26,212,0,27,217,0,5,128,106,144,35,151,
40,145,40,212,0,27,216,9,26,215,9,38,210,9,38,211,
9,40,168,24,213,9,50,128,6,244,2,6,12,2,128,67,
241,14,0,5,10,136,71,144,67,144,53,152,2,152,54,160,
35,157,59,152,45,208,10,40,214,4,41,243,15,6,12,2,
114,16,0,0,0,
28,0,80,7,33,0,41,7,233,0,0,0,0,122,18,70,
114,111,122,101,110,32,72,101,108,108,111,32,87,111,114,108,
100,122,8,115,121,115,46,97,114,103,118,218,6,99,111,110,
102,105,103,122,7,99,111,110,102,105,103,32,122,2,58,32,
41,5,218,12,112,114,111,103,114,97,109,95,110,97,109,101,
218,10,101,120,101,99,117,116,97,98,108,101,218,15,117,115,
101,95,101,110,118,105,114,111,110,109,101,110,116,218,17,99,
111,110,102,105,103,117,114,101,95,99,95,115,116,100,105,111,
218,14,98,117,102,102,101,114,101,100,95,115,116,100,105,111,
41,7,218,3,115,121,115,218,17,95,116,101,115,116,105,110,
116,101,114,110,97,108,99,97,112,105,218,5,112,114,105,110,
116,218,4,97,114,103,118,218,11,103,101,116,95,99,111,110,
102,105,103,115,114,3,0,0,0,218,3,107,101,121,169,0,
243,0,0,0,0,218,18,116,101,115,116,95,102,114,111,122,
101,110,109,97,105,110,46,112,121,218,8,60,109,111,100,117,
108,101,62,114,18,0,0,0,1,0,0,0,115,94,0,0,
0,241,3,1,1,1,243,8,0,1,11,219,0,24,225,0,
5,208,6,26,212,0,27,217,0,5,128,106,144,35,151,40,
145,40,212,0,27,216,9,26,215,9,38,210,9,38,211,9,
40,168,24,213,9,50,128,6,244,2,6,12,2,128,67,241,
14,0,5,10,136,71,144,67,144,53,152,2,152,54,160,35,
157,59,152,45,208,10,40,214,4,41,243,15,6,12,2,114,
16,0,0,0,
};
+71 -3
View File
@@ -10,6 +10,7 @@
#include "pycore_opcode_utils.h"
#include "pycore_opcode_metadata.h" // OPCODE_HAS_ARG, etc
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include <stdbool.h>
@@ -1125,6 +1126,8 @@ remove_redundant_nops(cfg_builder *g) {
return changes;
}
static int loads_const(int opcode);
static int
remove_redundant_nops_and_pairs(basicblock *entryblock)
{
@@ -1148,7 +1151,7 @@ remove_redundant_nops_and_pairs(basicblock *entryblock)
int opcode = instr->i_opcode;
bool is_redundant_pair = false;
if (opcode == POP_TOP) {
if (prev_opcode == LOAD_CONST || prev_opcode == LOAD_SMALL_INT) {
if (loads_const(prev_opcode)) {
is_redundant_pair = true;
}
else if (prev_opcode == COPY && prev_oparg == 1) {
@@ -1300,7 +1303,9 @@ jump_thread(basicblock *bb, cfg_instr *inst, cfg_instr *target, int opcode)
static int
loads_const(int opcode)
{
return OPCODE_HAS_CONST(opcode) || opcode == LOAD_SMALL_INT;
return OPCODE_HAS_CONST(opcode)
|| opcode == LOAD_SMALL_INT
|| opcode == LOAD_COMMON_CONSTANT;
}
/* Returns new reference */
@@ -1323,6 +1328,10 @@ get_const_value(int opcode, int oparg, PyObject *co_consts)
if (opcode == LOAD_SMALL_INT) {
return PyLong_FromLong(oparg);
}
if (opcode == LOAD_COMMON_CONSTANT) {
assert(oparg < NUM_COMMON_CONSTANTS);
return Py_NewRef(_PyInterpreterState_GET()->common_consts[oparg]);
}
if (constant == NULL) {
PyErr_SetString(PyExc_SystemError,
@@ -1437,6 +1446,46 @@ maybe_instr_make_load_smallint(cfg_instr *instr, PyObject *newconst,
return 0;
}
/* Does not steal reference to "newconst".
Return 1 if changed instruction to LOAD_COMMON_CONSTANT.
Return 0 if could not change instruction to LOAD_COMMON_CONSTANT.
Return -1 on error.
*/
static int
maybe_instr_make_load_common_const(cfg_instr *instr, PyObject *newconst)
{
int oparg;
if (newconst == Py_None) {
oparg = CONSTANT_NONE;
}
else if (newconst == Py_True) {
oparg = CONSTANT_TRUE;
}
else if (newconst == Py_False) {
oparg = CONSTANT_FALSE;
}
else if (PyUnicode_CheckExact(newconst)
&& PyUnicode_GET_LENGTH(newconst) == 0) {
oparg = CONSTANT_EMPTY_STR;
}
else if (PyLong_CheckExact(newconst)) {
int overflow;
long val = PyLong_AsLongAndOverflow(newconst, &overflow);
if (val == -1 && PyErr_Occurred()) {
return -1;
}
if (overflow || val != -1) {
return 0;
}
oparg = CONSTANT_MINUS_ONE;
}
else {
return 0;
}
assert(_Py_IsImmortal(newconst));
INSTR_SET_OP1(instr, LOAD_COMMON_CONSTANT, oparg);
return 1;
}
/* Steals reference to "newconst" */
static int
@@ -1452,6 +1501,14 @@ instr_make_load_const(cfg_instr *instr, PyObject *newconst,
if (res > 0) {
return SUCCESS;
}
res = maybe_instr_make_load_common_const(instr, newconst);
if (res < 0) {
Py_DECREF(newconst);
return ERROR;
}
if (res > 0) {
return SUCCESS;
}
int oparg = add_const(newconst, consts, const_cache, consts_index);
RETURN_IF_ERROR(oparg);
INSTR_SET_OP1(instr, LOAD_CONST, oparg);
@@ -2208,7 +2265,7 @@ basicblock_optimize_load_const(PyObject *const_cache, basicblock *bb,
oparg = inst->i_oparg;
}
assert(!IS_ASSEMBLER_OPCODE(opcode));
if (opcode != LOAD_CONST && opcode != LOAD_SMALL_INT) {
if (!loads_const(opcode)) {
continue;
}
int nextop = i+1 < bb->b_iused ? bb->b_instr[i+1].i_opcode : 0;
@@ -2308,6 +2365,17 @@ basicblock_optimize_load_const(PyObject *const_cache, basicblock *bb,
break;
}
}
if (inst->i_opcode == LOAD_CONST) {
PyObject *constant = get_const_value(inst->i_opcode, inst->i_oparg, consts);
if (constant == NULL) {
return ERROR;
}
int res = maybe_instr_make_load_common_const(inst, constant);
Py_DECREF(constant);
if (res < 0) {
return ERROR;
}
}
}
return SUCCESS;
}
+10 -2
View File
@@ -1,4 +1,6 @@
#include "Python.h"
#include "pycore_long.h"
#include "pycore_opcode_utils.h"
#include "pycore_optimizer.h"
#include "pycore_uops.h"
#include "pycore_uop_ids.h"
@@ -875,8 +877,14 @@ dummy_func(void) {
op(_LOAD_COMMON_CONSTANT, (-- value)) {
assert(oparg < NUM_COMMON_CONSTANTS);
PyObject *val = _PyInterpreterState_GET()->common_consts[oparg];
ADD_OP(_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);
value = PyJitRef_Borrow(sym_new_const(ctx, val));
if (_Py_IsImmortal(val)) {
ADD_OP(_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);
value = PyJitRef_Borrow(sym_new_const(ctx, val));
}
else {
ADD_OP(_LOAD_CONST_INLINE, 0, (uintptr_t)val);
value = sym_new_const(ctx, val);
}
}
op(_LOAD_SMALL_INT, (-- value)) {
+8 -2
View File
@@ -1911,8 +1911,14 @@
JitOptRef value;
assert(oparg < NUM_COMMON_CONSTANTS);
PyObject *val = _PyInterpreterState_GET()->common_consts[oparg];
ADD_OP(_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);
value = PyJitRef_Borrow(sym_new_const(ctx, val));
if (_Py_IsImmortal(val)) {
ADD_OP(_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);
value = PyJitRef_Borrow(sym_new_const(ctx, val));
}
else {
ADD_OP(_LOAD_CONST_INLINE, 0, (uintptr_t)val);
value = sym_new_const(ctx, val);
}
CHECK_STACK_BOUNDS(1);
stack_pointer[0] = value;
stack_pointer += 1;
+11 -5
View File
@@ -879,13 +879,19 @@ pycore_init_builtins(PyThreadState *tstate)
interp->common_consts[CONSTANT_ASSERTIONERROR] = PyExc_AssertionError;
interp->common_consts[CONSTANT_NOTIMPLEMENTEDERROR] = PyExc_NotImplementedError;
interp->common_consts[CONSTANT_BUILTIN_TUPLE] = (PyObject*)&PyTuple_Type;
interp->common_consts[CONSTANT_BUILTIN_TUPLE] = (PyObject *)&PyTuple_Type;
interp->common_consts[CONSTANT_BUILTIN_ALL] = all;
interp->common_consts[CONSTANT_BUILTIN_ANY] = any;
interp->common_consts[CONSTANT_BUILTIN_LIST] = (PyObject*)&PyList_Type;
interp->common_consts[CONSTANT_BUILTIN_SET] = (PyObject*)&PySet_Type;
for (int i=0; i < NUM_COMMON_CONSTANTS; i++) {
interp->common_consts[CONSTANT_BUILTIN_LIST] = (PyObject *)&PyList_Type;
interp->common_consts[CONSTANT_BUILTIN_SET] = (PyObject *)&PySet_Type;
interp->common_consts[CONSTANT_NONE] = Py_None;
interp->common_consts[CONSTANT_EMPTY_STR] =
Py_GetConstantBorrowed(Py_CONSTANT_EMPTY_STR);
interp->common_consts[CONSTANT_TRUE] = Py_True;
interp->common_consts[CONSTANT_FALSE] = Py_False;
interp->common_consts[CONSTANT_MINUS_ONE] =
(PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS - 1];
for (int i = 0; i < NUM_COMMON_CONSTANTS; i++) {
assert(interp->common_consts[i] != NULL);
}