mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
gh-87729: add LOAD_SUPER_ATTR instruction for faster super() (#103497)
This speeds up `super()` (by around 85%, for a simple one-level `super().meth()` microbenchmark) by avoiding allocation of a new single-use `super()` object on each use.
This commit is contained in:
parent
22bed58e53
commit
0dc8b50d33
18 changed files with 783 additions and 408 deletions
|
@ -9346,26 +9346,20 @@ 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.
|
||||
static PyObject *
|
||||
super_getattro(PyObject *self, PyObject *name)
|
||||
do_super_lookup(superobject *su, PyTypeObject *su_type, PyObject *su_obj,
|
||||
PyTypeObject *su_obj_type, PyObject *name, int *method)
|
||||
{
|
||||
superobject *su = (superobject *)self;
|
||||
PyTypeObject *starttype;
|
||||
PyObject *mro;
|
||||
PyObject *mro, *res;
|
||||
Py_ssize_t i, n;
|
||||
int temp_su = 0;
|
||||
|
||||
starttype = su->obj_type;
|
||||
if (starttype == NULL)
|
||||
if (su_obj_type == NULL)
|
||||
goto skip;
|
||||
|
||||
/* We want __class__ to return the class of the super object
|
||||
(i.e. super, or a subclass), not the class of su->obj. */
|
||||
if (PyUnicode_Check(name) &&
|
||||
PyUnicode_GET_LENGTH(name) == 9 &&
|
||||
_PyUnicode_Equal(name, &_Py_ID(__class__)))
|
||||
goto skip;
|
||||
|
||||
mro = starttype->tp_mro;
|
||||
mro = su_obj_type->tp_mro;
|
||||
if (mro == NULL)
|
||||
goto skip;
|
||||
|
||||
|
@ -9374,14 +9368,14 @@ super_getattro(PyObject *self, PyObject *name)
|
|||
|
||||
/* No need to check the last one: it's gonna be skipped anyway. */
|
||||
for (i = 0; i+1 < n; i++) {
|
||||
if ((PyObject *)(su->type) == PyTuple_GET_ITEM(mro, i))
|
||||
if ((PyObject *)(su_type) == PyTuple_GET_ITEM(mro, i))
|
||||
break;
|
||||
}
|
||||
i++; /* skip su->type (if any) */
|
||||
if (i >= n)
|
||||
goto skip;
|
||||
|
||||
/* keep a strong reference to mro because starttype->tp_mro can be
|
||||
/* keep a strong reference to mro because su_obj_type->tp_mro can be
|
||||
replaced during PyDict_GetItemWithError(dict, name) */
|
||||
Py_INCREF(mro);
|
||||
do {
|
||||
|
@ -9389,19 +9383,23 @@ super_getattro(PyObject *self, PyObject *name)
|
|||
PyObject *dict = _PyType_CAST(obj)->tp_dict;
|
||||
assert(dict != NULL && PyDict_Check(dict));
|
||||
|
||||
PyObject *res = PyDict_GetItemWithError(dict, name);
|
||||
res = PyDict_GetItemWithError(dict, name);
|
||||
if (res != NULL) {
|
||||
Py_INCREF(res);
|
||||
|
||||
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 *)starttype) ? NULL : su->obj,
|
||||
(PyObject *)starttype);
|
||||
Py_SETREF(res, res2);
|
||||
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);
|
||||
|
@ -9417,7 +9415,34 @@ super_getattro(PyObject *self, PyObject *name)
|
|||
Py_DECREF(mro);
|
||||
|
||||
skip:
|
||||
return PyObject_GenericGetAttr(self, name);
|
||||
if (su == NULL) {
|
||||
PyObject *args[] = {(PyObject *)su_type, su_obj};
|
||||
su = (superobject *)PyObject_Vectorcall((PyObject *)&PySuper_Type, args, 2, NULL);
|
||||
if (su == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
temp_su = 1;
|
||||
}
|
||||
res = PyObject_GenericGetAttr((PyObject *)su, name);
|
||||
if (temp_su) {
|
||||
Py_DECREF(su);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
super_getattro(PyObject *self, PyObject *name)
|
||||
{
|
||||
superobject *su = (superobject *)self;
|
||||
|
||||
/* We want __class__ to return the class of the super object
|
||||
(i.e. super, or a subclass), not the class of su->obj. */
|
||||
if (PyUnicode_Check(name) &&
|
||||
PyUnicode_GET_LENGTH(name) == 9 &&
|
||||
_PyUnicode_Equal(name, &_Py_ID(__class__)))
|
||||
return PyObject_GenericGetAttr(self, name);
|
||||
|
||||
return do_super_lookup(su, su->type, su->obj, su->obj_type, name, NULL);
|
||||
}
|
||||
|
||||
static PyTypeObject *
|
||||
|
@ -9473,6 +9498,18 @@ supercheck(PyTypeObject *type, PyObject *obj)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PySuper_Lookup(PyTypeObject *su_type, PyObject *su_obj, PyObject *name, int *method)
|
||||
{
|
||||
PyTypeObject *su_obj_type = supercheck(su_type, su_obj);
|
||||
if (su_obj_type == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *res = do_super_lookup(NULL, su_type, su_obj, su_obj_type, name, method);
|
||||
Py_DECREF(su_obj_type);
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
super_descr_get(PyObject *self, PyObject *obj, PyObject *type)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue