-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
GH-128685: Specialize (rather than quicken) LOAD_CONST into LOAD_CONST_[IM]MORTAL #128708
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GH-128685: Specialize (rather than quicken) LOAD_CONST into LOAD_CONST_[IM]MORTAL #128708
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, just a couple of thoughts.
Also, any perf numbers? I doubt it would be too significant, but this is a very perf-sensitive instruction/optimization.
@@ -265,6 +265,7 @@ Known values: | |||
Python 3.14a4 3610 (Add VALUE_WITH_FAKE_GLOBALS format to annotationlib) | |||
Python 3.14a4 3611 (Add NOT_TAKEN instruction) | |||
Python 3.14a4 3612 (Add POP_ITER and INSTRUMENTED_POP_ITER) | |||
Python 3.14a4 3613 (Add LOAD_CONST_MORTAL instruction) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a specialization, right? So we shouldn't need a magic bump (since the specialized variants don't occur in marshalled data).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding the extra instruction changes the allocated numbers for other instructions.
Even if it isn't absolutely necessary, it is harmless.
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 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the check for this_instr->op.code == LOAD_CONST
?
Also, minor, but maybe a bit more idiomatic with the rest of the bytecode definitions to split the specializing part out and reuse the code for loading the const? I think this would also make LOAD_CONST
a viable tier two instruction (which it currently isn't). Though actually tracing through one should be rare, I can think of cases where it might happen.
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 | |
} | |
specializing op(_SPECIALIZE_LOAD_CONST, (--)) { | |
/* We can't do this in the bytecode compiler as | |
* marshalling can intern strings and make them immortal. */ | |
#if ENABLE_SPECIALIZATION | |
this_instr->op.code = _Py_IsImmortal(obj) ? LOAD_CONST_IMMORTAL : LOAD_CONST_MORTAL; | |
#endif | |
} | |
macro(LOAD_CONST) = _SPECIALIZE_LOAD_CONST + LOAD_CONST_MORTAL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the check for this_instr->op.code == LOAD_CONST?
Instrumentation. The opcode might be INSTRUMENTED_LINE
for example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
split the specializing part out
The specializing part needs to load the value to test it, so separating out the specialization just duplicates that.
This was previously handled by `_PyCode_Quicken`, but moved to specialization in pythongh-128708. Enable it for the free-threaded build.
This was previously handled by `_PyCode_Quicken`, but moved to specialization in pythongh-128708. Enable it for the free-threaded build.
This PR changes
LOAD_CONST
to specialize into eitherLOAD_CONST
orLOAD_CONST_IMMORTAL
.This ensures that
LOAD_CONST
for immortals returns toLOAD_CONST_IMMORTAL
after instrumentation.This is unlikely to make any observable difference, but we generally expect instructions to return to their specialized forms after instrumentation is removed and
LOAD_CONST
is a very common instruction, so is likely to get instrumented.Skipping news as this should have no observable effect.
LOAD_CONST_IMMORTAL
doesn't survive being instrumented and de-instrumented. #128685