diff options
author | Victor Stinner <vstinner@python.org> | 2021-04-21 22:10:16 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-21 22:10:16 (GMT) |
commit | 760da626ff4124e1344fd8b7dbeb83b2c4b7c12c (patch) | |
tree | ca3bf154f0d0b0aefc2d35710a0b05bba09ada9b /Objects | |
parent | d4aaa34798f0dd8402f412e2aa9d6fa2d6cff5fa (diff) | |
download | cpython-760da626ff4124e1344fd8b7dbeb83b2c4b7c12c.zip cpython-760da626ff4124e1344fd8b7dbeb83b2c4b7c12c.tar.gz cpython-760da626ff4124e1344fd8b7dbeb83b2c4b7c12c.tar.bz2 |
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.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/typeobject.c | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c index ef38331..03af2c5 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, |