Skip to content

Commit e89de73

Browse files
jdemeyermiss-islington
authored andcommitted
bpo-34125: Enable profiling of method_descriptor in all cases (GH-8416)
`list.append([], None)` was profiled but `list.append([], None, **{})` was not profiled. Enable profiling for later case. https://bugs.python.org/issue34125
1 parent b3b8cb4 commit e89de73

File tree

3 files changed

+46
-3
lines changed

3 files changed

+46
-3
lines changed

Lib/test/test_sys_setprofile.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,24 @@ def f(p):
350350
self.check_events(f, [(1, 'call', f_ident),
351351
(1, 'return', f_ident)])
352352

353+
# Test an invalid call (bpo-34125)
354+
def test_unbound_method_no_args(self):
355+
kwargs = {}
356+
def f(p):
357+
dict.get(**kwargs)
358+
f_ident = ident(f)
359+
self.check_events(f, [(1, 'call', f_ident),
360+
(1, 'return', f_ident)])
361+
362+
# Test an invalid call (bpo-34125)
363+
def test_unbound_method_invalid_args(self):
364+
kwargs = {}
365+
def f(p):
366+
dict.get(print, 42, **kwargs)
367+
f_ident = ident(f)
368+
self.check_events(f, [(1, 'call', f_ident),
369+
(1, 'return', f_ident)])
370+
353371

354372
def ident(function):
355373
if hasattr(function, "f_code"):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Profiling of unbound built-in methods now works when ``**kwargs`` is given.

Python/ceval.c

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4642,15 +4642,39 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
46424642
static PyObject *
46434643
do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict)
46444644
{
4645+
PyObject *result;
4646+
46454647
if (PyCFunction_Check(func)) {
4646-
PyObject *result;
46474648
PyThreadState *tstate = PyThreadState_GET();
46484649
C_TRACE(result, PyCFunction_Call(func, callargs, kwdict));
46494650
return result;
46504651
}
4651-
else {
4652-
return PyObject_Call(func, callargs, kwdict);
4652+
else if (Py_TYPE(func) == &PyMethodDescr_Type) {
4653+
PyThreadState *tstate = PyThreadState_GET();
4654+
Py_ssize_t nargs = PyTuple_GET_SIZE(callargs);
4655+
if (nargs > 0 && tstate->use_tracing) {
4656+
/* We need to create a temporary bound method as argument
4657+
for profiling.
4658+
4659+
If nargs == 0, then this cannot work because we have no
4660+
"self". In any case, the call itself would raise
4661+
TypeError (foo needs an argument), so we just skip
4662+
profiling. */
4663+
PyObject *self = PyTuple_GET_ITEM(callargs, 0);
4664+
func = Py_TYPE(func)->tp_descr_get(func, self, (PyObject*)Py_TYPE(self));
4665+
if (func == NULL) {
4666+
return NULL;
4667+
}
4668+
4669+
C_TRACE(result, _PyCFunction_FastCallDict(func,
4670+
&PyTuple_GET_ITEM(callargs, 1),
4671+
nargs - 1,
4672+
kwdict));
4673+
Py_DECREF(func);
4674+
return result;
4675+
}
46534676
}
4677+
return PyObject_Call(func, callargs, kwdict);
46544678
}
46554679

46564680
/* Extract a slice index from a PyLong or an object with the

0 commit comments

Comments
 (0)