Skip to content

Commit f05fefc

Browse files
committed
gh-135832: Implement _Py_DECREF_SPECIALIZED and PyStackRef_CLOSE_SPECIALIZED for free-threading
This should help single-threaded performance.
1 parent 5afbb60 commit f05fefc

4 files changed

Lines changed: 62 additions & 4 deletions

File tree

Include/internal/pycore_object.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,11 +253,25 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct)
253253
}
254254

255255
#else
256-
// TODO: implement Py_DECREF specializations for Py_GIL_DISABLED build
257256
static inline void
258257
_Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct)
259258
{
260-
Py_DECREF(op);
259+
uint32_t local = _Py_atomic_load_uint32_relaxed(&op->ob_ref_local);
260+
if (local == _Py_IMMORTAL_REFCNT_LOCAL) {
261+
_Py_DECREF_IMMORTAL_STAT_INC();
262+
return;
263+
}
264+
_Py_DECREF_STAT_INC();
265+
if (_Py_IsOwnedByCurrentThread(op)) {
266+
local--;
267+
_Py_atomic_store_uint32_relaxed(&op->ob_ref_local, local);
268+
if (local == 0) {
269+
_Py_MergeZeroLocalRefcountSpecialized(op, destruct);
270+
}
271+
}
272+
else {
273+
_Py_DecRefShared(op);
274+
}
261275
}
262276

263277
static inline int
@@ -465,7 +479,7 @@ static inline void Py_DECREF_MORTAL_SPECIALIZED(PyObject *op, destructor destruc
465479
#endif
466480
#else // Py_GIL_DISABLED
467481
# define Py_DECREF_MORTAL(op) Py_DECREF(op)
468-
# define Py_DECREF_MORTAL_SPECIALIZED(op, destruct) Py_DECREF(op)
482+
# define Py_DECREF_MORTAL_SPECIALIZED(op, destruct) _Py_DECREF_SPECIALIZED(op, destruct)
469483
#endif
470484

471485
/* Inline functions trading binary compatibility for speed:

Include/refcount.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ PyAPI_FUNC(void) _Py_DecRefSharedDebug(PyObject *, const char *, int);
321321
// zero. Otherwise, the thread gives up ownership and merges the reference
322322
// count fields.
323323
PyAPI_FUNC(void) _Py_MergeZeroLocalRefcount(PyObject *);
324+
PyAPI_FUNC(void) _Py_MergeZeroLocalRefcountSpecialized(PyObject *, const destructor);
324325
#endif // Py_GIL_DISABLED
325326
#endif // Py_LIMITED_API
326327

Objects/object.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,30 @@ _Py_MergeZeroLocalRefcount(PyObject *op)
464464
}
465465
}
466466

467+
void
468+
_Py_MergeZeroLocalRefcountSpecialized(PyObject *op, const destructor destruct)
469+
{
470+
assert(op->ob_ref_local == 0);
471+
472+
Py_ssize_t shared = _Py_atomic_load_ssize_acquire(&op->ob_ref_shared);
473+
if (shared == 0) {
474+
destruct(op);
475+
return;
476+
}
477+
478+
_Py_atomic_store_uintptr_relaxed(&op->ob_tid, 0);
479+
480+
Py_ssize_t new_shared;
481+
do {
482+
new_shared = (shared & ~_Py_REF_SHARED_FLAG_MASK) | _Py_REF_MERGED;
483+
} while (!_Py_atomic_compare_exchange_ssize(&op->ob_ref_shared,
484+
&shared, new_shared));
485+
486+
if (new_shared == _Py_REF_MERGED) {
487+
destruct(op);
488+
}
489+
}
490+
467491
Py_ssize_t
468492
_Py_ExplicitMergeRefcount(PyObject *op, Py_ssize_t extra)
469493
{

Python/ceval.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,26 @@
132132
} while (0)
133133

134134
#undef _Py_DECREF_SPECIALIZED
135-
#define _Py_DECREF_SPECIALIZED(arg, dealloc) Py_DECREF(arg)
135+
#define _Py_DECREF_SPECIALIZED(arg, dealloc) \
136+
do { \
137+
PyObject *op = _PyObject_CAST(arg); \
138+
uint32_t local = _Py_atomic_load_uint32_relaxed(&op->ob_ref_local); \
139+
if (local == _Py_IMMORTAL_REFCNT_LOCAL) { \
140+
_Py_DECREF_IMMORTAL_STAT_INC(); \
141+
break; \
142+
} \
143+
_Py_DECREF_STAT_INC(); \
144+
if (_Py_IsOwnedByCurrentThread(op)) { \
145+
local--; \
146+
_Py_atomic_store_uint32_relaxed(&op->ob_ref_local, local); \
147+
if (local == 0) { \
148+
_Py_MergeZeroLocalRefcountSpecialized(op, dealloc); \
149+
} \
150+
} \
151+
else { \
152+
_Py_DecRefShared(op); \
153+
} \
154+
} while (0)
136155

137156
#endif
138157
#endif

0 commit comments

Comments
 (0)