From bf06c2d13e13c1efd2eb31d7c14658a66c1b0b0e Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 18 Mar 2025 12:20:06 +0000 Subject: [PATCH 1/4] Initial implementation of support for 'code like' objects in sys.monitoring --- .../pycore_global_objects_fini_generated.h | 2 + Include/internal/pycore_global_strings.h | 2 + Include/internal/pycore_instruments.h | 4 +- .../internal/pycore_runtime_init_generated.h | 2 + .../internal/pycore_unicodeobject_generated.h | 8 ++ Lib/test/test_monitoring.py | 30 +++++++- Objects/codeobject.c | 73 +++++++++++++++++++ Python/instrumentation.c | 71 +++++++++++------- 8 files changed, 160 insertions(+), 32 deletions(-) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 90214a314031d1..4005a6ea222ff2 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -626,6 +626,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__fspath__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__ge__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__get__)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__get_local_events__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__getattr__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__getattribute__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__getinitargs__)); @@ -712,6 +713,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__rtruediv__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__rxor__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__set__)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__set_local_events__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__set_name__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__setattr__)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__setitem__)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 5056128dc97ca0..13615b66a3592b 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -117,6 +117,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(__fspath__) STRUCT_FOR_ID(__ge__) STRUCT_FOR_ID(__get__) + STRUCT_FOR_ID(__get_local_events__) STRUCT_FOR_ID(__getattr__) STRUCT_FOR_ID(__getattribute__) STRUCT_FOR_ID(__getinitargs__) @@ -203,6 +204,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(__rtruediv__) STRUCT_FOR_ID(__rxor__) STRUCT_FOR_ID(__set__) + STRUCT_FOR_ID(__set_local_events__) STRUCT_FOR_ID(__set_name__) STRUCT_FOR_ID(__setattr__) STRUCT_FOR_ID(__setitem__) diff --git a/Include/internal/pycore_instruments.h b/Include/internal/pycore_instruments.h index 0e85f97073dd67..cb0113206dd786 100644 --- a/Include/internal/pycore_instruments.h +++ b/Include/internal/pycore_instruments.h @@ -29,8 +29,8 @@ typedef uint32_t _PyMonitoringEventSet; PyObject *_PyMonitoring_RegisterCallback(int tool_id, int event_id, PyObject *obj); int _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events); -int _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet events); -int _PyMonitoring_GetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet *events); +int _PyMonitoring_SetLocalEvents(PyObject *codelike, int tool_id, _PyMonitoringEventSet events); +int _PyMonitoring_GetLocalEvents(PyObject *codelike, int tool_id, _PyMonitoringEventSet *events); extern int _Py_call_instrumentation(PyThreadState *tstate, int event, diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index 4f928cc050bf8e..e71f1657f33cee 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -624,6 +624,7 @@ extern "C" { INIT_ID(__fspath__), \ INIT_ID(__ge__), \ INIT_ID(__get__), \ + INIT_ID(__get_local_events__), \ INIT_ID(__getattr__), \ INIT_ID(__getattribute__), \ INIT_ID(__getinitargs__), \ @@ -710,6 +711,7 @@ extern "C" { INIT_ID(__rtruediv__), \ INIT_ID(__rxor__), \ INIT_ID(__set__), \ + INIT_ID(__set_local_events__), \ INIT_ID(__set_name__), \ INIT_ID(__setattr__), \ INIT_ID(__setitem__), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 5b78d038fc1192..5ba92291556c6d 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -256,6 +256,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(__get_local_events__); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__getattr__); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -600,6 +604,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(__set_local_events__); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(__set_name__); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py index 263e4e6f394155..dd59daffef1250 100644 --- a/Lib/test/test_monitoring.py +++ b/Lib/test/test_monitoring.py @@ -1412,7 +1412,6 @@ def check_events(self, func, expected, tool=TEST_TOOL, recorders=()): for recorder in recorders: sys.monitoring.register_callback(tool, recorder.event_type, None) - def test_simple(self): def func1(): @@ -1461,6 +1460,27 @@ def test_set_non_local_event(self): with self.assertRaises(ValueError): sys.monitoring.set_local_events(TEST_TOOL, just_call.__code__, E.RAISE) + + def test_code_like(self): + class CodeLike: + + def __init__(self): + self.events = [ 0 ] * 8 + + def __get_local_events__(self, tool): + return self.events[tool] + + def __set_local_events__(self, tool, events): + self.events[tool] = events + + codelike = CodeLike() + tool = TEST_TOOL + for events in ((E.LINE | E.PY_START), (E.BRANCH_LEFT | E.BRANCH_RIGHT), 0): + sys.monitoring.set_local_events(tool, codelike, events) + self.assertEqual(codelike.__get_local_events__(tool), events) + self.assertEqual(sys.monitoring.get_local_events(tool, codelike), events) + + def line_from_offset(code, offset): for start, end, line in code.co_lines(): if start <= offset < end: @@ -2062,7 +2082,13 @@ def f(): pass def test_get_local_events_uninitialized(self): - self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, self.f.__code__), 0) + with self.assertRaises(ValueError): + sys.monitoring.get_local_events(TEST_TOOL, self.f.__code__) + sys.monitoring.use_tool_id(TEST_TOOL, "test unitialized") + try: + self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, self.f.__code__), 0) + finally: + sys.monitoring.free_tool_id(TEST_TOOL) class TestRegressions(MonitoringTestBase, unittest.TestCase): diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 90f0bfb7b92b7e..4d251d02c81730 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1540,6 +1540,73 @@ code_positionsiterator(PyObject *self, PyObject* Py_UNUSED(args)) return (PyObject*)pi; } +static PyObject* +code_offset_to_position(PyObject *self, PyObject* offset) +{ + PyCodeObject *code = (PyCodeObject*)self; + int addrq; + int err = PyLong_AsInt32(offset, &addrq); + if (err != 0) { + return NULL; + } + positionsiterator pi; + pi.pi_code = (PyCodeObject*)Py_NewRef(code); + _PyCode_InitAddressRange(code, &pi.pi_range); + pi.pi_offset = pi.pi_range.ar_end; + while (pi.pi_range.ar_end <= addrq) { + if (pi.pi_offset >= pi.pi_range.ar_end) { + assert(pi.pi_offset == pi.pi_range.ar_end); + if (at_end(&pi.pi_range)) { + return NULL; + } + advance_with_locations(&pi.pi_range, &pi.pi_endline, &pi.pi_column, &pi.pi_endcolumn); + } + pi.pi_offset += 2; + } + return Py_BuildValue("(O&O&O&O&)", + _source_offset_converter, &pi.pi_range.ar_line, + _source_offset_converter, &pi.pi_endline, + _source_offset_converter, &pi.pi_column, + _source_offset_converter, &pi.pi_endcolumn); +} + +static PyObject* +code_get_local_events(PyObject *self, PyObject* tool) { + int tool_id; + int err = PyLong_AsInt32(tool, &tool_id); + if (err != 0) { + return NULL; + } + _PyMonitoringEventSet events; + err = _PyMonitoring_GetLocalEvents(self, tool_id, &events); + if (err != 0) { + return NULL; + } + return PyLong_FromUInt32(events); +} + +static PyObject* +code_set_local_events(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { + int tool_id; + _PyMonitoringEventSet events; + if (!_PyArg_CheckPositional("__set_local_events__", nargs, 2, 2)) { + return NULL; + } + int err = PyLong_AsInt32(args[0], &tool_id); + if (err != 0) { + return NULL; + } + err = PyLong_AsUInt32(args[1], &events); + if (err != 0) { + return NULL; + } + err = _PyMonitoring_SetLocalEvents(self, tool_id, events); + if (err != 0) { + return NULL; + } + Py_RETURN_NONE; +} + /****************** * "extra" frame eval info (see PEP 523) @@ -2394,6 +2461,9 @@ static struct PyMethodDef code_methods[] = { CODE__VARNAME_FROM_OPARG_METHODDEF {"__replace__", _PyCFunction_CAST(code_replace), METH_FASTCALL|METH_KEYWORDS, PyDoc_STR("__replace__($self, /, **changes)\n--\n\nThe same as replace().")}, + {"co_offset_to_position", code_offset_to_position, METH_O}, + {"__get_local_events__", code_get_local_events, METH_O}, + {"__set_local_events__", _PyCFunction_CAST(code_set_local_events), METH_FASTCALL}, {NULL, NULL} /* sentinel */ }; @@ -2802,6 +2872,9 @@ _PyCode_Fini(PyInterpreterState *interp) #endif } + + + #ifdef Py_GIL_DISABLED // Thread-local bytecode (TLBC) diff --git a/Python/instrumentation.c b/Python/instrumentation.c index 299066d9c206b6..b580e2e49d052d 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -2035,8 +2035,29 @@ _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events) } int -_PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet events) +_PyMonitoring_SetLocalEvents(PyObject *codelike, int tool_id, _PyMonitoringEventSet events) { + if (!PyCode_Check(codelike)) { + PyObject *tool = PyLong_FromInt32(tool_id); + assert(tool != NULL); + PyObject *events_obj = PyLong_FromUInt32(events); + if (events_obj == NULL) { + return -1; + } + PyObject *args[3] = { + codelike, + tool, + events_obj + }; + PyObject *res = PyObject_VectorcallMethod(&_Py_ID(__set_local_events__), args, 3, NULL); + Py_DECREF(events_obj); + if (res == NULL) { + return -1; + } + Py_DECREF(res); + return 0; + } + PyCodeObject *code = (PyCodeObject *)codelike; assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); PyInterpreterState *interp = _PyInterpreterState_GET(); assert(events < (1 << _PY_MONITORING_LOCAL_EVENTS)); @@ -2073,9 +2094,24 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent } int -_PyMonitoring_GetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet *events) +_PyMonitoring_GetLocalEvents(PyObject *codelike, int tool_id, _PyMonitoringEventSet *events) { assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS); + if (!PyCode_Check(codelike)) { + PyObject *tool = PyLong_FromInt32(tool_id); + assert(tool != NULL); + PyObject *res = PyObject_CallMethodOneArg(codelike, &_Py_ID(__get_local_events__), tool); + if (res == NULL) { + return -1; + } + int err = PyLong_AsUInt32(res, events); + if (err < 0) { + return -1; + } + Py_DECREF(res); + return 0; + } + PyCodeObject *code = (PyCodeObject *)codelike; PyInterpreterState *interp = _PyInterpreterState_GET(); if (check_tool(interp, tool_id)) { return -1; @@ -2362,24 +2398,10 @@ monitoring_get_local_events_impl(PyObject *module, int tool_id, PyObject *code) /*[clinic end generated code: output=d3e92c1c9c1de8f9 input=bb0f927530386a94]*/ { - if (!PyCode_Check(code)) { - PyErr_Format( - PyExc_TypeError, - "code must be a code object" - ); - return -1; - } - if (check_valid_tool(tool_id)) { - return -1; - } - _PyMonitoringEventSet event_set = 0; - _PyCoMonitoringData *data = ((PyCodeObject *)code)->_co_monitoring; - if (data != NULL) { - for (int e = 0; e < _PY_MONITORING_LOCAL_EVENTS; e++) { - if ((data->local_monitors.tools[e] >> tool_id) & 1) { - event_set |= (1 << e); - } - } + _PyMonitoringEventSet event_set; + int err = _PyMonitoring_GetLocalEvents(code, tool_id, &event_set); + if (err < 0) { + return err; } return event_set; } @@ -2399,13 +2421,6 @@ monitoring_set_local_events_impl(PyObject *module, int tool_id, PyObject *code, int event_set) /*[clinic end generated code: output=68cc755a65dfea99 input=5655ecd78d937a29]*/ { - if (!PyCode_Check(code)) { - PyErr_Format( - PyExc_TypeError, - "code must be a code object" - ); - return NULL; - } if (check_valid_tool(tool_id)) { return NULL; } @@ -2423,7 +2438,7 @@ monitoring_set_local_events_impl(PyObject *module, int tool_id, return NULL; } - if (_PyMonitoring_SetLocalEvents((PyCodeObject*)code, tool_id, event_set)) { + if (_PyMonitoring_SetLocalEvents(code, tool_id, event_set)) { return NULL; } Py_RETURN_NONE; From a259ba43dedf428e26d326dbc0bb1a0f3b04ae8c Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 18 Mar 2025 14:02:50 +0000 Subject: [PATCH 2/4] Fix type error --- Python/legacy_tracing.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c index 124b219ea8af97..96618a570e6c56 100644 --- a/Python/legacy_tracing.c +++ b/Python/legacy_tracing.c @@ -131,7 +131,7 @@ _PyEval_SetOpcodeTrace( ) { assert(frame != NULL); - PyCodeObject *code = _PyFrame_GetCode(frame->f_frame); + PyObject *code = (PyObject *)_PyFrame_GetCode(frame->f_frame); _PyMonitoringEventSet events = 0; if (_PyMonitoring_GetLocalEvents(code, PY_MONITORING_SYS_TRACE_ID, &events) < 0) { From 2c4d0fd5555059d9ecbdab820b1c4d7366e02af1 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 18 Mar 2025 18:18:13 +0000 Subject: [PATCH 3/4] Use argument clinic --- .../pycore_global_objects_fini_generated.h | 2 + Include/internal/pycore_global_strings.h | 2 + .../internal/pycore_runtime_init_generated.h | 2 + .../internal/pycore_unicodeobject_generated.h | 8 ++ Objects/clinic/codeobject.c.h | 128 +++++++++++++++++- Objects/codeobject.c | 83 ++++++------ 6 files changed, 185 insertions(+), 40 deletions(-) diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h index 4005a6ea222ff2..7ccace21ede7fd 100644 --- a/Include/internal/pycore_global_objects_fini_generated.h +++ b/Include/internal/pycore_global_objects_fini_generated.h @@ -920,6 +920,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(errors)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(event)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(eventmask)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(events)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exc_type)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(exc_value)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(excepthook)); @@ -1257,6 +1258,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) { _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(times)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timetuple)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(timeunit)); + _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tool)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(top)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(trace_callback)); _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(traceback)); diff --git a/Include/internal/pycore_global_strings.h b/Include/internal/pycore_global_strings.h index 13615b66a3592b..96773c09d5e304 100644 --- a/Include/internal/pycore_global_strings.h +++ b/Include/internal/pycore_global_strings.h @@ -411,6 +411,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(errors) STRUCT_FOR_ID(event) STRUCT_FOR_ID(eventmask) + STRUCT_FOR_ID(events) STRUCT_FOR_ID(exc_type) STRUCT_FOR_ID(exc_value) STRUCT_FOR_ID(excepthook) @@ -748,6 +749,7 @@ struct _Py_global_strings { STRUCT_FOR_ID(times) STRUCT_FOR_ID(timetuple) STRUCT_FOR_ID(timeunit) + STRUCT_FOR_ID(tool) STRUCT_FOR_ID(top) STRUCT_FOR_ID(trace_callback) STRUCT_FOR_ID(traceback) diff --git a/Include/internal/pycore_runtime_init_generated.h b/Include/internal/pycore_runtime_init_generated.h index e71f1657f33cee..e91d2c03d3fd20 100644 --- a/Include/internal/pycore_runtime_init_generated.h +++ b/Include/internal/pycore_runtime_init_generated.h @@ -918,6 +918,7 @@ extern "C" { INIT_ID(errors), \ INIT_ID(event), \ INIT_ID(eventmask), \ + INIT_ID(events), \ INIT_ID(exc_type), \ INIT_ID(exc_value), \ INIT_ID(excepthook), \ @@ -1255,6 +1256,7 @@ extern "C" { INIT_ID(times), \ INIT_ID(timetuple), \ INIT_ID(timeunit), \ + INIT_ID(tool), \ INIT_ID(top), \ INIT_ID(trace_callback), \ INIT_ID(traceback), \ diff --git a/Include/internal/pycore_unicodeobject_generated.h b/Include/internal/pycore_unicodeobject_generated.h index 5ba92291556c6d..d29fc21322d232 100644 --- a/Include/internal/pycore_unicodeobject_generated.h +++ b/Include/internal/pycore_unicodeobject_generated.h @@ -1432,6 +1432,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(events); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(exc_type); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); @@ -2780,6 +2784,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) { _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); assert(PyUnicode_GET_LENGTH(string) != 1); + string = &_Py_ID(tool); + _PyUnicode_InternStatic(interp, &string); + assert(_PyUnicode_CheckConsistency(string, 1)); + assert(PyUnicode_GET_LENGTH(string) != 1); string = &_Py_ID(top); _PyUnicode_InternStatic(interp, &string); assert(_PyUnicode_CheckConsistency(string, 1)); diff --git a/Objects/clinic/codeobject.c.h b/Objects/clinic/codeobject.c.h index 2184742cc0d99d..fb922f16c5387c 100644 --- a/Objects/clinic/codeobject.c.h +++ b/Objects/clinic/codeobject.c.h @@ -466,4 +466,130 @@ code__varname_from_oparg(PyObject *self, PyObject *const *args, Py_ssize_t nargs exit: return return_value; } -/*[clinic end generated code: output=73861c79e93aaee5 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(code___get_local_events____doc__, +"__get_local_events__($self, /, tool)\n" +"--\n" +"\n"); + +#define CODE___GET_LOCAL_EVENTS___METHODDEF \ + {"__get_local_events__", _PyCFunction_CAST(code___get_local_events__), METH_FASTCALL|METH_KEYWORDS, code___get_local_events____doc__}, + +static int +code___get_local_events___impl(PyCodeObject *self, int tool); + +static PyObject * +code___get_local_events__(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 1 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(tool), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"tool", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "__get_local_events__", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[1]; + int tool; + int _return_value; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 1, /*maxpos*/ 1, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + tool = PyLong_AsInt(args[0]); + if (tool == -1 && PyErr_Occurred()) { + goto exit; + } + _return_value = code___get_local_events___impl((PyCodeObject *)self, tool); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyLong_FromLong((long)_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(code___set_local_events____doc__, +"__set_local_events__($self, /, tool, events)\n" +"--\n" +"\n"); + +#define CODE___SET_LOCAL_EVENTS___METHODDEF \ + {"__set_local_events__", _PyCFunction_CAST(code___set_local_events__), METH_FASTCALL|METH_KEYWORDS, code___set_local_events____doc__}, + +static PyObject * +code___set_local_events___impl(PyCodeObject *self, int tool, int events); + +static PyObject * +code___set_local_events__(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE) + + #define NUM_KEYWORDS 2 + static struct { + PyGC_Head _this_is_not_used; + PyObject_VAR_HEAD + PyObject *ob_item[NUM_KEYWORDS]; + } _kwtuple = { + .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS) + .ob_item = { &_Py_ID(tool), &_Py_ID(events), }, + }; + #undef NUM_KEYWORDS + #define KWTUPLE (&_kwtuple.ob_base.ob_base) + + #else // !Py_BUILD_CORE + # define KWTUPLE NULL + #endif // !Py_BUILD_CORE + + static const char * const _keywords[] = {"tool", "events", NULL}; + static _PyArg_Parser _parser = { + .keywords = _keywords, + .fname = "__set_local_events__", + .kwtuple = KWTUPLE, + }; + #undef KWTUPLE + PyObject *argsbuf[2]; + int tool; + int events; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, + /*minpos*/ 2, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf); + if (!args) { + goto exit; + } + tool = PyLong_AsInt(args[0]); + if (tool == -1 && PyErr_Occurred()) { + goto exit; + } + events = PyLong_AsInt(args[1]); + if (events == -1 && PyErr_Occurred()) { + goto exit; + } + return_value = code___set_local_events___impl((PyCodeObject *)self, tool, events); + +exit: + return return_value; +} +/*[clinic end generated code: output=1a1deec323e9b345 input=a9049054013a1b77]*/ diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 4d251d02c81730..5bfccf8d09eff8 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -1570,43 +1570,6 @@ code_offset_to_position(PyObject *self, PyObject* offset) _source_offset_converter, &pi.pi_endcolumn); } -static PyObject* -code_get_local_events(PyObject *self, PyObject* tool) { - int tool_id; - int err = PyLong_AsInt32(tool, &tool_id); - if (err != 0) { - return NULL; - } - _PyMonitoringEventSet events; - err = _PyMonitoring_GetLocalEvents(self, tool_id, &events); - if (err != 0) { - return NULL; - } - return PyLong_FromUInt32(events); -} - -static PyObject* -code_set_local_events(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { - int tool_id; - _PyMonitoringEventSet events; - if (!_PyArg_CheckPositional("__set_local_events__", nargs, 2, 2)) { - return NULL; - } - int err = PyLong_AsInt32(args[0], &tool_id); - if (err != 0) { - return NULL; - } - err = PyLong_AsUInt32(args[1], &events); - if (err != 0) { - return NULL; - } - err = _PyMonitoring_SetLocalEvents(self, tool_id, events); - if (err != 0) { - return NULL; - } - Py_RETURN_NONE; -} - /****************** * "extra" frame eval info (see PEP 523) @@ -2450,6 +2413,48 @@ code__varname_from_oparg_impl(PyCodeObject *self, int oparg) return Py_NewRef(name); } + +/*[clinic input] +code.__get_local_events__ -> int + + tool: int + +[clinic start generated code]*/ + +static int +code___get_local_events___impl(PyCodeObject *self, int tool) +/*[clinic end generated code: output=e66c1af8a8c6c2aa input=660474646897971f]*/ +{ + _PyMonitoringEventSet events; + int err = _PyMonitoring_GetLocalEvents((PyObject *)self, tool, &events); + if (err != 0) { + return err; + } + return events; +} + + +/*[clinic input] +code.__set_local_events__ + + + tool: int + events: int + +[clinic start generated code]*/ + +static PyObject * +code___set_local_events___impl(PyCodeObject *self, int tool, int events) +/*[clinic end generated code: output=d80a9ef8386753f7 input=68cdcca03494b242]*/ +{ + int err = _PyMonitoring_SetLocalEvents((PyObject *)self, tool, events); + if (err < 0) { + return NULL; + } + Py_RETURN_NONE; +} + + /* XXX code objects need to participate in GC? */ static struct PyMethodDef code_methods[] = { @@ -2462,8 +2467,8 @@ static struct PyMethodDef code_methods[] = { {"__replace__", _PyCFunction_CAST(code_replace), METH_FASTCALL|METH_KEYWORDS, PyDoc_STR("__replace__($self, /, **changes)\n--\n\nThe same as replace().")}, {"co_offset_to_position", code_offset_to_position, METH_O}, - {"__get_local_events__", code_get_local_events, METH_O}, - {"__set_local_events__", _PyCFunction_CAST(code_set_local_events), METH_FASTCALL}, + CODE___GET_LOCAL_EVENTS___METHODDEF + CODE___SET_LOCAL_EVENTS___METHODDEF {NULL, NULL} /* sentinel */ }; From 0fdb9a05a29a62712d5e968e2805e2c33c38a354 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 18 Mar 2025 20:19:54 +0000 Subject: [PATCH 4/4] Fix whitespace --- Objects/codeobject.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 5bfccf8d09eff8..cbeda39a122f29 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -2437,7 +2437,6 @@ code___get_local_events___impl(PyCodeObject *self, int tool) /*[clinic input] code.__set_local_events__ - tool: int events: int