]> granicus.if.org Git - python/commitdiff
bpo-34125: Enable profiling of method_descriptor in all cases (GH-8416)
authorjdemeyer <jdemeyer@cage.ugent.be>
Wed, 19 Sep 2018 10:06:20 +0000 (12:06 +0200)
committerMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Wed, 19 Sep 2018 10:06:20 +0000 (03:06 -0700)
`list.append([], None)` was profiled but `list.append([], None, **{})` was not profiled.
Enable profiling for later case.

https://bugs.python.org/issue34125

Lib/test/test_sys_setprofile.py
Misc/NEWS.d/next/Core and Builtins/2018-07-23-16-34-03.bpo-34125.jCl2Q2.rst [new file with mode: 0644]
Python/ceval.c

index 16467e7f7184fcebab19c5789e4eaaff1155bd6a..c2ecf8eeed9f9a0097cf87b2d4c171c5afc78641 100644 (file)
@@ -350,6 +350,24 @@ class ProfileSimulatorTestCase(TestCaseBase):
         self.check_events(f, [(1, 'call', f_ident),
                               (1, 'return', f_ident)])
 
+    # Test an invalid call (bpo-34125)
+    def test_unbound_method_no_args(self):
+        kwargs = {}
+        def f(p):
+            dict.get(**kwargs)
+        f_ident = ident(f)
+        self.check_events(f, [(1, 'call', f_ident),
+                              (1, 'return', f_ident)])
+
+    # Test an invalid call (bpo-34125)
+    def test_unbound_method_invalid_args(self):
+        kwargs = {}
+        def f(p):
+            dict.get(print, 42, **kwargs)
+        f_ident = ident(f)
+        self.check_events(f, [(1, 'call', f_ident),
+                              (1, 'return', f_ident)])
+
 
 def ident(function):
     if hasattr(function, "f_code"):
diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-07-23-16-34-03.bpo-34125.jCl2Q2.rst b/Misc/NEWS.d/next/Core and Builtins/2018-07-23-16-34-03.bpo-34125.jCl2Q2.rst
new file mode 100644 (file)
index 0000000..e6036b4
--- /dev/null
@@ -0,0 +1 @@
+Profiling of unbound built-in methods now works when ``**kwargs`` is given.
index 4a82bd3198aff1b963d29e25deedc60f609778bd..d0f9915b4f0a03628bfc8d7ef511590e48016f62 100644 (file)
@@ -4642,15 +4642,39 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
 static PyObject *
 do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict)
 {
+    PyObject *result;
+
     if (PyCFunction_Check(func)) {
-        PyObject *result;
         PyThreadState *tstate = PyThreadState_GET();
         C_TRACE(result, PyCFunction_Call(func, callargs, kwdict));
         return result;
     }
-    else {
-        return PyObject_Call(func, callargs, kwdict);
+    else if (Py_TYPE(func) == &PyMethodDescr_Type) {
+        PyThreadState *tstate = PyThreadState_GET();
+        Py_ssize_t nargs = PyTuple_GET_SIZE(callargs);
+        if (nargs > 0 && tstate->use_tracing) {
+            /* We need to create a temporary bound method as argument
+               for profiling.
+
+               If nargs == 0, then this cannot work because we have no
+               "self". In any case, the call itself would raise
+               TypeError (foo needs an argument), so we just skip
+               profiling. */
+            PyObject *self = PyTuple_GET_ITEM(callargs, 0);
+            func = Py_TYPE(func)->tp_descr_get(func, self, (PyObject*)Py_TYPE(self));
+            if (func == NULL) {
+                return NULL;
+            }
+
+            C_TRACE(result, _PyCFunction_FastCallDict(func,
+                                                      &PyTuple_GET_ITEM(callargs, 1),
+                                                      nargs - 1,
+                                                      kwdict));
+            Py_DECREF(func);
+            return result;
+        }
     }
+    return PyObject_Call(func, callargs, kwdict);
 }
 
 /* Extract a slice index from a PyLong or an object with the