Skip to content

Commit ec776b5

Browse files
committed
Hide old space flag as much as is practical.
1 parent 5027c77 commit ec776b5

File tree

1 file changed

+49
-39
lines changed

1 file changed

+49
-39
lines changed

Modules/gcmodule.c

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,31 @@ gc_decref(PyGC_Head *g)
116116
g->_gc_prev -= 1 << _PyGC_PREV_SHIFT;
117117
}
118118

119+
static inline uintptr_t
120+
gc_old_space(PyGC_Head *g)
121+
{
122+
return g->_gc_prev & _PyGC_PREV_MASK_OLD_SPACE_1;
123+
}
124+
125+
static inline uintptr_t
126+
flip_old_space(uintptr_t space)
127+
{
128+
return space ^ _PyGC_PREV_MASK_OLD_SPACE_1;
129+
}
130+
131+
static inline void
132+
gc_flip_old_space(PyGC_Head *g)
133+
{
134+
g->_gc_prev ^= _PyGC_PREV_MASK_OLD_SPACE_1;
135+
}
136+
137+
static inline void
138+
gc_set_old_space(PyGC_Head *g, uintptr_t space)
139+
{
140+
g->_gc_prev &= ~_PyGC_PREV_MASK_OLD_SPACE_1;
141+
g->_gc_prev |= space;
142+
}
143+
119144
/* set for debugging information */
120145
#define DEBUG_STATS (1<<0) /* print collection statistics */
121146
#define DEBUG_COLLECTABLE (1<<1) /* print collectable objects */
@@ -427,16 +452,16 @@ validate_list(PyGC_Head *head, enum flagstates flags)
427452
static void
428453
validate_old(GCState *gcstate)
429454
{
430-
for (uintptr_t gen = 0; gen < 2; gen++) {
431-
PyGC_Head *head = &gcstate->old[gen].head;
455+
for (uintptr_t space = 0; space < 2; space++) {
456+
PyGC_Head *head = &gcstate->old[space].head;
432457
PyGC_Head *prev = head;
433458
PyGC_Head *gc = GC_NEXT(head);
434459
while (gc != head) {
435460
PyGC_Head *trueprev = GC_PREV(gc);
436461
PyGC_Head *truenext = (PyGC_Head *)(gc->_gc_next & ~NEXT_MASK_UNREACHABLE);
437462
assert(truenext != NULL);
438463
assert(trueprev == prev);
439-
assert((gc->_gc_prev & _PyGC_PREV_MASK_OLD_SPACE_1) == gen);
464+
assert(gc_old_space(gc) == space);
440465
prev = gc;
441466
gc = truenext;
442467
}
@@ -454,7 +479,7 @@ validate_list_is_aging(PyGC_Head *head)
454479
while (gc != head) {
455480
PyGC_Head *truenext = (PyGC_Head *)(gc->_gc_next & ~NEXT_MASK_UNREACHABLE);
456481
assert(truenext != NULL);
457-
assert((gc->_gc_prev & _PyGC_PREV_MASK_OLD_SPACE_1) == aging_flag);
482+
assert(gc_old_space(gc) == aging_flag);
458483
prev = gc;
459484
gc = truenext;
460485
}
@@ -1240,25 +1265,13 @@ gc_collect_region(PyThreadState *tstate,
12401265
int untrack,
12411266
struct gc_collection_stats *stats);
12421267

1243-
static Py_ssize_t
1244-
make_space0(PyGC_Head *list)
1245-
{
1246-
Py_ssize_t size = 0;
1247-
PyGC_Head *gc;
1248-
for (gc = GC_NEXT(list); gc != list; gc = GC_NEXT(gc)) {
1249-
gc->_gc_prev &= ~_PyGC_PREV_MASK_OLD_SPACE_1;
1250-
size++;
1251-
}
1252-
return size;
1253-
}
1254-
1255-
static Py_ssize_t
1256-
make_space1(PyGC_Head *list)
1268+
static inline Py_ssize_t
1269+
gc_list_set_space(PyGC_Head *list, uintptr_t space)
12571270
{
12581271
Py_ssize_t size = 0;
12591272
PyGC_Head *gc;
12601273
for (gc = GC_NEXT(list); gc != list; gc = GC_NEXT(gc)) {
1261-
gc->_gc_prev |= _PyGC_PREV_MASK_OLD_SPACE_1;
1274+
gc_set_old_space(gc, space);
12621275
size++;
12631276
}
12641277
return size;
@@ -1285,7 +1298,7 @@ gc_collect_young(PyThreadState *tstate,
12851298
* do that here */
12861299
PyGC_Head *gc;
12871300
for (gc = GC_NEXT(young); gc != young; gc = GC_NEXT(gc)) {
1288-
gc->_gc_prev |= _PyGC_PREV_MASK_OLD_SPACE_1;
1301+
gc_set_old_space(gc, 1);
12891302
}
12901303
}
12911304
validate_old(gcstate);
@@ -1296,13 +1309,13 @@ gc_collect_young(PyThreadState *tstate,
12961309
Py_ssize_t surivivor_count = 0;
12971310
if (gcstate->aging_space) {
12981311
/* objects in aging space have bit set, so we set it here */
1299-
surivivor_count = make_space1(&survivors);
1312+
surivivor_count = gc_list_set_space(&survivors, 1);
13001313
}
13011314
else {
13021315
PyGC_Head *gc;
13031316
for (gc = GC_NEXT(&survivors); gc != &survivors; gc = GC_NEXT(gc)) {
13041317
#ifdef GC_DEBUG
1305-
assert((gc->_gc_prev & _PyGC_PREV_MASK_OLD_SPACE_1) == 0);
1318+
assert(gc_old_space(gc) == 0);
13061319
#endif
13071320
surivivor_count++;
13081321
}
@@ -1320,21 +1333,19 @@ static void
13201333
gc_collect_aging(PyThreadState *tstate,
13211334
struct gc_collection_stats *stats)
13221335
{
1323-
/* For now just collect middle generation */
13241336
GCState *gcstate = &tstate->interp->gc;
1337+
uintptr_t oldest_space = flip_old_space(gcstate->aging_space);
13251338
PyGC_Head *young = &gcstate->young.head;
13261339
PyGC_Head *aging = &gcstate->old[gcstate->aging_space].head;
1327-
PyGC_Head *oldest = &gcstate->old[gcstate->aging_space^1].head;
1340+
PyGC_Head *oldest = &gcstate->old[oldest_space].head;
13281341
/* Need to tag all objects as part of oldest generation */
1329-
Py_ssize_t size;
13301342
if (gcstate->aging_space) {
13311343
/* No need to tag young objects */
1332-
size = make_space0(aging);
13331344
}
13341345
else {
1335-
make_space1(young);
1336-
size = make_space1(aging);
1346+
gc_list_set_space(young, 1);
13371347
}
1348+
Py_ssize_t size = gc_list_set_space(aging, oldest_space);
13381349
/* merge young in pending before collecting */
13391350
gc_list_merge(young, aging);
13401351
gcstate->young.count = 0;
@@ -1348,10 +1359,10 @@ gc_collect_aging(PyThreadState *tstate,
13481359
}
13491360

13501361
static inline int
1351-
IS_IN_OLDEST(PyGC_Head *head, uintptr_t aging_space)
1362+
IS_IN_OLDEST(PyGC_Head *gc, uintptr_t aging_space)
13521363
{
1353-
assert(aging_space == 0 || aging_space == _PyGC_PREV_MASK_OLD_SPACE_1);
1354-
return (head->_gc_prev & _PyGC_PREV_MASK_OLD_SPACE_1) == (aging_space^_PyGC_PREV_MASK_OLD_SPACE_1);
1364+
assert(aging_space == 0 || flip_old_space(aging_space) == 0);
1365+
return gc_old_space(gc) != aging_space;
13551366
}
13561367

13571368
struct container_and_flag {
@@ -1365,13 +1376,13 @@ visit_add_to_container(PyObject *op, void *arg)
13651376
{
13661377
OBJECT_STAT_INC(object_visits);
13671378
struct container_and_flag *cf = (struct container_and_flag *)arg;
1368-
uintptr_t oldest_flag = cf->aging_space ^ _PyGC_PREV_MASK_OLD_SPACE_1;
1379+
uintptr_t aging = cf->aging_space;
13691380
if (_PyObject_IS_GC(op)) {
13701381
PyGC_Head *gc = AS_GC(op);
13711382
if (_PyObject_GC_IS_TRACKED(op) &&
1372-
(gc->_gc_prev & _PyGC_PREV_MASK_OLD_SPACE_1) == oldest_flag) {
1383+
gc_old_space(gc) != aging) {
13731384
assert(!_Py_IsImmortal(op));
1374-
gc->_gc_prev ^= _PyGC_PREV_MASK_OLD_SPACE_1;
1385+
gc_flip_old_space(gc);
13751386
gc_list_move(gc, cf->container);
13761387
}
13771388
}
@@ -1437,7 +1448,7 @@ gc_collect_increment(PyThreadState *tstate, struct gc_collection_stats *stats)
14371448
PyGC_Head *tmp = aging;
14381449
aging = oldest;
14391450
oldest = tmp;
1440-
gcstate->aging_space ^= _PyGC_PREV_MASK_OLD_SPACE_1;
1451+
gcstate->aging_space = flip_old_space(gcstate->aging_space);
14411452
}
14421453
validate_old(gcstate);
14431454
while (region_size < work_to_do) {
@@ -1447,8 +1458,7 @@ gc_collect_increment(PyThreadState *tstate, struct gc_collection_stats *stats)
14471458
}
14481459
PyGC_Head *gc = _PyGCHead_NEXT(oldest);
14491460
gc_list_move(gc, &increment);
1450-
gc->_gc_prev &= ~_PyGC_PREV_MASK_OLD_SPACE_1;
1451-
gc->_gc_prev |= gcstate->aging_space;
1461+
gc_set_old_space(gc, gcstate->aging_space);
14521462
region_size += expand_region_transitively_reachable(&increment, gcstate);
14531463
}
14541464
validate_old(gcstate);
@@ -1477,7 +1487,7 @@ gc_collect_full(PyThreadState *tstate,
14771487
gcstate->young.count = 0;
14781488
PyGC_Head *gc = GC_NEXT(old1);
14791489
while (gc != old1) {
1480-
gc->_gc_prev &= ~_PyGC_PREV_MASK_OLD_SPACE_1;
1490+
gc_set_old_space(gc, 0);
14811491
gc = GC_NEXT(gc);
14821492
}
14831493
gc_list_merge(old1, old0);
@@ -2137,7 +2147,7 @@ gc_freeze_impl(PyObject *module)
21372147
PyGC_Head*old1 = &gcstate->old[1].head;
21382148
gc_list_merge(old0, &gcstate->permanent_generation.head);
21392149
gcstate->old[0].count = 0;
2140-
make_space0(old1);
2150+
gc_list_set_space(old1, 0);
21412151
gc_list_merge(old1, &gcstate->permanent_generation.head);
21422152
gcstate->old[1].count = 0;
21432153
validate_old(gcstate);

0 commit comments

Comments
 (0)