@@ -1431,13 +1431,92 @@ completed_cycle(GCState *gcstate)
14311431 gc = next ;
14321432 }
14331433 gcstate -> work_to_do = 0 ;
1434+ gcstate -> phase = GC_PHASE_MARK ;
1435+ }
1436+
1437+ static void
1438+ gc_mark (PyThreadState * tstate , struct gc_collection_stats * stats )
1439+ {
1440+ // TO DO -- Make this incremental
1441+ GCState * gcstate = & tstate -> interp -> gc ;
1442+ validate_old (gcstate );
1443+ PyGC_Head * visited = & gcstate -> old [gcstate -> visited_space ].head ;
1444+ PyGC_Head reachable ;
1445+ gc_list_init (& reachable );
1446+ // Move all reachable objects into visited space.
1447+ PyGC_Head * gc = AS_GC (tstate -> interp -> sysdict );
1448+ if (gc_old_space (gc ) != gcstate -> visited_space ) {
1449+ gc_flip_old_space (gc );
1450+ gc_list_move (gc , & reachable );
1451+ }
1452+ gc = AS_GC (tstate -> interp -> builtins );
1453+ if (gc_old_space (gc ) != gcstate -> visited_space ) {
1454+ gc_flip_old_space (gc );
1455+ gc_list_move (gc , & reachable );
1456+ }
1457+ // Move all objects on stacks to reachable
1458+ _PyRuntimeState * runtime = & _PyRuntime ;
1459+ HEAD_LOCK (runtime );
1460+ PyThreadState * ts = PyInterpreterState_ThreadHead (tstate -> interp );
1461+ HEAD_UNLOCK (runtime );
1462+ Py_ssize_t objects_marked = 0 ;
1463+ while (ts ) {
1464+ _PyInterpreterFrame * frame = ts -> current_frame ;
1465+ while (frame ) {
1466+ _PyStackRef * locals = frame -> localsplus ;
1467+ _PyStackRef * sp = frame -> stackpointer ;
1468+ while (sp > locals ) {
1469+ sp -- ;
1470+ if (PyStackRef_IsNull (* sp )) {
1471+ continue ;
1472+ }
1473+ PyObject * op = PyStackRef_AsPyObjectBorrow (* sp );
1474+ if (!_Py_IsImmortal (op ) && _PyObject_IS_GC (op )) {
1475+ PyGC_Head * gc = AS_GC (op );
1476+ if (_PyObject_GC_IS_TRACKED (op ) &&
1477+ gc_old_space (gc ) != gcstate -> visited_space ) {
1478+ gc_flip_old_space (gc );
1479+ objects_marked ++ ;
1480+ gc_list_move (gc , & reachable );
1481+ }
1482+ }
1483+ }
1484+ frame = frame -> previous ;
1485+ }
1486+ HEAD_LOCK (runtime );
1487+ ts = PyThreadState_Next (ts );
1488+ HEAD_UNLOCK (runtime );
1489+ }
1490+ // Transitively traverse all objects from reachable, until empty
1491+ struct container_and_flag arg = {
1492+ .container = & reachable ,
1493+ .visited_space = gcstate -> visited_space ,
1494+ .size = 0
1495+ };
1496+ while (!gc_list_is_empty (& reachable )) {
1497+ PyGC_Head * gc = _PyGCHead_NEXT (& reachable );
1498+ assert (gc_old_space (gc ) == gcstate -> visited_space );
1499+ gc_list_move (gc , visited );
1500+ PyObject * op = FROM_GC (gc );
1501+ traverseproc traverse = Py_TYPE (op )-> tp_traverse ;
1502+ (void ) traverse (op ,
1503+ visit_add_to_container ,
1504+ & arg );
1505+ }
1506+ validate_old (gcstate );
1507+ gcstate -> work_to_do -= objects_marked ;
1508+ gcstate -> phase = GC_PHASE_COLLECT ;
14341509}
14351510
14361511static void
14371512gc_collect_increment (PyThreadState * tstate , struct gc_collection_stats * stats )
14381513{
14391514 GC_STAT_ADD (1 , collections , 1 );
14401515 GCState * gcstate = & tstate -> interp -> gc ;
1516+ if (gcstate -> phase == GC_PHASE_MARK ) {
1517+ gc_mark (tstate , stats );
1518+ return ;
1519+ }
14411520 PyGC_Head * not_visited = & gcstate -> old [gcstate -> visited_space ^1 ].head ;
14421521 PyGC_Head * visited = & gcstate -> old [gcstate -> visited_space ].head ;
14431522 PyGC_Head increment ;
0 commit comments