gh-87729: specialize LOAD_SUPER_ATTR_METHOD (#103809)

This commit is contained in:
Carl Meyer 2023-04-25 11:45:51 -06:00 committed by GitHub
parent cef542ca57
commit ef25febcf2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 539 additions and 357 deletions

View file

@ -9380,22 +9380,19 @@ super_repr(PyObject *self)
su->type ? su->type->tp_name : "NULL");
}
// if `method` is non-NULL, we are looking for a method descriptor,
// and setting `*method` to 1 means we found one.
/* Do a super lookup without executing descriptors or falling back to getattr
on the super object itself.
May return NULL with or without an exception set, like PyDict_GetItemWithError. */
static PyObject *
do_super_lookup(superobject *su, PyTypeObject *su_type, PyObject *su_obj,
PyTypeObject *su_obj_type, PyObject *name, int *method)
_super_lookup_descr(PyTypeObject *su_type, PyTypeObject *su_obj_type, PyObject *name)
{
PyObject *mro, *res;
Py_ssize_t i, n;
int temp_su = 0;
if (su_obj_type == NULL)
goto skip;
mro = su_obj_type->tp_mro;
if (mro == NULL)
goto skip;
return NULL;
assert(PyTuple_Check(mro));
n = PyTuple_GET_SIZE(mro);
@ -9407,7 +9404,7 @@ do_super_lookup(superobject *su, PyTypeObject *su_type, PyObject *su_obj,
}
i++; /* skip su->type (if any) */
if (i >= n)
goto skip;
return NULL;
/* keep a strong reference to mro because su_obj_type->tp_mro can be
replaced during PyDict_GetItemWithError(dict, name) */
@ -9420,22 +9417,6 @@ do_super_lookup(superobject *su, PyTypeObject *su_type, PyObject *su_obj,
res = PyDict_GetItemWithError(dict, name);
if (res != NULL) {
Py_INCREF(res);
if (method && _PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)) {
*method = 1;
}
else {
descrgetfunc f = Py_TYPE(res)->tp_descr_get;
if (f != NULL) {
PyObject *res2;
res2 = f(res,
/* Only pass 'obj' param if this is instance-mode super
(See SF ID #743627) */
(su_obj == (PyObject *)su_obj_type) ? NULL : su_obj,
(PyObject *)su_obj_type);
Py_SETREF(res, res2);
}
}
Py_DECREF(mro);
return res;
}
@ -9447,6 +9428,45 @@ do_super_lookup(superobject *su, PyTypeObject *su_type, PyObject *su_obj,
i++;
} while (i < n);
Py_DECREF(mro);
return NULL;
}
// if `method` is non-NULL, we are looking for a method descriptor,
// and setting `*method = 1` means we found one.
static PyObject *
do_super_lookup(superobject *su, PyTypeObject *su_type, PyObject *su_obj,
PyTypeObject *su_obj_type, PyObject *name, int *method)
{
PyObject *res;
int temp_su = 0;
if (su_obj_type == NULL) {
goto skip;
}
res = _super_lookup_descr(su_type, su_obj_type, name);
if (res != NULL) {
if (method && _PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)) {
*method = 1;
}
else {
descrgetfunc f = Py_TYPE(res)->tp_descr_get;
if (f != NULL) {
PyObject *res2;
res2 = f(res,
/* Only pass 'obj' param if this is instance-mode super
(See SF ID #743627) */
(su_obj == (PyObject *)su_obj_type) ? NULL : su_obj,
(PyObject *)su_obj_type);
Py_SETREF(res, res2);
}
}
return res;
}
else if (PyErr_Occurred()) {
return NULL;
}
skip:
if (su == NULL) {
@ -9544,6 +9564,18 @@ _PySuper_Lookup(PyTypeObject *su_type, PyObject *su_obj, PyObject *name, int *me
return res;
}
PyObject *
_PySuper_LookupDescr(PyTypeObject *su_type, PyObject *su_obj, PyObject *name)
{
PyTypeObject *su_obj_type = supercheck(su_type, su_obj);
if (su_obj_type == NULL) {
return NULL;
}
PyObject *res = _super_lookup_descr(su_type, su_obj_type, name);
Py_DECREF(su_obj_type);
return res;
}
static PyObject *
super_descr_get(PyObject *self, PyObject *obj, PyObject *type)
{