#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
argrepr = _intrinsic_2_descs[arg]
elif deop == LOAD_COMMON_CONSTANT:
obj = _common_constants[arg]
+ argval = obj
if isinstance(obj, type):
argrepr = obj.__name__
else:
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]
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,
_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"]]
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
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
freevars: ()
nlocals: 0
flags: 67108867
-consts: ("'doc string'", 'None')
+consts: ("'doc string'",)
>>> def keywordonly_args(a,b,*,k1):
... return a,b,k1
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"
],
[
("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),
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']
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,)
COMPARE_OP 72 (==)
LOAD_FAST_BORROW 0
STORE_ATTR 0
- LOAD_CONST 1
+ LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
"""
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,)
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,)
%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,
dis_bug42562 = """\
RESUME 0
- LOAD_CONST 0 (None)
+ LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
"""
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)
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
"""
%3d LOAD_GLOBAL 0 (spam)
POP_TOP
- LOAD_CONST 0 (None)
+ LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
"""
%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
"""
LOAD_SMALL_INT 1
BINARY_OP 0 (+)
STORE_NAME 0 (x)
- LOAD_CONST 1 (None)
+ LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
"""
LOAD_SMALL_INT 0
CALL 1
STORE_SUBSCR
- LOAD_CONST 2 (None)
+ LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
"""
MAKE_FUNCTION
SET_FUNCTION_ATTRIBUTE 16 (annotate)
STORE_NAME 0 (foo)
- LOAD_CONST 2 (None)
+ LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
"""
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
%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
%4d LOAD_SMALL_INT 2
STORE_FAST 2 (y)
- LOAD_CONST 1 (None)
+ LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
-- L8: COPY 3
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
%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
%4d LOAD_SMALL_INT 2
STORE_FAST 2 (y)
- LOAD_CONST 0 (None)
+ LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
%4d L12: CLEANUP_THROW
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
%4d LOAD_SMALL_INT 2
STORE_FAST 2 (y)
- LOAD_CONST 0 (None)
+ LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
-- L26: COPY 3
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)
%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 (*)
%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,
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,)
'',
'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',
'',
'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',
'',
])
f.__code__ = f.__code__.replace(co_linetable=b'')
expect = '\n'.join([
' RESUME 0',
- ' LOAD_CONST 0 (None)',
+ ' LOAD_COMMON_CONSTANT 7 (None)',
' RETURN_VALUE',
'',
])
Flags: OPTIMIZED, NEWLOCALS, VARARGS, VARKEYWORDS, GENERATOR
Constants:
0: <code object f at (.*), file "(.*)", line (.*)>
- 1: None
Variable names:
0: a
1: b
Flags: 0x0
Constants:
0: 1
- 1: None
Names:
0: x"""
Flags: OPTIMIZED, NEWLOCALS, COROUTINE
Constants:
0: 1
- 1: None
Names:
0: b
1: c
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),
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),
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),
]
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),
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),
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),
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),
]
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']:
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']:
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']:
expect = '''
0 RESUME 0
- 1 LOAD_CONST 0 (None)
+ 1 LOAD_COMMON_CONSTANT 7 (None)
RETURN_VALUE
'''
for flag in ['-S', '--specialized']:
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
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():
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):
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)
# 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:
('-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),
('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),
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)])
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])
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})])
('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)
('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)])
('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])
('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})])
('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
('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 = [
('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])
('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 = [
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])
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
]
expected = [
("LOAD_FAST_BORROW", 0, 1),
- ("LOAD_CONST", 1, 2),
+ ("LOAD_COMMON_CONSTANT", 7, 2),
("SWAP", 2, 3),
("POP_TOP", None, 4),
]
("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),
("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),
("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 = [
("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 = [
("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])
("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),
("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)
("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 = [
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;
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;
}
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,
};
#include "pycore_opcode_utils.h"
#include "pycore_opcode_metadata.h" // OPCODE_HAS_ARG, etc
+#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include <stdbool.h>
return changes;
}
+static int loads_const(int opcode);
+
static int
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) {
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 */
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,
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
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);
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;
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;
}
#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"
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)) {
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;
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);
}