@@ -11422,6 +11422,11 @@ static pytype_slotdef slotdefs[] = {
11422
11422
{NULL }
11423
11423
};
11424
11424
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
+
11425
11430
/* Given a type pointer and an offset gotten from a slotdef entry, return a
11426
11431
pointer to the actual slot. This is not quite the same as simply adding
11427
11432
the offset to the type pointer, since it takes care to indirect through the
@@ -11464,61 +11469,6 @@ slotptr(PyTypeObject *type, int ioffset)
11464
11469
return (void * * )ptr ;
11465
11470
}
11466
11471
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
-
11522
11472
// Return true if "name" corresponds to at least one slot definition. This is
11523
11473
// a more accurate but more expensive test compared to is_dunder_name().
11524
11474
static bool
@@ -11645,7 +11595,15 @@ update_one_slot(PyTypeObject *type, pytype_slotdef *p, pytype_slotdef **next_p,
11645
11595
}
11646
11596
if (Py_IS_TYPE (descr , & PyWrapperDescr_Type ) &&
11647
11597
((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
+
11649
11607
if (tptr == NULL || tptr == ptr )
11650
11608
generic = p -> function ;
11651
11609
d = (PyWrapperDescrObject * )descr ;
@@ -11858,6 +11816,76 @@ update_all_slots(PyTypeObject* type)
11858
11816
11859
11817
#endif
11860
11818
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
+
11861
11889
11862
11890
PyObject *
11863
11891
_PyType_GetSlotWrapperNames (void )
0 commit comments