Skip to content

Commit 760da62

Browse files
authored
bpo-40137: Optimize _PyType_GetModuleByDef() loop (pythonGH-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.
1 parent d4aaa34 commit 760da62

File tree

1 file changed

+21
-5
lines changed

1 file changed

+21
-5
lines changed

Objects/typeobject.c

+21-5
Original file line numberDiff line numberDiff line change
@@ -1987,14 +1987,20 @@ mro_invoke(PyTypeObject *type)
19871987

19881988
new_mro = PySequence_Tuple(mro_result);
19891989
Py_DECREF(mro_result);
1990-
if (new_mro == NULL)
1990+
if (new_mro == NULL) {
19911991
return NULL;
1992+
}
19921993

1993-
if (custom && mro_check(type, new_mro) < 0) {
1994+
if (PyTuple_GET_SIZE(new_mro) == 0) {
19941995
Py_DECREF(new_mro);
1996+
PyErr_Format(PyExc_TypeError, "type MRO must not be empty");
19951997
return NULL;
19961998
}
19971999

2000+
if (custom && mro_check(type, new_mro) < 0) {
2001+
Py_DECREF(new_mro);
2002+
return NULL;
2003+
}
19982004
return new_mro;
19992005
}
20002006

@@ -2034,8 +2040,9 @@ mro_internal(PyTypeObject *type, PyObject **p_old_mro)
20342040
new_mro = mro_invoke(type); /* might cause reentrance */
20352041
reent = (type->tp_mro != old_mro);
20362042
Py_XDECREF(old_mro);
2037-
if (new_mro == NULL)
2043+
if (new_mro == NULL) {
20382044
return -1;
2045+
}
20392046

20402047
if (reent) {
20412048
Py_DECREF(new_mro);
@@ -3590,9 +3597,17 @@ PyObject *
35903597
_PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)
35913598
{
35923599
assert(PyType_Check(type));
3600+
35933601
PyObject *mro = type->tp_mro;
3602+
// The type must be ready
35943603
assert(mro != NULL);
3595-
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(mro); i++) {
3604+
assert(PyTuple_Check(mro));
3605+
// mro_invoke() ensures that the type MRO cannot be empty, so we don't have
3606+
// to check i < PyTuple_GET_SIZE(mro) at the first loop iteration.
3607+
assert(PyTuple_GET_SIZE(mro) >= 1);
3608+
3609+
Py_ssize_t i = 0;
3610+
do {
35963611
PyObject *super = PyTuple_GET_ITEM(mro, i);
35973612
// _PyType_GetModuleByDef() must only be called on a heap type created
35983613
// by PyType_FromModuleAndSpec() or on its subclasses.
@@ -3605,7 +3620,8 @@ _PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)
36053620
if (module && PyModule_GetDef(module) == def) {
36063621
return module;
36073622
}
3608-
}
3623+
i++;
3624+
} while (i < PyTuple_GET_SIZE(mro));
36093625

36103626
PyErr_Format(
36113627
PyExc_TypeError,

0 commit comments

Comments
 (0)