From 481256db6dfa6073f20de83655f305ccbe6826fd Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 7 Mar 2024 11:07:51 +0000 Subject: [PATCH 1/2] Fix optimization: _CHECK_FUNCTION needs the function version --- Python/bytecodes.c | 4 ++-- Python/executor_cases.c.h | 4 ++-- Python/optimizer_analysis.c | 16 ++++++++++------ 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3276a4a9644b8f..1dade58113c008 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4120,8 +4120,8 @@ dummy_func( null = NULL; } - tier2 op(_CHECK_FUNCTION, (func/4 -- )) { - DEOPT_IF(frame->f_funcobj != func); + tier2 op(_CHECK_FUNCTION, (func_version/2 -- )) { + DEOPT_IF(frame->f_funcobj->func_version != func_version); } /* Internal -- for testing executors */ diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 2e7b970b4ddb9e..d8c25f0b3488c5 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3880,8 +3880,8 @@ } case _CHECK_FUNCTION: { - PyObject *func = (PyObject *)CURRENT_OPERAND(); - if (frame->f_funcobj != func) goto deoptimize; + uint32_t func_version = (uint32_t)CURRENT_OPERAND(); + if (frame->f_funcobj->func_version != func_version) goto deoptimize; break; } diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c index 0f255272fbb2e6..51ec14b718f291 100644 --- a/Python/optimizer_analysis.c +++ b/Python/optimizer_analysis.c @@ -141,9 +141,11 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, return 1; } PyObject *globals = frame->f_globals; - assert(PyFunction_Check(((PyFunctionObject *)frame->f_funcobj))); - assert(((PyFunctionObject *)frame->f_funcobj)->func_builtins == builtins); - assert(((PyFunctionObject *)frame->f_funcobj)->func_globals == globals); + PyFunctionObject *function = (PyFunctionObject *)frame->f_funcobj; + assert(PyFunction_Check(function)); + assert(function->func_builtins == builtins); + assert(function->func_globals == globals); + uint32_t function_version = _PyFunction_GetVersionForCurrentState(function); /* In order to treat globals as constants, we need to * know that the globals dict is the one we expected, and * that it hasn't changed @@ -181,7 +183,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, } else { buffer[pc].opcode = _CHECK_FUNCTION; - buffer[pc].operand = (uintptr_t)builtins; + buffer[pc].operand = function_version; function_checked |= 1; } break; @@ -203,7 +205,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, } else { buffer[pc].opcode = _CHECK_FUNCTION; - buffer[pc].operand = (uintptr_t)globals; + buffer[pc].operand = function_version; function_checked |= 1; } break; @@ -227,7 +229,8 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, return 1; } assert(PyFunction_Check(func)); - if (prechecked_function_version == func->func_version) { + function_version = func->func_version; + if (prechecked_function_version == function_version) { function_checked |= 1; } prechecked_function_version = 0; @@ -245,6 +248,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer, function_checked >>= 1; PyFunctionObject *func = (PyFunctionObject *)buffer[pc].operand; assert(PyFunction_Check(func)); + function_version = func->func_version; globals = func->func_globals; builtins = func->func_builtins; break; From 9c27552eaff2b05c2372884aeb8f71cde1702fce Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Thu, 7 Mar 2024 11:39:56 +0000 Subject: [PATCH 2/2] Add missing cast --- Python/bytecodes.c | 3 ++- Python/executor_cases.c.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 1dade58113c008..79f2def31e9ab9 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4121,7 +4121,8 @@ dummy_func( } tier2 op(_CHECK_FUNCTION, (func_version/2 -- )) { - DEOPT_IF(frame->f_funcobj->func_version != func_version); + assert(PyFunction_Check(frame->f_funcobj)); + DEOPT_IF(((PyFunctionObject *)frame->f_funcobj)->func_version != func_version); } /* Internal -- for testing executors */ diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index d8c25f0b3488c5..2a2346ba346887 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -3881,7 +3881,8 @@ case _CHECK_FUNCTION: { uint32_t func_version = (uint32_t)CURRENT_OPERAND(); - if (frame->f_funcobj->func_version != func_version) goto deoptimize; + assert(PyFunction_Check(frame->f_funcobj)); + if (((PyFunctionObject *)frame->f_funcobj)->func_version != func_version) goto deoptimize; break; }