@@ -155,13 +155,13 @@ gc_is_unreachable(PyObject *op)
155155 return gc_has_bit (op , _PyGC_BITS_UNREACHABLE );
156156}
157157
158- static void
158+ static inline void
159159gc_set_unreachable (PyObject * op )
160160{
161161 gc_set_bit (op , _PyGC_BITS_UNREACHABLE );
162162}
163163
164- static void
164+ static inline void
165165gc_clear_unreachable (PyObject * op )
166166{
167167 gc_clear_bit (op , _PyGC_BITS_UNREACHABLE );
@@ -174,14 +174,14 @@ gc_is_alive(PyObject *op)
174174}
175175
176176#ifdef GC_ENABLE_MARK_ALIVE
177- static void
177+ static inline void
178178gc_set_alive (PyObject * op )
179179{
180180 gc_set_bit (op , _PyGC_BITS_ALIVE );
181181}
182182#endif
183183
184- static void
184+ static inline void
185185gc_clear_alive (PyObject * op )
186186{
187187 gc_clear_bit (op , _PyGC_BITS_ALIVE );
@@ -448,22 +448,26 @@ gc_visit_thread_stacks(PyInterpreterState *interp)
448448}
449449
450450#ifdef GC_ENABLE_MARK_ALIVE
451- static bool
452- mark_alive_stack_push (_PyObjectStack * stack , PyObject * op )
451+ static int
452+ mark_alive_stack_push (PyObject * op , _PyObjectStack * stack )
453453{
454454 if (op == NULL ) {
455- return true;
455+ return 0 ;
456+ }
457+ if (!_PyObject_GC_IS_TRACKED (op )) {
458+ return 0 ;
459+ }
460+ if (gc_is_alive (op )) {
461+ return 0 ; // already visited this object
456462 }
457- assert (!gc_is_alive (op ));
458463 gc_set_alive (op );
459- //gc_maybe_merge_refcount(op);
460464 if (_PyObjectStack_Push (stack , op ) < 0 ) {
461- return false;
465+ _PyObjectStack_Clear (stack );
466+ return -1 ;
462467 }
463- return true ;
468+ return 0 ;
464469}
465470
466-
467471#ifdef GC_MARK_ALIVE_STACKS
468472static bool
469473gc_visit_stackref_mark_alive (_PyObjectStack * stack , _PyStackRef stackref )
@@ -472,11 +476,9 @@ gc_visit_stackref_mark_alive(_PyObjectStack *stack, _PyStackRef stackref)
472476 // Otherwise we might read into invalid memory due to non-deferred references
473477 // being dead already.
474478 if (PyStackRef_IsDeferred (stackref ) && !PyStackRef_IsNull (stackref )) {
475- PyObject * obj = PyStackRef_AsPyObjectBorrow (stackref );
476- if (_PyObject_GC_IS_TRACKED (obj ) && !gc_is_frozen (obj )) {
477- if (!mark_alive_stack_push (stack , obj )) {
478- return false;
479- }
479+ PyObject * op = PyStackRef_AsPyObjectBorrow (stackref );
480+ if (mark_alive_stack_push (op , stack ) < 0 ) {
481+ return false;
480482 }
481483 }
482484 return true;
@@ -836,16 +838,6 @@ static int
836838move_legacy_finalizer_reachable (struct collection_state * state );
837839
838840#ifdef GC_ENABLE_MARK_ALIVE
839- static int
840- visit_propagate_alive (PyObject * op , _PyObjectStack * stack )
841- {
842- if (_PyObject_GC_IS_TRACKED (op ) && !gc_is_alive (op )) {
843- gc_set_alive (op );
844- return _PyObjectStack_Push (stack , op );
845- }
846- return 0 ;
847- }
848-
849841static int
850842propagate_alive_bits (_PyObjectStack * stack )
851843{
@@ -857,27 +849,37 @@ propagate_alive_bits(_PyObjectStack *stack)
857849 assert (_PyObject_GC_IS_TRACKED (op ));
858850 assert (gc_is_alive (op ));
859851 traverseproc traverse = Py_TYPE (op )-> tp_traverse ;
860- if (traverse (op , (visitproc )& visit_propagate_alive , stack ) < 0 ) {
861- _PyObjectStack_Clear (stack );
852+ if (traverse (op , (visitproc )& mark_alive_stack_push , stack ) < 0 ) {
862853 return -1 ;
863854 }
864855 }
865856 return 0 ;
866857}
867858
859+ // Using tp_traverse, mark everything reachable from known root objects
860+ // (which must be non-garbage) as alive (_PyGC_BITS_ALIVE is set). In
861+ // most programs, this marks nearly all objects that are not actually
862+ // unreachable. Actually alive objects can be missed in this pass if
863+ // they are alive due to being referenced from an unknown root (e.g. an
864+ // extension module global), some tp_traverse methods are either missing
865+ // or not accurate, or objects that have been untracked (and objects
866+ // referenced by those). If gc.freeze() is used, this pass is disabled
867+ // since it is unlikely to help much. The next stages of cyclic GC will
868+ // ignore objects with the alive bit set.
869+ //
870+ // Returns -1 on failure (out of memory).
868871static int
869- mark_root_reachable (PyInterpreterState * interp ,
870- struct collection_state * state )
872+ mark_alive_from_roots (PyInterpreterState * interp ,
873+ struct collection_state * state )
871874{
872875#ifdef GC_DEBUG
873- // Check that all objects don't have ALIVE bits set
876+ // Check that all objects don't have alive bit set
874877 gc_visit_heaps (interp , & validate_alive_bits , & state -> base );
875878#endif
876879 _PyObjectStack stack = { NULL };
877880
878881 #define STACK_PUSH (op ) \
879- if (!mark_alive_stack_push(&stack, op)) { \
880- _PyObjectStack_Clear(&stack); \
882+ if (mark_alive_stack_push(op, &stack) < 0) { \
881883 return -1; \
882884 }
883885 STACK_PUSH (interp -> sysdict );
@@ -896,12 +898,12 @@ mark_root_reachable(PyInterpreterState *interp,
896898#endif
897899#ifdef GC_MARK_ALIVE_STACKS
898900 if (!gc_visit_thread_stacks_mark_alive (interp , & stack )) {
899- _PyObjectStack_Clear (& stack );
900901 return -1 ;
901902 }
902903#endif
903904 #undef STACK_PUSH
904905
906+ // Use tp_traverse to find everything reachable from roots.
905907 propagate_alive_bits (& stack );
906908
907909 return 0 ;
@@ -1472,7 +1474,7 @@ gc_collect_internal(PyInterpreterState *interp, struct collection_state *state,
14721474 if (!state -> gcstate -> freeze_active ) {
14731475 // Mark objects reachable from known roots as "alive". These will
14741476 // be ignored for rest of the GC pass.
1475- int err = mark_root_reachable (interp , state );
1477+ int err = mark_alive_from_roots (interp , state );
14761478 if (err < 0 ) {
14771479 _PyEval_StartTheWorld (interp );
14781480 PyErr_NoMemory ();
@@ -1490,7 +1492,7 @@ gc_collect_internal(PyInterpreterState *interp, struct collection_state *state,
14901492 }
14911493
14921494#ifdef GC_DEBUG
1493- // At this point, no object should have ALIVE bit set
1495+ // At this point, no object should have the alive bit set
14941496 gc_visit_heaps (interp , & validate_alive_bits , & state -> base );
14951497#endif
14961498
0 commit comments