Skip to content

Commit 8615062

Browse files
authored
gh-153083: Defer GC tracking of an array to the end of construction. (gh-153284)
1 parent 841e454 commit 8615062

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
@@ -872,7 +872,8 @@ static inline int _PyType_SUPPORTS_WEAKREFS(PyTypeObject *type) {
872872
return (type->tp_weaklistoffset != 0);
873873
}
874874

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

878879
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

@@ -752,7 +753,8 @@ class array.array "arrayobject *" "ArrayType"
752753
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a5c29edf59f176a3]*/
753754

754755
static PyObject *
755-
newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr)
756+
newarrayobject_untracked(PyTypeObject *type, Py_ssize_t size,
757+
const struct arraydescr *descr)
756758
{
757759
arrayobject *op;
758760
size_t nbytes;
@@ -767,7 +769,7 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des
767769
return PyErr_NoMemory();
768770
}
769771
nbytes = size * descr->itemsize;
770-
op = (arrayobject *) type->tp_alloc(type, 0);
772+
op = (arrayobject *) _PyType_AllocNoTrack(type, 0);
771773
if (op == NULL) {
772774
return NULL;
773775
}
@@ -789,6 +791,16 @@ newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *des
789791
return (PyObject *) op;
790792
}
791793

794+
static PyObject *
795+
newarrayobject(PyTypeObject *type, Py_ssize_t size, const struct arraydescr *descr)
796+
{
797+
PyObject *op = newarrayobject_untracked(type, size, descr);
798+
if (op != NULL) {
799+
_PyObject_GC_TRACK(op);
800+
}
801+
return op;
802+
}
803+
792804
static PyObject *
793805
getarrayitem(PyObject *op, Py_ssize_t i)
794806
{
@@ -990,13 +1002,14 @@ array_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
9901002
ihigh = ilow;
9911003
else if (ihigh > Py_SIZE(a))
9921004
ihigh = Py_SIZE(a);
993-
np = (arrayobject *) newarrayobject(state->ArrayType, ihigh - ilow, a->ob_descr);
1005+
np = (arrayobject *) newarrayobject_untracked(state->ArrayType, ihigh - ilow, a->ob_descr);
9941006
if (np == NULL)
9951007
return NULL;
9961008
if (ihigh > ilow) {
9971009
memcpy(np->ob_item, a->ob_item + ilow * a->ob_descr->itemsize,
9981010
(ihigh-ilow) * a->ob_descr->itemsize);
9991011
}
1012+
_PyObject_GC_TRACK(np);
10001013
return (PyObject *)np;
10011014
}
10021015

@@ -1067,7 +1080,7 @@ array_concat(PyObject *op, PyObject *bb)
10671080
return PyErr_NoMemory();
10681081
}
10691082
size = Py_SIZE(a) + Py_SIZE(b);
1070-
np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr);
1083+
np = (arrayobject *) newarrayobject_untracked(state->ArrayType, size, a->ob_descr);
10711084
if (np == NULL) {
10721085
return NULL;
10731086
}
@@ -1078,6 +1091,7 @@ array_concat(PyObject *op, PyObject *bb)
10781091
memcpy(np->ob_item + Py_SIZE(a)*a->ob_descr->itemsize,
10791092
b->ob_item, Py_SIZE(b)*b->ob_descr->itemsize);
10801093
}
1094+
_PyObject_GC_TRACK(np);
10811095
return (PyObject *)np;
10821096
#undef b
10831097
}
@@ -1095,16 +1109,19 @@ array_repeat(PyObject *op, Py_ssize_t n)
10951109
return PyErr_NoMemory();
10961110
}
10971111
Py_ssize_t size = array_length * n;
1098-
arrayobject* np = (arrayobject *) newarrayobject(state->ArrayType, size, a->ob_descr);
1112+
arrayobject* np = (arrayobject *) newarrayobject_untracked(state->ArrayType, size, a->ob_descr);
10991113
if (np == NULL)
11001114
return NULL;
1101-
if (size == 0)
1115+
if (size == 0) {
1116+
_PyObject_GC_TRACK(np);
11021117
return (PyObject *)np;
1118+
}
11031119

11041120
const Py_ssize_t oldbytes = array_length * a->ob_descr->itemsize;
11051121
const Py_ssize_t newbytes = oldbytes * n;
11061122
_PyBytes_RepeatBuffer(np->ob_item, newbytes, a->ob_item, oldbytes);
11071123

1124+
_PyObject_GC_TRACK(np);
11081125
return (PyObject *)np;
11091126
}
11101127

@@ -2666,17 +2683,17 @@ array_subscr(PyObject *op, PyObject *item)
26662683
return newarrayobject(state->ArrayType, 0, self->ob_descr);
26672684
}
26682685
else if (step == 1) {
2669-
PyObject *result = newarrayobject(state->ArrayType,
2670-
slicelength, self->ob_descr);
2686+
PyObject *result = newarrayobject_untracked(state->ArrayType, slicelength, self->ob_descr);
26712687
if (result == NULL)
26722688
return NULL;
26732689
memcpy(((arrayobject *)result)->ob_item,
26742690
self->ob_item + start * itemsize,
26752691
slicelength * itemsize);
2692+
_PyObject_GC_TRACK(result);
26762693
return result;
26772694
}
26782695
else {
2679-
result = newarrayobject(state->ArrayType, slicelength, self->ob_descr);
2696+
result = newarrayobject_untracked(state->ArrayType, slicelength, self->ob_descr);
26802697
if (!result) return NULL;
26812698

26822699
ar = (arrayobject*)result;
@@ -2688,6 +2705,7 @@ array_subscr(PyObject *op, PyObject *item)
26882705
itemsize);
26892706
}
26902707

2708+
_PyObject_GC_TRACK(result);
26912709
return result;
26922710
}
26932711
}
@@ -2973,7 +2991,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
29732991
else
29742992
len = 0;
29752993

2976-
a = newarrayobject(type, len, descr);
2994+
a = newarrayobject_untracked(type, len, descr);
29772995
if (a == NULL) {
29782996
Py_XDECREF(it);
29792997
return NULL;
@@ -3039,6 +3057,8 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
30393057
}
30403058
Py_DECREF(it);
30413059
}
3060+
// Track only once fully built.
3061+
_PyObject_GC_TRACK(a);
30423062
return a;
30433063
}
30443064
}
@@ -3140,7 +3160,7 @@ static PyType_Slot array_slots[] = {
31403160
{Py_tp_methods, array_methods},
31413161
{Py_tp_members, array_members},
31423162
{Py_tp_getset, array_getsets},
3143-
{Py_tp_alloc, PyType_GenericAlloc},
3163+
{Py_tp_alloc, _PyType_AllocNoTrack},
31443164
{Py_tp_new, array_new},
31453165
{Py_tp_traverse, _PyObject_VisitType},
31463166

0 commit comments

Comments
 (0)