Skip to content

Commit f0c305c

Browse files
committed
Use only lowest two bits of gc_prev.
1 parent ac3d5a8 commit f0c305c

File tree

3 files changed

+293
-223
lines changed

3 files changed

+293
-223
lines changed

Include/objimpl.h

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -249,37 +249,44 @@ PyAPI_FUNC(PyVarObject *) _PyObject_GC_Resize(PyVarObject *, Py_ssize_t);
249249

250250
/* GC information is stored BEFORE the object structure. */
251251
#ifndef Py_LIMITED_API
252-
typedef union _gc_head {
253-
struct {
254-
union _gc_head *gc_next; // NULL means the object is not tracked
255-
uintptr_t gc_prev; // Pointer to previous object in the list.
256-
// Lowest three bits are used for flags.
257-
} gc;
258-
double dummy; /* force worst-case alignment */
252+
typedef struct {
253+
// Pointer to next object in the list.
254+
// 0 means the object is not tracked
255+
uintptr_t _gc_next;
256+
257+
// Pointer to previous object in the list.
258+
// Lowest two bits are used for flags documented later.
259+
uintptr_t _gc_prev;
259260
} PyGC_Head;
260261

261262
extern PyGC_Head *_PyGC_generation0;
262263

263264
#define _Py_AS_GC(o) ((PyGC_Head *)(o)-1)
264265

265-
/* Bit flags for gc_prev */
266+
/* Bit flags for _gc_prev */
266267
/* Bit 0 is set when tp_finalize is called */
267268
#define _PyGC_PREV_MASK_FINALIZED (1)
268-
/* Bit 1 and 2 is used in gcmodule.c */
269-
#define _PyGC_PREV_MASK_INTERNAL (2 | 4)
270-
/* The (N-3) most significant bits contain the real address. */
271-
#define _PyGC_PREV_SHIFT (3)
269+
/* Bit 1 is set when the object is in generation which is GCed currently. */
270+
#define _PyGC_PREV_MASK_COLLECTING (2)
271+
/* The (N-2) most significant bits contain the real address. */
272+
#define _PyGC_PREV_SHIFT (2)
272273
#define _PyGC_PREV_MASK (((uintptr_t) -1) << _PyGC_PREV_SHIFT)
273274

274-
#define _PyGCHead_PREV(g) ((PyGC_Head*)((g)->gc.gc_prev & _PyGC_PREV_MASK))
275+
// Lowest bit of _gc_next is used for flags only in GC.
276+
// But it is always 0 for normal code.
277+
#define _PyGCHead_NEXT(g) ((PyGC_Head*)(g)->_gc_next)
278+
#define _PyGCHead_SET_NEXT(g, p) ((g)->_gc_next = (uintptr_t)(p))
279+
280+
// Lowest two bits of _gc_prev is used for flags described below.
281+
#define _PyGCHead_PREV(g) ((PyGC_Head*)((g)->_gc_prev & _PyGC_PREV_MASK))
275282
#define _PyGCHead_SET_PREV(g, p) do { \
276283
assert(((uintptr_t)p & ~_PyGC_PREV_MASK) == 0); \
277-
(g)->gc.gc_prev = ((g)->gc.gc_prev & ~_PyGC_PREV_MASK) \
284+
(g)->_gc_prev = ((g)->_gc_prev & ~_PyGC_PREV_MASK) \
278285
| ((uintptr_t)(p)); \
279286
} while (0)
280287

281-
#define _PyGCHead_FINALIZED(g) (((g)->gc.gc_prev & _PyGC_PREV_MASK_FINALIZED) != 0)
282-
#define _PyGCHead_SET_FINALIZED(g) ((g)->gc.gc_prev |= _PyGC_PREV_MASK_FINALIZED)
288+
#define _PyGCHead_FINALIZED(g) (((g)->_gc_prev & _PyGC_PREV_MASK_FINALIZED) != 0)
289+
#define _PyGCHead_SET_FINALIZED(g) ((g)->_gc_prev |= _PyGC_PREV_MASK_FINALIZED)
283290

