From 692a992f026f33bd4284cefbe584aedac6f37212 Mon Sep 17 00:00:00 2001 From: Ken Jin <28750310+Fidget-Spinner@users.noreply.github.com> Date: Tue, 28 Oct 2025 22:13:19 +0000 Subject: [PATCH] Fix INTERPRETER_EXIT tracing --- Include/internal/pycore_ceval.h | 3 + Include/internal/pycore_code.h | 6 ++ .../pycore_global_objects_fini_generated.h | 1 + Include/internal/pycore_global_strings.h | 1 + Include/internal/pycore_opcode_metadata.h | 4 +- .../internal/pycore_runtime_init_generated.h | 1 + .../internal/pycore_unicodeobject_generated.h | 4 + Python/bytecodes.c | 54 ++++++++------ Python/ceval.c | 53 ++++++++++--- Python/generated_cases.c.h | 74 +++++++++++-------- Python/optimizer.c | 31 +++----- Python/specialize.c | 6 -- 12 files changed, 148 insertions(+), 90 deletions(-) diff --git a/Include/internal/pycore_ceval.h b/Include/internal/pycore_ceval.h index 102a378f8f08..61917b01b7cb 100644 --- a/Include/internal/pycore_ceval.h +++ b/Include/internal/pycore_ceval.h @@ -391,6 +391,9 @@ _PyForIter_VirtualIteratorNext(PyThreadState* tstate, struct _PyInterpreterFrame #define SPECIAL___AEXIT__ 3 #define SPECIAL_MAX 3 +struct _PyCode12 _PyCode_DEF(12); +PyAPI_DATA(const struct _PyCode12) _PyEntryFrameCode; + #ifdef __cplusplus } #endif diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 2d7d81d491c1..434f47374f79 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -672,6 +672,12 @@ PyAPI_FUNC(int) _PyCode_ReturnsOnlyNone(PyCodeObject *); * compare bytes and str which can raise a BytesWarning exception. */ extern PyObject* _PyCode_ConstantKey(PyObject *obj); +#define NO_LOC_4 (128 | (PY_CODE_LOCATION_INFO_NONE << 3) | 3) + +static const PyBytesObject no_location = { + PyVarObject_HEAD_INIT(&PyBytes_Type, 1) + .ob_sval = { NO_LOC_4 } +}; #ifdef __cplusplus } diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 92ded14891a1..4e0a2a452728 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -1344,6 +1344,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(TextIOWrapper)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(True)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(WarningMessage)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_PyEval_EvalFrameDefault)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(_WindowsConsoleIO)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__IOBase_closed)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__abc_tpflags__)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index cd21b0847b7c..c150948e432c 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -67,6 +67,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(TextIOWrapper) STRUCT_FOR_ID(True) STRUCT_FOR_ID(WarningMessage) + STRUCT_FOR_ID(_PyEval_EvalFrameDefault) STRUCT_FOR_ID(_WindowsConsoleIO) STRUCT_FOR_ID(__IOBase_closed) STRUCT_FOR_ID(__abc_tpflags__) diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h index 8dda65a55b34..aa99a0c50406 100644 --- a/Include/internal/pycore_opcode_metadata.h +++ b/Include/internal/pycore_opcode_metadata.h @@ -1148,7 +1148,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [END_ASYNC_FOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG }, [END_FOR] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NO_SAVE_IP_FLAG }, [END_SEND] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_PURE_FLAG }, - [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, + [ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [EXIT_INIT_CHECK] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [EXTENDED_ARG] = { true, INSTR_FMT_IB, HAS_ARG_FLAG }, [FORMAT_SIMPLE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, @@ -1187,7 +1187,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = { [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, [INSTRUMENTED_RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [INSTRUMENTED_YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG }, - [INTERPRETER_EXIT] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG }, + [INTERPRETER_EXIT] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [IS_OP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ESCAPES_FLAG }, [JUMP_BACKWARD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, [JUMP_BACKWARD_JIT] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG }, diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 50d82d0a3650..0212a141fe2e 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -1342,6 +1342,7 @@ extern "C" { INIT_ID(TextIOWrapper), \ INIT_ID(True), \ INIT_ID(WarningMessage), \ + INIT_ID(_PyEval_EvalFrameDefault), \ INIT_ID(_WindowsConsoleIO), \ INIT_ID(__IOBase_closed), \ INIT_ID(__abc_tpflags__), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index b4d920154b6e..e1a5838dd074 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -56,6 +56,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(_PyEval_EvalFrameDefault); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(_WindowsConsoleIO); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index beed5e091b6f..d665f7db9c5d 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -170,7 +170,9 @@ dummy_func( op(_QUICKEN_RESUME, (--)) { #if ENABLE_SPECIALIZATION_FT - if (tstate->tracing == 0 && this_instr->op.code == RESUME) { + PyCodeObject *code = _PyFrame_GetCode(frame); + if (tstate->tracing == 0 && this_instr->op.code == RESUME && + code != (PyCodeObject *)&_Py_InitCleanup && code != (PyCodeObject *)&_PyEntryFrameCode) { FT_ATOMIC_STORE_UINT8_RELAXED(this_instr->op.code, RESUME_CHECK); } #endif /* ENABLE_SPECIALIZATION_FT */ @@ -1218,19 +1220,33 @@ dummy_func( tstate->current_frame = frame->previous; assert(!_PyErr_Occurred(tstate)); PyObject *result = PyStackRef_AsPyObjectSteal(retval); + if (IS_JIT_TRACING()) { +#if _Py_TIER2 + _PyJit_translate_single_bytecode_to_trace(tstate, frame, next_instr); + LEAVE_TRACING(); + int err = bail_tracing_and_jit(tstate, frame); + if (err < 0) { + Py_DECREF(result); + ERROR_IF(true); + } + return result; +#endif + } + else { #if !_Py_TAIL_CALL_INTERP - assert(frame == &entry.frame); + assert(frame == &entry.frame); #endif #ifdef _Py_TIER2 - _PyStackRef executor = frame->localsplus[0]; - assert(tstate->current_executor == NULL); - if (!PyStackRef_IsNull(executor)) { - tstate->current_executor = PyStackRef_AsPyObjectBorrow(executor); - PyStackRef_CLOSE(executor); - } + _PyStackRef executor = frame->localsplus[0]; + assert(tstate->current_executor == NULL); + if (!PyStackRef_IsNull(executor)) { + tstate->current_executor = PyStackRef_AsPyObjectBorrow(executor); + PyStackRef_CLOSE(executor); + } #endif - LLTRACE_RESUME_FRAME(); - return result; + LLTRACE_RESUME_FRAME(); + return result; + } } // The stack effect here is a bit misleading. @@ -3020,15 +3036,6 @@ dummy_func( tier1 inst(ENTER_EXECUTOR, (--)) { #ifdef _Py_TIER2 - // We want to end any current trace here, before we possibly need - // to start tracing new ones due to recursive traces in any inner C functions - // in tier2 code. - if (IS_JIT_TRACING()) { - _PyJit_translate_single_bytecode_to_trace(tstate, frame, next_instr); - LEAVE_TRACING(); - int err = bail_tracing_and_jit(tstate, frame); - ERROR_IF(err < 0); - } PyCodeObject *code = _PyFrame_GetCode(frame); _PyExecutorObject *executor = code->co_executors->executors[oparg & 255]; assert(executor->vm_data.index == INSTR_OFFSET() - 1); @@ -3038,14 +3045,19 @@ dummy_func( /* If the eval breaker is set then stay in tier 1. * This avoids any potentially infinite loops * involving _RESUME_CHECK */ - if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + if (IS_JIT_TRACING() || _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { opcode = executor->vm_data.opcode; oparg = (oparg & ~255) | executor->vm_data.oparg; next_instr = this_instr; if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]]) { PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter); } - DISPATCH_GOTO(); + if (IS_JIT_TRACING()) { + DISPATCH_GOTO_NON_TRACING(); + } + else { + DISPATCH_GOTO(); + } } assert(executor != tstate->interp->cold_executor); tstate->jit_exit = NULL; diff --git a/Python/ceval.c b/Python/ceval.c index 76b09488c3b8..f2dd8fc6e8d7 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -931,14 +931,39 @@ int _Py_CheckRecursiveCallPy( return 0; } -static const _Py_CODEUNIT _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS[] = { - /* Put a NOP at the start, so that the IP points into - * the code, rather than before it */ - { .op.code = NOP, .op.arg = 0 }, - { .op.code = INTERPRETER_EXIT, .op.arg = 0 }, /* reached on return */ - { .op.code = NOP, .op.arg = 0 }, - { .op.code = INTERPRETER_EXIT, .op.arg = 0 }, /* reached on yield */ - { .op.code = RESUME, .op.arg = RESUME_OPARG_DEPTH1_MASK | RESUME_AT_FUNC_START } + +#ifdef Py_GIL_DISABLED +static _PyCodeArray emtry_cleanup_tlbc = { + .size = 1, + .entries = {(char*) &_PyEntryFrameCode.co_code_adaptive}, +}; +#endif + +const struct _PyCode12 _PyEntryFrameCode = { + _PyVarObject_HEAD_INIT(&PyCode_Type, 5), + .co_consts = (PyObject *)&_Py_SINGLETON(tuple_empty), + .co_names = (PyObject *)&_Py_SINGLETON(tuple_empty), + .co_exceptiontable = (PyObject *)&_Py_SINGLETON(bytes_empty), + .co_flags = CO_OPTIMIZED | CO_NO_MONITORING_EVENTS, + .co_localsplusnames = (PyObject *)&_Py_SINGLETON(tuple_empty), + .co_localspluskinds = (PyObject *)&_Py_SINGLETON(bytes_empty), + .co_filename = &_Py_ID(_PyEval_EvalFrameDefault), + .co_name = &_Py_ID(_PyEval_EvalFrameDefault), + .co_qualname = &_Py_ID(_PyEval_EvalFrameDefault), + .co_linetable = (PyObject *)&no_location, + ._co_firsttraceable = 4, + .co_stacksize = 2, + .co_framesize = 2 + FRAME_SPECIALS_SIZE, +#ifdef Py_GIL_DISABLED + .co_tlbc = &emtry_cleanup_tlbc, +#endif + .co_code_adaptive = { + NOP, 0, + INTERPRETER_EXIT, 0, /* reached on return */ + NOP, 0, + INTERPRETER_EXIT, 0, /* reached on yield */ + RESUME, RESUME_OPARG_DEPTH1_MASK | RESUME_AT_FUNC_START + } }; #ifdef Py_DEBUG @@ -1014,7 +1039,13 @@ bail_tracing_and_jit(PyThreadState *tstate, _PyInterpreterFrame *frame) // Likewise, we hold a strong reference to the executor containing this exit, so the exit is guaranteed // to be valid to access. if (err <= 0) { - exit->temperature = restart_backoff_counter(exit->temperature); + // Some opcodes will forever be unchanged. Don't ever bother specializing for them ever again. + if (tstate->interp->jit_state.prev_instr->op.code == INTERPRETER_EXIT) { + exit->temperature = initial_unreachable_backoff_counter(); + } + else { + exit->temperature = restart_backoff_counter(exit->temperature); + } } else { exit->temperature = initial_temperature_backoff_counter(); @@ -1105,8 +1136,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int entry.frame.f_globals = (PyObject*)0xaaa3; entry.frame.f_builtins = (PyObject*)0xaaa4; #endif - entry.frame.f_executable = PyStackRef_None; - entry.frame.instr_ptr = (_Py_CODEUNIT *)_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS + 1; + entry.frame.f_executable = PyStackRef_FromPyObjectBorrow((PyObject *)&_PyEntryFrameCode); + entry.frame.instr_ptr = ((_Py_CODEUNIT *)_PyEntryFrameCode.co_code_adaptive) + 1; entry.frame.stackpointer = entry.stack; entry.frame.owner = FRAME_OWNED_BY_INTERPRETER; entry.frame.visited = 0; diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index c0dbf3091f45..10a1793ad284 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -5491,33 +5491,25 @@ INSTRUCTION_STATS(ENTER_EXECUTOR); opcode = ENTER_EXECUTOR; #ifdef _Py_TIER2 - - if (IS_JIT_TRACING()) { - _PyFrame_SetStackPointer(frame, stack_pointer); - _PyJit_translate_single_bytecode_to_trace(tstate, frame, next_instr); - stack_pointer = _PyFrame_GetStackPointer(frame); - LEAVE_TRACING(); - _PyFrame_SetStackPointer(frame, stack_pointer); - int err = bail_tracing_and_jit(tstate, frame); - stack_pointer = _PyFrame_GetStackPointer(frame); - if (err < 0) { - JUMP_TO_LABEL(error); - } - } PyCodeObject *code = _PyFrame_GetCode(frame); _PyExecutorObject *executor = code->co_executors->executors[oparg & 255]; assert(executor->vm_data.index == INSTR_OFFSET() - 1); assert(executor->vm_data.code == code); assert(executor->vm_data.valid); assert(tstate->current_executor == NULL); - if (_Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { + if (IS_JIT_TRACING() || _Py_atomic_load_uintptr_relaxed(&tstate->eval_breaker) & _PY_EVAL_EVENTS_MASK) { opcode = executor->vm_data.opcode; oparg = (oparg & ~255) | executor->vm_data.oparg; next_instr = this_instr; if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]]) { PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter); } - DISPATCH_GOTO(); + if (IS_JIT_TRACING()) { + DISPATCH_GOTO_NON_TRACING(); + } + else { + DISPATCH_GOTO(); + } } assert(executor != tstate->interp->cold_executor); tstate->jit_exit = NULL; @@ -7553,24 +7545,46 @@ tstate->current_frame = frame->previous; assert(!_PyErr_Occurred(tstate)); PyObject *result = PyStackRef_AsPyObjectSteal(retval); - #if !_Py_TAIL_CALL_INTERP - assert(frame == &entry.frame); - #endif - #ifdef _Py_TIER2 - _PyStackRef executor = frame->localsplus[0]; - assert(tstate->current_executor == NULL); - if (!PyStackRef_IsNull(executor)) { - tstate->current_executor = PyStackRef_AsPyObjectBorrow(executor); + if (IS_JIT_TRACING()) { + #if _Py_TIER2 stack_pointer += -1; assert(WITHIN_STACK_BOUNDS()); _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(executor); + _PyJit_translate_single_bytecode_to_trace(tstate, frame, next_instr); stack_pointer = _PyFrame_GetStackPointer(frame); - stack_pointer += 1; + LEAVE_TRACING(); + _PyFrame_SetStackPointer(frame, stack_pointer); + int err = bail_tracing_and_jit(tstate, frame); + stack_pointer = _PyFrame_GetStackPointer(frame); + if (err < 0) { + _PyFrame_SetStackPointer(frame, stack_pointer); + Py_DECREF(result); + stack_pointer = _PyFrame_GetStackPointer(frame); + JUMP_TO_LABEL(error); + } + return result; + #endif + } + else { + #if !_Py_TAIL_CALL_INTERP + assert(frame == &entry.frame); + #endif + #ifdef _Py_TIER2 + _PyStackRef executor = frame->localsplus[0]; + assert(tstate->current_executor == NULL); + if (!PyStackRef_IsNull(executor)) { + tstate->current_executor = PyStackRef_AsPyObjectBorrow(executor); + stack_pointer += -1; + assert(WITHIN_STACK_BOUNDS()); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(executor); + stack_pointer = _PyFrame_GetStackPointer(frame); + stack_pointer += 1; + } + #endif + LLTRACE_RESUME_FRAME(); + return result; } - #endif - LLTRACE_RESUME_FRAME(); - return result; } TARGET(IS_OP) { @@ -10325,7 +10339,9 @@ // _QUICKEN_RESUME { #if ENABLE_SPECIALIZATION_FT - if (tstate->tracing == 0 && this_instr->op.code == RESUME) { + PyCodeObject *code = _PyFrame_GetCode(frame); + if (tstate->tracing == 0 && this_instr->op.code == RESUME && + code != (PyCodeObject *)&_Py_InitCleanup && code != (PyCodeObject *)&_PyEntryFrameCode) { FT_ATOMIC_STORE_UINT8_RELAXED(this_instr->op.code, RESUME_CHECK); } #endif /* ENABLE_SPECIALIZATION_FT */ diff --git a/Python/optimizer.c b/Python/optimizer.c index 4a61509112ba..a3ae74fd944a 100644 --- a/Python/optimizer.c +++ b/Python/optimizer.c @@ -34,7 +34,7 @@ static bool has_space_for_executor(PyCodeObject *code, _Py_CODEUNIT *instr) { - if (code == (PyCodeObject *)&_Py_InitCleanup) { + if (code == (PyCodeObject *)&_Py_InitCleanup || code == (PyCodeObject *)&_PyEntryFrameCode) { return false; } if (instr->op.code == ENTER_EXECUTOR) { @@ -133,11 +133,6 @@ _PyOptimizer_Optimize( bool progress_needed = chain_depth == 0; PyCodeObject *code = (PyCodeObject *)tstate->interp->jit_state.initial_code; _Py_CODEUNIT *start = tstate->interp->jit_state.insert_exec_instr; - // A recursive trace might've cleared the values. In that case, bail. - if (code == NULL) { - interp->compiling = false; - return 0; - } if (progress_needed && !has_space_for_executor(code, start)) { interp->compiling = false; return 0; @@ -619,11 +614,6 @@ _PyJit_translate_single_bytecode_to_trace( } if (opcode == ENTER_EXECUTOR) { - int is_first_instr = tstate->interp->jit_state.close_loop_instr == next_instr || tstate->interp->jit_state.insert_exec_instr == next_instr; - if (is_first_instr && tstate->interp->jit_state.code_curr_size > 5) { - ADD_TO_TRACE(_JUMP_TO_TOP, 0, 0, 0); - goto done; - } goto full; } @@ -658,11 +648,6 @@ _PyJit_translate_single_bytecode_to_trace( if (opcode == WITH_EXCEPT_START || opcode == RERAISE || opcode == CLEANUP_THROW || opcode == PUSH_EXC_INFO) { DPRINTF(2, "Unsupported: strange control-flow\n"); - goto unsupported; - } - - if (frame->owner >= FRAME_OWNED_BY_INTERPRETER) { - DPRINTF(2, "Unsupported: frame owned by interpreter\n"); unsupported: { // Rewind to previous instruction and replace with _EXIT_TRACE. @@ -977,7 +962,7 @@ _PyJit_TryInitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame, _ tstate->interp->jit_state.insert_exec_instr = insert_exec_instr; tstate->interp->jit_state.close_loop_instr = close_loop_instr; tstate->interp->jit_state.initial_code = (PyCodeObject *)Py_NewRef(code); - tstate->interp->jit_state.initial_func = (PyFunctionObject *)Py_NewRef(_PyFrame_GetFunction(frame)); + tstate->interp->jit_state.initial_func = (PyFunctionObject *)Py_XNewRef(PyStackRef_AsPyObjectBorrow(frame->f_funcobj)); tstate->interp->jit_state.prev_exit = exit; tstate->interp->jit_state.initial_stack_depth = curr_stackdepth; tstate->interp->jit_state.initial_chain_depth = chain_depth; @@ -1580,11 +1565,15 @@ _Py_ExecutorDetach(_PyExecutorObject *executor) return; } _Py_CODEUNIT *instruction = &_PyCode_CODE(code)[executor->vm_data.index]; - assert(instruction->op.code == ENTER_EXECUTOR); int index = instruction->op.arg; - assert(code->co_executors->executors[index] == executor); - instruction->op.code = executor->vm_data.opcode; - instruction->op.arg = executor->vm_data.oparg; + // Due to a combination of re-entrancy and tracing, it's possible for an + // instruction to no longer be ENTER_EXECUTOR. In which case, no-op. + if (instruction->op.code == ENTER_EXECUTOR) { + assert(instruction->op.code == ENTER_EXECUTOR); + assert(code->co_executors->executors[index] == executor); + instruction->op.code = executor->vm_data.opcode; + instruction->op.arg = executor->vm_data.oparg; + } executor->vm_data.code = NULL; code->co_executors->executors[index] = NULL; Py_DECREF(executor); diff --git a/Python/specialize.c b/Python/specialize.c index a1c5dedd6156..0583873e09d2 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -3196,12 +3196,6 @@ _Py_GatherStats_GetIter(_PyStackRef iterable) * be lifted. */ -#define NO_LOC_4 (128 | (PY_CODE_LOCATION_INFO_NONE << 3) | 3) - -static const PyBytesObject no_location = { - PyVarObject_HEAD_INIT(&PyBytes_Type, 1) - .ob_sval = { NO_LOC_4 } -}; #ifdef Py_GIL_DISABLED static _PyCodeArray init_cleanup_tlbc = { -- 2.47.3