gh-100146: Steal references from stack when building a list (#100147)

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.
This commit is contained in:
L. A. F. Pereira 2023-01-03 10:49:49 -08:00 committed by GitHub
parent b3722ca058
commit e6d4440782
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 31 additions and 10 deletions

View 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

View File

@ -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`.

View 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

View 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);
}

View File

@ -1608,13 +1608,10 @@
}
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();
}