284291
#define _PyGC_FINALIZED(o) _PyGCHead_FINALIZED(_Py_AS_GC(o))
285292
#define _PyGC_SET_FINALIZED(o) _PyGCHead_SET_FINALIZED(_Py_AS_GC(o))
@@ -289,38 +296,41 @@ extern PyGC_Head *_PyGC_generation0;
289296
* NB: While the object is tracked by the collector, it must be safe to call the
290297
* ob_traverse method.
291298
*
292-
* Internal note: _PyGC_generation0->gc.gc_prev doesn't have any bit flags
293-
* because it's not object header. That's why we don't use _PyGCHead_SET_PREV()
294-
* for it.
299+
* Internal note: _PyGC_generation0->_gc_prev doesn't have any bit flags
300+
* because it's not object header. So we don't use _PyGCHead_PREV() and
301+
* _PyGCHead_SET_PREV() for it to avoid unnecessary bitwise operations.
295302
*/
296303
#define _PyObject_GC_TRACK(o) do { \
297304
PyGC_Head *g = _Py_AS_GC(o); \
298-
if (g->gc.gc_next != NULL) \
305+
if (g->_gc_next != 0) { \
299306
Py_FatalError("GC object already tracked"); \
300-
assert((g->gc.gc_prev & _PyGC_PREV_MASK_INTERNAL) == 0); \
301-
g->gc.gc_next = _PyGC_generation0; \
302-
_PyGCHead_SET_PREV(g, _PyGC_generation0->gc.gc_prev); \
303-
_PyGCHead_PREV(_PyGC_generation0)->gc.gc_next = g; \
304-
_PyGC_generation0->gc.gc_prev = (uintptr_t)g; \
307+
} \
308+
assert((g->_gc_prev & _PyGC_PREV_MASK_COLLECTING) == 0); \
309+
PyGC_Head *last = (PyGC_Head*)(_PyGC_generation0->_gc_prev); \
310+
_PyGCHead_SET_NEXT(last, g); \
311+
_PyGCHead_SET_PREV(g, last); \
312+
_PyGCHead_SET_NEXT(g, _PyGC_generation0); \
313+
_PyGC_generation0->_gc_prev = (uintptr_t)g; \
305314
} while (0);
306315

307316
/* Tell the GC to stop tracking this object.
308317
*
309-
* Internal note: This may be called while GC. So _PyGC_PREV_MASK_INTERNAL must
310-
* be cleared. Only _PyGC_PREV_MASK_FINALIZED bit is kept.
318+
* Internal note: This may be called while GC. So _PyGC_PREV_MASK_COLLECTING must
319+
* be cleared. But _PyGC_PREV_MASK_FINALIZED bit is kept.
311320
*/
312321
#define _PyObject_GC_UNTRACK(o) do { \
313322
PyGC_Head *g = _Py_AS_GC(o); \
314323
PyGC_Head *prev = _PyGCHead_PREV(g); \
315-
assert(g->gc.gc_next != NULL); \
316-
prev->gc.gc_next = g->gc.gc_next; \
317-
_PyGCHead_SET_PREV(g->gc.gc_next, prev); \
318-
g->gc.gc_next = NULL; \
319-
g->gc.gc_prev &= _PyGC_PREV_MASK_FINALIZED; \
324+
PyGC_Head *next = _PyGCHead_NEXT(g); \
325+
assert(next != NULL); \
326+
_PyGCHead_SET_NEXT(prev, next); \
327+
_PyGCHead_SET_PREV(next, prev); \
328+
g->_gc_next = 0; \
329+
g->_gc_prev &= _PyGC_PREV_MASK_FINALIZED; \
320330
} while (0);
321331

322332
/* True if the object is currently tracked by the GC. */
323-
#define _PyObject_GC_IS_TRACKED(o) (_Py_AS_GC(o)->gc.gc_next != NULL)
333+
#define _PyObject_GC_IS_TRACKED(o) (_Py_AS_GC(o)->_gc_next != 0)
324334

325335
/* True if the object may be tracked by the GC in the future, or already is.
326336
This can be useful to implement some optimizations. */

0 commit comments

Comments
 (0)