gh-152235: Defer GC tracking in set.union and set.difference (gh-152290)

This commit is contained in:
Donghee Na 2026-06-27 02:11:33 +09:00 committed by GitHub
parent a85e73b322
commit 5a549e82b8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 35 additions and 20 deletions

View file

@ -1,2 +1,3 @@
Defer GC tracking of :meth:`set.intersection`, :meth:`set.difference` and
:meth:`set.symmetric_difference`. Patch by Donghee Na.
Defer GC tracking of :meth:`set.intersection`, :meth:`set.difference`,
:meth:`set.symmetric_difference`, :meth:`set.union` and ``set.__sub__``.
Patch by Donghee Na.

View file

@ -1577,6 +1577,21 @@ _PySet_Freeze(PyObject *set)
return Py_NewRef(set);
}
static PyObject *
set_copy_untracked_lock_held(PySetObject *so)
{
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
PyObject *copy = make_new_set_basetype_untracked(Py_TYPE(so), NULL);
if (copy == NULL) {
return NULL;
}
if (set_merge_lock_held((PySetObject *)copy, (PyObject *)so) < 0) {
Py_DECREF(copy);
return NULL;
}
return copy;
}
/*[clinic input]
@critical_section
set.copy
@ -1589,14 +1604,9 @@ static PyObject *
set_copy_impl(PySetObject *so)
/*[clinic end generated code: output=c9223a1e1cc6b041 input=c169a4fbb8209257]*/
{
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(so);
PyObject *copy = make_new_set_basetype(Py_TYPE(so), NULL);
if (copy == NULL) {
return NULL;
}
if (set_merge_lock_held((PySetObject *)copy, (PyObject *)so) < 0) {
Py_DECREF(copy);
return NULL;
PyObject *copy = set_copy_untracked_lock_held(so);
if (copy != NULL) {
_PyObject_GC_TRACK(copy);
}
return copy;
}
@ -1652,7 +1662,8 @@ set_union_impl(PySetObject *so, PyObject * const *others,
PyObject *other;
Py_ssize_t i;
result = (PySetObject *)set_copy((PyObject *)so, NULL);
result = (PySetObject *)make_new_set_basetype_untracked(Py_TYPE(so),
(PyObject *)so);
if (result == NULL)
return NULL;
@ -1665,6 +1676,7 @@ set_union_impl(PySetObject *so, PyObject * const *others,
return NULL;
}
}
_PyObject_GC_TRACK(result);
return (PyObject *)result;
}
@ -2055,11 +2067,11 @@ set_difference_update_impl(PySetObject *so, PyObject * const *others,
}
static PyObject *
set_copy_and_difference(PySetObject *so, PyObject *other)
set_copy_and_difference_untracked(PySetObject *so, PyObject *other)
{
PyObject *result;
result = set_copy_impl(so);
result = set_copy_untracked_lock_held(so);
if (result == NULL)
return NULL;
if (set_difference_update_internal((PySetObject *) result, other) == 0)
@ -2069,7 +2081,7 @@ set_copy_and_difference(PySetObject *so, PyObject *other)
}
static PyObject *
set_difference(PySetObject *so, PyObject *other)
set_difference_untracked(PySetObject *so, PyObject *other)
{
PyObject *result;
PyObject *key;
@ -2085,13 +2097,13 @@ set_difference(PySetObject *so, PyObject *other)
other_size = PyDict_GET_SIZE(other);
}
else {
return set_copy_and_difference(so, other);
return set_copy_and_difference_untracked(so, other);
}
/* If len(so) much more than len(other), it's more efficient to simply copy
* so and then iterate other looking for common elements. */
if ((PySet_GET_SIZE(so) >> 2) > other_size) {
return set_copy_and_difference(so, other);
return set_copy_and_difference_untracked(so, other);
}
result = make_new_set_basetype_untracked(Py_TYPE(so), NULL);
@ -2118,7 +2130,6 @@ set_difference(PySetObject *so, PyObject *other)
}
Py_DECREF(key);
}
_PyObject_GC_TRACK(result);
return result;
}
@ -2142,7 +2153,6 @@ set_difference(PySetObject *so, PyObject *other)
}
Py_DECREF(key);
}
_PyObject_GC_TRACK(result);
return result;
}
@ -2169,7 +2179,7 @@ set_difference_multi_impl(PySetObject *so, PyObject * const *others,
other = others[0];
Py_BEGIN_CRITICAL_SECTION2(so, other);
result = set_difference(so, other);
result = set_difference_untracked(so, other);
Py_END_CRITICAL_SECTION2();
if (result == NULL)
return NULL;
@ -2185,6 +2195,7 @@ set_difference_multi_impl(PySetObject *so, PyObject * const *others,
return NULL;
}
}
_PyObject_GC_TRACK(result);
return result;
}
@ -2197,8 +2208,11 @@ set_sub(PyObject *self, PyObject *other)
PyObject *rv;
Py_BEGIN_CRITICAL_SECTION2(so, other);
rv = set_difference(so, other);
rv = set_difference_untracked(so, other);
Py_END_CRITICAL_SECTION2();
if (rv != NULL) {
_PyObject_GC_TRACK(rv);
}
return rv;
}