mirror of https://github.com/python/cpython
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:
parent
1b28187a0e
commit
818628c2da
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue