From: Victor Stinner Date: Wed, 21 Apr 2021 22:10:16 +0000 (+0200) Subject: bpo-40137: Optimize _PyType_GetModuleByDef() loop (GH-25505) X-Git-Tag: v3.10.0b1~221 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=760da626ff4124e1344fd8b7dbeb83b2c4b7c12c;p=thirdparty%2FPython%2Fcpython.git bpo-40137: Optimize _PyType_GetModuleByDef() loop (GH-25505) PyType_Ready() now ensures that a type MRO cannot be empty. _PyType_GetModuleByDef() no longer checks "i < PyTuple_GET_SIZE(mro)" at the first loop iteration to optimize the most common case, when the argument is the defining class. --- diff --git a/Objects/typeobject.c b/Objects/typeobject.c index ef3833155e01..03af2c5d75dd 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1987,14 +1987,20 @@ mro_invoke(PyTypeObject *type) new_mro = PySequence_Tuple(mro_result); Py_DECREF(mro_result); - if (new_mro == NULL) + if (new_mro == NULL) { return NULL; + } - if (custom && mro_check(type, new_mro) < 0) { + if (PyTuple_GET_SIZE(new_mro) == 0) { Py_DECREF(new_mro); + PyErr_Format(PyExc_TypeError, "type MRO must not be empty"); return NULL; } + if (custom && mro_check(type, new_mro) < 0) { + Py_DECREF(new_mro); + return NULL; + } return new_mro; } @@ -2034,8 +2040,9 @@ mro_internal(PyTypeObject *type, PyObject **p_old_mro) new_mro = mro_invoke(type); /* might cause reentrance */ reent = (type->tp_mro != old_mro); Py_XDECREF(old_mro); - if (new_mro == NULL) + if (new_mro == NULL) { return -1; + } if (reent) { Py_DECREF(new_mro); @@ -3590,9 +3597,17 @@ PyObject * _PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def) { assert(PyType_Check(type)); + PyObject *mro = type->tp_mro; + // The type must be ready assert(mro != NULL); - for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(mro); i++) { + assert(PyTuple_Check(mro)); + // mro_invoke() ensures that the type MRO cannot be empty, so we don't have + // to check i < PyTuple_GET_SIZE(mro) at the first loop iteration. + assert(PyTuple_GET_SIZE(mro) >= 1); + + Py_ssize_t i = 0; + do { PyObject *super = PyTuple_GET_ITEM(mro, i); // _PyType_GetModuleByDef() must only be called on a heap type created // by PyType_FromModuleAndSpec() or on its subclasses. @@ -3605,7 +3620,8 @@ _PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def) if (module && PyModule_GetDef(module) == def) { return module; } - } + i++; + } while (i < PyTuple_GET_SIZE(mro)); PyErr_Format( PyExc_TypeError,