summaryrefslogtreecommitdiffstats
path: root/Objects/object.c
diff options
context:
space:
mode:
authorSam Gross <colesbury@gmail.com>2025-03-26 18:38:47 (GMT)
committerGitHub <noreply@github.com>2025-03-26 18:38:47 (GMT)
commit67fbfb42bd5dfe861d0c58d9e6c48d8eef033d24 (patch)
tree282178fa55571c055c8327dc3d77fa6a882a404b /Objects/object.c
parent3d4ac1a2c2b610f35a9e164878d67185e4a3546f (diff)
downloadcpython-67fbfb42bd5dfe861d0c58d9e6c48d8eef033d24.zip
cpython-67fbfb42bd5dfe861d0c58d9e6c48d8eef033d24.tar.gz
cpython-67fbfb42bd5dfe861d0c58d9e6c48d8eef033d24.tar.bz2
gh-131586: Avoid refcount contention in some "special" calls (#131588)
In the free threaded build, the `_PyObject_LookupSpecial()` call can lead to reference count contention on the returned function object becuase it doesn't use stackrefs. Refactor some of the callers to use `_PyObject_MaybeCallSpecialNoArgs`, which uses stackrefs internally. This fixes the scaling bottleneck in the "lookup_special" microbenchmark in `ftscalingbench.py`. However, the are still some uses of `_PyObject_LookupSpecial()` that need to be addressed in future PRs.
Diffstat (limited to 'Objects/object.c')
-rw-r--r--Objects/object.c28
1 files changed, 20 insertions, 8 deletions
diff --git a/Objects/object.c b/Objects/object.c
index ecc5a86..974cf60 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -1680,14 +1680,20 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
Py_TYPE(name)->tp_name);
return NULL;
}
- Py_INCREF(name);
if (!_PyType_IsReady(tp)) {
if (PyType_Ready(tp) < 0)
- goto done;
+ return NULL;
}
- descr = _PyType_LookupRef(tp, name);
+ Py_INCREF(name);
+
+ PyThreadState *tstate = _PyThreadState_GET();
+ _PyCStackRef cref;
+ _PyThreadState_PushCStackRef(tstate, &cref);
+
+ _PyType_LookupStackRefAndVersion(tp, name, &cref.ref);
+ descr = PyStackRef_AsPyObjectBorrow(cref.ref);
f = NULL;
if (descr != NULL) {
@@ -1758,8 +1764,8 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
}
if (descr != NULL) {
- res = descr;
- descr = NULL;
+ res = PyStackRef_AsPyObjectSteal(cref.ref);
+ cref.ref = PyStackRef_NULL;
goto done;
}
@@ -1771,7 +1777,7 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
_PyObject_SetAttributeErrorContext(obj, name);
}
done:
- Py_XDECREF(descr);
+ _PyThreadState_PopCStackRef(tstate, &cref);
Py_DECREF(name);
return res;
}
@@ -1805,7 +1811,13 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
Py_INCREF(name);
Py_INCREF(tp);
- descr = _PyType_LookupRef(tp, name);
+
+ PyThreadState *tstate = _PyThreadState_GET();
+ _PyCStackRef cref;
+ _PyThreadState_PushCStackRef(tstate, &cref);
+
+ _PyType_LookupStackRefAndVersion(tp, name, &cref.ref);
+ descr = PyStackRef_AsPyObjectBorrow(cref.ref);
if (descr != NULL) {
f = Py_TYPE(descr)->tp_descr_set;
@@ -1872,7 +1884,7 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
_PyObject_SetAttributeErrorContext(obj, name);
}
done:
- Py_XDECREF(descr);
+ _PyThreadState_PopCStackRef(tstate, &cref);
Py_DECREF(tp);
Py_DECREF(name);
return res;