Skip to content

Commit 5d9e46e

Browse files
authored
[3.14] gh-153083: Defer GC tracking of an array to the end of construction. (gh-153284) (gh-153337)
(cherry picked from commit 8615062)
1 parent 3857128 commit 5d9e46e

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
@@ -875,7 +875,8 @@ static inline int _PyType_SUPPORTS_WEAKREFS(PyTypeObject *type) {
875875
return (type->tp_weaklistoffset != 0);
876876
}
877877

878-
extern PyObject* _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems);
878+
// Export for 'array' shared extension.
879+
PyAPI_FUNC(PyObject*) _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems);
879880
PyAPI_FUNC(PyObject *) _PyType_NewManagedObject(PyTypeObject *type);
880881

881882
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()
@@ -696,7 +697,8 @@ class array.array "arrayobject *" "ArrayType"
696697
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a5c29edf59f176a3]*/
697698

698699
static PyObject *
699-
newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr)
700+
newarrayobject_untracked(PyTypeObject *type, Py_ssize_t size,
701+
const struct arraydescr *descr)
700702
{
701703
arrayobject *op;
702704
size_t nbytes;
@@ -711,7 +713,7 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des
711713
return PyErr_NoMemory();
712714
}
713715
nbytes = size * descr->itemsize;
714-
op = (arrayobject *) type->tp_alloc(type, 0);
716+
op = (arrayobject *) _PyType_AllocNoTrack(type, 0);
715717
if (op == NULL) {
716718
return NULL;
717719
}
@@ -733,6 +735,16 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des
733735
return (PyObject *) op;
734736
}
735737

738+
static PyObject *
739+
newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr)
740+
{
741+
PyObject *op = newarrayobject_untracked(type, size, descr);
742+
if (op != NULL) {
743+
_PyObject_GC_TRACK(op);
744+
}
745+
return op;
746+
}
747+
736748
static PyObject *
737749
getarrayitem(PyObject *op, Py_ssize_t i)
738750
{
@@ -942,13 +954,14 @@ array_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
942954
ihigh = ilow;
943955
else if (ihigh > Py_SIZE(a))
944956
ihigh = Py_SIZE(a);
945-
np = (arrayobject *) newarrayobject(state->ArrayType, ihigh - ilow, a->ob_descr);
957+
np = (arrayobject *) newarrayobject_untracked(state->ArrayType, ihigh - ilow, a->ob_descr);
946958
if (np == NULL)
947959
return NULL;
948960
if (ihigh > ilow) {
949961
memcpy(np->ob_item, a->ob_item + ilow * a->ob_descr->itemsize,
950962
(ihigh-ilow) * a->ob_descr->itemsize);
951963
}
964+
_PyObject_GC_TRACK(np);
952965
return (PyObject *)np;
953966
}
954967

@@ -1019,7 +1032,7 @@ array_concat(PyObject *op, PyObject *bb)
10191032
return PyErr_NoMemory();
10201033
}
10211034
size = Py_SIZE(a) + Py_SIZE(b);
1022-
np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr);
1035+
np = (arrayobject *) newarrayobject_untracked(state->ArrayType, size, a->ob_descr);
10231036
if (np == NULL) {
10241037
return NULL;
10251038
}
@@ -1030,6 +1043,7 @@ array_concat(PyObject *op, PyObject *bb)
10301043
memcpy(np->ob_item + Py_SIZE(a)*a->ob_descr->itemsize,
10311044
b->ob_item, Py_SIZE(b)*b->ob_descr->itemsize);
10321045
}
1046+
_PyObject_GC_TRACK(np);
10331047
return (PyObject *)np;
10341048
#undef b
10351049
}
@@ -1047,16 +1061,19 @@ array_repeat(PyObject *op, Py_ssize_t n)
10471061
return PyErr_NoMemory();
10481062
}
10491063
Py_ssize_t size = array_length * n;
1050-
arrayobject* np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr);
1064+
arrayobject* np = (arrayobject *) newarrayobject_untracked(state->ArrayType, size, a->ob_descr);
10511065
if (np == NULL)
10521066
return NULL;
1053-
if (size == 0)
1067+
if (size == 0) {
1068+
_PyObject_GC_TRACK(np);
10541069
return (PyObject *)np;
1070+
}
10551071

10561072
const Py_ssize_t oldbytes = array_length * a->ob_descr->itemsize;
10571073
const Py_ssize_t newbytes = oldbytes * n;
10581074
_PyBytes_Repeat(np->ob_item, newbytes, a->ob_item, oldbytes);
10591075

1076+
_PyObject_GC_TRACK(np);
10601077
return (PyObject *)np;
10611078
}
10621079

@@ -2534,17 +2551,17 @@ array_subscr(PyObject *op, PyObject *item)
25342551
return newarrayobject(state->ArrayType, 0, self->ob_descr);
25352552
}
25362553
else if (step == 1) {
2537-
PyObject *result = newarrayobject(state->ArrayType,
2538-
slicelength, self->ob_descr);
2554+
PyObject *result = newarrayobject_untracked(state->ArrayType, slicelength, self->ob_descr);
25392555
if (result == NULL)
25402556
return NULL;
25412557
memcpy(((arrayobject *)result)->ob_item,
25422558
self->ob_item + start * itemsize,
25432559
slicelength * itemsize);
2560+
_PyObject_GC_TRACK(result);
25442561
return result;
25452562
}
25462563
else {
2547-
result = newarrayobject(state->ArrayType, slicelength, self->ob_descr);
2564+
result = newarrayobject_untracked(state->ArrayType, slicelength, self->ob_descr);
25482565
if (!result) return NULL;
25492566

25502567
ar = (arrayobject*)result;
@@ -2556,6 +2573,7 @@ array_subscr(PyObject *op, PyObject *item)
25562573
itemsize);
25572574
}
25582575

2576+
_PyObject_GC_TRACK(result);
25592577
return result;
25602578
}
25612579
}
@@ -2855,7 +2873,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
28552873
else
28562874
len = 0;
28572875

2858-
a = newarrayobject(type, len, descr);
2876+
a = newarrayobject_untracked(type, len, descr);
28592877
if (a == NULL) {
28602878
Py_XDECREF(it);
28612879
return NULL;
@@ -2943,6 +2961,8 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
29432961
}
29442962
Py_DECREF(it);
29452963
}
2964+
// Track only once fully built.
2965+
_PyObject_GC_TRACK(a);
29462966
return a;
29472967
}
29482968
}
@@ -3035,7 +3055,7 @@ static PyType_Slot array_slots[] = {
30353055
{Py_tp_methods, array_methods},
30363056
{Py_tp_members, array_members},
30373057
{Py_tp_getset, array_getsets},
3038-
{Py_tp_alloc, PyType_GenericAlloc},
3058+
{Py_tp_alloc, _PyType_AllocNoTrack},
30393059
{Py_tp_new, array_new},
30403060
{Py_tp_traverse, array_tp_traverse},
30413061

0 commit comments

Comments
 (0)