diff options
author | Mark Shannon <mark@hotpy.org> | 2023-05-12 11:21:20 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-12 11:21:20 (GMT) |
commit | 45f5aa8fc73acf516071d52ef8213532f0381316 (patch) | |
tree | bc1f7219305185a7befef7003688d7a4359f98e4 /Python/legacy_tracing.c | |
parent | 19ee53d52e8adf267dfd588c2142967734a3b65a (diff) | |
download | cpython-45f5aa8fc73acf516071d52ef8213532f0381316.zip cpython-45f5aa8fc73acf516071d52ef8213532f0381316.tar.gz cpython-45f5aa8fc73acf516071d52ef8213532f0381316.tar.bz2 |
GH-103082: Filter LINE events in VM, to simplify tool implementation. (GH-104387)
When monitoring LINE events, instrument all instructions that can have a predecessor on a different line.
Then check that the a new line has been hit in the instrumentation code.
This brings the behavior closer to that of 3.11, simplifying implementation and porting of tools.
Diffstat (limited to 'Python/legacy_tracing.c')
-rw-r--r-- | Python/legacy_tracing.c | 73 |
1 files changed, 19 insertions, 54 deletions
diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c index e509e63..5143b79 100644 --- a/Python/legacy_tracing.c +++ b/Python/legacy_tracing.c @@ -4,6 +4,7 @@ #include <stddef.h> #include "Python.h" +#include "opcode.h" #include "pycore_ceval.h" #include "pycore_object.h" #include "pycore_sysmodule.h" @@ -213,7 +214,6 @@ trace_line( if (line < 0) { Py_RETURN_NONE; } - frame ->f_last_traced_line = line; Py_INCREF(frame); frame->f_lineno = line; int err = tstate->c_tracefunc(tstate->c_traceobj, frame, self->event, Py_None); @@ -245,14 +245,12 @@ sys_trace_line_func( return NULL; } assert(args[0] == (PyObject *)frame->f_frame->f_code); - if (frame ->f_last_traced_line == line) { - /* Already traced this line */ - Py_RETURN_NONE; - } return trace_line(tstate, self, frame, line); } - +/* sys.settrace generates line events for all backward + * edges, even if on the same line. + * Handle that case here */ static PyObject * sys_trace_jump_func( _PyLegacyEventHandler *self, PyObject *const *args, @@ -268,61 +266,33 @@ sys_trace_jump_func( assert(from >= 0); int to = _PyLong_AsInt(args[2])/sizeof(_Py_CODEUNIT); assert(to >= 0); - PyFrameObject *frame = PyEval_GetFrame(); - if (frame == NULL) { - PyErr_SetString(PyExc_SystemError, - "Missing frame when calling trace function."); - return NULL; - } - if (!frame->f_trace_lines) { - Py_RETURN_NONE; + if (to > from) { + /* Forward jump */ + return &_PyInstrumentation_DISABLE; } PyCodeObject *code = (PyCodeObject *)args[0]; assert(PyCode_Check(code)); - assert(code == frame->f_frame->f_code); /* We can call _Py_Instrumentation_GetLine because we always set * line events for tracing */ int to_line = _Py_Instrumentation_GetLine(code, to); - /* Backward jump: Always generate event - * Forward jump: Only generate event if jumping to different line. */ - if (to > from && frame->f_last_traced_line == to_line) { - /* Already traced this line */ - Py_RETURN_NONE; + int from_line = _Py_Instrumentation_GetLine(code, from); + if (to_line != from_line) { + /* Will be handled by target INSTRUMENTED_LINE */ + return &_PyInstrumentation_DISABLE; } - return trace_line(tstate, self, frame, to_line); -} - -/* We don't care about the exception here, - * we just treat it as a possible new line - */ -static PyObject * -sys_trace_exception_handled( - _PyLegacyEventHandler *self, PyObject *const *args, - size_t nargsf, PyObject *kwnames -) { - assert(kwnames == NULL); - PyThreadState *tstate = _PyThreadState_GET(); - if (tstate->c_tracefunc == NULL) { - Py_RETURN_NONE; - } - assert(PyVectorcall_NARGS(nargsf) == 3); PyFrameObject *frame = PyEval_GetFrame(); - PyCodeObject *code = (PyCodeObject *)args[0]; - assert(PyCode_Check(code)); + if (frame == NULL) { + PyErr_SetString(PyExc_SystemError, + "Missing frame when calling trace function."); + return NULL; + } assert(code == frame->f_frame->f_code); - assert(PyLong_Check(args[1])); - int offset = _PyLong_AsInt(args[1])/sizeof(_Py_CODEUNIT); - /* We can call _Py_Instrumentation_GetLine because we always set - * line events for tracing */ - int line = _Py_Instrumentation_GetLine(code, offset); - if (frame->f_last_traced_line == line) { - /* Already traced this line */ + if (!frame->f_trace_lines) { Py_RETURN_NONE; } - return trace_line(tstate, self, frame, line); + return trace_line(tstate, self, frame, to_line); } - PyTypeObject _PyLegacyEventHandler_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "sys.legacy_event_handler", @@ -487,7 +457,7 @@ _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) } if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, (vectorcallfunc)sys_trace_jump_func, PyTrace_LINE, - PY_MONITORING_EVENT_JUMP, PY_MONITORING_EVENT_BRANCH)) { + PY_MONITORING_EVENT_JUMP, -1)) { return -1; } if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, @@ -495,11 +465,6 @@ _PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) PY_MONITORING_EVENT_INSTRUCTION, -1)) { return -1; } - if (set_callbacks(PY_MONITORING_SYS_TRACE_ID, - (vectorcallfunc)sys_trace_exception_handled, PyTrace_LINE, - PY_MONITORING_EVENT_EXCEPTION_HANDLED, -1)) { - return -1; - } } int delta = (func != NULL) - (tstate->c_tracefunc != NULL); |