https://github.com/python/cpython/commit/c5f925c8c948736bd64652918b4e0186b91abbb5
commit: c5f925c8c948736bd64652918b4e0186b91abbb5
branch: main
author: Tian Gao <gaogaotiant...@hotmail.com>
committer: markshannon <m...@hotpy.org>
date: 2025-02-25T15:43:49Z
summary:

gh-122029: Move monitoring after method expand for CALL_KW (GH-130488)

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2025-02-23-20-48-31.gh-issue-122029.iW8GvA.rst
M Lib/test/test_sys_setprofile.py
M Python/bytecodes.c
M Python/generated_cases.c.h

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/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.
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,

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to