]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-100146: Steal references from stack when building a list (#100147)
authorL. A. F. Pereira <l.pereira@microsoft.com>
Tue, 3 Jan 2023 18:49:49 +0000 (10:49 -0800)
committerGitHub <noreply@github.com>
Tue, 3 Jan 2023 18:49:49 +0000 (10:49 -0800)
When executing the BUILD_LIST opcode, steal the references from the stack,
in a manner similar to the BUILD_TUPLE opcode.  Implement this by offloading
the logic to a new private API, _PyList_FromArraySteal(), that works similarly
to _PyTuple_FromArraySteal().

This way, instead of performing multiple stack pointer adjustments while the
list is being initialized, the stack is adjusted only once and a fast memory
copy operation is performed in one fell swoop.

Include/internal/pycore_list.h
Misc/NEWS.d/next/Core and Builtins/2022-12-09-13-18-42.gh-issue-100146.xLVKg0.rst [new file with mode: 0644]
Objects/listobject.c
Python/bytecodes.c
Python/generated_cases.c.h

index 628267cc8a9618763f875e63c05b7086e2754599..2fcbe12cd6559eb357c88828ab223db4b742a1fa 100644 (file)
@@ -75,6 +75,8 @@ typedef struct {
     PyListObject *it_seq; /* Set to NULL when iterator is exhausted */
 } _PyListIterObject;
 
+extern PyObject *_PyList_FromArraySteal(PyObject *const *src, Py_ssize_t n);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-12-09-13-18-42.gh-issue-100146.xLVKg0.rst b/Misc/NEWS.d/next/Core and Builtins/2022-12-09-13-18-42.gh-issue-100146.xLVKg0.rst
new file mode 100644 (file)
index 0000000..8023a36
--- /dev/null
@@ -0,0 +1,4 @@
+Improve ``BUILD_LIST`` opcode so that it works similarly to the
+``BUILD_TUPLE`` opcode, by stealing references from the stack rather than
+repeatedly using stack operations to set list elements.  Implementation
+details are in a new private API :c:func:`_PyList_FromArraySteal`.
index b093f88a35fc475af8fbe2b7ce313af0bca5566e..6629775604b67b223f948bd77fd79829e7739d7f 100644 (file)
@@ -2565,6 +2565,27 @@ PyList_AsTuple(PyObject *v)
     return _PyTuple_FromArray(((PyListObject *)v)->ob_item, Py_SIZE(v));
 }
 
+PyObject *
+_PyList_FromArraySteal(PyObject *const *src, Py_ssize_t n)
+{
+    if (n == 0) {
+        return PyList_New(0);
+    }
+
+    PyListObject *list = (PyListObject *)PyList_New(n);
+    if (list == NULL) {
+        for (Py_ssize_t i = 0; i < n; i++) {
+            Py_DECREF(src[i]);
+        }
+        return NULL;
+    }
+
+    PyObject **dst = list->ob_item;
+    memcpy(dst, src, n * sizeof(PyObject *));
+
+    return (PyObject *)list;
+}
+
 /*[clinic input]
 list.index
 
index e1c73ab6b32fbf017fc97ba6827c1a76152c21c6..839fac3fcd1176738c8601f844c90ec9f48f1679 100644 (file)
@@ -1390,13 +1390,10 @@ dummy_func(
 
         // stack effect: (__array[oparg] -- __0)
         inst(BUILD_LIST) {
-            PyObject *list =  PyList_New(oparg);
+            STACK_SHRINK(oparg);
+            PyObject *list = _PyList_FromArraySteal(stack_pointer, oparg);
             if (list == NULL)
                 goto error;
-            while (--oparg >= 0) {
-                PyObject *item = POP();
-                PyList_SET_ITEM(list, oparg, item);
-            }
             PUSH(list);
         }
 
index 1179bdfc696c6254e0f4a0d82b8587f8ba1228e3..ed89e90b7c564d19f8fa3e60f0688e861e2d7bf5 100644 (file)
         }
 
         TARGET(BUILD_LIST) {
-            PyObject *list =  PyList_New(oparg);
+            STACK_SHRINK(oparg);
+            PyObject *list = _PyList_FromArraySteal(stack_pointer, oparg);
             if (list == NULL)
                 goto error;
-            while (--oparg >= 0) {
-                PyObject *item = POP();
-                PyList_SET_ITEM(list, oparg, item);
-            }
             PUSH(list);
             DISPATCH();
         }