@@ -1129,6 +1129,38 @@ dictkeys_generic_lookup(PyDictObject *mp, PyDictKeysObject* dk, PyObject *key, P
11291129 return do_lookup (mp , dk , key , hash , compare_generic );
11301130}
11311131
1132+ #ifdef Py_GIL_DISABLED
1133+ static Py_ssize_t
1134+ unicodekeys_lookup_unicode_threadsafe (PyDictKeysObject * dk , PyObject * key ,
1135+ Py_hash_t hash );
1136+ #endif
1137+
1138+ static Py_ssize_t
1139+ unicodekeys_lookup_split (PyDictKeysObject * dk , PyObject * key , Py_hash_t hash )
1140+ {
1141+ Py_ssize_t ix ;
1142+ assert (dk -> dk_kind == DICT_KEYS_SPLIT );
1143+ assert (PyUnicode_CheckExact (key ));
1144+
1145+ #ifdef Py_GIL_DISABLED
1146+ // A split dictionaries keys can be mutated by other dictionaries
1147+ // but if we have a unicode key we can avoid locking the shared
1148+ // keys.
1149+ ix = unicodekeys_lookup_unicode_threadsafe (dk , key , hash );
1150+ if (ix == DKIX_KEY_CHANGED ) {
1151+ LOCK_KEYS (dk );
1152+ ix = unicodekeys_lookup_unicode (dk , key , hash );
1153+ UNLOCK_KEYS (dk );
1154+ }
1155+ else {
1156+ ix = unicodekeys_lookup_unicode (dk , key , hash );
1157+ }
1158+ #else
1159+ ix = unicodekeys_lookup_unicode (dk , key , hash );
1160+ #endif
1161+ return ix ;
1162+ }
1163+
11321164/* Lookup a string in a (all unicode) dict keys.
11331165 * Returns DKIX_ERROR if key is not a string,
11341166 * or if the dict keys is not all strings.
@@ -1153,13 +1185,24 @@ _PyDictKeys_StringLookup(PyDictKeysObject* dk, PyObject *key)
11531185 return unicodekeys_lookup_unicode (dk , key , hash );
11541186}
11551187
1156- #ifdef Py_GIL_DISABLED
1157-
1158- static Py_ssize_t
1159- unicodekeys_lookup_unicode_threadsafe (PyDictKeysObject * dk , PyObject * key ,
1160- Py_hash_t hash );
1161-
1162- #endif
1188+ /* Like _PyDictKeys_StringLookup() but only works on split keys. Note
1189+ * that in free-threaded builds this locks the keys object as required.
1190+ */
1191+ Py_ssize_t
1192+ _PyDictKeys_StringLookupSplit (PyDictKeysObject * dk , PyObject * key )
1193+ {
1194+ assert (dk -> dk_kind == DICT_KEYS_SPLIT );
1195+ assert (PyUnicode_CheckExact (key ));
1196+ Py_hash_t hash = unicode_get_hash (key );
1197+ if (hash == -1 ) {
1198+ hash = PyUnicode_Type .tp_hash (key );
1199+ if (hash == -1 ) {
1200+ PyErr_Clear ();
1201+ return DKIX_ERROR ;
1202+ }
1203+ }
1204+ return unicodekeys_lookup_split (dk , key , hash );
1205+ }
11631206
11641207/*
11651208The basic lookup function used by all operations.
@@ -1192,15 +1235,7 @@ _Py_dict_lookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **valu
11921235 if (PyUnicode_CheckExact (key )) {
11931236#ifdef Py_GIL_DISABLED
11941237 if (kind == DICT_KEYS_SPLIT ) {
1195- // A split dictionaries keys can be mutated by other
1196- // dictionaries but if we have a unicode key we can avoid
1197- // locking the shared keys.
1198- ix = unicodekeys_lookup_unicode_threadsafe (dk , key , hash );
1199- if (ix == DKIX_KEY_CHANGED ) {
1200- LOCK_KEYS (dk );
1201- ix = unicodekeys_lookup_unicode (dk , key , hash );
1202- UNLOCK_KEYS (dk );
1203- }
1238+ ix = unicodekeys_lookup_split (dk , key , hash );
12041239 }
12051240 else {
12061241 ix = unicodekeys_lookup_unicode (dk , key , hash );
@@ -6967,7 +7002,12 @@ _PyObject_TryGetInstanceAttribute(PyObject *obj, PyObject *name, PyObject **attr
69677002
69687003 PyDictKeysObject * keys = CACHED_KEYS (Py_TYPE (obj ));
69697004 assert (keys != NULL );
6970- Py_ssize_t ix = _PyDictKeys_StringLookup (keys , name );
7005+ Py_ssize_t ix ;
7006+ if (keys -> dk_kind == DICT_KEYS_SPLIT ) {
7007+ ix = _PyDictKeys_StringLookupSplit (keys , name );
7008+ } else {
7009+ ix = _PyDictKeys_StringLookup (keys , name );
7010+ }
69717011 if (ix == DKIX_EMPTY ) {
69727012 * attr = NULL ;
69737013 return true;
0 commit comments