Skip to content

Commit 968a42a

Browse files
committed
Use a faster implementation
1 parent 4dec7ec commit 968a42a

File tree

1 file changed

+27
-16
lines changed

1 file changed

+27
-16
lines changed

mypyc/lib-rt/list_ops.c

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -235,17 +235,35 @@ void CPyList_SetItemUnsafe(PyObject *list, Py_ssize_t index, PyObject *value) {
235235
PyList_SET_ITEM(list, index, value);
236236
}
237237

238-
PyObject *CPyList_PopLast(PyObject *obj)
238+
#ifdef Py_GIL_DISABLED
239+
// The original optimized list.pop implementation doesn't work on free-threaded
240+
// builds, so provide an alternative that is a bit slower but works.
241+
//
242+
// Note that this implementation isn't intended to be atomic.
243+
static inline PyObject *list_pop_index(PyObject *list, Py_ssize_t index) {
244+
PyObject *item = PyList_GetItemRef(list, index);
245+
if (item == NULL) {
246+
return NULL;
247+
}
248+
if (PySequence_DelItem(list, index) < 0) {
249+
Py_DECREF(item);
250+
return NULL;
251+
}
252+
return item;
253+
}
254+
#endif
255+
256+
PyObject *CPyList_PopLast(PyObject *list)
239257
{
240258
#ifdef Py_GIL_DISABLED
241-
// The optimized version causes segfaults on a free-threaded Python 3.14b4 build,
242-
// at least on macOS, so fall back to a generic implementation.
243-
return PyObject_CallMethod(obj, "pop", NULL);
259+
// The other implementation causes segfaults on a free-threaded Python 3.14b4 build.
260+
Py_ssize_t index = PyList_GET_SIZE(list) - 1;
261+
return list_pop_index(list, index);
244262
#else
245263
// I tried a specalized version of pop_impl for just removing the
246264
// last element and it wasn't any faster in microbenchmarks than
247265
// the generic one so I ditched it.
248-
return list_pop_impl((PyListObject *)obj, -1);
266+
return list_pop_impl((PyListObject *)list, -1);
249267
#endif
250268
}
251269

@@ -254,18 +272,11 @@ PyObject *CPyList_Pop(PyObject *obj, CPyTagged index)
254272
if (CPyTagged_CheckShort(index)) {
255273
Py_ssize_t n = CPyTagged_ShortAsSsize_t(index);
256274
#ifdef Py_GIL_DISABLED
257-
static PyObject *interned_pop_str = NULL;
258-
if (!interned_pop_str) {
259-
interned_pop_str = PyUnicode_InternFromString("pop");
260-
if (!interned_pop_str)
261-
return NULL;
275+
// We must use a slower implementation on free-threaded builds.
276+
if (n < 0) {
277+
n += PyList_GET_SIZE(obj);
262278
}
263-
PyObject *index_obj = PyLong_FromLong(n); // New reference
264-
if (index_obj == NULL)
265-
return NULL;
266-
PyObject *result = PyObject_CallMethodOneArg(obj, interned_pop_str, index_obj);
267-
Py_DECREF(index_obj);
268-
return result;
279+
return list_pop_index(obj, n);
269280
#else
270281
return list_pop_impl((PyListObject *)obj, n);
271282
#endif

0 commit comments

Comments
 (0)