Skip to content

Commit 6f96653

Browse files
committed
gh-135832: implement Py_DECREF specializations for Py_GIL_DISABLED build
1 parent ac9d37c commit 6f96653

File tree

1 file changed

+79
-3
lines changed

1 file changed

+79
-3
lines changed

Include/internal/pycore_object.h

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
276276
static 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

282316
static 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

288364
static inline int

0 commit comments

Comments
 (0)