[3.15] gh-153083: Defer GC tracking of an array to the end of construction. (gh-153284) (gh-153336)

gh-153083: Defer GC tracking of an array to the end of construction. (gh-153284)
(cherry picked from commit 8615062fd5)

Co-authored-by: Donghee Na <donghee.na@python.org>
This commit is contained in:
Miss Islington (bot)
2026-07-08 14:59:13 +02:00
committed by GitHub
parent a9d4473232
commit 8cb4b84c69
3 changed files with 35 additions and 12 deletions
+2 -1
View File
@@ -873,7 +873,8 @@ static inline int _PyType_SUPPORTS_WEAKREFS(PyTypeObject *type) {
return (type->tp_weaklistoffset != 0);
}
extern PyObject* _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems);
// Export for 'array' shared extension.
PyAPI_FUNC(PyObject*) _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems);
PyAPI_FUNC(PyObject *) _PyType_NewManagedObject(PyTypeObject *type);
extern PyTypeObject* _PyType_CalculateMetaclass(PyTypeObject *, PyObject *);
@@ -0,0 +1,2 @@
Defer GC tracking of an :class:`array.array` to the end of its construction.
Patch by Donghee Na.
+31 -11
View File
@@ -14,6 +14,7 @@
#include "pycore_floatobject.h" // _PY_FLOAT_BIG_ENDIAN
#include "pycore_modsupport.h" // _PyArg_NoKeywords()
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_object.h" // _PyObject_GC_TRACK()
#include "pycore_tuple.h" // _PyTuple_FromPairSteal
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
@@ -796,7 +797,8 @@ class array.array "arrayobject *" "ArrayType"
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a5c29edf59f176a3]*/
static PyObject *
newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr)
newarrayobject_untracked(PyTypeObject *type, Py_ssize_t size,
const struct arraydescr *descr)
{
arrayobject *op;
size_t nbytes;
@@ -811,7 +813,7 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des
return PyErr_NoMemory();
}
nbytes = size * descr->itemsize;
op = (arrayobject *) type->tp_alloc(type, 0);
op = (arrayobject *) _PyType_AllocNoTrack(type, 0);
if (op == NULL) {
return NULL;
}
@@ -833,6 +835,16 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des
return (PyObject *) op;
}
static PyObject *
newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr)
{
PyObject *op = newarrayobject_untracked(type, size, descr);
if (op != NULL) {
_PyObject_GC_TRACK(op);
}
return op;
}
static PyObject *
getarrayitem(PyObject *op, Py_ssize_t i)
{
@@ -1034,13 +1046,14 @@ array_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
ihigh = ilow;
else if (ihigh > Py_SIZE(a))
ihigh = Py_SIZE(a);
np = (arrayobject *) newarrayobject(state->ArrayType, ihigh - ilow, a->ob_descr);
np = (arrayobject *) newarrayobject_untracked(state->ArrayType, ihigh - ilow, a->ob_descr);
if (np == NULL)
return NULL;
if (ihigh > ilow) {
memcpy(np->ob_item, a->ob_item + ilow * a->ob_descr->itemsize,
(ihigh-ilow) * a->ob_descr->itemsize);
}
_PyObject_GC_TRACK(np);
return (PyObject *)np;
}
@@ -1111,7 +1124,7 @@ array_concat(PyObject *op, PyObject *bb)
return PyErr_NoMemory();
}
size = Py_SIZE(a) + Py_SIZE(b);
np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr);
np = (arrayobject *) newarrayobject_untracked(state->ArrayType, size, a->ob_descr);
if (np == NULL) {
return NULL;
}
@@ -1122,6 +1135,7 @@ array_concat(PyObject *op, PyObject *bb)
memcpy(np->ob_item + Py_SIZE(a)*a->ob_descr->itemsize,
b->ob_item, Py_SIZE(b)*b->ob_descr->itemsize);
}
_PyObject_GC_TRACK(np);
return (PyObject *)np;
#undef b
}
@@ -1139,16 +1153,19 @@ array_repeat(PyObject *op, Py_ssize_t n)
return PyErr_NoMemory();
}
Py_ssize_t size = array_length * n;
arrayobject* np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr);
arrayobject* np = (arrayobject *) newarrayobject_untracked(state->ArrayType, size, a->ob_descr);
if (np == NULL)
return NULL;
if (size == 0)
if (size == 0) {
_PyObject_GC_TRACK(np);
return (PyObject *)np;
}
const Py_ssize_t oldbytes = array_length * a->ob_descr->itemsize;
const Py_ssize_t newbytes = oldbytes * n;
_PyBytes_Repeat(np->ob_item, newbytes, a->ob_item, oldbytes);
_PyObject_GC_TRACK(np);
return (PyObject *)np;
}
@@ -2741,17 +2758,17 @@ array_subscr(PyObject *op, PyObject *item)
return newarrayobject(state->ArrayType, 0, self->ob_descr);
}
else if (step == 1) {
PyObject *result = newarrayobject(state->ArrayType,
slicelength, self->ob_descr);
PyObject *result = newarrayobject_untracked(state->ArrayType, slicelength, self->ob_descr);
if (result == NULL)
return NULL;
memcpy(((arrayobject *)result)->ob_item,
self->ob_item + start * itemsize,
slicelength * itemsize);
_PyObject_GC_TRACK(result);
return result;
}
else {
result = newarrayobject(state->ArrayType, slicelength, self->ob_descr);
result = newarrayobject_untracked(state->ArrayType, slicelength, self->ob_descr);
if (!result) return NULL;
ar = (arrayobject*)result;
@@ -2763,6 +2780,7 @@ array_subscr(PyObject *op, PyObject *item)
itemsize);
}
_PyObject_GC_TRACK(result);
return result;
}
}
@@ -3060,7 +3078,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
else
len = 0;
a = newarrayobject(type, len, descr);
a = newarrayobject_untracked(type, len, descr);
if (a == NULL) {
Py_XDECREF(it);
return NULL;
@@ -3148,6 +3166,8 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
}
Py_DECREF(it);
}
// Track only once fully built.
_PyObject_GC_TRACK(a);
return a;
}
}
@@ -3243,7 +3263,7 @@ static PyType_Slot array_slots[] = {
{Py_tp_methods, array_methods},
{Py_tp_members, array_members},
{Py_tp_getset, array_getsets},
{Py_tp_alloc, PyType_GenericAlloc},
{Py_tp_alloc, _PyType_AllocNoTrack},
{Py_tp_new, array_new},
{Py_tp_traverse, _PyObject_VisitType},