Skip to content

Commit 5f7f9a4

Browse files
committed
pythongh-152235: Defer GC tracking in more set operations
1 parent 05679f3 commit 5f7f9a4

2 files changed

Lines changed: 38 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: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,14 +1345,16 @@ set_update_impl(PySetObject *so, PyObject * const *others,
13451345
can be retrieved or updated in a single cache line.
13461346
*/
13471347

1348+
// Allocate a set/frozenset and fill it from `iterable` (if any), leaving it
1349+
// GC-untracked: filling runs user code, so a half-built set must not be
1350+
// reachable from another thread via gc.get_objects(). The caller must
1351+
// _PyObject_GC_TRACK() it once it is fully built.
13481352
static PyObject *
1349-
make_new_set(PyTypeObject *type, PyObject *iterable)
1353+
make_new_set_untracked(PyTypeObject *type, PyObject *iterable)
13501354
{
13511355
assert(PyType_Check(type));
13521356
PySetObject *so;
13531357

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().
13561358
so = (PySetObject *)_PyType_AllocNoTrack(type, 0);
13571359
if (so == NULL)
13581360
return NULL;
@@ -1372,21 +1374,39 @@ make_new_set(PyTypeObject *type, PyObject *iterable)
13721374
}
13731375
}
13741376

1375-
// Track only once fully built.
1376-
_PyObject_GC_TRACK(so);
13771377
return (PyObject *)so;
13781378
}
13791379

13801380
static PyObject *
1381-
make_new_set_basetype(PyTypeObject *type, PyObject *iterable)
1381+
make_new_set(PyTypeObject *type, PyObject *iterable)
1382+
{
1383+
PyObject *so = make_new_set_untracked(type, iterable);
1384+
if (so != NULL) {
1385+
_PyObject_GC_TRACK(so);
1386+
}
1387+
return so;
1388+
}
1389+
1390+
static PyObject *
1391+
make_new_set_basetype_untracked(PyTypeObject *type, PyObject *iterable)
13821392
{
13831393
if (type != &PySet_Type && type != &PyFrozenSet_Type) {
13841394
if (PyType_IsSubtype(type, &PySet_Type))
13851395
type = &PySet_Type;
13861396
else
13871397
type = &PyFrozenSet_Type;
13881398
}
1389-
return make_new_set(type, iterable);
1399+
return make_new_set_untracked(type, iterable);
1400+
}
1401+
1402+
static PyObject *
1403+
make_new_set_basetype(PyTypeObject *type, PyObject *iterable)
1404+
{
1405+
PyObject *so = make_new_set_basetype_untracked(type, iterable);
1406+
if (so != NULL) {
1407+
_PyObject_GC_TRACK(so);
1408+
}
1409+
return so;
13901410
}
13911411

13921412
// gh-140232: check whether a frozenset can be untracked from the GC
@@ -1696,7 +1716,7 @@ set_intersection(PySetObject *so, PyObject *other)
16961716
if ((PyObject *)so == other)
16971717
return set_copy_impl(so);
16981718

1699-
result = (PySetObject *)make_new_set_basetype(Py_TYPE(so), NULL);
1719+
result = (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), NULL);
17001720
if (result == NULL)
17011721
return NULL;
17021722

@@ -1729,6 +1749,7 @@ set_intersection(PySetObject *so, PyObject *other)
17291749
}
17301750
Py_DECREF(key);
17311751
}
1752+
_PyObject_GC_TRACK(result);
17321753
return (PyObject *)result;
17331754
}
17341755

@@ -1760,6 +1781,7 @@ set_intersection(PySetObject *so, PyObject *other)
17601781
Py_DECREF(result);
17611782
return NULL;
17621783
}
1784+
_PyObject_GC_TRACK(result);
17631785
return (PyObject *)result;
17641786
error:
17651787
Py_DECREF(it);
@@ -2074,7 +2096,7 @@ set_difference(PySetObject *so, PyObject *other)
20742096
return set_copy_and_difference(so, other);
20752097
}
20762098

2077-
result = make_new_set_basetype(Py_TYPE(so), NULL);
2099+
result = make_new_set_basetype_untracked(Py_TYPE(so), NULL);
20782100
if (result == NULL)
20792101
return NULL;
20802102

@@ -2098,6 +2120,7 @@ set_difference(PySetObject *so, PyObject *other)
20982120
}
20992121
Py_DECREF(key);
21002122
}
2123+
_PyObject_GC_TRACK(result);
21012124
return result;
21022125
}
21032126

@@ -2121,6 +2144,7 @@ set_difference(PySetObject *so, PyObject *other)
21212144
}
21222145
Py_DECREF(key);
21232146
}
2147+
_PyObject_GC_TRACK(result);
21242148
return result;
21252149
}
21262150

@@ -2322,7 +2346,8 @@ static PyObject *
23222346
set_symmetric_difference_impl(PySetObject *so, PyObject *other)
23232347
/*[clinic end generated code: output=270ee0b5d42b0797 input=8c29b0be90d47feb]*/
23242348
{
2325-
PySetObject *result = (PySetObject *)make_new_set_basetype(Py_TYPE(so), NULL);
2349+
PySetObject *result =
2350+
(PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so), NULL);
23262351
if (result == NULL) {
23272352
return NULL;
23282353
}
@@ -2334,6 +2359,7 @@ set_symmetric_difference_impl(PySetObject *so, PyObject *other)
23342359
Py_DECREF(result);
23352360
return NULL;
23362361
}
2362+
_PyObject_GC_TRACK(result);
23372363
return (PyObject *)result;
23382364
}
23392365

0 commit comments

Comments
 (0)