Skip to content

Commit 8cb4b84

Browse files
[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 8615062) Co-authored-by: Donghee Na <donghee.na@python.org>
1 parent a9d4473 commit 8cb4b84

3 files changed

Lines changed: 35 additions & 12 deletions

File tree

Include/internal/pycore_object.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -873,7 +873,8 @@ static inline int _PyType_SUPPORTS_WEAKREFS(PyTypeObject *type) {
873873
return (type->tp_weaklistoffset != 0);
874874
}
875875

876-
extern PyObject* _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems);
876+
// Export for 'array' shared extension.
877+
PyAPI_FUNC(PyObject*) _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems);
877878
PyAPI_FUNC(PyObject *) _PyType_NewManagedObject(PyTypeObject *type);
878879

879880
extern PyTypeObject* _PyType_CalculateMetaclass(PyTypeObject *, PyObject *);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Defer GC tracking of an :class:`array.array` to the end of its construction.
2+
Patch by Donghee Na.

Modules/arraymodule.c

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "pycore_floatobject.h" // _PY_FLOAT_BIG_ENDIAN
1515
#include "pycore_modsupport.h" // _PyArg_NoKeywords()
1616
#include "pycore_moduleobject.h" // _PyModule_GetState()
17+
#include "pycore_object.h" // _PyObject_GC_TRACK()
1718
#include "pycore_tuple.h" // _PyTuple_FromPairSteal
1819
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
1920

@@ -796,7 +797,8 @@ class array.array "arrayobject *" "ArrayType"
796797
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a5c29edf59f176a3]*/
797798

798799
static PyObject *
799-
newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr)
800+
newarrayobject_untracked(PyTypeObject *type, Py_ssize_t size,
801+
const struct arraydescr *descr)
800802
{
801803
arrayobject *op;
802804
size_t nbytes;
@@ -811,7 +813,7 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des
811813
return PyErr_NoMemory();
812814
}
813815
nbytes = size * descr->itemsize;
814-
op = (arrayobject *) type->tp_alloc(type, 0);
816+
op = (arrayobject *) _PyType_AllocNoTrack(type, 0);
815817
if (op == NULL) {
816818
return NULL;
817819
}
@@ -833,6 +835,16 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des
833835
return (PyObject *) op;
834836
}
835837

838+
static PyObject *
839+
newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr)
840+
{
841+
PyObject *op = newarrayobject_untracked(type, size, descr);
842+
if (op != NULL) {
843+
_PyObject_GC_TRACK(op);
844+
}
845+
return op;
846+
}
847+
836848
static PyObject *
837849
getarrayitem(PyObject *op, Py_ssize_t i)
838850
{
@@ -1034,13 +1046,14 @@ array_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
10341046
ihigh = ilow;
10351047
else if (ihigh > Py_SIZE(a))
10361048
ihigh = Py_SIZE(a);
1037-
np = (arrayobject *) newarrayobject(state->ArrayType, ihigh - ilow, a->ob_descr);
1049+
np = (arrayobject *) newarrayobject_untracked(state->ArrayType, ihigh - ilow, a->ob_descr);
10381050
if (np == NULL)
10391051
return NULL;
10401052
if (ihigh > ilow) {
10411053
memcpy(np->ob_item, a->ob_item + ilow * a->ob_descr->itemsize,
10421054
(ihigh-ilow) * a->ob_descr->itemsize);
10431055
}
1056+
_PyObject_GC_TRACK(np);
10441057
return (PyObject *)np;
10451058
}
10461059

