@@ -5269,124 +5269,87 @@ PyType_GetModuleByDef(PyTypeObject *type, PyModuleDef *def)
52695269
52705270
52715271static 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