diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h index 628267cc8a9..2fcbe12cd65 100644 --- a/Include/internal/pycore_list.h +++ b/Include/internal/pycore_list.h @@ -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 index 00000000000..8023a366a0e --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-12-09-13-18-42.gh-issue-100146.xLVKg0.rst @@ -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`. diff --git a/Objects/listobject.c b/Objects/listobject.c index b093f88a35f..6629775604b 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -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 diff --git a/Python/bytecodes.c b/Python/bytecodes.c index e1c73ab6b32..839fac3fcd1 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -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); } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 1179bdfc696..ed89e90b7c5 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -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(); }