bpo-44531: Add _PyType_AllocNoTrack() function (GH-26947)

Add an internal _PyType_AllocNoTrack() function to allocate an object
without tracking it in the GC.

Modify dict_new() to use _PyType_AllocNoTrack(): dict subclasses are
now only tracked once all PyDictObject members are initialized.
Calling _PyObject_GC_UNTRACK() is no longer needed for the dict type.

Similar change in tuple_subtype_new() for tuple subclasses.

Replace tuple_gc_track() with _PyObject_GC_TRACK().
This commit is contained in:
Victor Stinner 2021-07-01 02:30:46 +02:00 committed by GitHub
parent 1b28187a0e
commit 818628c2da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 28 deletions

View File

@ -178,6 +178,8 @@ extern int _Py_CheckSlotResult(
// See also the Py_TPFLAGS_READY flag. // See also the Py_TPFLAGS_READY flag.
#define _PyType_IsReady(type) ((type)->tp_dict != NULL) #define _PyType_IsReady(type) ((type)->tp_dict != NULL)
extern PyObject* _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -3324,19 +3324,16 @@ static PyNumberMethods dict_as_number = {
static PyObject * static PyObject *
dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds) dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{ {
PyObject *self; assert(type != NULL);
PyDictObject *d; assert(type->tp_alloc != NULL);
// dict subclasses must implement the GC protocol
assert(_PyType_IS_GC(type));
assert(type != NULL && type->tp_alloc != NULL); PyObject *self = type->tp_alloc(type, 0);
self = type->tp_alloc(type, 0); if (self == NULL) {
if (self == NULL)
return NULL; return NULL;
d = (PyDictObject *)self;
/* The object has been implicitly tracked by tp_alloc */
if (type == &PyDict_Type) {
_PyObject_GC_UNTRACK(d);
} }
PyDictObject *d = (PyDictObject *)self;
d->ma_used = 0; d->ma_used = 0;
d->ma_version_tag = DICT_NEXT_VERSION(); d->ma_version_tag = DICT_NEXT_VERSION();
@ -3344,6 +3341,17 @@ dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
d->ma_keys = Py_EMPTY_KEYS; d->ma_keys = Py_EMPTY_KEYS;
d->ma_values = empty_values; d->ma_values = empty_values;
ASSERT_CONSISTENT(d); ASSERT_CONSISTENT(d);
if (type != &PyDict_Type) {
// Don't track if a subclass tp_alloc is PyType_GenericAlloc()
if (!_PyObject_GC_IS_TRACKED(d)) {
_PyObject_GC_TRACK(d);
}
}
else {
// _PyType_AllocNoTrack() does not track the created object
assert(!_PyObject_GC_IS_TRACKED(d));
}
return self; return self;
} }
@ -3441,7 +3449,7 @@ PyTypeObject PyDict_Type = {
0, /* tp_descr_set */ 0, /* tp_descr_set */
0, /* tp_dictoffset */ 0, /* tp_dictoffset */
dict_init, /* tp_init */ dict_init, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */ _PyType_AllocNoTrack, /* tp_alloc */
dict_new, /* tp_new */ dict_new, /* tp_new */
PyObject_GC_Del, /* tp_free */ PyObject_GC_Del, /* tp_free */
.tp_vectorcall = dict_vectorcall, .tp_vectorcall = dict_vectorcall,

View File

@ -25,13 +25,6 @@ get_tuple_state(void)
#endif #endif
static inline void
tuple_gc_track(PyTupleObject *op)
{
_PyObject_GC_TRACK(op);
}
/* Print summary info about the state of the optimized allocator */ /* Print summary info about the state of the optimized allocator */
void void
_PyTuple_DebugMallocStats(FILE *out) _PyTuple_DebugMallocStats(FILE *out)
@ -48,10 +41,12 @@ _PyTuple_DebugMallocStats(FILE *out)
#endif #endif
} }
/* Allocate an uninitialized tuple object. Before making it public following /* Allocate an uninitialized tuple object. Before making it public, following
steps must be done: steps must be done:
- initialize its items
- call tuple_gc_track() on it - Initialize its items.
- Call _PyObject_GC_TRACK() on it.
Because the empty tuple is always reused and it's already tracked by GC, Because the empty tuple is always reused and it's already tracked by GC,
this function must not be called with size == 0 (unless from PyTuple_New() this function must not be called with size == 0 (unless from PyTuple_New()
which wraps this function). which wraps this function).
@ -161,7 +156,7 @@ PyTuple_New(Py_ssize_t size)
for (Py_ssize_t i = 0; i < size; i++) { for (Py_ssize_t i = 0; i < size; i++) {
op->ob_item[i] = NULL; op->ob_item[i] = NULL;
} }
tuple_gc_track(op); _PyObject_GC_TRACK(op);
return (PyObject *) op; return (PyObject *) op;
} }
@ -257,7 +252,7 @@ PyTuple_Pack(Py_ssize_t n, ...)
items[i] = o; items[i] = o;
} }
va_end(vargs); va_end(vargs);
tuple_gc_track(result); _PyObject_GC_TRACK(result);
return (PyObject *)result; return (PyObject *)result;
} }
@ -473,7 +468,7 @@ _PyTuple_FromArray(PyObject *const *src, Py_ssize_t n)
Py_INCREF(item); Py_INCREF(item);
dst[i] = item; dst[i] = item;
} }
tuple_gc_track(tuple); _PyObject_GC_TRACK(tuple);
return (PyObject *)tuple; return (PyObject *)tuple;
} }
@ -551,7 +546,7 @@ tupleconcat(PyTupleObject *a, PyObject *bb)
Py_INCREF(v); Py_INCREF(v);
dest[i] = v; dest[i] = v;
} }
tuple_gc_track(np); _PyObject_GC_TRACK(np);
return (PyObject *)np; return (PyObject *)np;
} }
@ -588,7 +583,7 @@ tuplerepeat(PyTupleObject *a, Py_ssize_t n)
p++; p++;
} }
} }
tuple_gc_track(np); _PyObject_GC_TRACK(np);
return (PyObject *) np; return (PyObject *) np;
} }
@ -783,6 +778,9 @@ tuple_subtype_new(PyTypeObject *type, PyObject *iterable)
Py_ssize_t i, n; Py_ssize_t i, n;
assert(PyType_IsSubtype(type, &PyTuple_Type)); assert(PyType_IsSubtype(type, &PyTuple_Type));
// tuple subclasses must implement the GC protocol
assert(_PyType_IS_GC(type));
tmp = tuple_new_impl(&PyTuple_Type, iterable); tmp = tuple_new_impl(&PyTuple_Type, iterable);
if (tmp == NULL) if (tmp == NULL)
return NULL; return NULL;
@ -798,6 +796,11 @@ tuple_subtype_new(PyTypeObject *type, PyObject *iterable)
PyTuple_SET_ITEM(newobj, i, item); PyTuple_SET_ITEM(newobj, i, item);
} }
Py_DECREF(tmp); Py_DECREF(tmp);
// Don't track if a subclass tp_alloc is PyType_GenericAlloc()
if (!_PyObject_GC_IS_TRACKED(newobj)) {
_PyObject_GC_TRACK(newobj);
}
return newobj; return newobj;
} }
@ -857,7 +860,7 @@ tuplesubscript(PyTupleObject* self, PyObject* item)
dest[i] = it; dest[i] = it;
} }
tuple_gc_track(result); _PyObject_GC_TRACK(result);
return (PyObject *)result; return (PyObject *)result;
} }
} }

View File

@ -1164,7 +1164,7 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
} }
PyObject * PyObject *
PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems) _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems)
{ {
PyObject *obj; PyObject *obj;
const size_t size = _PyObject_VAR_SIZE(type, nitems+1); const size_t size = _PyObject_VAR_SIZE(type, nitems+1);
@ -1189,6 +1189,16 @@ PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
else { else {
_PyObject_InitVar((PyVarObject *)obj, type, nitems); _PyObject_InitVar((PyVarObject *)obj, type, nitems);
} }
return obj;
}
PyObject *
PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
{
PyObject *obj = _PyType_AllocNoTrack(type, nitems);
if (obj == NULL) {
return NULL;
}
if (_PyType_IS_GC(type)) { if (_PyType_IS_GC(type)) {
_PyObject_GC_TRACK(obj); _PyObject_GC_TRACK(obj);