Skip to content

Commit 6b5c405

Browse files
committed
Use ob_flags for object's GC state
1 parent c176543 commit 6b5c405

20 files changed

+64
-41
lines changed

Include/internal/pycore_freelist.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ extern "C" {
1313
#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_STORE_PTR_RELAXED()
1414
#include "pycore_pystate.h" // _PyThreadState_GET
1515
#include "pycore_stats.h" // OBJECT_STAT_INC
16+
#include "pycore_gc.h" // _Py_GC_OBJECT
1617

1718
static inline struct _Py_freelists *
1819
_Py_freelists_GET(void)
@@ -38,8 +39,8 @@ _Py_freelists_GET(void)
3839
_PyFreeList_Push(&_Py_freelists_GET()->NAME, _PyObject_CAST(op), limit)
3940

4041
// Pops a PyObject from the freelist, returns NULL if the freelist is empty.
41-
#define _Py_FREELIST_POP(TYPE, NAME) \
42-
_Py_CAST(TYPE*, _PyFreeList_Pop(&_Py_freelists_GET()->NAME))
42+
#define _Py_FREELIST_POP(TYPE, NAME, IS_GC) \
43+
_Py_CAST(TYPE*, _PyFreeList_Pop(&_Py_freelists_GET()->NAME, (IS_GC) ? _Py_GC_OBJECT : 0))
4344

4445
// Pops a non-PyObject data structure from the freelist, returns NULL if the
4546
// freelist is empty.
@@ -82,13 +83,28 @@ _PyFreeList_PopNoStats(struct _Py_freelist *fl)
8283
return obj;
8384
}
8485

86+
#ifndef NDEBUG
87+
static int
88+
consistent_flags(PyObject *op, int flags)
89+
{
90+
if (Py_TYPE(op)->tp_flags & Py_TPFLAGS_HAVE_GC) {
91+
return flags == _Py_GC_OBJECT;
92+
}
93+
else {
94+
return flags == 0;
95+
}
96+
}
97+
#endif
98+
8599
static inline PyObject *
86-
_PyFreeList_Pop(struct _Py_freelist *fl)
100+
_PyFreeList_Pop(struct _Py_freelist *fl, int flags)
87101
{
88102
PyObject *op = _PyFreeList_PopNoStats(fl);
89103
if (op != NULL) {
90104
OBJECT_STAT_INC(from_freelist);
91105
_Py_NewReference(op);
106+
assert(consistent_flags(op, flags));
107+
op->ob_flags = flags;
92108
}
93109
return op;
94110
}

Include/internal/pycore_gc.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,16 @@ _PyObject_CLEAR_GC_BITS(PyObject *op, uint8_t bits_to_clear)
6969

7070
#endif
7171

72+
#define _Py_GC_OBJECT (1 << 4)
73+
#define _Py_GC_TRACKED (1 << 5)
74+
75+
7276
/* True if the object is currently tracked by the GC. */
7377
static inline int _PyObject_GC_IS_TRACKED(PyObject *op) {
7478
#ifdef Py_GIL_DISABLED
7579
return _PyObject_HAS_GC_BITS(op, _PyGC_BITS_TRACKED);
7680
#else
77-
PyGC_Head *gc = _Py_AS_GC(op);
78-
return (gc->_gc_next != 0);
81+
return (op->ob_flags & _Py_GC_TRACKED) != 0;
7982
#endif
8083
}
8184
#define _PyObject_GC_IS_TRACKED(op) _PyObject_GC_IS_TRACKED(_Py_CAST(PyObject*, op))
@@ -246,6 +249,8 @@ static inline void _PyObject_GC_TRACK(
246249
uintptr_t not_visited = 1 ^ interp->gc.visited_space;
247250
gc->_gc_next = ((uintptr_t)generation0) | not_visited;
248251
generation0->_gc_prev = (uintptr_t)gc;
252+
assert(op->ob_flags & _Py_GC_OBJECT);
253+
op->ob_flags |= _Py_GC_TRACKED;
249254
#endif
250255
}
251256

@@ -280,6 +285,7 @@ static inline void _PyObject_GC_UNTRACK(
280285
_PyGCHead_SET_PREV(next, prev);
281286
gc->_gc_next = 0;
282287
gc->_gc_prev &= _PyGC_PREV_MASK_FINALIZED;
288+
op->ob_flags &= ~_Py_GC_TRACKED;
283289
#endif
284290
}
285291

Include/internal/pycore_object.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -853,9 +853,7 @@ _PyObject_GET_WEAKREFS_LISTPTR_FROM_OFFSET(PyObject *op)
853853
static inline int
854854
_PyObject_IS_GC(PyObject *obj)
855855
{
856-
PyTypeObject *type = Py_TYPE(obj);
857-
return (_PyType_IS_GC(type)
858-
&& (type->tp_is_gc == NULL || type->tp_is_gc(obj)));
856+
return (obj->ob_flags & _Py_GC_OBJECT) != 0;
859857
}
860858