@@ -1111,7 +1124,7 @@ array_concat(PyObject *op, PyObject *bb)
11111124
return PyErr_NoMemory();
11121125
}
11131126
size = Py_SIZE(a) + Py_SIZE(b);
1114-
np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr);
1127+
np = (arrayobject *) newarrayobject_untracked(state->ArrayType, size, a->ob_descr);
11151128
if (np == NULL) {
11161129
return NULL;
11171130
}
@@ -1122,6 +1135,7 @@ array_concat(PyObject *op, PyObject *bb)
11221135
memcpy(np->ob_item + Py_SIZE(a)*a->ob_descr->itemsize,
11231136
b->ob_item, Py_SIZE(b)*b->ob_descr->itemsize);
11241137
}
1138+
_PyObject_GC_TRACK(np);
11251139
return (PyObject *)np;
11261140
#undef b
11271141
}
@@ -1139,16 +1153,19 @@ array_repeat(PyObject *op, Py_ssize_t n)
11391153
return PyErr_NoMemory();
11401154
}
11411155
Py_ssize_t size = array_length * n;
1142-
arrayobject* np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr);
1156+
arrayobject* np = (arrayobject *) newarrayobject_untracked(state->ArrayType, size, a->ob_descr);
11431157
if (np == NULL)
11441158
return NULL;
1145-
if (size == 0)
1159+
if (size == 0) {
1160+
_PyObject_GC_TRACK(np);
11461161
return (PyObject *)np;
1162+
}
11471163

11481164
const Py_ssize_t oldbytes = array_length * a->ob_descr->itemsize;
11491165
const Py_ssize_t newbytes = oldbytes * n;
11501166
_PyBytes_Repeat(np->ob_item, newbytes, a->ob_item, oldbytes);
11511167

1168+
_PyObject_GC_TRACK(np);
11521169
return (PyObject *)np;
11531170
}
11541171

@@ -2741,17 +2758,17 @@ array_subscr(PyObject *op, PyObject *item)
27412758
return newarrayobject(state->ArrayType, 0, self->ob_descr);
27422759
}
27432760
else if (step == 1) {
2744-
PyObject *result = newarrayobject(state->ArrayType,
2745-
slicelength, self->ob_descr);
2761+
PyObject *result = newarrayobject_untracked(state->ArrayType, slicelength, self->ob_descr);
27462762
if (result == NULL)
27472763
return NULL;
27482764
memcpy(((arrayobject *)result)->ob_item,
27492765
self->ob_item + start * itemsize,
27502766
slicelength * itemsize);
2767+
_PyObject_GC_TRACK(result);
27512768
return result;
27522769
}
27532770
else {
2754-
result = newarrayobject(state->ArrayType, slicelength, self->ob_descr);
2771+
result = newarrayobject_untracked(state->ArrayType, slicelength, self->ob_descr);
27552772
if (!result) return NULL;
27562773

27572774
ar = (arrayobject*)result;
@@ -2763,6 +2780,7 @@ array_subscr(PyObject *op, PyObject *item)
27632780
itemsize);
27642781
}
27652782

2783+
_PyObject_GC_TRACK(result);
27662784
return result;
27672785
}
27682786
}
@@ -3060,7 +3078,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
30603078
else
30613079
len = 0;
30623080

3063-
a = newarrayobject(type, len, descr);
3081+
a = newarrayobject_untracked(type, len, descr);
30643082
if (a == NULL) {
30653083
Py_XDECREF(it);
30663084
return NULL;
@@ -3148,6 +3166,8 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
31483166
}
31493167
Py_DECREF(it);
31503168
}
3169+
// Track only once fully built.
3170+
_PyObject_GC_TRACK(a);
31513171
return a;
31523172
}
31533173
}
@@ -3243,7 +3263,7 @@ static PyType_Slot array_slots[] = {
32433263
{Py_tp_methods, array_methods},
32443264
{Py_tp_members, array_members},
32453265
{Py_tp_getset, array_getsets},
3246-
{Py_tp_alloc, PyType_GenericAlloc},
3266+
{Py_tp_alloc, _PyType_AllocNoTrack},
32473267
{Py_tp_new, array_new},
32483268
{Py_tp_traverse, _PyObject_VisitType},
32493269

0 commit comments

Comments
 (0)