Skip to content

Commit 161eee1

Browse files
committed
Reduce PyGC_Head size
1 parent c651275 commit 161eee1

File tree

3 files changed

+213
-122
lines changed

3 files changed

+213
-122
lines changed

Include/objimpl.h

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -251,9 +251,8 @@ PyAPI_FUNC(PyVarObject *) _PyObject_GC_Resize(PyVarObject *, Py_ssize_t);
251251
#ifndef Py_LIMITED_API
252252
typedef union _gc_head {
253253
struct {
254-
union _gc_head *gc_next;
255-
union _gc_head *gc_prev;
256-
Py_ssize_t gc_refs;
254+
union _gc_head *gc_next; // NULL means the object is not tracked
255+
uintptr_t gc_prev;
257256
} gc;
258257
double dummy; /* force worst-case alignment */
259258
} PyGC_Head;
@@ -263,44 +262,39 @@ extern PyGC_Head *_PyGC_generation0;
263262
#define _Py_AS_GC(o) ((PyGC_Head *)(o)-1)
264263

265264
/* Bit 0 is set when tp_finalize is called */
266-
#define _PyGC_REFS_MASK_FINALIZED (1 << 0)
267-
/* The (N-1) most significant bits contain the gc state / refcount */
268-
#define _PyGC_REFS_SHIFT (1)
269-
#define _PyGC_REFS_MASK (((size_t) -1) << _PyGC_REFS_SHIFT)
270-
271-
#define _PyGCHead_REFS(g) ((g)->gc.gc_refs >> _PyGC_REFS_SHIFT)
272-
#define _PyGCHead_SET_REFS(g, v) do { \
273-
(g)->gc.gc_refs = ((g)->gc.gc_refs & ~_PyGC_REFS_MASK) \
274-
| (((size_t)(v)) << _PyGC_REFS_SHIFT); \
265+
#define _PyGC_PREV_MASK_FINALIZED (1 << 0)
266+
/* Bit 1 and 2 is used in gcmodule.c */
267+
/* The (N-3) most significant bits contain the real address. */
268+
#define _PyGC_PREV_SHIFT (3)
269+
#define _PyGC_PREV_MASK (((uintptr_t) -1) << _PyGC_PREV_SHIFT)
270+
271+
#define _PyGCHead_PREV(g) ((PyGC_Head*)((g)->gc.gc_prev & _PyGC_PREV_MASK))
272+
#define _PyGCHead_SET_PREV(g, p) do { \
273+
assert(((uintptr_t)p & ~_PyGC_PREV_MASK) == 0); \
274+
(g)->gc.gc_prev = ((g)->gc.gc_prev & ~_PyGC_PREV_MASK) \
275+
| ((uintptr_t)(p)); \
275276
} while (0)
276-
#define _PyGCHead_DECREF(g) ((g)->gc.gc_refs -= 1 << _PyGC_REFS_SHIFT)
277277

278-
#define _PyGCHead_FINALIZED(g) (((g)->gc.gc_refs & _PyGC_REFS_MASK_FINALIZED) != 0)
278+
#define _PyGCHead_FINALIZED(g) (((g)->gc.gc_prev & _PyGC_PREV_MASK_FINALIZED) != 0)
279279
#define _PyGCHead_SET_FINALIZED(g, v) do { \
280-
(g)->gc.gc_refs = ((g)->gc.gc_refs & ~_PyGC_REFS_MASK_FINALIZED) \
280+
(g)->gc.gc_prev = ((g)->gc.gc_prev & ~_PyGC_PREV_MASK_FINALIZED) \
281281
| (v != 0); \
282282
} while (0)
283283

284284
#define _PyGC_FINALIZED(o) _PyGCHead_FINALIZED(_Py_AS_GC(o))
285285
#define _PyGC_SET_FINALIZED(o, v) _PyGCHead_SET_FINALIZED(_Py_AS_GC(o), v)
286286

287-
#define _PyGC_REFS(o) _PyGCHead_REFS(_Py_AS_GC(o))
288-
289-
#define _PyGC_REFS_UNTRACKED (-2)
290-
#define _PyGC_REFS_REACHABLE (-3)
291-
#define _PyGC_REFS_TENTATIVELY_UNREACHABLE (-4)
292-
293287
/* Tell the GC to track this object. NB: While the object is tracked the
294288
* collector it must be safe to call the ob_traverse method. */
295289
#define _PyObject_GC_TRACK(o) do { \
296290
PyGC_Head *g = _Py_AS_GC(o); \
297-
if (_PyGCHead_REFS(g) != _PyGC_REFS_UNTRACKED) \
291+
if (g->gc.gc_next != NULL) \
298292
Py_FatalError("GC object already tracked"); \
299-
_PyGCHead_SET_REFS(g, _PyGC_REFS_REACHABLE); \
293+
assert((g->gc.gc_prev & 6) == 0); \
300294
g->gc.gc_next = _PyGC_generation0; \
301-
g->gc.gc_prev = _PyGC_generation0->gc.gc_prev; \
302-
g->gc.gc_prev->gc.gc_next = g; \
303-
_PyGC_generation0->gc.gc_prev = g; \
295+
_PyGCHead_SET_PREV(g, _PyGC_generation0->gc.gc_prev); \
296+
_PyGCHead_PREV(_PyGC_generation0)->gc.gc_next = g; \
297+
_PyGC_generation0->gc.gc_prev = (uintptr_t)g; \
304298
} while (0);
305299

306300
/* Tell the GC to stop tracking this object.
@@ -309,16 +303,15 @@ extern PyGC_Head *_PyGC_generation0;
309303
*/
310304
#define _PyObject_GC_UNTRACK(o) do { \
311305
PyGC_Head *g = _Py_AS_GC(o); \
312-
assert(_PyGCHead_REFS(g) != _PyGC_REFS_UNTRACKED); \
313-
_PyGCHead_SET_REFS(g, _PyGC_REFS_UNTRACKED); \
314-
g->gc.gc_prev->gc.gc_next = g->gc.gc_next; \
315-
g->gc.gc_next->gc.gc_prev = g->gc.gc_prev; \
306+
assert(g->gc.gc_next != NULL); \
307+
_PyGCHead_PREV(g)->gc.gc_next = g->gc.gc_next; \
308+
_PyGCHead_SET_PREV(g->gc.gc_next, _PyGCHead_PREV(g)); \
316309
g->gc.gc_next = NULL; \
310+
g->gc.gc_prev &= _PyGC_PREV_MASK_FINALIZED; \
317311
} while (0);
318312

319313
/* True if the object is currently tracked by the GC. */
320-
#define _PyObject_GC_IS_TRACKED(o) \
321-
(_PyGC_REFS(o) != _PyGC_REFS_UNTRACKED)
314+
#define _PyObject_GC_IS_TRACKED(o) (_Py_AS_GC(o)->gc.gc_next != NULL)
322315

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

0 commit comments

Comments
 (0)