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

This commit is contained in:
Tian Gao 2025-02-25 10:43:49 -05:00 committed by GitHub
parent 3774d9f7b5
commit c5f925c8c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 45 additions and 28 deletions

View file

@ -493,6 +493,24 @@ class TestEdgeCases(unittest.TestCase):
# The last c_call is the call to sys.setprofile # The last c_call is the call to sys.setprofile
self.assertEqual(events, ['c_call', 'c_return', 'c_call']) 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__": if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -0,0 +1 @@
``INSTRUMENTED_CALL_KW`` will expand the method before monitoring to reflect the actual behavior more accurately.

View file

@ -4509,8 +4509,8 @@ dummy_func(
macro(INSTRUMENTED_CALL_KW) = macro(INSTRUMENTED_CALL_KW) =
counter/1 + counter/1 +
unused/2 + unused/2 +
_MONITOR_CALL_KW +
_MAYBE_EXPAND_METHOD_KW + _MAYBE_EXPAND_METHOD_KW +
_MONITOR_CALL_KW +
_DO_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)) { op(_CHECK_IS_NOT_PY_CALLABLE_KW, (callable[1], unused[1], unused[oparg], kwnames -- callable[1], unused[1], unused[oparg], kwnames)) {

View file

@ -6413,14 +6413,37 @@
_PyStackRef *callable; _PyStackRef *callable;
_PyStackRef *self_or_null; _PyStackRef *self_or_null;
_PyStackRef *args; _PyStackRef *args;
_PyStackRef kwnames;
_PyStackRef kwnames_in; _PyStackRef kwnames_in;
_PyStackRef *func; _PyStackRef *func;
_PyStackRef *maybe_self; _PyStackRef *maybe_self;
_PyStackRef kwnames_out; _PyStackRef kwnames_out;
_PyStackRef kwnames;
_PyStackRef res; _PyStackRef res;
/* Skip 1 cache entry */ /* Skip 1 cache entry */
/* Skip 2 cache entries */ /* 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 // _MONITOR_CALL_KW
{ {
args = &stack_pointer[-1 - oparg]; args = &stack_pointer[-1 - oparg];
@ -6440,6 +6463,7 @@
} }
} }
PyObject *function = PyStackRef_AsPyObjectBorrow(callable[0]); PyObject *function = PyStackRef_AsPyObjectBorrow(callable[0]);
stack_pointer[-1] = kwnames_out;
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
int err = _Py_call_instrumentation_2args( int err = _Py_call_instrumentation_2args(
tstate, PY_MONITORING_EVENT_CALL, tstate, PY_MONITORING_EVENT_CALL,
@ -6449,32 +6473,9 @@
JUMP_TO_LABEL(error); 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 // _DO_CALL_KW
{ {
kwnames = kwnames_out; 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 *callable_o = PyStackRef_AsPyObjectBorrow(callable[0]);
PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames); PyObject *kwnames_o = PyStackRef_AsPyObjectBorrow(kwnames);
// oparg counts all of the args, but *not* self: // oparg counts all of the args, but *not* self:
@ -6492,7 +6493,6 @@
{ {
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable_o))->co_flags; 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)); PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable_o));
stack_pointer[-1] = kwnames;
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
_PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
tstate, callable[0], locals, tstate, callable[0], locals,
@ -6519,7 +6519,6 @@
/* Callable is not a normal Python function */ /* Callable is not a normal Python function */
STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o); STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o);
if (CONVERSION_FAILED(args_o)) { if (CONVERSION_FAILED(args_o)) {
stack_pointer[-1] = kwnames;
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
_PyStackRef tmp = kwnames; _PyStackRef tmp = kwnames;
kwnames = PyStackRef_NULL; kwnames = PyStackRef_NULL;
@ -6541,7 +6540,6 @@
assert(WITHIN_STACK_BOUNDS()); assert(WITHIN_STACK_BOUNDS());
JUMP_TO_LABEL(error); JUMP_TO_LABEL(error);
} }
stack_pointer[-1] = kwnames;
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
PyObject *res_o = PyObject_Vectorcall( PyObject *res_o = PyObject_Vectorcall(
callable_o, args_o, callable_o, args_o,