]> granicus.if.org Git - python/commitdiff
Issue #27809: map_next() uses fast call
authorVictor Stinner <victor.stinner@gmail.com>
Tue, 23 Aug 2016 15:56:06 +0000 (17:56 +0200)
committerVictor Stinner <victor.stinner@gmail.com>
Tue, 23 Aug 2016 15:56:06 +0000 (17:56 +0200)
Use a small stack allocated in the C stack for up to 5 iterator functions,
otherwise allocates a stack on the heap memory.

Python/bltinmodule.c

index 00a85b57415ad177e37e8c56cd7d557c665c0a2a..a77dfe84c1e0a13934c42dbd412d8cf729cb3aa8 100644 (file)
@@ -1156,27 +1156,43 @@ map_traverse(mapobject *lz, visitproc visit, void *arg)
 static PyObject *
 map_next(mapobject *lz)
 {
-    PyObject *val;
-    PyObject *argtuple;
-    PyObject *result;
-    Py_ssize_t numargs, i;
+    PyObject *small_stack[5];
+    PyObject **stack;
+    Py_ssize_t niters, nargs, i;
+    PyObject *result = NULL;
 
-    numargs = PyTuple_GET_SIZE(lz->iters);
-    argtuple = PyTuple_New(numargs);
-    if (argtuple == NULL)
-        return NULL;
+    niters = PyTuple_GET_SIZE(lz->iters);
+    if (niters <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) {
+        stack = small_stack;
+    }
+    else {
+        stack = PyMem_Malloc(niters * sizeof(PyObject*));
+        if (stack == NULL) {
+            PyErr_NoMemory();
+            return NULL;
+        }
+    }
 
-    for (i=0 ; i<numargs ; i++) {
+    nargs = 0;
+    for (i=0; i < niters; i++) {
         PyObject *it = PyTuple_GET_ITEM(lz->iters, i);
-        val = Py_TYPE(it)->tp_iternext(it);
+        PyObject *val = Py_TYPE(it)->tp_iternext(it);
         if (val == NULL) {
-            Py_DECREF(argtuple);
-            return NULL;
+            goto exit;
         }
-        PyTuple_SET_ITEM(argtuple, i, val);
+        stack[i] = val;
+        nargs++;
+    }
+
+    result = _PyObject_FastCall(lz->func, stack, nargs);
+
+exit:
+    for (i=0; i < nargs; i++) {
+        Py_DECREF(stack[i]);
+    }
+    if (stack != small_stack) {
+        PyMem_Free(stack);
     }
-    result = PyObject_Call(lz->func, argtuple, NULL);
-    Py_DECREF(argtuple);
     return result;
 }