@@ -106,7 +106,7 @@ gc_old_space(PyGC_Head *g)
106
106
}
107
107
108
108
static inline int
109
- flip_old_space (int space )
109
+ other_space (int space )
110
110
{
111
111
assert (space == 0 || space == 1 );
112
112
return space ^ _PyGC_NEXT_MASK_OLD_SPACE_1 ;
@@ -430,18 +430,27 @@ validate_list(PyGC_Head *head, enum flagstates flags)
430
430
#endif
431
431
432
432
#ifdef GC_EXTRA_DEBUG
433
+
434
+
433
435
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 )
435
446
{
447
+ int visited = gcstate -> visited_space ;
448
+ int not_visited = other_space (visited );
449
+ gc_list_validate_space (& gcstate -> young .head , not_visited );
436
450
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 );
444
452
}
453
+ gc_list_validate_space (& gcstate -> permanent_generation .head , visited );
445
454
}
446
455
447
456
static void
@@ -463,14 +472,6 @@ validate_consistent_old_space(PyGC_Head *head)
463
472
assert (prev == GC_PREV (head ));
464
473
}
465
474
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
- }
474
475
475
476
#else
476
477
#define validate_old (g ) do{}while(0)
@@ -494,7 +495,7 @@ update_refs(PyGC_Head *containers)
494
495
next = GC_NEXT (gc );
495
496
PyObject * op = FROM_GC (gc );
496
497
if (_Py_IsImmortal (op )) {
497
- gc_list_move ( gc , & get_gc_state () -> permanent_generation . head );
498
+ _PyObject_GC_UNTRACK ( op );
498
499
gc = next ;
499
500
continue ;
500
501
}
@@ -1293,6 +1294,7 @@ gc_collect_young(PyThreadState *tstate,
1293
1294
struct gc_collection_stats * stats )
1294
1295
{
1295
1296
GCState * gcstate = & tstate -> interp -> gc ;
1297
+ validate_spaces (gcstate );
1296
1298
PyGC_Head * young = & gcstate -> young .head ;
1297
1299
PyGC_Head * visited = & gcstate -> old [gcstate -> visited_space ].head ;
1298
1300
GC_STAT_ADD (0 , collections , 1 );
@@ -1326,7 +1328,7 @@ gc_collect_young(PyThreadState *tstate,
1326
1328
}
1327
1329
(void )survivor_count ; // Silence compiler warning
1328
1330
gc_list_merge (& survivors , visited );
1329
- validate_old (gcstate );
1331
+ validate_spaces (gcstate );
1330
1332
gcstate -> young .count = 0 ;
1331
1333
gcstate -> old [gcstate -> visited_space ].count ++ ;
1332
1334
Py_ssize_t scale_factor = gcstate -> old [0 ].threshold ;
@@ -1335,13 +1337,14 @@ gc_collect_young(PyThreadState *tstate,
1335
1337
}
1336
1338
gcstate -> work_to_do += gcstate -> heap_size / SCAN_RATE_DIVISOR / scale_factor ;
1337
1339
add_stats (gcstate , 0 , stats );
1340
+ validate_spaces (gcstate );
1338
1341
}
1339
1342
1340
1343
#ifndef NDEBUG
1341
1344
static inline int
1342
1345
IS_IN_VISITED (PyGC_Head * gc , int visited_space )
1343
1346
{
1344
- assert (visited_space == 0 || flip_old_space (visited_space ) == 0 );
1347
+ assert (visited_space == 0 || other_space (visited_space ) == 0 );
1345
1348
return gc_old_space (gc ) == visited_space ;
1346
1349
}
1347
1350
#endif
@@ -1406,19 +1409,15 @@ expand_region_transitively_reachable(PyGC_Head *container, PyGC_Head *gc, GCStat
1406
1409
static void
1407
1410
completed_cycle (GCState * gcstate )
1408
1411
{
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 );
1421
1419
gcstate -> work_to_do = 0 ;
1420
+ assert (gc_list_is_empty (& gcstate -> old [visited ].head ));
1422
1421
}
1423
1422
1424
1423
static void
@@ -1461,11 +1460,11 @@ gc_collect_increment(PyThreadState *tstate, struct gc_collection_stats *stats)
1461
1460
gcstate -> work_to_do += gcstate -> heap_size / SCAN_RATE_DIVISOR / scale_factor ;
1462
1461
gcstate -> work_to_do -= increment_size ;
1463
1462
1464
- validate_old (gcstate );
1465
1463
add_stats (gcstate , 1 , stats );
1466
1464
if (gc_list_is_empty (not_visited )) {
1467
1465
completed_cycle (gcstate );
1468
1466
}
1467
+ validate_spaces (gcstate );
1469
1468
}
1470
1469
1471
1470
static void
@@ -1474,7 +1473,7 @@ gc_collect_full(PyThreadState *tstate,
1474
1473
{
1475
1474
GC_STAT_ADD (2 , collections , 1 );
1476
1475
GCState * gcstate = & tstate -> interp -> gc ;
1477
- validate_old (gcstate );
1476
+ validate_spaces (gcstate );
1478
1477
PyGC_Head * young = & gcstate -> young .head ;
1479
1478
PyGC_Head * pending = & gcstate -> old [gcstate -> visited_space ^1 ].head ;
1480
1479
PyGC_Head * visited = & gcstate -> old [gcstate -> visited_space ].head ;
@@ -1484,16 +1483,18 @@ gc_collect_full(PyThreadState *tstate,
1484
1483
gc_list_set_space (pending , gcstate -> visited_space );
1485
1484
gcstate -> young .count = 0 ;
1486
1485
gc_list_merge (pending , visited );
1486
+ validate_spaces (gcstate );
1487
1487
1488
1488
gc_collect_region (tstate , visited , visited ,
1489
1489
stats );
1490
+ validate_spaces (gcstate );
1490
1491
gcstate -> young .count = 0 ;
1491
1492
gcstate -> old [0 ].count = 0 ;
1492
1493
gcstate -> old [1 ].count = 0 ;
1493
1494
completed_cycle (gcstate );
1494
1495
gcstate -> work_to_do = - gcstate -> young .threshold * 2 ;
1495
1496
_PyGC_ClearAllFreeLists (tstate -> interp );
1496
- validate_old (gcstate );
1497
+ validate_spaces (gcstate );
1497
1498
add_stats (gcstate , 2 , stats );
1498
1499
}
1499
1500
@@ -1735,30 +1736,32 @@ void
1735
1736
_PyGC_Freeze (PyInterpreterState * interp )
1736
1737
{
1737
1738
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 );
1743
1741
gc_list_merge (& gcstate -> young .head , & gcstate -> permanent_generation .head );
1744
1742
gcstate -> young .count = 0 ;
1745
1743
PyGC_Head * old0 = & gcstate -> old [0 ].head ;
1746
1744
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
+ }
1747
1751
gc_list_merge (old0 , & gcstate -> permanent_generation .head );
1748
1752
gcstate -> old [0 ].count = 0 ;
1749
- gc_list_set_space (old1 , 0 );
1750
1753
gc_list_merge (old1 , & gcstate -> permanent_generation .head );
1751
1754
gcstate -> old [1 ].count = 0 ;
1752
- validate_old (gcstate );
1755
+ validate_spaces (gcstate );
1753
1756
}
1754
1757
1755
1758
void
1756
1759
_PyGC_Unfreeze (PyInterpreterState * interp )
1757
1760
{
1758
1761
GCState * gcstate = & interp -> gc ;
1759
1762
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 );
1762
1765
}
1763
1766
1764
1767
Py_ssize_t
@@ -1863,7 +1866,7 @@ _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason)
1863
1866
_Py_stats -> object_stats .object_visits = 0 ;
1864
1867
}
1865
1868
#endif
1866
- validate_old (gcstate );
1869
+ validate_spaces (gcstate );
1867
1870
_Py_atomic_store_int (& gcstate -> collecting , 0 );
1868
1871
return stats .uncollectable + stats .collected ;
1869
1872
}
0 commit comments