Skip to content

Commit 120b891

Browse files
authored
gh-124153: Simplify PyType_GetBaseByToken (GH-124488)
1 parent 87d7315 commit 120b891

File tree

1 file changed

+43
-80
lines changed

1 file changed

+43
-80
lines changed

Objects/typeobject.c

+43-80
Original file line numberDiff line numberDiff line change
@@ -5269,124 +5269,87 @@ PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def)
52695269

52705270

52715271
static PyTypeObject *
5272-
get_base_by_token_recursive(PyTypeObject *type, void *token)
5272+
get_base_by_token_recursive(PyObject *bases, void *token)
52735273
{
5274-
assert(PyType_GetSlot(type, Py_tp_token) != token);
5275-
PyObject *bases = lookup_tp_bases(type);
52765274
assert(bases != NULL);
5275+
PyTypeObject *res = NULL;
52775276
Py_ssize_t n = PyTuple_GET_SIZE(bases);
52785277
for (Py_ssize_t i = 0; i < n; i++) {
52795278
PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(bases, i));
52805279
if (!_PyType_HasFeature(base, Py_TPFLAGS_HEAPTYPE)) {
52815280
continue;
52825281
}
52835282
if (((PyHeapTypeObject*)base)->ht_token == token) {
5284-
return base;
5283+
res = base;
5284+
break;
52855285
}
5286-
base = get_base_by_token_recursive(base, token);
5286+
base = get_base_by_token_recursive(lookup_tp_bases(base), token);
52875287
if (base != NULL) {
5288-
return base;
5288+
res = base;
5289+
break;
52895290
}
52905291
}
5291-
return NULL;
5292+
return res; // Prefer to return recursively from one place
52925293
}
52935294

5294-
static inline PyTypeObject *
5295-
get_base_by_token_from_mro(PyTypeObject *type, void *token)
5295+
int
5296+
PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result)
52965297
{
5297-
// Bypass lookup_tp_mro() as PyType_IsSubtype() does
5298-
PyObject *mro = type->tp_mro;
5299-
assert(mro != NULL);
5300-
assert(PyTuple_Check(mro));
5301-
// mro_invoke() ensures that the type MRO cannot be empty.
5302-
assert(PyTuple_GET_SIZE(mro) >= 1);
5303-
// Also, the first item in the MRO is the type itself, which is supposed
5304-
// to be already checked by the caller. We skip it in the loop.
5305-
assert(PyTuple_GET_ITEM(mro, 0) == (PyObject *)type);
5306-
assert(PyType_GetSlot(type, Py_tp_token) != token);
5307-
5308-
Py_ssize_t n = PyTuple_GET_SIZE(mro);
5309-
for (Py_ssize_t i = 1; i < n; i++) {
5310-
PyTypeObject *base = _PyType_CAST(PyTuple_GET_ITEM(mro, i));
5311-
if (!_PyType_HasFeature(base, Py_TPFLAGS_HEAPTYPE)) {
5312-
continue;
5313-
}
5314-
if (((PyHeapTypeObject*)base)->ht_token == token) {
5315-
return base;
5316-
}
5298+
if (result != NULL) {
5299+
*result = NULL;
53175300
}
5318-
return NULL;
5319-
}
53205301

5321-
static int
5322-
check_base_by_token(PyTypeObject *type, void *token) {
5323-
// Chain the branches, which will be optimized exclusive here
53245302
if (token == NULL) {
53255303
PyErr_Format(PyExc_SystemError,
53265304
"PyType_GetBaseByToken called with token=NULL");
53275305
return -1;
53285306
}
5329-
else if (!PyType_Check(type)) {
5307+
if (!PyType_Check(type)) {
53305308
PyErr_Format(PyExc_TypeError,
53315309
"expected a type, got a '%T' object", type);
53325310
return -1;
53335311
}
5334-
else if (!_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
5335-
return 0;
5336-
}
5337-
else if (((PyHeapTypeObject*)type)->ht_token == token) {
5338-
return 1;
5339-
}
5340-
else if (type->tp_mro != NULL) {
5341-
// This will not be inlined
5342-
return get_base_by_token_from_mro(type, token) ? 1 : 0;
5343-
}
5344-
else {
5345-
return get_base_by_token_recursive(type, token) ? 1 : 0;
5346-
}
5347-
}
53485312

5349-
int
5350-
PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result)
5351-
{
5352-
if (result == NULL) {
5353-
// If the `result` is checked only once here, the subsequent
5354-
// branches will become trivial to optimize.
5355-
return check_base_by_token(type, token);
5356-
}
5357-
if (token == NULL || !PyType_Check(type)) {
5358-
*result = NULL;
5359-
return check_base_by_token(type, token);
5360-
}
5361-
5362-
// Chain the branches, which will be optimized exclusive here
5363-
PyTypeObject *base;
53645313
if (!_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
53655314
// No static type has a heaptype superclass,
53665315
// which is ensured by type_ready_mro().
5367-
*result = NULL;
53685316
return 0;
53695317
}
5370-
else if (((PyHeapTypeObject*)type)->ht_token == token) {
5371-
*result = (PyTypeObject *)Py_NewRef(type);
5318+
if (((PyHeapTypeObject*)type)->ht_token == token) {
5319+
found:
5320+
if (result != NULL) {
5321+
*result = (PyTypeObject *)Py_NewRef(type);
5322+
}
53725323
return 1;
53735324
}
5374-
else if (type->tp_mro != NULL) {
5375-
// Expect this to be inlined
5376-
base = get_base_by_token_from_mro(type, token);
5377-
}
5378-
else {
5379-
base = get_base_by_token_recursive(type, token);
5380-
}
53815325

5382-
if (base != NULL) {
5383-
*result = (PyTypeObject *)Py_NewRef(base);
5384-
return 1;
5385-
}
5386-
else {
5387-
*result = NULL;
5326+
PyObject *mro = type->tp_mro; // No lookup, following PyType_IsSubtype()
5327+
if (mro == NULL) {
5328+
PyTypeObject *base;
5329+
base = get_base_by_token_recursive(lookup_tp_bases(type), token);
5330+
if (base != NULL) {
5331+
// Copying the given type can cause a slowdown,
5332+
// unlike the overwrite below.
5333+
type = base;
5334+
goto found;
5335+
}
53885336
return 0;
53895337
}
5338+
// mro_invoke() ensures that the type MRO cannot be empty.
5339+
assert(PyTuple_GET_SIZE(mro) >= 1);
5340+
// Also, the first item in the MRO is the type itself, which
5341+
// we already checked above. We skip it in the loop.
5342+
assert(PyTuple_GET_ITEM(mro, 0) == (PyObject *)type);
5343+
Py_ssize_t n = PyTuple_GET_SIZE(mro);
5344+
for (Py_ssize_t i = 1; i < n; i++) {
5345+
PyTypeObject *base = (PyTypeObject *)PyTuple_GET_ITEM(mro, i);
5346+
if (_PyType_HasFeature(base, Py_TPFLAGS_HEAPTYPE)
5347+
&& ((PyHeapTypeObject*)base)->ht_token == token) {
5348+
type = base;
5349+
goto found;
5350+
}
5351+
}
5352+
return 0;
53905353
}
53915354

53925355

0 commit comments

Comments
 (0)