From: Alper Date: Tue, 11 Nov 2025 20:27:21 +0000 (-0800) Subject: gh-140476: optimize `PySet_Add` for `frozenset` in free-threading (#140440) X-Git-Tag: v3.15.0a2~103 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=298e9074cdffb09d518e6aceea556e8f4a8a745d;p=thirdparty%2FPython%2Fcpython.git gh-140476: optimize `PySet_Add` for `frozenset` in free-threading (#140440) Avoids critical section in `PySet_Add` when adding items to newly created frozensets. Co-authored-by: Kumar Aditya --- diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-10-22-12-48-05.gh-issue-140476.F3-d1P.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-10-22-12-48-05.gh-issue-140476.F3-d1P.rst new file mode 100644 index 000000000000..a24033208c55 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-10-22-12-48-05.gh-issue-140476.F3-d1P.rst @@ -0,0 +1,2 @@ +Optimize :c:func:`PySet_Add` for :class:`frozenset` in :term:`free threaded +` build. diff --git a/Objects/setobject.c b/Objects/setobject.c index 2401176576eb..85f4d7d40317 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -2775,17 +2775,24 @@ PySet_Discard(PyObject *set, PyObject *key) int PySet_Add(PyObject *anyset, PyObject *key) { - if (!PySet_Check(anyset) && - (!PyFrozenSet_Check(anyset) || !_PyObject_IsUniquelyReferenced(anyset))) { - PyErr_BadInternalCall(); - return -1; + if (PySet_Check(anyset)) { + int rv; + Py_BEGIN_CRITICAL_SECTION(anyset); + rv = set_add_key((PySetObject *)anyset, key); + Py_END_CRITICAL_SECTION(); + return rv; } - int rv; - Py_BEGIN_CRITICAL_SECTION(anyset); - rv = set_add_key((PySetObject *)anyset, key); - Py_END_CRITICAL_SECTION(); - return rv; + if (PyFrozenSet_Check(anyset) && _PyObject_IsUniquelyReferenced(anyset)) { + // We can only change frozensets if they are uniquely referenced. The + // API limits the usage of `PySet_Add` to "fill in the values of brand + // new frozensets before they are exposed to other code". In this case, + // this can be done without a lock. + return set_add_key((PySetObject *)anyset, key); + } + + PyErr_BadInternalCall(); + return -1; } int