1818#include "pydtrace.h"
1919#include "pycore_uniqueid.h" // _PyObject_MergeThreadLocalRefcounts()
2020
21+
22+ // enable the "mark alive" pass of GC
23+ #define GC_ENABLE_MARK_ALIVE 1
24+
25+ // include addtional roots in "mark alive" pass
26+ //#define GC_MARK_ALIVE_EXTRA_ROOTS 1
27+
28+ // include Python stacks as set of known roots
29+ //#define GC_MARK_ALIVE_STACKS 1
30+
31+
2132#ifdef Py_GIL_DISABLED
2233
2334typedef struct _gc_runtime_state GCState ;
@@ -34,7 +45,7 @@ typedef struct _gc_runtime_state GCState;
3445// Automatically choose the generation that needs collecting.
3546#define GENERATION_AUTO (-1)
3647
37- #if WITH_GC_TIMING_STATS
48+ #ifdef WITH_GC_TIMING_STATS
3849
3950static void p2engine_init (p2_engine * engine , const double quantiles [QUANTILE_COUNT ]) {
4051 engine -> count = 0 ;
@@ -312,11 +323,13 @@ gc_is_alive(PyObject *op)
312323 return gc_has_bit (op , _PyGC_BITS_ALIVE );
313324}
314325
326+ #ifdef GC_ENABLE_MARK_ALIVE
315327static void
316328gc_set_alive (PyObject * op )
317329{
318330 gc_set_bit (op , _PyGC_BITS_ALIVE );
319331}
332+ #endif
320333
321334static void
322335gc_clear_alive (PyObject * op )
@@ -584,8 +597,9 @@ gc_visit_thread_stacks(PyInterpreterState *interp)
584597 _Py_FOR_EACH_TSTATE_END (interp );
585598}
586599
600+ #ifdef GC_ENABLE_MARK_ALIVE
587601static bool
588- mark_stack_push (_PyObjectStack * stack , PyObject * op )
602+ mark_alive_stack_push (_PyObjectStack * stack , PyObject * op )
589603{
590604 if (op == NULL ) {
591605 return true;
@@ -599,7 +613,9 @@ mark_stack_push(_PyObjectStack *stack, PyObject *op)
599613 return true;
600614}
601615
602- static inline void
616+
617+ #ifdef GC_MARK_ALIVE_STACKS
618+ static bool
603619gc_visit_stackref_mark_alive (_PyObjectStack * stack , _PyStackRef stackref )
604620{
605621 // Note: we MUST check that it is deferred before checking the rest.
@@ -608,12 +624,15 @@ gc_visit_stackref_mark_alive(_PyObjectStack *stack, _PyStackRef stackref)
608624 if (PyStackRef_IsDeferred (stackref ) && !PyStackRef_IsNull (stackref )) {
609625 PyObject * obj = PyStackRef_AsPyObjectBorrow (stackref );
610626 if (_PyObject_GC_IS_TRACKED (obj ) && !gc_is_frozen (obj )) {
611- mark_stack_push (stack , obj );
627+ if (!mark_alive_stack_push (stack , obj )) {
628+ return false;
629+ }
612630 }
613631 }
632+ return true;
614633}
615634
616- static void
635+ static bool
617636gc_visit_thread_stacks_mark_alive (PyInterpreterState * interp , _PyObjectStack * stack )
618637{
619638 _Py_FOR_EACH_TSTATE_BEGIN (interp , p ) {
@@ -625,14 +644,21 @@ gc_visit_thread_stacks_mark_alive(PyInterpreterState *interp, _PyObjectStack *st
625644
626645 PyCodeObject * co = (PyCodeObject * )executable ;
627646 int max_stack = co -> co_nlocalsplus + co -> co_stacksize ;
628- gc_visit_stackref (f -> f_executable );
647+ if (!gc_visit_stackref_mark_alive (stack , f -> f_executable )) {
648+ return false;
649+ }
629650 for (int i = 0 ; i < max_stack ; i ++ ) {
630- gc_visit_stackref_mark_alive (stack , f -> localsplus [i ]);
651+ if (!gc_visit_stackref_mark_alive (stack , f -> localsplus [i ])) {
652+ return false;
653+ }
631654 }
632655 }
633656 }
634657 _Py_FOR_EACH_TSTATE_END (interp );
658+ return true;
635659}
660+ #endif // GC_MARK_ALIVE_STACKS
661+ #endif // GC_ENABLE_MARK_ALIVE
636662
637663static void
638664queue_untracked_obj_decref (PyObject * op , struct collection_state * state )
@@ -974,7 +1000,7 @@ scan_heap_visitor(const mi_heap_t *heap, const mi_heap_area_t *area,
9741000static int
9751001move_legacy_finalizer_reachable (struct collection_state * state );
9761002
977- #if WITH_GC_TIMING_STATS
1003+ #ifdef WITH_GC_TIMING_STATS
9781004FILE * gc_log ;
9791005static void
9801006print_gc_times (GCState * gcstate )
@@ -989,6 +1015,7 @@ print_gc_times(GCState *gcstate)
9891015}
9901016#endif // WITH_GC_TIMING_STATS
9911017
1018+ #ifdef GC_ENABLE_MARK_ALIVE
9921019static int
9931020visit_propagate_alive (PyObject * op , _PyObjectStack * stack )
9941021{
@@ -1022,7 +1049,7 @@ static int
10221049mark_root_reachable (PyInterpreterState * interp ,
10231050 struct collection_state * state )
10241051{
1025- #if WITH_GC_TIMING_STATS
1052+ #ifdef WITH_GC_TIMING_STATS
10261053 PyTime_t t1 ;
10271054 (void )PyTime_PerfCounterRaw (& t1 );
10281055#endif
@@ -1032,29 +1059,45 @@ mark_root_reachable(PyInterpreterState *interp,
10321059 gc_visit_heaps (interp , & validate_alive_bits , & state -> base );
10331060#endif
10341061 _PyObjectStack stack = { NULL };
1035- gc_visit_thread_stacks_mark_alive (interp , & stack );
1036- mark_stack_push (& stack , interp -> sysdict );
1037- mark_stack_push (& stack , interp -> builtins );
1038- mark_stack_push (& stack , interp -> dict );
1062+
1063+ #define STACK_PUSH (op ) \
1064+ if (!mark_alive_stack_push(&stack, op)) { \
1065+ _PyObjectStack_Clear(&stack); \
1066+ return -1; \
1067+ }
1068+ STACK_PUSH (interp -> sysdict );
1069+ #ifdef GC_MARK_ALIVE_EXTRA_ROOTS
1070+ STACK_PUSH (interp -> builtins );
1071+ STACK_PUSH (interp -> dict );
10391072 struct types_state * types = & interp -> types ;
10401073 for (int i = 0 ; i < _Py_MAX_MANAGED_STATIC_BUILTIN_TYPES ; i ++ ) {
1041- mark_stack_push ( & stack , types -> builtins .initialized [i ].tp_dict );
1042- mark_stack_push ( & stack , types -> builtins .initialized [i ].tp_subclasses );
1074+ STACK_PUSH ( types -> builtins .initialized [i ].tp_dict );
1075+ STACK_PUSH ( types -> builtins .initialized [i ].tp_subclasses );
10431076 }
10441077 for (int i = 0 ; i < _Py_MAX_MANAGED_STATIC_EXT_TYPES ; i ++ ) {
1045- mark_stack_push (& stack , types -> for_extensions .initialized [i ].tp_dict );
1046- mark_stack_push (& stack , types -> for_extensions .initialized [i ].tp_subclasses );
1078+ STACK_PUSH (types -> for_extensions .initialized [i ].tp_dict );
1079+ STACK_PUSH (types -> for_extensions .initialized [i ].tp_subclasses );
1080+ }
1081+ #endif
1082+ #ifdef GC_MARK_ALIVE_STACKS
1083+ if (!gc_visit_thread_stacks_mark_alive (interp , & stack )) {
1084+ _PyObjectStack_Clear (& stack );
1085+ return -1 ;
10471086 }
1087+ #endif
1088+ #undef STACK_PUSH
1089+
10481090 propagate_alive_bits (& stack );
10491091
1050- #if WITH_GC_TIMING_STATS
1092+ #ifdef WITH_GC_TIMING_STATS
10511093 PyTime_t t2 ;
10521094 (void )PyTime_PerfCounterRaw (& t2 );
10531095 interp -> gc .timing_state .gc_mark_time += t2 - t1 ;
10541096#endif
10551097
10561098 return 0 ;
10571099}
1100+ #endif // GC_ENABLE_MARK_ALIVE
10581101
10591102
10601103static int
@@ -1245,7 +1288,7 @@ _PyGC_Init(PyInterpreterState *interp)
12451288 return _PyStatus_NO_MEMORY ();
12461289 }
12471290
1248- #if WITH_GC_TIMING_STATS
1291+ #ifdef WITH_GC_TIMING_STATS
12491292 gc_log = fopen ("/tmp/gc_timing.log" , "a" );
12501293 //p2engine_init(&gcstate->timing_state.auto_all, gc_timing_quantiles);
12511294 p2engine_init (& gcstate -> timing_state .auto_full , gc_timing_quantiles );
@@ -1630,7 +1673,7 @@ gc_collect_internal(PyInterpreterState *interp, struct collection_state *state,
16301673
16311674 process_delayed_frees (interp , state );
16321675
1633- #if 1
1676+ #ifdef GC_ENABLE_MARK_ALIVE
16341677 if (!state -> gcstate -> freeze_used ) {
16351678 // Mark objects reachable from known roots as "alive". These will
16361679 // be ignored for rest of the GC pass.
@@ -1744,7 +1787,7 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason)
17441787 invoke_gc_callback (tstate , "start" , generation , 0 , 0 );
17451788 }
17461789
1747- #if WITH_GC_TIMING_STATS
1790+ #ifdef WITH_GC_TIMING_STATS
17481791 PyTime_t gc_timing_t1 ;
17491792 (void )PyTime_PerfCounterRaw (& gc_timing_t1 );
17501793#endif
@@ -1782,7 +1825,7 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason)
17821825 n + m , n , state .long_lived_total , d );
17831826 }
17841827
1785- #if WITH_GC_TIMING_STATS
1828+ #ifdef WITH_GC_TIMING_STATS
17861829 PyTime_t gc_timing_t2 , dt ;
17871830 (void )PyTime_PerfCounterRaw (& gc_timing_t2 );
17881831 dt = gc_timing_t2 - gc_timing_t1 ;
@@ -1831,7 +1874,7 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason)
18311874 }
18321875#endif
18331876
1834- #if WITH_GC_TIMING_STATS
1877+ #ifdef WITH_GC_TIMING_STATS
18351878 fprintf (gc_log , "gc alive %d collected %ld checked %d gc %d\n" , num_alive , m , num_checked , num_gc );
18361879 fflush (gc_log );
18371880 #endif
@@ -2165,7 +2208,7 @@ _PyGC_Fini(PyInterpreterState *interp)
21652208 Py_CLEAR (gcstate -> garbage );
21662209 Py_CLEAR (gcstate -> callbacks );
21672210
2168- #if WITH_GC_TIMING_STATS
2211+ #ifdef WITH_GC_TIMING_STATS
21692212 print_gc_times (gcstate );
21702213 #if 0 // no generations so all are full collections
21712214 for (int i = 0 ; i < QUANTILE_COUNT ; i ++ ) {
0 commit comments