summaryrefslogtreecommitdiffstats
path: root/Python/ceval.c
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2022-01-06 13:09:25 (GMT)
committerGitHub <noreply@github.com>2022-01-06 13:09:25 (GMT)
commite028ae99ecee671c0e8a3eabb829b5b2acfc4441 (patch)
tree497e68f1caeb92104bf3a464977bb0e024131f69 /Python/ceval.c
parent3e43fac2503afe219336742b150b3ef6e470686f (diff)
downloadcpython-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.c117
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) {