From ff23f21535bcd2c5294ab7c6dea1d710e7dce131 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Wed, 28 May 2025 13:31:05 +0000 Subject: [PATCH 1/2] Thin POC. --- Python/gc_free_threading.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index d2ea5b5e06ba43..ed63a279e2e5f0 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -1170,6 +1170,26 @@ has_legacy_finalizer(PyObject *op) return Py_TYPE(op)->tp_del != NULL; } +static void +maybe_enable_deferred_refcount(PyObject *op) +{ + assert(op != NULL); + if (has_legacy_finalizer(op)) { + // Objects with finalizers would be broken by + // deferred reference counting. + return; + } + + uint8_t bits = op->ob_gc_bits; + if ((bits & _PyGC_BITS_DEFERRED) != 0) { + // This object already has deferred refcounting + return; + } + + op->ob_gc_bits |= _PyGC_BITS_DEFERRED; + op->ob_ref_shared += _Py_REF_SHARED(_Py_REF_DEFERRED, 0); +} + static bool scan_heap_visitor(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *args) @@ -1198,6 +1218,11 @@ scan_heap_visitor(const mi_heap_t *heap, const mi_heap_area_t *area, worklist_push(&state->unreachable, op); } return true; + } else if (_Py_REF_SHARED(Py_REFCNT(op), 0) >= 3) { + // Objects with 3 or more shared references are candidates + // for deferred reference counting. + // This probably needs tuning. + maybe_enable_deferred_refcount(op); } if (state->reason == _Py_GC_REASON_SHUTDOWN) { From 091429e6a118b4d69cd799a54f69ba756fbd8b10 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Thu, 29 May 2025 07:07:43 -0400 Subject: [PATCH 2/2] Only check the shared field. --- Python/gc_free_threading.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c index ed63a279e2e5f0..98e4fb0d8849e5 100644 --- a/Python/gc_free_threading.c +++ b/Python/gc_free_threading.c @@ -1218,8 +1218,8 @@ scan_heap_visitor(const mi_heap_t *heap, const mi_heap_area_t *area, worklist_push(&state->unreachable, op); } return true; - } else if (_Py_REF_SHARED(Py_REFCNT(op), 0) >= 3) { - // Objects with 3 or more shared references are candidates + } else if (_Py_REF_SHARED(op->ob_ref_shared, 0) >= 3) { + // Objects with 10 or more shared references are candidates // for deferred reference counting. // This probably needs tuning. maybe_enable_deferred_refcount(op);