GH-128685: Specialize (rather than quicken) LOAD_CONST into LOAD_CONST_[IM]MORTAL (GH-128708)

This commit is contained in:
Mark Shannon 2025-01-13 10:30:28 +00:00 committed by GitHub
parent 29fe8072cf
commit ddd959987c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 121 additions and 65 deletions

View file

@ -285,11 +285,25 @@ dummy_func(
}
family(LOAD_CONST, 0) = {
LOAD_CONST_MORTAL,
LOAD_CONST_IMMORTAL,
};
pure inst(LOAD_CONST, (-- value)) {
value = PyStackRef_FromPyObjectNew(GETITEM(FRAME_CO_CONSTS, oparg));
inst(LOAD_CONST, (-- value)) {
/* We can't do this in the bytecode compiler as
* marshalling can intern strings and make them immortal. */
PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg);
value = PyStackRef_FromPyObjectNew(obj);
#if ENABLE_SPECIALIZATION
if (this_instr->op.code == LOAD_CONST) {
this_instr->op.code = _Py_IsImmortal(obj) ? LOAD_CONST_IMMORTAL : LOAD_CONST_MORTAL;
}
#endif
}
inst(LOAD_CONST_MORTAL, (-- value)) {
PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg);
value = PyStackRef_FromPyObjectNew(obj);
}
inst(LOAD_CONST_IMMORTAL, (-- value)) {

View file

@ -209,10 +209,13 @@
break;
}
case _LOAD_CONST: {
/* _LOAD_CONST is not a viable micro-op for tier 2 because it uses the 'this_instr' variable */
case _LOAD_CONST_MORTAL: {
_PyStackRef value;
oparg = CURRENT_OPARG();
value = PyStackRef_FromPyObjectNew(GETITEM(FRAME_CO_CONSTS, oparg));
PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg);
value = PyStackRef_FromPyObjectNew(obj);
stack_pointer[0] = value;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());

View file

@ -5913,8 +5913,18 @@
next_instr += 1;
INSTRUCTION_STATS(LOAD_CONST);
PREDICTED(LOAD_CONST);
_Py_CODEUNIT* const this_instr = next_instr - 1;
(void)this_instr;
_PyStackRef value;
value = PyStackRef_FromPyObjectNew(GETITEM(FRAME_CO_CONSTS, oparg));
/* We can't do this in the bytecode compiler as
* marshalling can intern strings and make them immortal. */
PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg);
value = PyStackRef_FromPyObjectNew(obj);
#if ENABLE_SPECIALIZATION
if (this_instr->op.code == LOAD_CONST) {
this_instr->op.code = _Py_IsImmortal(obj) ? LOAD_CONST_IMMORTAL : LOAD_CONST_MORTAL;
}
#endif
stack_pointer[0] = value;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
@ -5936,6 +5946,20 @@
DISPATCH();
}
TARGET(LOAD_CONST_MORTAL) {
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(LOAD_CONST_MORTAL);
static_assert(0 == 0, "incorrect cache size");
_PyStackRef value;
PyObject *obj = GETITEM(FRAME_CO_CONSTS, oparg);
value = PyStackRef_FromPyObjectNew(obj);
stack_pointer[0] = value;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
DISPATCH();
}
TARGET(LOAD_DEREF) {
frame->instr_ptr = next_instr;
next_instr += 1;

View file

@ -207,6 +207,7 @@ static void *opcode_targets[256] = {
&&TARGET_LOAD_ATTR_SLOT,
&&TARGET_LOAD_ATTR_WITH_HINT,
&&TARGET_LOAD_CONST_IMMORTAL,
&&TARGET_LOAD_CONST_MORTAL,
&&TARGET_LOAD_GLOBAL_BUILTIN,
&&TARGET_LOAD_GLOBAL_MODULE,
&&TARGET_LOAD_SUPER_ATTR_ATTR,
@ -233,7 +234,6 @@ static void *opcode_targets[256] = {
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
&&TARGET_INSTRUMENTED_END_FOR,
&&TARGET_INSTRUMENTED_POP_ITER,
&&TARGET_INSTRUMENTED_END_SEND,

View file

@ -479,6 +479,13 @@ dummy_func(void) {
value = sym_new_const(ctx, val);
}
op(_LOAD_CONST_MORTAL, (-- value)) {
PyObject *val = PyTuple_GET_ITEM(co->co_consts, this_instr->oparg);
int opcode = _Py_IsImmortal(val) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE;
REPLACE_OP(this_instr, opcode, 0, (uintptr_t)val);
value = sym_new_const(ctx, val);
}
op(_LOAD_CONST_IMMORTAL, (-- value)) {
PyObject *val = PyTuple_GET_ITEM(co->co_consts, this_instr->oparg);
REPLACE_OP(this_instr, _LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)val);

View file

@ -58,7 +58,9 @@
break;
}
case _LOAD_CONST: {
/* _LOAD_CONST is not a viable micro-op for tier 2 */
case _LOAD_CONST_MORTAL: {
_Py_UopsSymbol *value;
PyObject *val = PyTuple_GET_ITEM(co->co_consts, this_instr->oparg);
int opcode = _Py_IsImmortal(val) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE;

View file

@ -478,15 +478,6 @@ _PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, PyObject *consts,
}
i += caches;
}
else if (opcode == LOAD_CONST) {
/* We can't do this in the bytecode compiler as
* marshalling can intern strings and make them immortal. */
PyObject *obj = PyTuple_GET_ITEM(consts, oparg);
if (_Py_IsImmortal(obj)) {
instructions[i].op.code = LOAD_CONST_IMMORTAL;
}
}
if (opcode != EXTENDED_ARG) {
oparg = 0;
}