mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
gh-134043: use stackrefs in vectorcalling methods (#134044)
Adds `_PyObject_GetMethodStackRef` which uses stackrefs and takes advantage of deferred reference counting in free-threading while calling method objects in vectorcall.
This commit is contained in:
parent
3f9eb55e09
commit
a380d57873
4 changed files with 148 additions and 13 deletions
110
Objects/object.c
110
Objects/object.c
|
@ -1664,6 +1664,116 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_PyObject_GetMethodStackRef(PyThreadState *ts, PyObject *obj,
|
||||
PyObject *name, _PyStackRef *method)
|
||||
{
|
||||
int meth_found = 0;
|
||||
|
||||
assert(PyStackRef_IsNull(*method));
|
||||
|
||||
PyTypeObject *tp = Py_TYPE(obj);
|
||||
if (!_PyType_IsReady(tp)) {
|
||||
if (PyType_Ready(tp) < 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (tp->tp_getattro != PyObject_GenericGetAttr || !PyUnicode_CheckExact(name)) {
|
||||
PyObject *res = PyObject_GetAttr(obj, name);
|
||||
if (res != NULL) {
|
||||
*method = PyStackRef_FromPyObjectSteal(res);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
_PyType_LookupStackRefAndVersion(tp, name, method);
|
||||
PyObject *descr = PyStackRef_AsPyObjectBorrow(*method);
|
||||
descrgetfunc f = NULL;
|
||||
if (descr != NULL) {
|
||||
if (_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR)) {
|
||||
meth_found = 1;
|
||||
}
|
||||
else {
|
||||
f = Py_TYPE(descr)->tp_descr_get;
|
||||
if (f != NULL && PyDescr_IsData(descr)) {
|
||||
PyObject *value = f(descr, obj, (PyObject *)Py_TYPE(obj));
|
||||
PyStackRef_CLEAR(*method);
|
||||
if (value != NULL) {
|
||||
*method = PyStackRef_FromPyObjectSteal(value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
PyObject *dict, *attr;
|
||||
if ((tp->tp_flags & Py_TPFLAGS_INLINE_VALUES) &&
|
||||
_PyObject_TryGetInstanceAttribute(obj, name, &attr)) {
|
||||
if (attr != NULL) {
|
||||
PyStackRef_CLEAR(*method);
|
||||
*method = PyStackRef_FromPyObjectSteal(attr);
|
||||
return 0;
|
||||
}
|
||||
dict = NULL;
|
||||
}
|
||||
else if ((tp->tp_flags & Py_TPFLAGS_MANAGED_DICT)) {
|
||||
dict = (PyObject *)_PyObject_GetManagedDict(obj);
|
||||
}
|
||||
else {
|
||||
PyObject **dictptr = _PyObject_ComputedDictPointer(obj);
|
||||
if (dictptr != NULL) {
|
||||
dict = FT_ATOMIC_LOAD_PTR_ACQUIRE(*dictptr);
|
||||
}
|
||||
else {
|
||||
dict = NULL;
|
||||
}
|
||||
}
|
||||
if (dict != NULL) {
|
||||
// TODO: use _Py_dict_lookup_threadsafe_stackref
|
||||
Py_INCREF(dict);
|
||||
PyObject *value;
|
||||
if (PyDict_GetItemRef(dict, name, &value) != 0) {
|
||||
// found or error
|
||||
Py_DECREF(dict);
|
||||
PyStackRef_CLEAR(*method);
|
||||
if (value != NULL) {
|
||||
*method = PyStackRef_FromPyObjectSteal(value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// not found
|
||||
Py_DECREF(dict);
|
||||
}
|
||||
|
||||
if (meth_found) {
|
||||
assert(!PyStackRef_IsNull(*method));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (f != NULL) {
|
||||
PyObject *value = f(descr, obj, (PyObject *)Py_TYPE(obj));
|
||||
PyStackRef_CLEAR(*method);
|
||||
if (value) {
|
||||
*method = PyStackRef_FromPyObjectSteal(value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (descr != NULL) {
|
||||
assert(!PyStackRef_IsNull(*method));
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyErr_Format(PyExc_AttributeError,
|
||||
"'%.100s' object has no attribute '%U'",
|
||||
tp->tp_name, name);
|
||||
|
||||
_PyObject_SetAttributeErrorContext(obj, name);
|
||||
assert(PyStackRef_IsNull(*method));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Generic GetAttr functions - put these in your tp_[gs]etattro slot. */
|
||||
|
||||
PyObject *
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue