@@ -272,17 +272,93 @@ _Py_DECREF_NO_DEALLOC(PyObject *op)
272272}
273273
274274#else
275- // TODO: implement Py_DECREF specializations for Py_GIL_DISABLED build
275+
276276static inline void
277277_Py_DECREF_SPECIALIZED (PyObject * op , const destructor destruct )
278278{
279- Py_DECREF (op );
279+ uint32_t local = _Py_atomic_load_uint32_relaxed (& op -> ob_ref_local );
280+ if (local == _Py_IMMORTAL_REFCNT_LOCAL ) {
281+ _Py_DECREF_IMMORTAL_STAT_INC ();
282+ return ;
283+ }
284+ _Py_DECREF_STAT_INC ();
285+ #ifdef Py_REF_DEBUG
286+ _Py_DECREF_DecRefTotal ();
287+ #endif
288+ if (_Py_IsOwnedByCurrentThread (op )) {
289+ local -- ;
290+ _Py_atomic_store_uint32_relaxed (& op -> ob_ref_local , local );
291+ if (local == 0 ) {
292+ _Py_MergeZeroLocalRefcount (op );
293+ }
294+ }
295+ else {
296+ Py_ssize_t shared = _Py_atomic_load_ssize_relaxed (& op -> ob_ref_shared );
297+ for (;;) {
298+ Py_ssize_t new_shared = shared - (1 << _Py_REF_SHARED_SHIFT );
299+ if (_Py_atomic_compare_exchange_ssize (
300+ & op -> ob_ref_shared ,
301+ & shared ,
302+ new_shared )) {
303+ if (new_shared == 0 ) {
304+ #ifdef Py_TRACE_REFS
305+ _Py_ForgetReference (op );
306+ #endif
307+ _PyReftracerTrack (op , PyRefTracer_DESTROY );
308+ destruct (op );
309+ }
310+ break ;
311+ }
312+ }
313+ }
280314}
281315
282316static inline void
283317_Py_DECREF_NO_DEALLOC (PyObject * op )
284318{
285- Py_DECREF (op );
319+ uint32_t local = _Py_atomic_load_uint32_relaxed (& op -> ob_ref_local );
320+ if (local == _Py_IMMORTAL_REFCNT_LOCAL ) {
321+ _Py_DECREF_IMMORTAL_STAT_INC ();
322+ return ;
323+ }
324+ _Py_DECREF_STAT_INC ();
325+ #ifdef Py_REF_DEBUG
326+ _Py_DECREF_DecRefTotal ();
327+ #endif
328+ if (_Py_IsOwnedByCurrentThread (op )) {
329+ local -- ;
330+ _Py_atomic_store_uint32_relaxed (& op -> ob_ref_local , local );
331+ if (local == 0 ) {
332+ _Py_MergeZeroLocalRefcount (op );
333+ }
334+ }
335+ else {
336+ Py_ssize_t shared = _Py_atomic_load_ssize_relaxed (& op -> ob_ref_shared );
337+ for (;;) {
338+ Py_ssize_t new_shared = shared - (1 << _Py_REF_SHARED_SHIFT );
339+ if (_Py_atomic_compare_exchange_ssize (
340+ & op -> ob_ref_shared ,
341+ & shared ,
342+ new_shared )) {
343+ break ;
344+ }
345+ }
346+ }
347+ #ifdef Py_DEBUG
348+ // Check that the refcount is still positive after decrement
349+ if (_Py_IsOwnedByCurrentThread (op )) {
350+ uint32_t final_local = _Py_atomic_load_uint32_relaxed (& op -> ob_ref_local );
351+ if (final_local == 0 ) {
352+ _Py_FatalRefcountError ("Expected a positive remaining refcount" );
353+ }
354+ }
355+ else {
356+ Py_ssize_t final_shared = _Py_atomic_load_ssize_relaxed (& op -> ob_ref_shared );
357+ if ((final_shared >> _Py_REF_SHARED_SHIFT ) <= 0 ) {
358+ _Py_FatalRefcountError ("Expected a positive remaining refcount" );
359+ }
360+ }
361+ #endif
286362}
287363
288364static inline int
0 commit comments