https://github.com/python/cpython/commit/6d28aaf24d8e6406944cf96995e7b34b4b625eea
commit: 6d28aaf24d8e6406944cf96995e7b34b4b625eea
branch: 3.14
author: Sam Gross <[email protected]>
committer: colesbury <[email protected]>
date: 2026-03-11T11:50:13Z
summary:

[3.14] gh-145685: Avoid contention on TYPE_LOCK in super() lookups (gh-145775) 
(#145804)

(cherry picked from commit bdf6de8c3f0c2ec0d737f38014a32c1eed02c7f1)

files:
M Include/internal/pycore_stackref.h
M Objects/typeobject.c
M Tools/ftscalingbench/ftscalingbench.py

diff --git a/Include/internal/pycore_stackref.h 
b/Include/internal/pycore_stackref.h
index 52acd918c9b9f9..76f6333739dfd6 100644
--- a/Include/internal/pycore_stackref.h
+++ b/Include/internal/pycore_stackref.h
@@ -735,6 +735,13 @@ _PyThreadState_PushCStackRef(PyThreadState *tstate, 
_PyCStackRef *ref)
     ref->ref = PyStackRef_NULL;
 }
 
+static inline void
+_PyThreadState_PushCStackRefNew(PyThreadState *tstate, _PyCStackRef *ref, 
PyObject *obj)
+{
+    _PyThreadState_PushCStackRef(tstate, ref);
+    ref->ref = PyStackRef_FromPyObjectNew(obj);
+}
+
 static inline void
 _PyThreadState_PopCStackRef(PyThreadState *tstate, _PyCStackRef *ref)
 {
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 232ead49a7f098..9777055c5f2313 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -11820,18 +11820,16 @@ _super_lookup_descr(PyTypeObject *su_type, 
PyTypeObject *su_obj_type, PyObject *
     PyObject *mro, *res;
     Py_ssize_t i, n;
 
-    BEGIN_TYPE_LOCK();
     mro = lookup_tp_mro(su_obj_type);
-    /* keep a strong reference to mro because su_obj_type->tp_mro can be
-       replaced during PyDict_GetItemRef(dict, name, &res) and because
-       another thread can modify it after we end the critical section
-       below  */
-    Py_XINCREF(mro);
-    END_TYPE_LOCK();
-
     if (mro == NULL)
         return NULL;
 
+    /* Keep a strong reference to mro because su_obj_type->tp_mro can be
+       replaced during PyDict_GetItemRef(dict, name, &res). */
+    PyThreadState *tstate = _PyThreadState_GET();
+    _PyCStackRef mro_ref;
+    _PyThreadState_PushCStackRefNew(tstate, &mro_ref, mro);
+
     assert(PyTuple_Check(mro));
     n = PyTuple_GET_SIZE(mro);
 
@@ -11842,7 +11840,7 @@ _super_lookup_descr(PyTypeObject *su_type, PyTypeObject 
*su_obj_type, PyObject *
     }
     i++;  /* skip su->type (if any)  */
     if (i >= n) {
-        Py_DECREF(mro);
+        _PyThreadState_PopCStackRef(tstate, &mro_ref);
         return NULL;
     }
 
@@ -11853,13 +11851,13 @@ _super_lookup_descr(PyTypeObject *su_type, 
PyTypeObject *su_obj_type, PyObject *
 
         if (PyDict_GetItemRef(dict, name, &res) != 0) {
             // found or error
-            Py_DECREF(mro);
+            _PyThreadState_PopCStackRef(tstate, &mro_ref);
             return res;
         }
 
         i++;
     } while (i < n);
-    Py_DECREF(mro);
+    _PyThreadState_PopCStackRef(tstate, &mro_ref);
     return NULL;
 }
 
diff --git a/Tools/ftscalingbench/ftscalingbench.py 
b/Tools/ftscalingbench/ftscalingbench.py
index b815376b7ed56f..cc7d8575f5cfc9 100644
--- a/Tools/ftscalingbench/ftscalingbench.py
+++ b/Tools/ftscalingbench/ftscalingbench.py
@@ -201,6 +201,23 @@ def instantiate_dataclass():
     for _ in range(1000 * WORK_SCALE):
         obj = MyDataClass(x=1, y=2, z=3)
 
+@register_benchmark
+def super_call():
+    # TODO: super() on the same class from multiple threads still doesn't
+    # scale well, so use a class per-thread here for now.
+    class Base:
+        def method(self):
+            return 1
+
+    class Derived(Base):
+        def method(self):
+            return super().method()
+
+    obj = Derived()
+    for _ in range(1000 * WORK_SCALE):
+        obj.method()
+
+
 def bench_one_thread(func):
     t0 = time.perf_counter_ns()
     func()

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to