@@ -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