861859
// Fast inlined version of PyObject_Hash()

Modules/_asynciomodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2052,7 +2052,7 @@ future_new_iter(PyObject *fut)
20522052
asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
20532053
ENSURE_FUTURE_ALIVE(state, fut)
20542054

2055-
it = _Py_FREELIST_POP(futureiterobject, futureiters);
2055+
it = _Py_FREELIST_POP(futureiterobject, futureiters, 1);
20562056
if (it == NULL) {
20572057
it = PyObject_GC_New(futureiterobject, state->FutureIterType);
20582058
if (it == NULL) {

Objects/classobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ PyMethod_New(PyObject *func, PyObject *self)
114114
PyErr_BadInternalCall();
115115
return NULL;
116116
}
117-
PyMethodObject *im = _Py_FREELIST_POP(PyMethodObject, pymethodobjects);
117+
PyMethodObject *im = _Py_FREELIST_POP(PyMethodObject, pymethodobjects, 1);
118118
if (im == NULL) {
119119
im = PyObject_GC_New(PyMethodObject, &PyMethod_Type);
120120
if (im == NULL) {

Objects/complexobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ complex_subtype_from_c_complex(PyTypeObject *type, Py_complex cval)
410410
PyObject *
411411
PyComplex_FromCComplex(Py_complex cval)
412412
{
413-
PyComplexObject *op = _Py_FREELIST_POP(PyComplexObject, complexes);
413+
PyComplexObject *op = _Py_FREELIST_POP(PyComplexObject, complexes, 0);
414414

415415
if (op == NULL) {
416416
/* Inline PyObject_New */

Objects/dictobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,7 @@ new_dict(PyInterpreterState *interp,
872872
Py_ssize_t used, int free_values_on_failure)
873873
{
874874
assert(keys != NULL);
875-
PyDictObject *mp = _Py_FREELIST_POP(PyDictObject, dicts);
875+
PyDictObject *mp = _Py_FREELIST_POP(PyDictObject, dicts, 1);
876876
if (mp == NULL) {
877877
mp = PyObject_GC_New(PyDictObject, &PyDict_Type);
878878
if (mp == NULL) {

Objects/exceptions.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3978,6 +3978,8 @@ get_memory_error(int allow_allocation, PyObject *args, PyObject *kwds)
39783978
self->dict = NULL;
39793979
self->args = (PyObject *)&_Py_SINGLETON(tuple_empty);
39803980
_Py_NewReference((PyObject *)self);
3981+
assert(((PyObject *)self)->ob_flags == 0);
3982+
((PyObject *)self)->ob_flags = _Py_GC_OBJECT;
39813983
_PyObject_GC_TRACK(self);
39823984
}
39833985
MEMERRORS_UNLOCK(state);

Objects/floatobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ PyFloat_GetInfo(void)
123123
PyObject *
124124
PyFloat_FromDouble(double fval)
125125
{
126-
PyFloatObject *op = _Py_FREELIST_POP(PyFloatObject, floats);
126+
PyFloatObject *op = _Py_FREELIST_POP(PyFloatObject, floats, 0);
127127
if (op == NULL) {
128128
op = PyObject_Malloc(sizeof(PyFloatObject));
129129
if (!op) {

Objects/genobject.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1972,7 +1972,7 @@ PyTypeObject _PyAsyncGenASend_Type = {
19721972
static PyObject *
19731973
async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval)
19741974
{
1975-
PyAsyncGenASend *ags = _Py_FREELIST_POP(PyAsyncGenASend, async_gen_asends);
1975+
PyAsyncGenASend *ags = _Py_FREELIST_POP(PyAsyncGenASend, async_gen_asends, 1);
19761976
if (ags == NULL) {
19771977
ags = PyObject_GC_New(PyAsyncGenASend, &_PyAsyncGenASend_Type);
19781978
if (ags == NULL) {
@@ -2059,7 +2059,7 @@ _PyAsyncGenValueWrapperNew(PyThreadState *tstate, PyObject *val)
20592059
{
20602060
assert(val);
20612061

2062-
_PyAsyncGenWrappedValue *o = _Py_FREELIST_POP(_PyAsyncGenWrappedValue, async_gens);
2062+
_PyAsyncGenWrappedValue *o = _Py_FREELIST_POP(_PyAsyncGenWrappedValue, async_gens, 1);
20632063
if (o == NULL) {
20642064
o = PyObject_GC_New(_PyAsyncGenWrappedValue,
20652065
&_PyAsyncGenWrappedValue_Type);

0 commit comments

Comments
 (0)