Skip to content

Commit aadb482

Browse files
add _Py_dict_lookup_unicode_threadsafe_stackref to lookup method
1 parent 109ff8b commit aadb482

File tree

3 files changed

+76
-32
lines changed

3 files changed

+76
-32
lines changed

Include/internal/pycore_dict.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ extern void _PyDictKeys_DecRef(PyDictKeysObject *keys);
112112
extern Py_ssize_t _Py_dict_lookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr);
113113
extern Py_ssize_t _Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr);
114114
extern Py_ssize_t _Py_dict_lookup_threadsafe_stackref(PyDictObject *mp, PyObject *key, Py_hash_t hash, _PyStackRef *value_addr);
115+
extern Py_ssize_t _Py_dict_lookup_unicode_threadsafe_stackref(PyDictObject *mp, PyObject *key, Py_hash_t hash, _PyStackRef *value_addr);
115116

116117
extern Py_ssize_t _PyDict_LookupIndex(PyDictObject *, PyObject *);
117118
extern Py_ssize_t _PyDictKeys_StringLookup(PyDictKeysObject* dictkeys, PyObject *key);

Objects/dictobject.c

Lines changed: 73 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -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

16251660
Py_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

16491701
int

Objects/object.c

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,18 +1759,9 @@ _PyObject_GetMethodStackRef(PyThreadState *ts, PyObject *obj,
17591759
assert(hash != -1);
17601760
// ref is not visible to gc so there should be
17611761
// no escaping calls before assigning it to method
1762-
PyDictObject *mp = (PyDictObject *)dict;
1763-
PyDictKeysObject *keys = FT_ATOMIC_LOAD_PTR_ACQUIRE(mp->ma_keys);
1764-
bool unicode_keys = DK_IS_UNICODE(keys);
17651762
_PyStackRef ref;
1766-
if (!unicode_keys) {
1767-
Py_INCREF(mp);
1768-
}
1769-
Py_ssize_t ix = _Py_dict_lookup_threadsafe_stackref(mp, name,
1770-
hash, &ref);
1771-
if (!unicode_keys) {
1772-
Py_DECREF(mp);
1773-
}
1763+
Py_ssize_t ix = _Py_dict_lookup_unicode_threadsafe_stackref((PyDictObject *)dict,
1764+
name, hash, &ref);
17741765
if (ix == DKIX_ERROR) {
17751766
// error
17761767
PyStackRef_CLEAR(*method);

0 commit comments

Comments
 (0)