@@ -159,6 +159,25 @@ gc_decref(PyObject *op)
159159 op -> ob_tid -= 1 ;
160160}
161161
162+ static inline Py_ssize_t
163+ gc_refcount (PyObject * op )
164+ {
165+ Py_ssize_t refcount = Py_REFCNT (op );
166+ if (_PyObject_HasDeferredRefcount (op )) {
167+ refcount -= 1 ;
168+ }
169+ return refcount ;
170+ }
171+
172+ static void
173+ disable_deferred_refcounting (PyObject * op )
174+ {
175+ if (_PyObject_HasDeferredRefcount (op )) {
176+ op -> ob_gc_bits &= ~_PyGC_BITS_DEFERRED ;
177+ op -> ob_ref_shared -= (1 << _Py_REF_SHARED_SHIFT );
178+ }
179+ }
180+
162181static Py_ssize_t
163182merge_refcount (PyObject * op , Py_ssize_t extra )
164183{
@@ -375,9 +394,10 @@ update_refs(const mi_heap_t *heap, const mi_heap_area_t *area,
375394 }
376395
377396 Py_ssize_t refcount = Py_REFCNT (op );
397+ refcount -= _PyObject_HasDeferredRefcount (op );
378398 _PyObject_ASSERT (op , refcount >= 0 );
379399
380- if (refcount > 0 ) {
400+ if (refcount > 0 && ! _PyObject_HasDeferredRefcount ( op ) ) {
381401 // Untrack tuples and dicts as necessary in this pass, but not objects
382402 // with zero refcount, which we will want to collect.
383403 if (PyTuple_CheckExact (op )) {
@@ -466,6 +486,9 @@ mark_heap_visitor(const mi_heap_t *heap, const mi_heap_area_t *area,
466486 return true;
467487 }
468488
489+ _PyObject_ASSERT_WITH_MSG (op , gc_get_refs (op ) >= 0 ,
490+ "refcount is too small" );
491+
469492 if (gc_is_unreachable (op ) && gc_get_refs (op ) != 0 ) {
470493 // Object is reachable but currently marked as unreachable.
471494 // Mark it as reachable and traverse its pointers to find
@@ -499,6 +522,10 @@ scan_heap_visitor(const mi_heap_t *heap, const mi_heap_area_t *area,
499522
500523 struct collection_state * state = (struct collection_state * )args ;
501524 if (gc_is_unreachable (op )) {
525+ // Disable deferred refcounting for unreachable objects so that they
526+ // are collected immediately after finalization.
527+ disable_deferred_refcounting (op );
528+
502529 // Merge and add one to the refcount to prevent deallocation while we
503530 // are holding on to it in a worklist.
504531 merge_refcount (op , 1 );
0 commit comments