Skip to content

Commit 754bb68

Browse files
committed
Tidy up visited tracking and add consistency asserts
1 parent 2b0a2c5 commit 754bb68

File tree

1 file changed

+48
-45
lines changed

1 file changed

+48
-45
lines changed

Python/gc.c

Lines changed: 48 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ gc_old_space(PyGC_Head *g)
106106
}
107107

108108
static inline int
109-
flip_old_space(int space)
109+
other_space(int space)
110110
{
111111
assert(space == 0 || space == 1);
112112
return space ^ _PyGC_NEXT_MASK_OLD_SPACE_1;
@@ -430,18 +430,27 @@ validate_list(PyGC_Head *head, enum flagstates flags)
430430
#endif
431431

432432
#ifdef GC_EXTRA_DEBUG
433+
434+
433435
static void
434-
validate_old(GCState *gcstate)
436+
gc_list_validate_space(PyGC_Head *head, int space) {
437+
PyGC_Head *gc = GC_NEXT(head);
438+
while (gc != head) {
439+
assert(gc_old_space(gc) == space);
440+
gc = GC_NEXT(gc);
441+
}
442+
}
443+
444+
static void
445+
validate_spaces(GCState *gcstate)
435446
{
447+
int visited = gcstate->visited_space;
448+
int not_visited = other_space(visited);
449+
gc_list_validate_space(&gcstate->young.head, not_visited);
436450
for (int space = 0; space < 2; space++) {
437-
PyGC_Head *head = &gcstate->old[space].head;
438-
PyGC_Head *gc = GC_NEXT(head);
439-
while (gc != head) {
440-
PyGC_Head *next = GC_NEXT(gc);
441-
assert(gc_old_space(gc) == space);
442-
gc = next;
443-
}
451+
gc_list_validate_space(&gcstate->old[space].head, space);
444452
}
453+
gc_list_validate_space(&gcstate->permanent_generation.head, visited);
445454
}
446455

447456
static void
@@ -463,14 +472,6 @@ validate_consistent_old_space(PyGC_Head *head)
463472
assert(prev == GC_PREV(head));
464473
}
465474

466-
static void
467-
gc_list_validate_space(PyGC_Head *head, int space) {
468-
PyGC_Head *gc = GC_NEXT(head);
469-
while (gc != head) {
470-
assert(gc_old_space(gc) == space);
471-
gc = GC_NEXT(gc);
472-
}
473-
}
474475

475476
#else
476477
#define validate_old(g) do{}while(0)
@@ -494,7 +495,7 @@ update_refs(PyGC_Head *containers)
494495
next = GC_NEXT(gc);
495496
PyObject *op = FROM_GC(gc);
496497
if (_Py_IsImmortal(op)) {
497-
gc_list_move(gc, &get_gc_state()->permanent_generation.head);
498+
_PyObject_GC_UNTRACK(op);
498499
gc = next;
499500
continue;
500501
}
@@ -1293,6 +1294,7 @@ gc_collect_young(PyThreadState *tstate,
12931294
struct gc_collection_stats *stats)
12941295
{
12951296
GCState *gcstate = &tstate->interp->gc;
1297+
validate_spaces(gcstate);
12961298
PyGC_Head *young = &gcstate->young.head;
12971299
PyGC_Head *visited = &gcstate->old[gcstate->visited_space].head;
12981300
GC_STAT_ADD(0, collections, 1);
@@ -1326,7 +1328,7 @@ gc_collect_young(PyThreadState *tstate,
13261328
}
13271329
(void)survivor_count; // Silence compiler warning
13281330
gc_list_merge(&survivors, visited);
1329-
validate_old(gcstate);
1331+
validate_spaces(gcstate);
13301332
gcstate->young.count = 0;
13311333
gcstate->old[gcstate->visited_space].count++;
13321334
Py_ssize_t scale_factor = gcstate->old[0].threshold;
@@ -1335,13 +1337,14 @@ gc_collect_young(PyThreadState *tstate,
13351337
}
13361338
gcstate->work_to_do += gcstate->heap_size / SCAN_RATE_DIVISOR / scale_factor;
13371339
add_stats(gcstate, 0, stats);
1340+
validate_spaces(gcstate);
13381341
}
13391342

