From a240df1589fe2d4a88e619f849f81db3a9afcbae Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 13 Mar 2022 23:08:23 -0400 Subject: [PATCH 1/3] Streamline list.append for the common case --- Include/internal/pycore_list.h | 18 +++++++++++++++++ Objects/listobject.c | 36 +++++++++++++++++----------------- Python/ceval.c | 13 ++++-------- 3 files changed, 40 insertions(+), 27 deletions(-) diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h index 0717a1f9563a2a..60b0113e20efce 100644 --- a/Include/internal/pycore_list.h +++ b/Include/internal/pycore_list.h @@ -37,6 +37,24 @@ struct _Py_list_state { #define _PyList_ITEMS(op) (_PyList_CAST(op)->ob_item) +PyAPI_FUNC(int) +_PyList_AppendTakeRefListResize(PyListObject *self, PyObject *newitem); + +static inline int +_PyList_AppendTakeRef(PyListObject *self, PyObject *newitem) +{ + assert(self != NULL && newitem != NULL); + assert(PyList_Check(self)); + Py_ssize_t len = PyList_GET_SIZE(self); + Py_ssize_t allocated = self->allocated; + assert((size_t)len + 1 < PY_SSIZE_T_MAX); + if (allocated > len) { + PyList_SET_ITEM(self, len, newitem); + Py_SET_SIZE(self, len + 1); + return 0; + } + return _PyList_AppendTakeRefListResize(self, newitem); +} #ifdef __cplusplus } diff --git a/Objects/listobject.c b/Objects/listobject.c index d50633d2b31321..ccb9b91ba930d7 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -301,26 +301,27 @@ PyList_Insert(PyObject *op, Py_ssize_t where, PyObject *newitem) return ins1((PyListObject *)op, where, newitem); } -static int -app1(PyListObject *self, PyObject *v) +/* internal, used by _PyList_AppendTakeRef */ +int +_PyList_AppendTakeRefListResize(PyListObject *self, PyObject *newitem) { - Py_ssize_t n = PyList_GET_SIZE(self); - - assert (v != NULL); - assert((size_t)n + 1 < PY_SSIZE_T_MAX); - if (list_resize(self, n+1) < 0) + Py_ssize_t len = PyList_GET_SIZE(self); + assert(self->allocated == -1 || self->allocated == len); + if (list_resize(self, len + 1) < 0) { + Py_DECREF(newitem); return -1; - - Py_INCREF(v); - PyList_SET_ITEM(self, n, v); + } + PyList_SET_ITEM(self, len, newitem); return 0; } int PyList_Append(PyObject *op, PyObject *newitem) { - if (PyList_Check(op) && (newitem != NULL)) - return app1((PyListObject *)op, newitem); + if (PyList_Check(op) && (newitem != NULL)) { + Py_INCREF(newitem); + return _PyList_AppendTakeRef((PyListObject *)op, newitem); + } PyErr_BadInternalCall(); return -1; } @@ -844,9 +845,10 @@ static PyObject * list_append(PyListObject *self, PyObject *object) /*[clinic end generated code: output=7c096003a29c0eae input=43a3fe48a7066e91]*/ { - if (app1(self, object) == 0) - Py_RETURN_NONE; - return NULL; + if (_PyList_AppendTakeRef(self, Py_NewRef(object)) < 0) { + return NULL; + } + Py_RETURN_NONE; } /*[clinic input] @@ -963,9 +965,7 @@ list_extend(PyListObject *self, PyObject *iterable) Py_SET_SIZE(self, Py_SIZE(self) + 1); } else { - int status = app1(self, item); - Py_DECREF(item); /* append creates a new ref */ - if (status < 0) + if (_PyList_AppendTakeRef(self, item) < 0) goto error; } } diff --git a/Python/ceval.c b/Python/ceval.c index f7514796642196..7039a10c1a67ec 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2234,10 +2234,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int TARGET(LIST_APPEND) { PyObject *v = POP(); PyObject *list = PEEK(oparg); - int err; - err = PyList_Append(list, v); - Py_DECREF(v); - if (err != 0) + if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto error; PREDICT(JUMP_ABSOLUTE); DISPATCH(); @@ -5070,14 +5067,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DEOPT_IF(!PyList_Check(list), PRECALL); STAT_INC(PRECALL, hit); SKIP_CALL(); - PyObject *arg = TOP(); - int err = PyList_Append(list, arg); - if (err) { + PyObject *arg = POP(); + if (_PyList_AppendTakeRef((PyListObject *)list, arg) < 0) { goto error; } - Py_DECREF(arg); Py_DECREF(list); - STACK_SHRINK(2); + STACK_SHRINK(1); Py_INCREF(Py_None); SET_TOP(Py_None); Py_DECREF(callable); From e03817691816d1eb722a86d33b8025c0cdc8af71 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Mon, 14 Mar 2022 09:45:12 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core and Builtins/2022-03-14-09-45-10.bpo-47009.ZI05b5.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-03-14-09-45-10.bpo-47009.ZI05b5.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-14-09-45-10.bpo-47009.ZI05b5.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-14-09-45-10.bpo-47009.ZI05b5.rst new file mode 100644 index 00000000000000..0c65c34d310ec0 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-03-14-09-45-10.bpo-47009.ZI05b5.rst @@ -0,0 +1 @@ +Improved the performance of :meth:`list.append()` and list comprehensions by optimizing for the common case, where no resize is needed. Patch by Dennis Sweeney. From 8ad202ff494f4072d9888edf7f603b44c88ff894 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Mon, 21 Mar 2022 03:21:02 -0400 Subject: [PATCH 3/3] PyAPI_FUNC --> extern --- Include/internal/pycore_list.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/internal/pycore_list.h b/Include/internal/pycore_list.h index 60b0113e20efce..860dce1fd5d393 100644 --- a/Include/internal/pycore_list.h +++ b/Include/internal/pycore_list.h @@ -37,7 +37,7 @@ struct _Py_list_state { #define _PyList_ITEMS(op) (_PyList_CAST(op)->ob_item) -PyAPI_FUNC(int) +extern int _PyList_AppendTakeRefListResize(PyListObject *self, PyObject *newitem); static inline int