diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-10-04-01-40-31.gh-issue-158790.F3kQ7z.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-04-01-40-31.gh-issue-158790.F3kQ7z.rst new file mode 100644 index 00000000000000..b509071e16eea2 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-04-01-40-31.gh-issue-158790.F3kQ7z.rst @@ -0,0 +1 @@ +Speed up :meth:`list.insert` and item deletion via :keyword:`del` in free-threaded builds by using :manpage:`memmove(3)`. diff --git a/Objects/listobject.c b/Objects/listobject.c index 81eb3e1102159b..8a4594945226de 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -478,10 +478,43 @@ end:; return ret; } +static void ptr_wise_atomic_memmove(PyListObject *a, PyObject **dest, + PyObject **src, Py_ssize_t n); + +static inline void +list_shift_items_right_lock_held(PyListObject *self, Py_ssize_t first, + Py_ssize_t last) +{ +#ifdef Py_GIL_DISABLED + ptr_wise_atomic_memmove(self, &self->ob_item[first + 1], + &self->ob_item[first], last - first); +#else + PyObject **items = self->ob_item; + for (Py_ssize_t i = last; --i >= first; ) { + items[i + 1] = items[i]; + } +#endif +} + +static inline void +list_shift_items_left_lock_held(PyListObject *self, Py_ssize_t first, + Py_ssize_t last) +{ +#ifdef Py_GIL_DISABLED + ptr_wise_atomic_memmove(self, &self->ob_item[first], + &self->ob_item[first + 1], last - first); +#else + PyObject **items = self->ob_item; + for (Py_ssize_t i = first; i < last; i++) { + items[i] = items[i + 1]; + } +#endif +} + static int ins1(PyListObject *self, Py_ssize_t where, PyObject *v) { - Py_ssize_t i, n = Py_SIZE(self); + Py_ssize_t n = Py_SIZE(self); PyObject **items; if (v == NULL) { PyErr_BadInternalCall(); @@ -500,8 +533,9 @@ ins1(PyListObject *self, Py_ssize_t where, PyObject *v) if (where > n) where = n; items = self->ob_item; - for (i = n; --i >= where; ) - FT_ATOMIC_STORE_PTR_RELEASE(items[i+1], items[i]); + if (where < n) { + list_shift_items_right_lock_held(self, where, n); + } FT_ATOMIC_STORE_PTR_RELEASE(items[where], Py_NewRef(v)); return 0; } @@ -1145,8 +1179,8 @@ list_ass_item_lock_held(PyListObject *a, Py_ssize_t i, PyObject *v) PyObject *tmp = a->ob_item[i]; if (v == NULL) { Py_ssize_t size = Py_SIZE(a); - for (Py_ssize_t idx = i; idx < size - 1; idx++) { - FT_ATOMIC_STORE_PTR_RELEASE(a->ob_item[idx], a->ob_item[idx + 1]); + if (i < size - 1) { + list_shift_items_left_lock_held(a, i, size - 1); } Py_SET_SIZE(a, size - 1); }