@@ -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