[Python-checkins] cpython: PyObject_CallMethodObjArgs() now uses fast call

victor.stinner python-checkins at python.org
Tue Aug 23 18:09:09 EDT 2016


https://hg.python.org/cpython/rev/0e4f26083bbb
changeset:   102874:0e4f26083bbb
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Wed Aug 24 00:01:56 2016 +0200
summary:
  PyObject_CallMethodObjArgs() now uses fast call

Issue #27809:

* PyObject_CallMethodObjArgs(), _PyObject_CallMethodIdObjArgs() and
  PyObject_CallFunctionObjArgs() now use fast call to avoid the creation of a
  temporary tuple
* Rename objargs_mktuple() to objargs_mkstack()
* objargs_mkstack() now stores objects in a C array using borrowed references,
  instead of storing arguments into a tuple

objargs_mkstack() uses a small buffer allocated on the C stack for 5 arguments
or less, or allocates a buffer in the heap memory.

files:
  Objects/abstract.c |  113 ++++++++++++++++++++++----------
  1 files changed, 76 insertions(+), 37 deletions(-)


diff --git a/Objects/abstract.c b/Objects/abstract.c
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -2499,32 +2499,52 @@
     return retval;
 }
 
-static PyObject *
-objargs_mktuple(va_list va)
+static PyObject **
+objargs_mkstack(PyObject **small_stack, Py_ssize_t small_stack_size,
+                va_list va, Py_ssize_t *p_nargs)
 {
-    int i, n = 0;
+    Py_ssize_t i, n;
     va_list countva;
-    PyObject *result, *tmp;
-
-        Py_VA_COPY(countva, va);
-
-    while (((PyObject *)va_arg(countva, PyObject *)) != NULL)
-        ++n;
-    result = PyTuple_New(n);
-    if (result != NULL && n > 0) {
-        for (i = 0; i < n; ++i) {
-            tmp = (PyObject *)va_arg(va, PyObject *);
-            PyTuple_SET_ITEM(result, i, tmp);
-            Py_INCREF(tmp);
+    PyObject **stack;
+
+    /* Count the number of arguments */
+    Py_VA_COPY(countva, va);
+
+    n = 0;
+    while (1) {
+        PyObject *arg = (PyObject *)va_arg(countva, PyObject *);
+        if (arg == NULL) {
+            break;
+        }
+        n++;
+    }
+    *p_nargs = n;
+
+    /* Copy arguments */
+    if (small_stack_size <= n) {
+        stack = small_stack;
+    }
+    else {
+        stack = PyMem_Malloc(n * sizeof(PyObject**));
+        if (stack == NULL) {
+            PyErr_NoMemory();
+            return NULL;
         }
     }
-    return result;
+
+    for (i = 0; i < n; ++i) {
+        stack[i] = va_arg(va, PyObject *);
+    }
+    return stack;
 }
 
 PyObject *
 PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...)
 {
-    PyObject *args, *tmp;
+    PyObject *small_stack[5];
+    PyObject **stack;
+    Py_ssize_t nargs;
+    PyObject *result;
     va_list vargs;
 
     if (callable == NULL || name == NULL) {
@@ -2537,24 +2557,31 @@
 
     /* count the args */
     va_start(vargs, name);
-    args = objargs_mktuple(vargs);
+    stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack),
+                            vargs, &nargs);
     va_end(vargs);
-    if (args == NULL) {
+    if (stack == NULL) {
         Py_DECREF(callable);
         return NULL;
     }
-    tmp = PyObject_Call(callable, args, NULL);
-    Py_DECREF(args);
+
+    result = _PyObject_FastCall(callable, stack, nargs);
     Py_DECREF(callable);
-
-    return tmp;
+    if (stack != small_stack) {
+        PyMem_Free(stack);
+    }
+
+    return result;
 }
 
 PyObject *
 _PyObject_CallMethodIdObjArgs(PyObject *callable,
         struct _Py_Identifier *name, ...)
 {
-    PyObject *args, *tmp;
+    PyObject *small_stack[5];
+    PyObject **stack;
+    Py_ssize_t nargs;
+    PyObject *result;
     va_list vargs;
 
     if (callable == NULL || name == NULL) {
@@ -2567,23 +2594,30 @@
 
     /* count the args */
     va_start(vargs, name);
-    args = objargs_mktuple(vargs);
+    stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack),
+                            vargs, &nargs);
     va_end(vargs);
-    if (args == NULL) {
+    if (stack == NULL) {
         Py_DECREF(callable);
         return NULL;
     }
-    tmp = PyObject_Call(callable, args, NULL);
-    Py_DECREF(args);
+
+    result = _PyObject_FastCall(callable, stack, nargs);
     Py_DECREF(callable);
-
-    return tmp;
+    if (stack != small_stack) {
+        PyMem_Free(stack);
+    }
+
+    return result;
 }
 
 PyObject *
 PyObject_CallFunctionObjArgs(PyObject *callable, ...)
 {
-    PyObject *args, *tmp;
+    PyObject *small_stack[5];
+    PyObject **stack;
+    Py_ssize_t nargs;
+    PyObject *result;
     va_list vargs;
 
     if (callable == NULL) {
@@ -2592,14 +2626,19 @@
 
     /* count the args */
     va_start(vargs, callable);
-    args = objargs_mktuple(vargs);
+    stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack),
+                            vargs, &nargs);
     va_end(vargs);
-    if (args == NULL)
+    if (stack == NULL) {
         return NULL;
-    tmp = PyObject_Call(callable, args, NULL);
-    Py_DECREF(args);
-
-    return tmp;
+    }
+
+    result = _PyObject_FastCall(callable, stack, nargs);
+    if (stack != small_stack) {
+        PyMem_Free(stack);
+    }
+
+    return result;
 }
 
 

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


More information about the Python-checkins mailing list