@@ -447,6 +447,23 @@ gc_visit_thread_stacks(PyInterpreterState *interp)
447447    _Py_FOR_EACH_TSTATE_END (interp );
448448}
449449
450+ // Untrack objects that can never create reference cycles. 
451+ // Return true if the object was untracked. 
452+ static  bool 
453+ gc_maybe_untrack (PyObject  * op )
454+ {
455+     // Currently we only check for tuples containing only non-GC objects.  In 
456+     // theory we could check other immutable objects that contain references 
457+     // to non-GC objects. 
458+     if  (PyTuple_CheckExact (op )) {
459+         _PyTuple_MaybeUntrack (op );
460+         if  (!_PyObject_GC_IS_TRACKED (op )) {
461+             return  true;
462+         }
463+     }
464+     return  false;
465+ }
466+ 
450467#ifdef  GC_ENABLE_MARK_ALIVE 
451468static  int 
452469mark_alive_stack_push (PyObject  * op , _PyObjectStack  * stack )
@@ -460,16 +477,12 @@ mark_alive_stack_push(PyObject *op, _PyObjectStack *stack)
460477    if  (gc_is_alive (op )) {
461478        return  0 ; // already visited this object 
462479    }
463-     if  (!_PyObject_HasDeferredRefcount (op )) {
464-         // Untrack objects that can never create reference cycles.  Currently 
465-         // we only check for tuples containing only non-GC objects. 
466-         if  (PyTuple_CheckExact (op )) {
467-             _PyTuple_MaybeUntrack (op );
468-             if  (!_PyObject_GC_IS_TRACKED (op )) {
469-                 return  0 ;
470-             }
471-         }
480+     if  (gc_maybe_untrack (op )) {
481+         return  0 ; // was untracked, don't visit it 
472482    }
483+ 
484+     // Need to call tp_traverse on this object. Add to stack and mark it 
485+     // alive so we don't re-visit it a second time. 
473486    gc_set_alive (op );
474487    if  (_PyObjectStack_Push (stack , op ) <  0 ) {
475488        _PyObjectStack_Clear (stack );
@@ -632,14 +645,9 @@ update_refs(const mi_heap_t *heap, const mi_heap_area_t *area,
632645    _PyObject_ASSERT (op , refcount  >= 0 );
633646
634647    if  (refcount  >  0  &&  !_PyObject_HasDeferredRefcount (op )) {
635-         // Untrack tuples and dicts as necessary in this pass, but not objects 
636-         // with zero refcount, which we will want to collect. 
637-         if  (PyTuple_CheckExact (op )) {
638-             _PyTuple_MaybeUntrack (op );
639-             if  (!_PyObject_GC_IS_TRACKED (op )) {
640-                 gc_restore_refs (op );
641-                 return  true;
642-             }
648+         if  (gc_maybe_untrack (op )) {
649+             gc_restore_refs (op );
650+             return  true;
643651        }
644652    }
645653
0 commit comments