13401343
#ifndef NDEBUG
13411344
static inline int
13421345
IS_IN_VISITED(PyGC_Head *gc, int visited_space)
13431346
{
1344-
assert(visited_space == 0 || flip_old_space(visited_space) == 0);
1347+
assert(visited_space == 0 || other_space(visited_space) == 0);
13451348
return gc_old_space(gc) == visited_space;
13461349
}
13471350
#endif
@@ -1406,19 +1409,15 @@ expand_region_transitively_reachable(PyGC_Head *container, PyGC_Head *gc, GCStat
14061409
static void
14071410
completed_cycle(GCState *gcstate)
14081411
{
1409-
int not_visited = flip_old_space(gcstate->visited_space);
1410-
assert(gc_list_is_empty(&gcstate->old[not_visited].head));
1411-
gcstate->visited_space = not_visited;
1412-
gcstate->visited_space = flip_old_space(gcstate->visited_space);
1413-
/* Make sure all young objects have old space bit set correctly */
1414-
PyGC_Head *young = &gcstate->young.head;
1415-
PyGC_Head *gc = GC_NEXT(young);
1416-
while (gc != young) {
1417-
PyGC_Head *next = GC_NEXT(gc);
1418-
gc_set_old_space(gc, not_visited);
1419-
gc = next;
1420-
}
1412+
/* Flip spaces */
1413+
int not_visited = gcstate->visited_space;
1414+
int visited = other_space(not_visited);
1415+
gcstate->visited_space = visited;
1416+
/* Make sure all objects have visited bit set correctly */
1417+
gc_list_set_space(&gcstate->young.head, not_visited);
1418+
gc_list_set_space(&gcstate->permanent_generation.head, visited);
14211419
gcstate->work_to_do = 0;
1420+
assert(gc_list_is_empty(&gcstate->old[visited].head));
14221421
}
14231422

14241423
static void
@@ -1461,11 +1460,11 @@ gc_collect_increment(PyThreadState *tstate, struct gc_collection_stats *stats)
14611460
gcstate->work_to_do += gcstate->heap_size / SCAN_RATE_DIVISOR / scale_factor;
14621461
gcstate->work_to_do -= increment_size;
14631462

1464-
validate_old(gcstate);
14651463
add_stats(gcstate, 1, stats);
14661464
if (gc_list_is_empty(not_visited)) {
14671465
completed_cycle(gcstate);
14681466
}
1467+
validate_spaces(gcstate);
14691468
}
14701469

14711470
static void
@@ -1474,7 +1473,7 @@ gc_collect_full(PyThreadState *tstate,
14741473
{
14751474
GC_STAT_ADD(2, collections, 1);
14761475
GCState *gcstate = &tstate->interp->gc;
1477-
validate_old(gcstate);
1476+
validate_spaces(gcstate);
14781477
PyGC_Head *young = &gcstate->young.head;
14791478
PyGC_Head *pending = &gcstate->old[gcstate->visited_space^1].head;
14801479
PyGC_Head *visited = &gcstate->old[gcstate->visited_space].head;
@@ -1484,16 +1483,18 @@ gc_collect_full(PyThreadState *tstate,
14841483
gc_list_set_space(pending, gcstate->visited_space);
14851484
gcstate->young.count = 0;
14861485
gc_list_merge(pending, visited);
1486+
validate_spaces(gcstate);
14871487

14881488
gc_collect_region(tstate, visited, visited,
14891489
stats);
1490+
validate_spaces(gcstate);
14901491
gcstate->young.count = 0;
14911492
gcstate->old[0].count = 0;
14921493
gcstate->old[1].count = 0;
14931494
completed_cycle(gcstate);
14941495
gcstate->work_to_do = - gcstate->young.threshold * 2;
14951496
_PyGC_ClearAllFreeLists(tstate->interp);
1496-
validate_old(gcstate);
1497+
validate_spaces(gcstate);
14971498
add_stats(gcstate, 2, stats);
14981499
}
14991500

@@ -1735,30 +1736,32 @@ void
17351736
_PyGC_Freeze(PyInterpreterState *interp)
17361737
{
17371738
GCState *gcstate = &interp->gc;
1738-
/* The permanent_generation has its old space bit set to zero */
1739-
if (gcstate->visited_space == 0) {
1740-
gc_list_set_space(&gcstate->young.head, 0);
1741-
}
1742-
gc_list_validate_space(&gcstate->young.head, 0);
1739+
/* The permanent_generation must be visited */
1740+
gc_list_set_space(&gcstate->young.head, gcstate->visited_space);
17431741
gc_list_merge(&gcstate->young.head, &gcstate->permanent_generation.head);
17441742
gcstate->young.count = 0;
17451743
PyGC_Head*old0 = &gcstate->old[0].head;
17461744
PyGC_Head*old1 = &gcstate->old[1].head;
1745+
if (gcstate->visited_space) {
1746+
gc_list_set_space(old0, 1);
1747+
}
1748+
else {
1749+
gc_list_set_space(old1, 0);
1750+
}
17471751
gc_list_merge(old0, &gcstate->permanent_generation.head);
17481752
gcstate->old[0].count = 0;
1749-
gc_list_set_space(old1, 0);
17501753
gc_list_merge(old1, &gcstate->permanent_generation.head);
17511754
gcstate->old[1].count = 0;
1752-
validate_old(gcstate);
1755+
validate_spaces(gcstate);
17531756
}
17541757

17551758
void
17561759
_PyGC_Unfreeze(PyInterpreterState *interp)
17571760
{
17581761
GCState *gcstate = &interp->gc;
17591762
gc_list_merge(&gcstate->permanent_generation.head,
1760-
&gcstate->old[0].head);
1761-
validate_old(gcstate);
1763+
&gcstate->old[gcstate->visited_space].head);
1764+
validate_spaces(gcstate);
17621765
}
17631766

17641767
Py_ssize_t
@@ -1863,7 +1866,7 @@ _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason)
18631866
_Py_stats->object_stats.object_visits = 0;
18641867
}
18651868
#endif
1866-
validate_old(gcstate);
1869+
validate_spaces(gcstate);
18671870
_Py_atomic_store_int(&gcstate->collecting, 0);
18681871
return stats.uncollectable + stats.collected;
18691872
}

0 commit comments

Comments
 (0)