diff options
author | Mark Shannon <mark@hotpy.org> | 2022-01-06 13:09:25 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-06 13:09:25 (GMT) |
commit | e028ae99ecee671c0e8a3eabb829b5b2acfc4441 (patch) | |
tree | 497e68f1caeb92104bf3a464977bb0e024131f69 /Python/ceval.c | |
parent | 3e43fac2503afe219336742b150b3ef6e470686f (diff) | |
download | cpython-e028ae99ecee671c0e8a3eabb829b5b2acfc4441.zip cpython-e028ae99ecee671c0e8a3eabb829b5b2acfc4441.tar.gz cpython-e028ae99ecee671c0e8a3eabb829b5b2acfc4441.tar.bz2 |
bpo-45923: Handle call events in bytecode (GH-30364)
* Add a RESUME instruction to handle "call" events.
Diffstat (limited to 'Python/ceval.c')
-rw-r--r-- | Python/ceval.c | 117 |
1 files changed, 73 insertions, 44 deletions
diff --git a/Python/ceval.c b/Python/ceval.c index 86d834c..be26ffd 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1546,6 +1546,17 @@ eval_frame_handle_pending(PyThreadState *tstate) #define TRACE_FUNCTION_ENTRY() \ if (cframe.use_tracing) { \ + _PyFrame_SetStackPointer(frame, stack_pointer); \ + int err = trace_function_entry(tstate, frame); \ + stack_pointer = _PyFrame_GetStackPointer(frame); \ + if (err) { \ + goto error; \ + } \ + } + +#define TRACE_FUNCTION_THROW_ENTRY() \ + if (cframe.use_tracing) { \ + assert(frame->stacktop >= 0); \ if (trace_function_entry(tstate, frame)) { \ goto exit_unwind; \ } \ @@ -1694,7 +1705,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr tstate->recursion_remaining--; goto exit_unwind; } - TRACE_FUNCTION_ENTRY(); + TRACE_FUNCTION_THROW_ENTRY(); DTRACE_FUNCTION_ENTRY(); goto resume_with_error; } @@ -1734,17 +1745,6 @@ start_frame: goto exit_unwind; } - assert(tstate->cframe == &cframe); - assert(frame == cframe.current_frame); - - TRACE_FUNCTION_ENTRY(); - DTRACE_FUNCTION_ENTRY(); - - if (_Py_IncrementCountAndMaybeQuicken(frame->f_code) < 0) { - goto exit_unwind; - } - frame->f_state = FRAME_EXECUTING; - resume_frame: SET_LOCALS_FROM_FRAME(); @@ -1825,6 +1825,24 @@ check_eval_breaker: DISPATCH(); } + TARGET(RESUME) { + assert(tstate->cframe == &cframe); + assert(frame == cframe.current_frame); + + int err = _Py_IncrementCountAndMaybeQuicken(frame->f_code); + if (err) { + if (err < 0) { + goto error; + } + /* Update first_instr and next_instr to point to newly quickened code */ + int nexti = INSTR_OFFSET(); + first_instr = frame->f_code->co_firstinstr; + next_instr = first_instr + nexti; + } + frame->f_state = FRAME_EXECUTING; + DISPATCH(); + } + TARGET(LOAD_CLOSURE) { /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ PyObject *value = GETLOCAL(oparg); @@ -3134,7 +3152,7 @@ check_eval_breaker: PyObject *initial = GETLOCAL(oparg); PyObject *cell = PyCell_New(initial); if (cell == NULL) { - goto error; + goto resume_with_error; } SETLOCAL(oparg, cell); DISPATCH(); @@ -5209,33 +5227,40 @@ check_eval_breaker: int instr_prev = skip_backwards_over_extended_args(frame->f_code, frame->f_lasti); frame->f_lasti = INSTR_OFFSET(); TRACING_NEXTOPARG(); - if (PyDTrace_LINE_ENABLED()) { - maybe_dtrace_line(frame, &tstate->trace_info, instr_prev); + if (opcode == RESUME) { + /* Call tracing */ + TRACE_FUNCTION_ENTRY(); + DTRACE_FUNCTION_ENTRY(); } - /* line-by-line tracing support */ - - if (cframe.use_tracing && - tstate->c_tracefunc != NULL && !tstate->tracing) { - int err; - /* see maybe_call_line_trace() - for expository comments */ - _PyFrame_SetStackPointer(frame, stack_pointer); - - err = maybe_call_line_trace(tstate->c_tracefunc, - tstate->c_traceobj, - tstate, frame, instr_prev); - if (err) { - /* trace function raised an exception */ - next_instr++; - goto error; + else { + /* line-by-line tracing support */ + if (PyDTrace_LINE_ENABLED()) { + maybe_dtrace_line(frame, &tstate->trace_info, instr_prev); } - /* Reload possibly changed frame fields */ - JUMPTO(frame->f_lasti); - stack_pointer = _PyFrame_GetStackPointer(frame); - frame->stacktop = -1; - TRACING_NEXTOPARG(); + if (cframe.use_tracing && + tstate->c_tracefunc != NULL && !tstate->tracing) { + int err; + /* see maybe_call_line_trace() + for expository comments */ + _PyFrame_SetStackPointer(frame, stack_pointer); + + err = maybe_call_line_trace(tstate->c_tracefunc, + tstate->c_traceobj, + tstate, frame, instr_prev); + if (err) { + /* trace function raised an exception */ + next_instr++; + goto error; + } + /* Reload possibly changed frame fields */ + JUMPTO(frame->f_lasti); + + stack_pointer = _PyFrame_GetStackPointer(frame); + frame->stacktop = -1; + } } + TRACING_NEXTOPARG(); PRE_DISPATCH_GOTO(); DISPATCH_GOTO(); } @@ -6046,6 +6071,7 @@ _PyEval_Vector(PyThreadState *tstate, PyFunctionObject *func, return NULL; } PyObject *retval = _PyEval_EvalFrame(tstate, frame, 0); + assert(frame->stacktop >= 0); assert(_PyFrame_GetStackPointer(frame) == _PyFrame_Stackbase(frame)); _PyEvalFrameClearAndPop(tstate, frame); return retval; @@ -6492,13 +6518,9 @@ call_trace(Py_tracefunc func, PyObject *obj, if (f == NULL) { return -1; } - if (frame->f_lasti < 0) { - f->f_lineno = frame->f_code->co_firstlineno; - } - else { - initialize_trace_info(&tstate->trace_info, frame); - f->f_lineno = _PyCode_CheckLineNumber(frame->f_lasti*sizeof(_Py_CODEUNIT), &tstate->trace_info.bounds); - } + assert (frame->f_lasti >= 0); + initialize_trace_info(&tstate->trace_info, frame); + f->f_lineno = _PyCode_CheckLineNumber(frame->f_lasti*sizeof(_Py_CODEUNIT), &tstate->trace_info.bounds); result = func(obj, f, what, arg); f->f_lineno = 0; _PyThreadState_ResumeTracing(tstate); @@ -6534,7 +6556,14 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, then call the trace function if we're tracing source lines. */ initialize_trace_info(&tstate->trace_info, frame); - int lastline = _PyCode_CheckLineNumber(instr_prev*sizeof(_Py_CODEUNIT), &tstate->trace_info.bounds); + _Py_CODEUNIT prev = ((_Py_CODEUNIT *)PyBytes_AS_STRING(frame->f_code->co_code))[instr_prev]; + int lastline; + if (_Py_OPCODE(prev) == RESUME && _Py_OPARG(prev) == 0) { + lastline = -1; + } + else { + lastline = _PyCode_CheckLineNumber(instr_prev*sizeof(_Py_CODEUNIT), &tstate->trace_info.bounds); + } int line = _PyCode_CheckLineNumber(frame->f_lasti*sizeof(_Py_CODEUNIT), &tstate->trace_info.bounds); PyFrameObject *f = _PyFrame_GetFrameObject(frame); if (f == NULL) { |