mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
gh-117045: Add code object to function version cache (#117028)
Changes to the function version cache: - In addition to the function object, also store the code object, and allow the latter to be retrieved even if the function has been evicted. - Stop assigning new function versions after a critical attribute (e.g. `__code__`) has been modified; the version is permanently reset to zero in this case. - Changes to `__annotations__` are no longer considered critical. (This fixes gh-109998.) Changes to the Tier 2 optimization machinery: - If we cannot map a function version to a function, but it is still mapped to a code object, we continue projecting the trace. The operand of the `_PUSH_FRAME` and `_POP_FRAME` opcodes can be either NULL, a function object, or a code object with the lowest bit set. This allows us to trace through code that calls an ephemeral function, i.e., a function that may not be alive when we are constructing the executor, e.g. a generator expression or certain nested functions. We will lose globals removal inside such functions, but we can still do other peephole operations (and even possibly [call inlining](https://github.com/python/cpython/pull/116290), if we decide to do it), which only need the code object. As before, if we cannot retrieve the code object from the cache, we stop projecting.
This commit is contained in:
parent
c85d84166a
commit
570a82d46a
8 changed files with 208 additions and 95 deletions
|
@ -228,7 +228,12 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
|
|||
builtins_watched <<= 1;
|
||||
globals_watched <<= 1;
|
||||
function_checked <<= 1;
|
||||
PyFunctionObject *func = (PyFunctionObject *)buffer[pc].operand;
|
||||
uint64_t operand = buffer[pc].operand;
|
||||
if (operand == 0 || (operand & 1)) {
|
||||
// It's either a code object or NULL, so bail
|
||||
return 1;
|
||||
}
|
||||
PyFunctionObject *func = (PyFunctionObject *)operand;
|
||||
if (func == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -251,7 +256,15 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
|
|||
builtins_watched >>= 1;
|
||||
globals_watched >>= 1;
|
||||
function_checked >>= 1;
|
||||
PyFunctionObject *func = (PyFunctionObject *)buffer[pc].operand;
|
||||
uint64_t operand = buffer[pc].operand;
|
||||
if (operand == 0 || (operand & 1)) {
|
||||
// It's either a code object or NULL, so bail
|
||||
return 1;
|
||||
}
|
||||
PyFunctionObject *func = (PyFunctionObject *)operand;
|
||||
if (func == NULL) {
|
||||
return 1;
|
||||
}
|
||||
assert(PyFunction_Check(func));
|
||||
function_version = func->func_version;
|
||||
globals = func->func_globals;
|
||||
|
@ -522,7 +535,7 @@ remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size)
|
|||
static void
|
||||
peephole_opt(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, int buffer_size)
|
||||
{
|
||||
PyCodeObject *co = (PyCodeObject *)frame->f_executable;
|
||||
PyCodeObject *co = _PyFrame_GetCode(frame);
|
||||
for (int pc = 0; pc < buffer_size; pc++) {
|
||||
int opcode = buffer[pc].opcode;
|
||||
switch(opcode) {
|
||||
|
@ -545,11 +558,16 @@ peephole_opt(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, int buffer_s
|
|||
case _PUSH_FRAME:
|
||||
case _POP_FRAME:
|
||||
{
|
||||
PyFunctionObject *func = (PyFunctionObject *)buffer[pc].operand;
|
||||
if (func == NULL) {
|
||||
uint64_t operand = buffer[pc].operand;
|
||||
if (operand & 1) {
|
||||
co = (PyCodeObject *)(operand & ~1);
|
||||
assert(PyCode_Check(co));
|
||||
}
|
||||
else if (operand == 0) {
|
||||
co = NULL;
|
||||
}
|
||||
else {
|
||||
PyFunctionObject *func = (PyFunctionObject *)operand;
|
||||
assert(PyFunction_Check(func));
|
||||
co = (PyCodeObject *)func->func_code;
|
||||
}
|
||||
|
@ -587,7 +605,7 @@ _Py_uop_analyze_and_optimize(
|
|||
peephole_opt(frame, buffer, buffer_size);
|
||||
|
||||
err = optimize_uops(
|
||||
(PyCodeObject *)frame->f_executable, buffer,
|
||||
_PyFrame_GetCode(frame), buffer,
|
||||
buffer_size, curr_stacklen, dependencies);
|
||||
|
||||
if (err == 0) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue