Skip to content

Commit 4a435e5

Browse files
authored
[3.13] gh-153083: Defer GC tracking of an array to the end of construction. (gh-153284) (gh-153338)
(cherry picked from commit 8615062)
1 parent 9a03953 commit 4a435e5

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
@@ -766,7 +766,8 @@ static inline int _PyType_SUPPORTS_WEAKREFS(PyTypeObject *type) {
766766
return (type->tp_weaklistoffset != 0);
767767
}
768768

769-
extern PyObject* _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems);
769+
// Export for 'array' shared extension.
770+
PyAPI_FUNC(PyObject*) _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems);
770771
extern PyObject *_PyType_NewManagedObject(PyTypeObject *type);
771772

772773
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
@@ -13,6 +13,7 @@
1313
#include "pycore_ceval.h" // _PyEval_GetBuiltin()
1414
#include "pycore_modsupport.h" // _PyArg_NoKeywords()
1515
#include "pycore_moduleobject.h" // _PyModule_GetState()
16+
#include "pycore_object.h" // _PyObject_GC_TRACK()
1617
#include "pycore_weakref.h" // FT_CLEAR_WEAKREFS()
1718

1819
#include <stddef.h> // offsetof()
@@ -677,7 +678,8 @@ class array.array "arrayobject *" "ArrayType"
677678
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a5c29edf59f176a3]*/
678679

679680
static PyObject *
680-
newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr)
681+
newarrayobject_untracked(PyTypeObject *type, Py_ssize_t size,
682+
const struct arraydescr *descr)
681683
{
682684
arrayobject *op;
683685
size_t nbytes;
@@ -692,7 +694,7 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des
692694
return PyErr_NoMemory();
693695
}
694696
nbytes = size * descr->itemsize;
695-
op = (arrayobject *) type->tp_alloc(type, 0);
697+
op = (arrayobject *) _PyType_AllocNoTrack(type, 0);
696698
if (op == NULL) {
697699
return NULL;
698700
}
@@ -714,6 +716,16 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des
714716
return (PyObject *) op;
715717
}
716718

719+
static PyObject *
720+
newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr)
721+
{
722+
PyObject *op = newarrayobject_untracked(type, size, descr);
723+
if (op != NULL) {
724+
_PyObject_GC_TRACK(op);
725+
}
726+
return op;
727+
}
728+
717729
static PyObject *
718730
getarrayitem(PyObject *op, Py_ssize_t i)
719731
{
@@ -921,13 +933,14 @@ array_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
921933
ihigh = ilow;
922934
else if (ihigh > Py_SIZE(a))
923935
ihigh = Py_SIZE(a);
924-
np = (arrayobject *) newarrayobject(state->ArrayType, ihigh - ilow, a->ob_descr);
936+
np = (arrayobject *) newarrayobject_untracked(state->ArrayType, ihigh - ilow, a->ob_descr);
925937
if (np == NULL)
926938
return NULL;
927939
if (ihigh > ilow) {
928940
memcpy(np->ob_item, a->ob_item + ilow * a->ob_descr->itemsize,
929941
(ihigh-ilow) * a->ob_descr->itemsize);
930942
}
943+
_PyObject_GC_TRACK(np);
931944
return (PyObject *)np;
932945
}
933946

@@ -997,7 +1010,7 @@ array_concat(arrayobject *a, PyObject *bb)
9971010
return PyErr_NoMemory();
9981011
}
9991012
size = Py_SIZE(a) + Py_SIZE(b);
1000-
np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr);
1013+
np = (arrayobject *) newarrayobject_untracked(state->ArrayType, size, a->ob_descr);
10011014
if (np == NULL) {
10021015
return NULL;
10031016
}
@@ -1008,6 +1021,7 @@ array_concat(arrayobject *a, PyObject *bb)
10081021
memcpy(np->ob_item + Py_SIZE(a)*a->ob_descr->itemsize,
10091022
b->ob_item, Py_SIZE(b)*b->ob_descr->itemsize);
10101023
}
1024+
_PyObject_GC_TRACK(np);
10111025
return (PyObject *)np;
10121026
#undef b
10131027
}
@@ -1024,16 +1038,19 @@ array_repeat(arrayobject *a, Py_ssize_t n)
10241038
return PyErr_NoMemory();
10251039
}
10261040
Py_ssize_t size = array_length * n;
1027-
arrayobject* np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr);
1041+
arrayobject* np = (arrayobject *) newarrayobject_untracked(state->ArrayType, size, a->ob_descr);
10281042
if (np == NULL)
10291043
return NULL;
1030-
if (size == 0)
1044+
if (size == 0) {
1045+
_PyObject_GC_TRACK(np);
10311046
return (PyObject *)np;
1047+
}
10321048

10331049
const Py_ssize_t oldbytes = array_length * a->ob_descr->itemsize;
10341050
const Py_ssize_t newbytes = oldbytes * n;
10351051
_PyBytes_Repeat(np->ob_item, newbytes, a->ob_item, oldbytes);
10361052

1053+
_PyObject_GC_TRACK(np);
10371054
return (PyObject *)np;
10381055
}
10391056

@@ -2504,17 +2521,17 @@ array_subscr(arrayobject* self, PyObject* item)
25042521
return newarrayobject(state->ArrayType, 0, self->ob_descr);
25052522
}
25062523
else if (step == 1) {
2507-
PyObject *result = newarrayobject(state->ArrayType,
2508-
slicelength, self->ob_descr);
2524+
PyObject *result = newarrayobject_untracked(state->ArrayType, slicelength, self->ob_descr);
25092525
if (result == NULL)
25102526
return NULL;
25112527
memcpy(((arrayobject *)result)->ob_item,
25122528
self->ob_item + start * itemsize,
25132529
slicelength * itemsize);
2530+
_PyObject_GC_TRACK(result);
25142531
return result;
25152532
}
25162533
else {
2517-
result = newarrayobject(state->ArrayType, slicelength, self->ob_descr);
2534+
result = newarrayobject_untracked(state->ArrayType, slicelength, self->ob_descr);
25182535
if (!result) return NULL;
25192536

25202537
ar = (arrayobject*)result;
@@ -2526,6 +2543,7 @@ array_subscr(arrayobject* self, PyObject* item)
25262543
itemsize);
25272544
}
25282545

2546+
_PyObject_GC_TRACK(result);
25292547
return result;
25302548
}
25312549
}
@@ -2822,7 +2840,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
28222840
else
28232841
len = 0;
28242842

2825-
a = newarrayobject(type, len, descr);
2843+
a = newarrayobject_untracked(type, len, descr);
28262844
if (a == NULL) {
28272845
Py_XDECREF(it);
28282846
return NULL;
@@ -2911,6 +2929,8 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
29112929
}
29122930
Py_DECREF(it);
29132931
}
2932+
// Track only once fully built.
2933+
_PyObject_GC_TRACK(a);
29142934
return a;
29152935
}
29162936
}
@@ -3003,7 +3023,7 @@ static PyType_Slot array_slots[] = {
30033023
{Py_tp_methods, array_methods},
30043024
{Py_tp_members, array_members},
30053025
{Py_tp_getset, array_getsets},
3006-
{Py_tp_alloc, PyType_GenericAlloc},
3026+
{Py_tp_alloc, _PyType_AllocNoTrack},
30073027
{Py_tp_new, array_new},
30083028
{Py_tp_traverse, array_tp_traverse},
30093029

0 commit comments

Comments
 (0)