diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 8c0b55c15a8c7e..291684b33a3e27 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -63,6 +63,7 @@ typedef struct _PyInterpreterFrame { // example, it may be an inline CACHE entry, an instruction we just jumped // over, or (in the case of a newly-created frame) a totally invalid value: _Py_CODEUNIT *prev_instr; + _Py_CODEUNIT *prev_traced_instr; /* The instruction that is currently executing (possibly not started yet). */ _Py_CODEUNIT *instr_ptr; int stacktop; /* Offset of TOS from localsplus */ @@ -173,6 +174,7 @@ _PyFrame_Initialize( frame->f_locals = locals; frame->stacktop = code->co_nlocalsplus; frame->frame_obj = NULL; + frame->prev_traced_instr = NULL; frame->prev_instr = _PyCode_CODE(code) - 1; frame->instr_ptr = _PyCode_CODE(code); frame->return_offset = 0; @@ -339,6 +341,7 @@ _PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int frame->f_locals = NULL; frame->stacktop = code->co_nlocalsplus + stackdepth; frame->frame_obj = NULL; + frame->prev_traced_instr = NULL; frame->prev_instr = _PyCode_CODE(code) + previous_instr; frame->instr_ptr = _PyCode_CODE(code) + previous_instr + 1; frame->owner = FRAME_OWNED_BY_THREAD; diff --git a/Python/ceval.c b/Python/ceval.c index 0522d46eab35ed..4b2083c40b8616 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -791,8 +791,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int case INSTRUMENTED_LINE: #endif { - _Py_CODEUNIT *prev = frame->prev_instr; - _Py_CODEUNIT *here = frame->instr_ptr = frame->prev_instr = next_instr; + DUMP_FRAME("INSTRUMENTED_LINE"); + _Py_CODEUNIT *prev = frame->prev_traced_instr; + _Py_CODEUNIT *here = frame->instr_ptr = frame->prev_instr = frame->prev_traced_instr = next_instr; _PyFrame_SetStackPointer(frame, stack_pointer); int original_opcode = _Py_call_instrumentation_line( tstate, frame, here, prev); @@ -801,7 +802,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int next_instr = here+1; goto error; } - next_instr = frame->prev_instr; + next_instr = frame->prev_traced_instr; if (next_instr != here) { DISPATCH(); } diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 0768c82ba29882..c3ead0d5575b4f 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -1120,7 +1120,6 @@ _Py_Instrumentation_GetLine(PyCodeObject *code, int index) int _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *prev) { - assert(frame->prev_instr == instr); PyCodeObject *code = _PyFrame_GetCode(frame); assert(is_version_up_to_date(code, tstate->interp)); assert(instrumentation_cross_checks(tstate->interp, code)); @@ -1135,15 +1134,17 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, int8_t line_delta = line_data->line_delta; int line = compute_line(code, i, line_delta); assert(line >= 0); - int prev_index = (int)(prev - _PyCode_CODE(code)); - int prev_line = _Py_Instrumentation_GetLine(code, prev_index); - if (prev_line == line) { - int prev_opcode = _PyCode_CODE(code)[prev_index].op.code; - /* RESUME and INSTRUMENTED_RESUME are needed for the operation of - * instrumentation, so must never be hidden by an INSTRUMENTED_LINE. - */ - if (prev_opcode != RESUME && prev_opcode != INSTRUMENTED_RESUME) { - goto done; + if (prev != NULL) { + int prev_index = (int)(prev - _PyCode_CODE(code)); + int prev_line = _Py_Instrumentation_GetLine(code, prev_index); + if (prev_line == line) { + int prev_opcode = _PyCode_CODE(code)[prev_index].op.code; + /* RESUME and INSTRUMENTED_RESUME are needed for the operation of + * instrumentation, so must never be hidden by an INSTRUMENTED_LINE. + */ + if (prev_opcode != RESUME && prev_opcode != INSTRUMENTED_RESUME) { + goto done; + } } } uint8_t tools = code->_co_monitoring->line_tools != NULL ?