@@ -1185,6 +1185,37 @@ dictkeys_generic_lookup(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, P
11851185    return  do_lookup (mp , dk , key , hash , compare_generic );
11861186}
11871187
1188+ #ifdef  Py_GIL_DISABLED 
1189+ 
1190+ static  Py_ssize_t 
1191+ unicodekeys_lookup_unicode_threadsafe (PyDictKeysObject *  dk , PyObject  * key ,
1192+                                       Py_hash_t  hash );
1193+ 
1194+ #endif 
1195+ 
1196+ static  Py_ssize_t 
1197+ unicodekeys_lookup_split (PyDictKeysObject *  dk , PyObject  * key , Py_hash_t  hash )
1198+ {
1199+     Py_ssize_t  ix ;
1200+     assert (dk -> dk_kind  ==  DICT_KEYS_SPLIT );
1201+     assert (PyUnicode_CheckExact (key ));
1202+ 
1203+ #ifdef  Py_GIL_DISABLED 
1204+     // A split dictionaries keys can be mutated by other dictionaries 
1205+     // but if we have a unicode key we can avoid locking the shared 
1206+     // keys. 
1207+     ix  =  unicodekeys_lookup_unicode_threadsafe (dk , key , hash );
1208+     if  (ix  ==  DKIX_KEY_CHANGED ) {
1209+         LOCK_KEYS (dk );
1210+         ix  =  unicodekeys_lookup_unicode (dk , key , hash );
1211+         UNLOCK_KEYS (dk );
1212+     }
1213+ #else 
1214+     ix  =  unicodekeys_lookup_unicode (dk , key , hash );
1215+ #endif 
1216+     return  ix ;
1217+ }
1218+ 
11881219/* Lookup a string in a (all unicode) dict keys. 
11891220 * Returns DKIX_ERROR if key is not a string, 
11901221 * or if the dict keys is not all strings. 
@@ -1209,13 +1240,24 @@ _PyDictKeys_StringLookup(PyDictKeysObject* dk, PyObject *key)
12091240    return  unicodekeys_lookup_unicode (dk , key , hash );
12101241}
12111242
1212- #ifdef  Py_GIL_DISABLED 
1213- 
1214- static  Py_ssize_t 
1215- unicodekeys_lookup_unicode_threadsafe (PyDictKeysObject *  dk , PyObject  * key ,
1216-                                       Py_hash_t  hash );
1217- 
1218- #endif 
1243+ /* Like _PyDictKeys_StringLookup() but only works on split keys.  Note 
1244+  * that in free-threaded builds this locks the keys object as required. 
1245+  */ 
1246+ Py_ssize_t 
1247+ _PyDictKeys_StringLookupSplit (PyDictKeysObject *  dk , PyObject  * key )
1248+ {
1249+     assert (dk -> dk_kind  ==  DICT_KEYS_SPLIT );
1250+     assert (PyUnicode_CheckExact (key ));
1251+     Py_hash_t  hash  =  unicode_get_hash (key );
1252+     if  (hash  ==  -1 ) {
1253+         hash  =  PyUnicode_Type .tp_hash (key );
1254+         if  (hash  ==  -1 ) {
1255+             PyErr_Clear ();
1256+             return  DKIX_ERROR ;
1257+         }
1258+     }
1259+     return  unicodekeys_lookup_split (dk , key , hash );
1260+ }
12191261
12201262/* 
12211263The basic lookup function used by all operations. 
@@ -6976,7 +7018,7 @@ _PyObject_TryGetInstanceAttribute(PyObject *obj, PyObject *name, PyObject **attr
69767018
69777019    PyDictKeysObject  * keys  =  CACHED_KEYS (Py_TYPE (obj ));
69787020    assert (keys  !=  NULL );
6979-     Py_ssize_t  ix  =  _PyDictKeys_StringLookup (keys , name );
7021+     Py_ssize_t  ix  =  _PyDictKeys_StringLookupSplit (keys , name );
69807022    if  (ix  ==  DKIX_EMPTY ) {
69817023        * attr  =  NULL ;
69827024        return  true;
0 commit comments