summaryrefslogtreecommitdiffstats
path: root/Python/legacy_tracing.c
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2023-05-12 11:21:20 (GMT)
committerGitHub <noreply@github.com>2023-05-12 11:21:20 (GMT)
commit45f5aa8fc73acf516071d52ef8213532f0381316 (patch)
treebc1f7219305185a7befef7003688d7a4359f98e4 /Python/legacy_tracing.c
parent19ee53d52e8adf267dfd588c2142967734a3b65a (diff)
downloadcpython-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.c73
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);