Skip to content

Commit 13cce66

Browse files
committed
Move old-space flag from _gc_prev to _gc_next to support 32 bit machines.
1 parent ec776b5 commit 13cce66

File tree

3 files changed

+32
-24
lines changed

3 files changed

+32
-24
lines changed

Include/internal/pycore_gc.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,31 +56,36 @@ static inline int _PyObject_GC_MAY_BE_TRACKED(PyObject *obj) {
5656

5757

5858
/* Bit flags for _gc_prev */
59-
/* Bit 2 is set when tp_finalize is called */
60-
#define _PyGC_PREV_MASK_FINALIZED 4
59+
/* Bit 0 is set when tp_finalize is called */
60+
#define _PyGC_PREV_MASK_FINALIZED 1
6161
/* Bit 1 is set when the object is in generation which is GCed currently. */
6262
#define _PyGC_PREV_MASK_COLLECTING 2
63+
6364
/* Bit 0 is set if the object belongs to old space 1 */
64-
#define _PyGC_PREV_MASK_OLD_SPACE_1 1
65-
/* The (N-3) most significant bits contain the real address. */
66-
#define _PyGC_PREV_SHIFT 3
65+
#define _PyGC_NEXT_MASK_OLD_SPACE_1 1
66+
67+
/* The (N-2) most significant bits contain the real address. */
68+
#define _PyGC_PREV_SHIFT 2
6769
#define _PyGC_PREV_MASK (((uintptr_t) -1) << _PyGC_PREV_SHIFT)
6870

6971
// Lowest bit of _gc_next is used for flags only in GC.
7072
// But it is always 0 for normal code.
7173
static inline PyGC_Head* _PyGCHead_NEXT(PyGC_Head *gc) {
72-
uintptr_t next = gc->_gc_next;
74+
uintptr_t next = gc->_gc_next & _PyGC_PREV_MASK;
7375
return (PyGC_Head*)next;
7476
}
7577
static inline void _PyGCHead_SET_NEXT(PyGC_Head *gc, PyGC_Head *next) {
76-
gc->_gc_next = (uintptr_t)next;
78+
uintptr_t unext = (uintptr_t)next;
79+
assert((unext & ~_PyGC_PREV_MASK) == 0);
80+
gc->_gc_next = (gc->_gc_next & ~_PyGC_PREV_MASK) | unext;
7781
}
7882

7983
// Lowest two bits of _gc_prev is used for _PyGC_PREV_MASK_* flags.
8084
static inline PyGC_Head* _PyGCHead_PREV(PyGC_Head *gc) {
8185
uintptr_t prev = (gc->_gc_prev & _PyGC_PREV_MASK);
8286
return (PyGC_Head*)prev;
8387
}
88+
8489
static inline void _PyGCHead_SET_PREV(PyGC_Head *gc, PyGC_Head *prev) {
8590
uintptr_t uprev = (uintptr_t)prev;
8691
assert((uprev & ~_PyGC_PREV_MASK) == 0);

Include/internal/pycore_object.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ static inline void _PyObject_GC_TRACK(
243243
_PyGCHead_SET_NEXT(last, gc);
244244
_PyGCHead_SET_PREV(gc, last);
245245
_PyGCHead_SET_NEXT(gc, generation0);
246-
assert((gc->_gc_prev & _PyGC_PREV_MASK_OLD_SPACE_1) == 0);
246+
assert((gc->_gc_next & _PyGC_NEXT_MASK_OLD_SPACE_1) == 0);
247247
generation0->_gc_prev = (uintptr_t)gc;
248248
}
249249

Modules/gcmodule.c

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ module gc
6868
// move_legacy_finalizers() removes this flag instead.
6969
// Between them, unreachable list is not normal list and we can not use
7070
// most gc_list_* functions for it.
71-
#define NEXT_MASK_UNREACHABLE (1)
71+
#define NEXT_MASK_UNREACHABLE (2)
7272

7373
#define AS_GC(op) _Py_AS_GC(op)
7474
#define FROM_GC(gc) _Py_FROM_GC(gc)
@@ -102,7 +102,7 @@ gc_set_refs(PyGC_Head *g, Py_ssize_t refs)
102102
static inline void
103103
gc_reset_refs(PyGC_Head *g, Py_ssize_t refs)
104104
{
105-
g->_gc_prev = (g->_gc_prev & ~_PyGC_PREV_MASK)
105+
g->_gc_prev = (g->_gc_prev & _PyGC_PREV_MASK_FINALIZED)
106106
| PREV_MASK_COLLECTING
107107
| ((uintptr_t)(refs) << _PyGC_PREV_SHIFT);
108108
}
@@ -119,26 +119,27 @@ gc_decref(PyGC_Head *g)
119119
static inline uintptr_t
120120
gc_old_space(PyGC_Head *g)
121121
{
122-
return g->_gc_prev & _PyGC_PREV_MASK_OLD_SPACE_1;
122+
return g->_gc_next & _PyGC_NEXT_MASK_OLD_SPACE_1;
123123
}
124124

125125
static inline uintptr_t
126126
flip_old_space(uintptr_t space)
127127
{
128-
return space ^ _PyGC_PREV_MASK_OLD_SPACE_1;
128+
return space ^ _PyGC_NEXT_MASK_OLD_SPACE_1;
129129
}
130130

131131
static inline void
132132
gc_flip_old_space(PyGC_Head *g)
133133
{
134-
g->_gc_prev ^= _PyGC_PREV_MASK_OLD_SPACE_1;
134+
g->_gc_next ^= _PyGC_NEXT_MASK_OLD_SPACE_1;
135135
}
136136

137137
static inline void
138138
gc_set_old_space(PyGC_Head *g, uintptr_t space)
139139
{
140-
g->_gc_prev &= ~_PyGC_PREV_MASK_OLD_SPACE_1;
141-
g->_gc_prev |= space;
140+
assert(space == 0 || space == _PyGC_NEXT_MASK_OLD_SPACE_1);
141+
g->_gc_next &= ~_PyGC_NEXT_MASK_OLD_SPACE_1;
142+
g->_gc_next |= space;
142143
}
143144

144145
/* set for debugging information */
@@ -286,6 +287,7 @@ gc_list_is_empty(PyGC_Head *list)
286287
static inline void
287288
gc_list_append(PyGC_Head *node, PyGC_Head *list)
288289
{
290+
assert((list->_gc_prev & ~_PyGC_PREV_MASK) == 0);
289291
PyGC_Head *last = (PyGC_Head *)list->_gc_prev;
290292

291293
// last <-> node
@@ -434,7 +436,7 @@ validate_list(PyGC_Head *head, enum flagstates flags)
434436
PyGC_Head *gc = GC_NEXT(head);
435437
while (gc != head) {
436438
PyGC_Head *trueprev = GC_PREV(gc);
437-
PyGC_Head *truenext = (PyGC_Head *)(gc->_gc_next & ~NEXT_MASK_UNREACHABLE);
439+
PyGC_Head *truenext = GC_NEXT(gc);
438440
assert(truenext != NULL);
439441
assert(trueprev == prev);
440442
assert((gc->_gc_prev & PREV_MASK_COLLECTING) == prev_value);
@@ -458,7 +460,7 @@ validate_old(GCState *gcstate)
458460
PyGC_Head *gc = GC_NEXT(head);
459461
while (gc != head) {
460462
PyGC_Head *trueprev = GC_PREV(gc);
461-
PyGC_Head *truenext = (PyGC_Head *)(gc->_gc_next & ~NEXT_MASK_UNREACHABLE);
463+
PyGC_Head *truenext = GC_NEXT(gc);
462464
assert(truenext != NULL);
463465
assert(trueprev == prev);
464466
assert(gc_old_space(gc) == space);
@@ -477,7 +479,7 @@ validate_list_is_aging(PyGC_Head *head)
477479
PyGC_Head *gc = GC_NEXT(head);
478480
uintptr_t aging_flag = gcstate->aging_space;
479481
while (gc != head) {
480-
PyGC_Head *truenext = (PyGC_Head *)(gc->_gc_next & ~NEXT_MASK_UNREACHABLE);
482+
PyGC_Head *truenext = GC_NEXT(gc);
481483
assert(truenext != NULL);
482484
assert(gc_old_space(gc) == aging_flag);
483485
prev = gc;
@@ -611,12 +613,13 @@ visit_reachable(PyObject *op, PyGC_Head *reachable)
611613
// Manually unlink gc from unreachable list because the list functions
612614
// don't work right in the presence of NEXT_MASK_UNREACHABLE flags.
613615
PyGC_Head *prev = GC_PREV(gc);
614-
PyGC_Head *next = (PyGC_Head*)(gc->_gc_next & ~NEXT_MASK_UNREACHABLE);
616+
PyGC_Head *next = GC_NEXT(gc);
615617
_PyObject_ASSERT(FROM_GC(prev),
616618
prev->_gc_next & NEXT_MASK_UNREACHABLE);
617619
_PyObject_ASSERT(FROM_GC(next),
618620
next->_gc_next & NEXT_MASK_UNREACHABLE);
619621
prev->_gc_next = gc->_gc_next; // copy NEXT_MASK_UNREACHABLE
622+
gc->_gc_next &= ~NEXT_MASK_UNREACHABLE;
620623
_PyGCHead_SET_PREV(next, prev);
621624

622625
gc_list_append(gc, reachable);
@@ -658,7 +661,6 @@ move_unreachable(PyGC_Head *young, PyGC_Head *unreachable)
658661
// previous elem in the young list, used for restore gc_prev.
659662
PyGC_Head *prev = young;
660663
PyGC_Head *gc = GC_NEXT(young);
661-
662664
/* Invariants: all objects "to the left" of us in young are reachable
663665
* (directly or indirectly) from outside the young list as it was at entry.
664666
*
@@ -718,12 +720,12 @@ move_unreachable(PyGC_Head *young, PyGC_Head *unreachable)
718720
gc->_gc_next = (NEXT_MASK_UNREACHABLE | (uintptr_t)unreachable);
719721
unreachable->_gc_prev = (uintptr_t)gc;
720722
}
721-
gc = (PyGC_Head*)prev->_gc_next;
723+
gc = _PyGCHead_NEXT(prev);
722724
}
723725
// young->_gc_prev must be last element remained in the list.
724726
young->_gc_prev = (uintptr_t)prev;
725727
// don't let the pollution of the list head's next pointer leak
726-
unreachable->_gc_next &= ~NEXT_MASK_UNREACHABLE;
728+
unreachable->_gc_next &= _PyGC_PREV_MASK;
727729
}
728730

729731
static void
@@ -780,7 +782,7 @@ move_legacy_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers)
780782
PyObject *op = FROM_GC(gc);
781783

782784
_PyObject_ASSERT(op, gc->_gc_next & NEXT_MASK_UNREACHABLE);
783-
gc->_gc_next &= ~NEXT_MASK_UNREACHABLE;
785+
gc->_gc_next &= _PyGC_PREV_MASK;
784786
next = (PyGC_Head*)gc->_gc_next;
785787

786788
if (has_legacy_finalizer(op)) {
@@ -800,7 +802,7 @@ clear_unreachable_mask(PyGC_Head *unreachable)
800802
assert((unreachable->_gc_next & NEXT_MASK_UNREACHABLE) == 0);
801803
for (gc = GC_NEXT(unreachable); gc != unreachable; gc = next) {
802804
_PyObject_ASSERT((PyObject*)FROM_GC(gc), gc->_gc_next & NEXT_MASK_UNREACHABLE);
803-
gc->_gc_next &= ~NEXT_MASK_UNREACHABLE;
805+
gc->_gc_next &= _PyGC_PREV_MASK;
804806
next = (PyGC_Head*)gc->_gc_next;
805807
}
806808
validate_list(unreachable, collecting_set_unreachable_clear);
@@ -1525,6 +1527,7 @@ gc_collect_region(PyThreadState *tstate,
15251527
assert(gcstate->garbage != NULL);
15261528
assert(!_PyErr_Occurred(tstate));
15271529

1530+
validate_list(from, collecting_clear_unreachable_clear);
15281531
validate_list(to, collecting_clear_unreachable_clear);
15291532

15301533
deduce_unreachable(from, &unreachable);

0 commit comments

Comments
 (0)