diff options
author | Sam Gross <colesbury@gmail.com> | 2025-03-26 18:38:47 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-03-26 18:38:47 (GMT) |
commit | 67fbfb42bd5dfe861d0c58d9e6c48d8eef033d24 (patch) | |
tree | 282178fa55571c055c8327dc3d77fa6a882a404b /Objects/object.c | |
parent | 3d4ac1a2c2b610f35a9e164878d67185e4a3546f (diff) | |
download | cpython-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.c | 28 |
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; |