@@ -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