From c2ca18d09f761255a52d1f09e8e13d46450b1b46 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Sun, 23 Feb 2025 15:40:23 -0500 Subject: [PATCH 1/2] Move monitoring after method expand for CALL_KW --- Lib/test/test_sys_setprofile.py | 18 ++++++++++++ Python/bytecodes.c | 2 +- Python/generated_cases.c.h | 52 ++++++++++++++++----------------- 3 files changed, 44 insertions(+), 28 deletions(-) diff --git a/Lib/test/test_sys_setprofile.py b/Lib/test/test_sys_setprofile.py index 311a4d2cafe88d..0753a9d8b8e0ee 100644 --- a/Lib/test/test_sys_setprofile.py +++ b/Lib/test/test_sys_setprofile.py @@ -493,6 +493,24 @@ class A: # The last c_call is the call to sys.setprofile self.assertEqual(events, ['c_call', 'c_return', 'c_call']) + class B: + f = classmethod(max) + events = [] + sys.setprofile(lambda frame, event, args: events.append(event)) + # Not important, we only want to trigger INSTRUMENTED_CALL_KW + B().f(1, key=lambda x: 0) + sys.setprofile(None) + # The last c_call is the call to sys.setprofile + self.assertEqual( + events, + ['c_call', + 'call', 'return', + 'call', 'return', + 'c_return', + 'c_call' + ] + ) + if __name__ == "__main__": unittest.main() diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 3c5cb07709d66c..6f91b10b8b8a9b 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -4509,8 +4509,8 @@ dummy_func( macro(INSTRUMENTED_CALL_KW) = counter/1 + unused/2 + - _MONITOR_CALL_KW + _MAYBE_EXPAND_METHOD_KW + + _MONITOR_CALL_KW + _DO_CALL_KW; op(_CHECK_IS_NOT_PY_CALLABLE_KW, (callable[1], unused[1], unused[oparg], kwnames -- callable[1], unused[1], unused[oparg], kwnames)) { diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 268e8836994bc4..377be6fb6d6390 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -6413,14 +6413,37 @@ _PyStackRef *callable; _PyStackRef *self_or_null; _PyStackRef *args; - _PyStackRef kwnames; _PyStackRef kwnames_in; _PyStackRef *func; _PyStackRef *maybe_self; _PyStackRef kwnames_out; + _PyStackRef kwnames; _PyStackRef res; /* Skip 1 cache entry */ /* Skip 2 cache entries */ + // _MAYBE_EXPAND_METHOD_KW + { + kwnames_in = stack_pointer[-1]; + args = &stack_pointer[-1 - oparg]; + self_or_null = &stack_pointer[-2 - oparg]; + callable = &stack_pointer[-3 - oparg]; + func = &stack_pointer[-3 - oparg]; + maybe_self = &stack_pointer[-2 - oparg]; + args = &stack_pointer[-1 - oparg]; + (void)args; + if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { + PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); + PyObject *self = ((PyMethodObject *)callable_o)->im_self; + maybe_self[0] = PyStackRef_FromPyObjectNew(self); + PyObject *method = ((PyMethodObject *)callable_o)->im_func; + _PyStackRef temp = callable[0]; + func[0] = PyStackRef_FromPyObjectNew(method); + _PyFrame_SetStackPointer(frame, stack_pointer); + PyStackRef_CLOSE(temp); + stack_pointer = _PyFrame_GetStackPointer(frame); + } + kwnames_out = kwnames_in; + } // _MONITOR_CALL_KW { args = &stack_pointer[-1 - oparg]; @@ -6440,6 +6463,7 @@ } } PyObject *function = PyStackRef_AsPyObjectBorrow(callable[0]); + stack_pointer[-1] = kwnames_out; _PyFrame_SetStackPointer(frame, stack_pointer); int err = _Py_call_instrumentation_2args( tstate, PY_MONITORING_EVENT_CALL, @@ -6449,32 +6473,9 @@ JUMP_TO_LABEL(error); } } - // _MAYBE_EXPAND_METHOD_KW - { - kwnames_in = stack_pointer[-1]; - func = &stack_pointer[-3 - oparg]; - maybe_self = &stack_pointer[-2 - oparg]; - args = &stack_pointer[-1 - oparg]; - (void)args; - if (PyStackRef_TYPE(callable[0]) == &PyMethod_Type && PyStackRef_IsNull(self_or_null[0])) { - PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); - PyObject *self = ((PyMethodObject *)callable_o)->im_self; - maybe_self[0] = PyStackRef_FromPyObjectNew(self); - PyObject *method = ((PyMethodObject *)callable_o)->im_func; - _PyStackRef temp = callable[0]; - func[0] = PyStackRef_FromPyObjectNew(method); - _PyFrame_SetStackPointer(frame, stack_pointer); - PyStackRef_CLOSE(temp); - stack_pointer = _PyFrame_GetStackPointer(frame); - } - kwnames_out = kwnames_in; - } // _DO_CALL_KW { kwnames = kwnames_out; - args = &stack_pointer[-1 - oparg]; - self_or_null = &stack_pointer[-2 - oparg]; - callable = &stack_pointer[-3 - oparg]; PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]); PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); // oparg counts all of the args, but *not* self: @@ -6492,7 +6493,6 @@ { int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o)); - stack_pointer[-1] = kwnames; _PyFrame_SetStackPointer(frame, stack_pointer); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( tstate, callable[0], locals, @@ -6519,7 +6519,6 @@ /* Callable is not a normal Python function */ STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); if (CONVERSION_FAILED(args_o)) { - stack_pointer[-1] = kwnames; _PyFrame_SetStackPointer(frame, stack_pointer); _PyStackRef tmp = kwnames; kwnames = PyStackRef_NULL; @@ -6541,7 +6540,6 @@ assert(WITHIN_STACK_BOUNDS()); JUMP_TO_LABEL(error); } - stack_pointer[-1] = kwnames; _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *res_o = PyObject_Vectorcall( callable_o, args_o, From 2409ecb9c61a558a9a46ac75a569abcc8bf27899 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sun, 23 Feb 2025 20:48:34 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2025-02-23-20-48-31.gh-issue-122029.iW8GvA.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-02-23-20-48-31.gh-issue-122029.iW8GvA.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-02-23-20-48-31.gh-issue-122029.iW8GvA.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-02-23-20-48-31.gh-issue-122029.iW8GvA.rst new file mode 100644 index 00000000000000..ec7d774a16fdb0 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-02-23-20-48-31.gh-issue-122029.iW8GvA.rst @@ -0,0 +1 @@ +``INSTRUMENTED_CALL_KW`` will expand the method before monitoring to reflect the actual behavior more accurately.