From f63e33717292c9e779d4dee3889f6c6e2eca27fb Mon Sep 17 00:00:00 2001 From: Donghee Nals Date: Sat, 16 Mar 2024 17:20:43 +0900 Subject: [PATCH 1/2] gh-116621: Specialize list.extend for dict items --- Objects/listobject.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/Objects/listobject.c b/Objects/listobject.c index 6f919ce02b3ce2..840feaa3183f76 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1320,6 +1320,35 @@ list_extend_dict(PyListObject *self, PyDictObject *dict, int which_item) return 0; } +static int +list_extend_dictitems(PyListObject *self, PyDictObject *dict) +{ + Py_ssize_t m = Py_SIZE(self); + Py_ssize_t n = PyDict_GET_SIZE(dict); + if (list_resize(self, m + n) < 0) { + return -1; + } + + // TODO: Don't start a garbage collection cycle when creating tuples + PyObject **dest = self->ob_item + m; + Py_ssize_t pos = 0; + Py_ssize_t i = 0; + PyObject *key, *value; + while (_PyDict_Next((PyObject *)dict, &pos, &key, &value, NULL)) { + PyObject *item = PyTuple_Pack(2, key, value); + if (item == NULL) { + Py_SET_SIZE(self, m + i); + return -1; + } + FT_ATOMIC_STORE_PTR_RELAXED(*dest, item); + dest++; + i++; + } + + Py_SET_SIZE(self, m + n); + return 0; +} + static int _list_extend(PyListObject *self, PyObject *iterable) { @@ -1359,6 +1388,12 @@ _list_extend(PyListObject *self, PyObject *iterable) res = list_extend_dict(self, dict, 1 /*values*/); Py_END_CRITICAL_SECTION2(); } + else if (Py_IS_TYPE(iterable, &PyDictItems_Type)) { + PyDictObject *dict = ((_PyDictViewObject *)iterable)->dv_dict; + Py_BEGIN_CRITICAL_SECTION2(self, dict); + res = list_extend_dictitems(self, dict); + Py_END_CRITICAL_SECTION2(); + } else { Py_BEGIN_CRITICAL_SECTION(self); res = list_extend_iter_lock_held(self, iterable); From c764ce8799e031bf3d6e13768e1644f89e886f66 Mon Sep 17 00:00:00 2001 From: Donghee Nals Date: Tue, 19 Mar 2024 09:03:46 +0900 Subject: [PATCH 2/2] Address code review --- Objects/listobject.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 840feaa3183f76..4cb409cc524f22 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1289,7 +1289,7 @@ list_extend_set(PyListObject *self, PySetObject *other) PyObject **dest = self->ob_item + m; while (_PySet_NextEntry((PyObject *)other, &setpos, &key, &hash)) { Py_INCREF(key); - *dest = key; + FT_ATOMIC_STORE_PTR_RELEASE(*dest, key); dest++; } Py_SET_SIZE(self, m + n); @@ -1312,7 +1312,7 @@ list_extend_dict(PyListObject *self, PyDictObject *dict, int which_item) while (_PyDict_Next((PyObject *)dict, &pos, &keyvalue[0], &keyvalue[1], NULL)) { PyObject *obj = keyvalue[which_item]; Py_INCREF(obj); - *dest = obj; + FT_ATOMIC_STORE_PTR_RELEASE(*dest, obj); dest++; } @@ -1329,7 +1329,6 @@ list_extend_dictitems(PyListObject *self, PyDictObject *dict) return -1; } - // TODO: Don't start a garbage collection cycle when creating tuples PyObject **dest = self->ob_item + m; Py_ssize_t pos = 0; Py_ssize_t i = 0; @@ -1340,7 +1339,7 @@ list_extend_dictitems(PyListObject *self, PyDictObject *dict) Py_SET_SIZE(self, m + i); return -1; } - FT_ATOMIC_STORE_PTR_RELAXED(*dest, item); + FT_ATOMIC_STORE_PTR_RELEASE(*dest, item); dest++; i++; } @@ -1354,7 +1353,6 @@ _list_extend(PyListObject *self, PyObject *iterable) { // Special case: // lists and tuples which can use PySequence_Fast ops - // TODO(@corona10): Add more special cases for other types. int res = -1; if ((PyObject *)self == iterable) { Py_BEGIN_CRITICAL_SECTION(self);