@@ -11422,6 +11422,11 @@ static pytype_slotdef slotdefs[] = {
1142211422 {NULL }
1142311423};
1142411424
11425+ /* Stores the number of times where slotdefs has elements with same name.
11426+ This counter precalculated by _PyType_InitSlotDefs() when the main
11427+ interpreter starts. */
11428+ static uint8_t slotdefs_name_counts [Py_ARRAY_LENGTH (slotdefs )];
11429+
1142511430/* Given a type pointer and an offset gotten from a slotdef entry, return a
1142611431 pointer to the actual slot. This is not quite the same as simply adding
1142711432 the offset to the type pointer, since it takes care to indirect through the
@@ -11464,61 +11469,6 @@ slotptr(PyTypeObject *type, int ioffset)
1146411469 return (void * * )ptr ;
1146511470}
1146611471
11467- /* Return a slot pointer for a given name, but ONLY if the attribute has
11468- exactly one slot function. The name must be an interned string. */
11469- static void * *
11470- resolve_slotdups (PyTypeObject * type , PyObject * name )
11471- {
11472- /* XXX Maybe this could be optimized more -- but is it worth it? */
11473-
11474- #ifdef Py_GIL_DISABLED
11475- pytype_slotdef * ptrs [MAX_EQUIV ];
11476- pytype_slotdef * * pp = ptrs ;
11477- /* Collect all slotdefs that match name into ptrs. */
11478- for (pytype_slotdef * p = slotdefs ; p -> name_strobj ; p ++ ) {
11479- if (p -> name_strobj == name )
11480- * pp ++ = p ;
11481- }
11482- * pp = NULL ;
11483- #else
11484- /* pname and ptrs act as a little cache */
11485- PyInterpreterState * interp = _PyInterpreterState_GET ();
11486- #define pname _Py_INTERP_CACHED_OBJECT(interp, type_slots_pname)
11487- #define ptrs _Py_INTERP_CACHED_OBJECT(interp, type_slots_ptrs)
11488- pytype_slotdef * p , * * pp ;
11489-
11490- if (pname != name ) {
11491- /* Collect all slotdefs that match name into ptrs. */
11492- pname = name ;
11493- pp = ptrs ;
11494- for (p = slotdefs ; p -> name_strobj ; p ++ ) {
11495- if (p -> name_strobj == name )
11496- * pp ++ = p ;
11497- }
11498- * pp = NULL ;
11499- }
11500- #endif
11501-
11502- /* Look in all slots of the type matching the name. If exactly one of these
11503- has a filled-in slot, return a pointer to that slot.
11504- Otherwise, return NULL. */
11505- void * * res , * * ptr ;
11506- res = NULL ;
11507- for (pp = ptrs ; * pp ; pp ++ ) {
11508- ptr = slotptr (type , (* pp )-> offset );
11509- if (ptr == NULL || * ptr == NULL )
11510- continue ;
11511- if (res != NULL )
11512- return NULL ;
11513- res = ptr ;
11514- }
11515- #ifndef Py_GIL_DISABLED
11516- #undef pname
11517- #undef ptrs
11518- #endif
11519- return res ;
11520- }
11521-
1152211472// Return true if "name" corresponds to at least one slot definition. This is
1152311473// a more accurate but more expensive test compared to is_dunder_name().
1152411474static bool
@@ -11645,7 +11595,15 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p, pytype_slotdef **next_p,
1164511595 }
1164611596 if (Py_IS_TYPE (descr , & PyWrapperDescr_Type ) &&
1164711597 ((PyWrapperDescrObject * )descr )-> d_base -> name_strobj == p -> name_strobj ) {
11648- void * * tptr = resolve_slotdups (type , p -> name_strobj );
11598+ void * * tptr ;
11599+ size_t index = (p - slotdefs ) / sizeof (slotdefs [0 ]);
11600+ if (slotdefs_name_counts [index ] == 1 ) {
11601+ tptr = slotptr (type , p -> offset );
11602+ }
11603+ else {
11604+ tptr = NULL ;
11605+ }
11606+
1164911607 if (tptr == NULL || tptr == ptr )
1165011608 generic = p -> function ;
1165111609 d = (PyWrapperDescrObject * )descr ;
@@ -11858,6 +11816,76 @@ update_all_slots(PyTypeObject* type)
1185811816
1185911817#endif
1186011818
11819+ int
11820+ _PyType_InitSlotDefs (PyInterpreterState * interp )
11821+ {
11822+ if (!_Py_IsMainInterpreter (interp )) {
11823+ return 0 ;
11824+ }
11825+ PyObject * bytearray = NULL ;
11826+ PyObject * cache = PyDict_New ();
11827+ if (!cache ) {
11828+ return -1 ;
11829+ }
11830+
11831+ pytype_slotdef * p ;
11832+ Py_ssize_t idx = 0 ;
11833+ for (p = slotdefs ; p -> name_strobj ; p ++ , idx ++ ) {
11834+ assert (idx < 255 );
11835+
11836+ if (PyDict_GetItemRef (cache , p -> name_strobj , & bytearray ) < 0 ) {
11837+ goto error ;
11838+ }
11839+
11840+ if (!bytearray ) {
11841+ Py_ssize_t size = sizeof (uint8_t ) * (1 + MAX_EQUIV );
11842+ bytearray = PyByteArray_FromStringAndSize (NULL , size );
11843+ if (!bytearray ) {
11844+ goto error ;
11845+ }
11846+
11847+ uint8_t * data = (uint8_t * )PyByteArray_AS_STRING (bytearray );
11848+ data [0 ] = 0 ;
11849+
11850+ if (PyDict_SetItem (cache , p -> name_strobj , bytearray ) < 0 ) {
11851+ goto error ;
11852+ }
11853+ }
11854+
11855+ assert (PyByteArray_CheckExact (bytearray ));
11856+ uint8_t * data = (uint8_t * )PyByteArray_AS_STRING (bytearray );
11857+
11858+ data [0 ] += 1 ;
11859+ assert (data [0 ] < MAX_EQUIV );
11860+
11861+ data [data [0 ]] = (uint8_t )idx ;
11862+
11863+ Py_CLEAR (bytearray );
11864+ }
11865+
11866+ memset (slotdefs_name_counts , 0 , sizeof (slotdefs_name_counts ));
11867+
11868+ Py_ssize_t pos = 0 ;
11869+ PyObject * key = NULL ;
11870+ PyObject * value = NULL ;
11871+ while (PyDict_Next (cache , & pos , & key , & value )) {
11872+ uint8_t * data = (uint8_t * )PyByteArray_AS_STRING (value );
11873+ uint8_t n = data [0 ];
11874+ for (uint8_t i = 0 ; i < n ; i ++ ) {
11875+ uint8_t idx = data [i + 1 ];
11876+ slotdefs_name_counts [idx ] = n ;
11877+ }
11878+ }
11879+
11880+ Py_DECREF (cache );
11881+ return 0 ;
11882+
11883+ error :
11884+ Py_XDECREF (bytearray );
11885+ Py_DECREF (cache );
11886+ return -1 ;
11887+ }
11888+
1186111889
1186211890PyObject *
1186311891_PyType_GetSlotWrapperNames (void )
0 commit comments