Skip to content

Commit 7ed6737

Browse files
[3.15] gh-152235: Defer GC tracking in more set operations (gh-152273) (gh-152278)
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 c48673b commit 7ed6737

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
@@ -1345,14 +1345,14 @@ set_update_impl(PySetObject *so, PyObject * const *others,
13451345
can be retrieved or updated in a single cache line.
13461346
*/
13471347

1348+
// Build a set/frozenset left GC-untracked; the caller must _PyObject_GC_TRACK()
1349+
// it once fully built, so a half-built set is never exposed during filling.
13481350
static PyObject *
1349-
make_new_set(PyTypeObject *type, PyObject *iterable)
1351+
make_new_set_untracked(PyTypeObject *type, PyObject *iterable)
13501352
{
13511353
assert(PyType_Check(type));
13521354
PySetObject *so;
13531355

1354-
// Allocate untracked: the fill below runs user code, and a half-built
1355-
// set must not be reachable from another thread via gc.get_objects().
13561356
so = (PySetObject *)_PyType_AllocNoTrack(type, 0);
13571357
if (so == NULL)
13581358
return NULL;
@@ -1372,21 +1372,39 @@ make_new_set(PyTypeObject *type, PyObject *iterable)
13721372
}
13731373
}
13741374

1375-
// Track only once fully built.
1376-
_PyObject_GC_TRACK(so);
13771375
return (PyObject *)so;
13781376
}
13791377

13801378
static PyObject *
1381-
make_new_set_basetype(PyTypeObject *type, PyObject *iterable)
1379+
make_new_set(PyTypeObject *type, PyObject *iterable)
1380+
{
1381+
PyObject *so = make_new_set_untracked(type, iterable);
1382+
if (so != NULL) {
1383+
_PyObject_GC_TRACK(so);
1384+
}
1385+
return so;
1386+
}
1387+
1388+
static PyObject *
1389+
make_new_set_basetype_untracked(PyTypeObject *type, PyObject *iterable)
13821390
{
13831391
if (type != &PySet_Type && type != &PyFrozenSet_Type) {
13841392
if (PyType_IsSubtype(type, &PySet_Type))
13851393
type = &PySet_Type;
13861394
else
13871395
type = &PyFrozenSet_Type;
13881396
}
1389-
return make_new_set(type, iterable);
1397+
return make_new_set_untracked(type, iterable);
1398+
}
1399+
1400+
static PyObject *
1401+
make_new_set_basetype(PyTypeObject *type, PyObject *iterable)
1402+
{
1403+
PyObject *so = make_new_set_basetype_untracked(type, iterable);
1404+
if (so != NULL) {
1405+
_PyObject_GC_TRACK(so);
1406+
}
1407+
return so;
13901408
}
13911409

13921410
// gh-140232: check whether a frozenset can be untracked from the GC
@@ -1686,7 +1704,7 @@ set_intersection(PySetObject *so, PyObject *other)
16861704
if ((PyObject *)so == other)
16871705
return set_copy_impl(so);
16881706

1689-
result = (PySetObject *)make_new_set_basetype(Py_TYPE(so), NULL);
1707+
result = (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), NULL);
16901708
if (result == NULL)
16911709
return NULL;
16921710

@@ -1719,6 +1737,7 @@ set_intersection(PySetObject *so, PyObject *other)
17191737
}
17201738
Py_DECREF(key);
17211739
}
1740+
_PyObject_GC_TRACK(result);
17221741
return (PyObject *)result;
17231742
}
17241743

@@ -1750,6 +1769,7 @@ set_intersection(PySetObject *so, PyObject *other)
17501769
Py_DECREF(result);
17511770
return NULL;
17521771
}
1772+
_PyObject_GC_TRACK(result);
17531773
return (PyObject *)result;
17541774
error:
17551775
Py_DECREF(it);
@@ -2064,7 +2084,7 @@ set_difference(PySetObject *so, PyObject *other)
20642084
return set_copy_and_difference(so, other);
20652085
}
20662086

2067-
result = make_new_set_basetype(Py_TYPE(so), NULL);
2087+
result = make_new_set_basetype_untracked(Py_TYPE(so), NULL);
20682088
if (result == NULL)
20692089
return NULL;
20702090

@@ -2088,6 +2108,7 @@ set_difference(PySetObject *so, PyObject *other)
20882108
}
20892109
Py_DECREF(key);
20902110
}
2111+
_PyObject_GC_TRACK(result);
20912112
return result;
20922113
}
20932114

@@ -2111,6 +2132,7 @@ set_difference(PySetObject *so, PyObject *other)
21112132
}
21122133
Py_DECREF(key);
21132134
}
2135+
_PyObject_GC_TRACK(result);
21142136
return result;
21152137
}
21162138

@@ -2312,7 +2334,8 @@ static PyObject *
23122334
set_symmetric_difference_impl(PySetObject *so, PyObject *other)
23132335
/*[clinic end generated code: output=270ee0b5d42b0797 input=8c29b0be90d47feb]*/
23142336
{
2315-
PySetObject *result = (PySetObject *)make_new_set_basetype(Py_TYPE(so), NULL);
2337+
PySetObject *result =
2338+
(PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), NULL);
23162339
if (result == NULL) {
23172340
return NULL;
23182341
}
@@ -2324,6 +2347,7 @@ set_symmetric_difference_impl(PySetObject *so, PyObject *other)
23242347
Py_DECREF(result);
23252348
return NULL;
23262349
}
2350+
_PyObject_GC_TRACK(result);
23272351
return (PyObject *)result;
23282352
}
23292353

0 commit comments

Comments
 (0)