[Python-checkins] cpython: method_call() and slot_tp_new() now uses fast call

victor.stinner python-checkins at python.org
Wed Aug 24 19:14:25 EDT 2016


https://hg.python.org/cpython/rev/316e5de8a96b
changeset:   102904:316e5de8a96b
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Thu Aug 25 01:04:14 2016 +0200
summary:
  method_call() and slot_tp_new() now uses fast call

Issue #27841: Add _PyObject_Call_Prepend() helper function to prepend an
argument to existing arguments to call a function. This helper uses fast calls.

Modify method_call() and slot_tp_new() to use _PyObject_Call_Prepend().

files:
  Include/abstract.h    |   4 +++
  Objects/abstract.c    |  39 +++++++++++++++++++++++++++++++
  Objects/classobject.c |  29 +++++-----------------
  Objects/typeobject.c  |  25 ++++---------------
  4 files changed, 56 insertions(+), 41 deletions(-)


diff --git a/Include/abstract.h b/Include/abstract.h
--- a/Include/abstract.h
+++ b/Include/abstract.h
@@ -309,6 +309,10 @@
                                 Py_ssize_t nargs,
                                 Py_ssize_t nkwargs);
 
+    PyAPI_FUNC(PyObject *) _PyObject_Call_Prepend(PyObject *func,
+                                                  PyObject *obj, PyObject *args,
+                                                  PyObject *kwargs);
+
      PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(PyObject *func,
                                                     PyObject *result,
                                                     const char *where);
diff --git a/Objects/abstract.c b/Objects/abstract.c
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -2388,6 +2388,45 @@
     return result;
 }
 
+/* Positional arguments are obj followed args. */
+PyObject *
+_PyObject_Call_Prepend(PyObject *func,
+                       PyObject *obj, PyObject *args, PyObject *kwargs)
+{
+    PyObject *small_stack[8];
+    PyObject **stack;
+    Py_ssize_t argcount;
+    PyObject *result;
+
+    assert(PyTuple_Check(args));
+
+    argcount = PyTuple_GET_SIZE(args);
+    if (argcount + 1 <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
+        stack = small_stack;
+    }
+    else {
+        stack = PyMem_Malloc((argcount + 1) * sizeof(PyObject *));
+        if (stack == NULL) {
+            PyErr_NoMemory();
+            return NULL;
+        }
+    }
+
+    /* use borrowed references */
+    stack[0] = obj;
+    Py_MEMCPY(&stack[1],
+              &PyTuple_GET_ITEM(args, 0),
+              argcount * sizeof(PyObject *));
+
+    result = _PyObject_FastCallDict(func,
+                                    stack, argcount + 1,
+                                    kwargs);
+    if (stack != small_stack) {
+        PyMem_Free(stack);
+    }
+    return result;
+}
+
 static PyObject*
 call_function_tail(PyObject *callable, PyObject *args)
 {
diff --git a/Objects/classobject.c b/Objects/classobject.c
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -302,34 +302,19 @@
 }
 
 static PyObject *
-method_call(PyObject *func, PyObject *arg, PyObject *kw)
+method_call(PyObject *method, PyObject *args, PyObject *kwargs)
 {
-    PyObject *self = PyMethod_GET_SELF(func);
-    PyObject *result;
+    PyObject *self, *func;
 
-    func = PyMethod_GET_FUNCTION(func);
+    self = PyMethod_GET_SELF(method);
     if (self == NULL) {
         PyErr_BadInternalCall();
         return NULL;
     }
-    else {
-        Py_ssize_t argcount = PyTuple_Size(arg);
-        PyObject *newarg = PyTuple_New(argcount + 1);
-        int i;
-        if (newarg == NULL)
-            return NULL;
-        Py_INCREF(self);
-        PyTuple_SET_ITEM(newarg, 0, self);
-        for (i = 0; i < argcount; i++) {
-            PyObject *v = PyTuple_GET_ITEM(arg, i);
-            Py_XINCREF(v);
-            PyTuple_SET_ITEM(newarg, i+1, v);
-        }
-        arg = newarg;
-    }
-    result = PyObject_Call((PyObject *)func, arg, kw);
-    Py_DECREF(arg);
-    return result;
+
+    func = PyMethod_GET_FUNCTION(method);
+
+    return _PyObject_Call_Prepend(func, self, args, kwargs);
 }
 
 static PyObject *
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -6356,29 +6356,16 @@
 static PyObject *
 slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 {
-    PyObject *func;
-    PyObject *newargs, *x;
-    Py_ssize_t i, n;
+    PyObject *func, *result;
 
     func = _PyObject_GetAttrId((PyObject *)type, &PyId___new__);
-    if (func == NULL)
+    if (func == NULL) {
         return NULL;
-    assert(PyTuple_Check(args));
-    n = PyTuple_GET_SIZE(args);
-    newargs = PyTuple_New(n+1);
-    if (newargs == NULL)
-        return NULL;
-    Py_INCREF(type);
-    PyTuple_SET_ITEM(newargs, 0, (PyObject *)type);
-    for (i = 0; i < n; i++) {
-        x = PyTuple_GET_ITEM(args, i);
-        Py_INCREF(x);
-        PyTuple_SET_ITEM(newargs, i+1, x);
-    }
-    x = PyObject_Call(func, newargs, kwds);
-    Py_DECREF(newargs);
+    }
+
+    result = _PyObject_Call_Prepend(func, (PyObject *)type, args, kwds);
     Py_DECREF(func);
-    return x;
+    return result;
 }
 
 static void

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list