@@ -1581,33 +1581,41 @@ _Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyOb
15811581 return ix ;
15821582}
15831583
1584- Py_ssize_t
1585- _Py_dict_lookup_threadsafe_stackref ( PyDictObject * mp , PyObject * key , Py_hash_t hash , _PyStackRef * value_addr )
1584+ static Py_ssize_t
1585+ unicodekeys_lookup_unicode_threadsafe_stackref ( PyDictKeysObject * dk , PyObject * key , Py_hash_t hash , _PyStackRef * value_addr )
15861586{
1587- PyDictKeysObject * dk = _Py_atomic_load_ptr (& mp -> ma_keys );
1588- if (dk -> dk_kind == DICT_KEYS_UNICODE && PyUnicode_CheckExact (key )) {
1589- Py_ssize_t ix = unicodekeys_lookup_unicode_threadsafe (dk , key , hash );
1590- if (ix == DKIX_EMPTY ) {
1587+ assert (PyUnicode_CheckExact (key ));
1588+ assert (dk -> dk_kind == DICT_KEYS_UNICODE );
1589+ Py_ssize_t ix = unicodekeys_lookup_unicode_threadsafe (dk , key , hash );
1590+ if (ix == DKIX_EMPTY ) {
1591+ * value_addr = PyStackRef_NULL ;
1592+ return DKIX_EMPTY ;
1593+ } else if (ix >= 0 ) {
1594+ PyObject * * addr_of_value = & DK_UNICODE_ENTRIES (dk )[ix ].me_value ;
1595+ PyObject * value = _Py_atomic_load_ptr (addr_of_value );
1596+ if (value == NULL ) {
15911597 * value_addr = PyStackRef_NULL ;
1598+ return DKIX_EMPTY ;
1599+ }
1600+ if (_PyObject_HasDeferredRefcount (value )) {
1601+ * value_addr = (_PyStackRef ){ .bits = (uintptr_t )value | Py_TAG_DEFERRED };
15921602 return ix ;
15931603 }
1594- else if (ix >= 0 ) {
1595- PyObject * * addr_of_value = & DK_UNICODE_ENTRIES (dk )[ix ].me_value ;
1596- PyObject * value = _Py_atomic_load_ptr (addr_of_value );
1597- if (value == NULL ) {
1598- * value_addr = PyStackRef_NULL ;
1599- return DKIX_EMPTY ;
1600- }
1601- if (_PyObject_HasDeferredRefcount (value )) {
1602- * value_addr = (_PyStackRef ){ .bits = (uintptr_t )value | Py_TAG_DEFERRED };
1603- return ix ;
1604- }
1605- if (_Py_TryIncrefCompare (addr_of_value , value )) {
1606- * value_addr = PyStackRef_FromPyObjectSteal (value );
1607- return ix ;
1608- }
1604+ if (_Py_TryIncrefCompare (addr_of_value , value )) {
1605+ * value_addr = PyStackRef_FromPyObjectSteal (value );
1606+ return ix ;
16091607 }
16101608 }
1609+ }
1610+
1611+
1612+ Py_ssize_t
1613+ _Py_dict_lookup_threadsafe_stackref (PyDictObject * mp , PyObject * key , Py_hash_t hash , _PyStackRef * value_addr )
1614+ {
1615+ PyDictKeysObject * dk = _Py_atomic_load_ptr (& mp -> ma_keys );
1616+ if (dk -> dk_kind == DICT_KEYS_UNICODE && PyUnicode_CheckExact (key )) {
1617+ return unicodekeys_lookup_unicode_threadsafe_stackref (dk , key , hash , value_addr );
1618+ }
16111619
16121620 PyObject * obj ;
16131621 Py_ssize_t ix = _Py_dict_lookup_threadsafe (mp , key , hash , & obj );
@@ -1620,6 +1628,33 @@ _Py_dict_lookup_threadsafe_stackref(PyDictObject *mp, PyObject *key, Py_hash_t h
16201628 return ix ;
16211629}
16221630
1631+ // This is similar to _Py_dict_lookup_threadsafe_stackref() but
1632+ // it is used when dict is borrowed reference and key is known to be unicode.
1633+ // It avoids increfing the dict if dict only has unicode keys in which case
1634+ // the lookup is safe, otherwise it increfs the dict and lookups the key.
1635+
1636+ Py_ssize_t
1637+ _Py_dict_lookup_unicode_threadsafe_stackref (PyDictObject * mp , PyObject * key , Py_hash_t hash , _PyStackRef * value_addr )
1638+ {
1639+ assert (PyUnicode_CheckExact (key ));
1640+ PyDictKeysObject * dk = _Py_atomic_load_ptr (& mp -> ma_keys );
1641+ if (dk -> dk_kind == DICT_KEYS_UNICODE ) {
1642+ return unicodekeys_lookup_unicode_threadsafe_stackref (dk , key , hash , value_addr );
1643+ }
1644+
1645+ PyObject * obj ;
1646+ Py_INCREF (mp );
1647+ Py_ssize_t ix = _Py_dict_lookup_threadsafe (mp , key , hash , & obj );
1648+ Py_DECREF (mp );
1649+ if (ix >= 0 && obj != NULL ) {
1650+ * value_addr = PyStackRef_FromPyObjectSteal (obj );
1651+ }
1652+ else {
1653+ * value_addr = PyStackRef_NULL ;
1654+ }
1655+ return ix ;
1656+ }
1657+
16231658#else // Py_GIL_DISABLED
16241659
16251660Py_ssize_t
@@ -1644,6 +1679,23 @@ _Py_dict_lookup_threadsafe_stackref(PyDictObject *mp, PyObject *key, Py_hash_t h
16441679 return ix ;
16451680}
16461681
1682+ Py_ssize_t
1683+ _Py_dict_lookup_unicode_threadsafe_stackref (PyDictObject * mp , PyObject * key , Py_hash_t hash , _PyStackRef * value_addr )
1684+ {
1685+ assert (PyUnicode_CheckExact (key ));
1686+ PyObject * val ;
1687+ Py_INCREF (mp );
1688+ Py_ssize_t ix = _Py_dict_lookup (mp , key , hash , & val );
1689+ Py_DECREF (mp );
1690+ if (ix >= 0 && val != NULL ) {
1691+ * value_addr = PyStackRef_FromPyObjectNew (val );
1692+ }
1693+ else {
1694+ * value_addr = PyStackRef_NULL ;
1695+ }
1696+ return ix ;
1697+ }
1698+
16471699#endif
16481700
16491701int
0 commit comments