Skip to content

Commit e1dc5f5

Browse files
[3.14] gh-152235: Defer GC tracking in more set operations (gh-152273) (gh-152279)
gh-152235: Defer GC tracking in more set operations (gh-152273) (cherry picked from commit a87d24a) Co-authored-by: Donghee Na <donghee.na@python.org>
1 parent 99311f5 commit e1dc5f5

2 files changed

Lines changed: 36 additions & 10 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Defer GC tracking of :meth:`set.intersection`, :meth:`set.difference` and
2+
:meth:`set.symmetric_difference`. Patch by Donghee Na.

Objects/setobject.c

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,14 +1137,14 @@ set_update_impl(PySetObject *so, PyObject * const *others,
11371137
can be retrieved or updated in a single cache line.
11381138
*/
11391139

1140+
// Build a set/frozenset left GC-untracked; the caller must _PyObject_GC_TRACK()
1141+
// it once fully built, so a half-built set is never exposed during filling.
11401142
static PyObject *
1141-
make_new_set(PyTypeObject *type, PyObject *iterable)
1143+
make_new_set_untracked(PyTypeObject *type, PyObject *iterable)
11421144
{
11431145
assert(PyType_Check(type));
11441146
PySetObject *so;
11451147

1146-
// Allocate untracked: the fill below runs user code, and a half-built
1147-
// set must not be reachable from another thread via gc.get_objects().
11481148
so = (PySetObject *)_PyType_AllocNoTrack(type, 0);
11491149
if (so == NULL)
11501150
return NULL;
@@ -1164,21 +1164,39 @@ make_new_set(PyTypeObject *type, PyObject *iterable)
11641164
}
11651165
}
11661166

1167-
// Track only once fully built.
1168-
_PyObject_GC_TRACK(so);
11691167
return (PyObject *)so;
11701168
}
11711169

11721170
static PyObject *
1173-
make_new_set_basetype(PyTypeObject *type, PyObject *iterable)
1171+
make_new_set(PyTypeObject *type, PyObject *iterable)
1172+
{
1173+
PyObject *so = make_new_set_untracked(type, iterable);
1174+
if (so != NULL) {
1175+
_PyObject_GC_TRACK(so);
1176+
}
1177+
return so;
1178+
}
1179+
1180+
static PyObject *
1181+
make_new_set_basetype_untracked(PyTypeObject *type, PyObject *iterable)
11741182
{
11751183
if (type != &PySet_Type && type != &PyFrozenSet_Type) {
11761184
if (PyType_IsSubtype(type, &PySet_Type))
11771185
type = &PySet_Type;
11781186
else
11791187
type = &PyFrozenSet_Type;
11801188
}
1181-
return make_new_set(type, iterable);
1189+
return make_new_set_untracked(type, iterable);
1190+
}
1191+
1192+
static PyObject *
1193+
make_new_set_basetype(PyTypeObject *type, PyObject *iterable)
1194+
{
1195+
PyObject *so = make_new_set_basetype_untracked(type, iterable);
1196+
if (so != NULL) {
1197+
_PyObject_GC_TRACK(so);
1198+
}
1199+
return so;
11821200
}
11831201

11841202
static PyObject *
@@ -1423,7 +1441,7 @@ set_intersection(PySetObject *so, PyObject *other)
14231441
if ((PyObject *)so == other)
14241442
return set_copy_impl(so);
14251443

1426-
result = (PySetObject *)make_new_set_basetype(Py_TYPE(so), NULL);
1444+
result = (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), NULL);
14271445
if (result == NULL)
14281446
return NULL;
14291447

@@ -1456,6 +1474,7 @@ set_intersection(PySetObject *so, PyObject *other)
14561474
}
14571475
Py_DECREF(key);
14581476
}
1477+
_PyObject_GC_TRACK(result);
14591478
return (PyObject *)result;
14601479
}
14611480

@@ -1487,6 +1506,7 @@ set_intersection(PySetObject *so, PyObject *other)
14871506
Py_DECREF(result);
14881507
return NULL;
14891508
}
1509+
_PyObject_GC_TRACK(result);
14901510
return (PyObject *)result;
14911511
error:
14921512
Py_DECREF(it);
@@ -1801,7 +1821,7 @@ set_difference(PySetObject *so, PyObject *other)
18011821
return set_copy_and_difference(so, other);
18021822
}
18031823

1804-
result = make_new_set_basetype(Py_TYPE(so), NULL);
1824+
result = make_new_set_basetype_untracked(Py_TYPE(so), NULL);
18051825
if (result == NULL)
18061826
return NULL;
18071827

@@ -1825,6 +1845,7 @@ set_difference(PySetObject *so, PyObject *other)
18251845
}
18261846
Py_DECREF(key);
18271847
}
1848+
_PyObject_GC_TRACK(result);
18281849
return result;
18291850
}
18301851

@@ -1848,6 +1869,7 @@ set_difference(PySetObject *so, PyObject *other)
18481869
}
18491870
Py_DECREF(key);
18501871
}
1872+
_PyObject_GC_TRACK(result);
18511873
return result;
18521874
}
18531875

@@ -2037,7 +2059,8 @@ static PyObject *
20372059
set_symmetric_difference_impl(PySetObject *so, PyObject *other)
20382060
/*[clinic end generated code: output=270ee0b5d42b0797 input=624f6e7bbdf70db1]*/
20392061
{
2040-
PySetObject *result = (PySetObject *)make_new_set_basetype(Py_TYPE(so), NULL);
2062+
PySetObject *result =
2063+
(PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), NULL);
20412064
if (result == NULL) {
20422065
return NULL;
20432066
}
@@ -2049,6 +2072,7 @@ set_symmetric_difference_impl(PySetObject *so, PyObject *other)
20492072
Py_DECREF(result);
20502073
return NULL;
20512074
}
2075+
_PyObject_GC_TRACK(result);
20522076
return (PyObject *)result;
20532077
}
20542078

0 commit comments

Comments
 (0)