Skip to content

Commit 207cccd

Browse files
GH-137759:Limit _PyObject_HashFast to dicts keys, rename it, and mark it as Py_ALWAYS_INLINE
1 parent 04f8ef6 commit 207cccd

File tree

5 files changed

+27
-25
lines changed

5 files changed

+27
-25
lines changed

Include/internal/pycore_object.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -858,9 +858,11 @@ _PyObject_IS_GC(PyObject *obj)
858858
&& (type->tp_is_gc == NULL || type->tp_is_gc(obj)));
859859
}
860860

861-
// Fast inlined version of PyObject_Hash()
862-
static inline Py_hash_t
863-
_PyObject_HashFast(PyObject *op)
861+
// Fast inlined version of PyObject_Hash(). Dictionaries are very
862+
// likely to include string keys (class and instance attributes,
863+
// json, ...) so we include a fast path for strings.
864+
static inline Py_ALWAYS_INLINE Py_hash_t
865+
_PyObject_HashDictKey(PyObject *op)
864866
{
865867
if (PyUnicode_CheckExact(op)) {
866868
Py_hash_t hash = FT_ATOMIC_LOAD_SSIZE_RELAXED(

Modules/_collectionsmodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2565,7 +2565,7 @@ _collections__count_elements_impl(PyObject *module, PyObject *mapping,
25652565
if (key == NULL)
25662566
break;
25672567

2568-
hash = _PyObject_HashFast(key);
2568+
hash = _PyObject_HashDictKey(key);
25692569
if (hash == -1) {
25702570
goto done;
25712571
}

Objects/dictobject.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2281,7 +2281,7 @@ dict_getitem(PyObject *op, PyObject *key, const char *warnmsg)
22812281
}
22822282
PyDictObject *mp = (PyDictObject *)op;
22832283

2284-
Py_hash_t hash = _PyObject_HashFast(key);
2284+
Py_hash_t hash = _PyObject_HashDictKey(key);
22852285
if (hash == -1) {
22862286
PyErr_FormatUnraisable(warnmsg);
22872287
return NULL;
@@ -2349,7 +2349,7 @@ _PyDict_LookupIndex(PyDictObject *mp, PyObject *key)
23492349
assert(PyDict_CheckExact((PyObject*)mp));
23502350
assert(PyUnicode_CheckExact(key));
23512351

2352-
Py_hash_t hash = _PyObject_HashFast(key);
2352+
Py_hash_t hash = _PyObject_HashDictKey(key);
23532353
if (hash == -1) {
23542354
dict_unhashable_type(key);
23552355
return -1;
@@ -2446,7 +2446,7 @@ PyDict_GetItemRef(PyObject *op, PyObject *key, PyObject **result)
24462446
return -1;
24472447
}
24482448

2449-
Py_hash_t hash = _PyObject_HashFast(key);
2449+
Py_hash_t hash = _PyObject_HashDictKey(key);
24502450
if (hash == -1) {
24512451
dict_unhashable_type(key);
24522452
*result = NULL;
@@ -2462,7 +2462,7 @@ _PyDict_GetItemRef_Unicode_LockHeld(PyDictObject *op, PyObject *key, PyObject **
24622462
ASSERT_DICT_LOCKED(op);
24632463
assert(PyUnicode_CheckExact(key));
24642464

2465-
Py_hash_t hash = _PyObject_HashFast(key);
2465+
Py_hash_t hash = _PyObject_HashDictKey(key);
24662466
if (hash == -1) {
24672467
dict_unhashable_type(key);
24682468
*result = NULL;
@@ -2500,7 +2500,7 @@ PyDict_GetItemWithError(PyObject *op, PyObject *key)
25002500
PyErr_BadInternalCall();
25012501
return NULL;
25022502
}
2503-
hash = _PyObject_HashFast(key);
2503+
hash = _PyObject_HashDictKey(key);
25042504
if (hash == -1) {
25052505
dict_unhashable_type(key);
25062506
return NULL;
@@ -2571,7 +2571,7 @@ _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key)
25712571
Py_hash_t hash;
25722572
PyObject *value;
25732573

2574-
hash = _PyObject_HashFast(key);
2574+
hash = _PyObject_HashDictKey(key);
25752575
if (hash == -1) {
25762576
return NULL;
25772577
}
@@ -2595,7 +2595,7 @@ _PyDict_LoadGlobalStackRef(PyDictObject *globals, PyDictObject *builtins, PyObje
25952595
Py_ssize_t ix;
25962596
Py_hash_t hash;
25972597

2598-
hash = _PyObject_HashFast(key);
2598+
hash = _PyObject_HashDictKey(key);
25992599
if (hash == -1) {
26002600
*res = PyStackRef_NULL;
26012601
return;
@@ -2658,7 +2658,7 @@ setitem_take2_lock_held(PyDictObject *mp, PyObject *key, PyObject *value)
26582658
assert(key);
26592659
assert(value);
26602660
assert(PyDict_Check(mp));
2661-
Py_hash_t hash = _PyObject_HashFast(key);
2661+
Py_hash_t hash = _PyObject_HashDictKey(key);
26622662
if (hash == -1) {
26632663
dict_unhashable_type(key);
26642664
Py_DECREF(key);
@@ -2810,7 +2810,7 @@ int
28102810
PyDict_DelItem(PyObject *op, PyObject *key)
28112811
{
28122812
assert(key);
2813-
Py_hash_t hash = _PyObject_HashFast(key);
2813+
Py_hash_t hash = _PyObject_HashDictKey(key);
28142814
if (hash == -1) {
28152815
dict_unhashable_type(key);
28162816
return -1;
@@ -3138,7 +3138,7 @@ pop_lock_held(PyObject *op, PyObject *key, PyObject **result)
31383138
return 0;
31393139
}
31403140

3141-
Py_hash_t hash = _PyObject_HashFast(key);
3141+
Py_hash_t hash = _PyObject_HashDictKey(key);
31423142
if (hash == -1) {
31433143
dict_unhashable_type(key);
31443144
if (result) {
@@ -3472,7 +3472,7 @@ dict_subscript(PyObject *self, PyObject *key)
34723472
Py_hash_t hash;
34733473
PyObject *value;
34743474

3475-
hash = _PyObject_HashFast(key);
3475+
hash = _PyObject_HashDictKey(key);
34763476
if (hash == -1) {
34773477
dict_unhashable_type(key);
34783478
return NULL;
@@ -4353,7 +4353,7 @@ dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value)
43534353
Py_hash_t hash;
43544354
Py_ssize_t ix;
43554355

4356-
hash = _PyObject_HashFast(key);
4356+
hash = _PyObject_HashDictKey(key);
43574357
if (hash == -1) {
43584358
dict_unhashable_type(key);
43594359
return NULL;
@@ -4386,7 +4386,7 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
43864386
return -1;
43874387
}
43884388

4389-
hash = _PyObject_HashFast(key);
4389+
hash = _PyObject_HashDictKey(key);
43904390
if (hash == -1) {
43914391
dict_unhashable_type(key);
43924392
if (result) {
@@ -4816,7 +4816,7 @@ static PyMethodDef mapp_methods[] = {
48164816
int
48174817
PyDict_Contains(PyObject *op, PyObject *key)
48184818
{
4819-
Py_hash_t hash = _PyObject_HashFast(key);
4819+
Py_hash_t hash = _PyObject_HashDictKey(key);
48204820
if (hash == -1) {
48214821
dict_unhashable_type(key);
48224822
return -1;
@@ -6903,7 +6903,7 @@ int
69036903
_PyDict_SetItem_LockHeld(PyDictObject *dict, PyObject *name, PyObject *value)
69046904
{
69056905
if (value == NULL) {
6906-
Py_hash_t hash = _PyObject_HashFast(name);
6906+
Py_hash_t hash = _PyObject_HashDictKey(name);
69076907
if (hash == -1) {
69086908
dict_unhashable_type(name);
69096909
return -1;

Objects/setobject.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ set_unhashable_type(PyObject *key)
231231
int
232232
_PySet_AddTakeRef(PySetObject *so, PyObject *key)
233233
{
234-
Py_hash_t hash = _PyObject_HashFast(key);
234+
Py_hash_t hash = PyObject_Hash(key);
235235
if (hash == -1) {
236236
set_unhashable_type(key);
237237
Py_DECREF(key);
@@ -400,7 +400,7 @@ set_discard_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
400400
static int
401401
set_add_key(PySetObject *so, PyObject *key)
402402
{
403-
Py_hash_t hash = _PyObject_HashFast(key);
403+
Py_hash_t hash = PyObject_Hash(key);
404404
if (hash == -1) {
405405
set_unhashable_type(key);
406406
return -1;
@@ -411,7 +411,7 @@ set_add_key(PySetObject *so, PyObject *key)
411411
static int
412412
set_contains_key(PySetObject *so, PyObject *key)
413413
{
414-
Py_hash_t hash = _PyObject_HashFast(key);
414+
Py_hash_t hash = PyObject_Hash(key);
415415
if (hash == -1) {
416416
set_unhashable_type(key);
417417
return -1;
@@ -422,7 +422,7 @@ set_contains_key(PySetObject *so, PyObject *key)
422422
static int
423423
set_discard_key(PySetObject *so, PyObject *key)
424424
{
425-
Py_hash_t hash = _PyObject_HashFast(key);
425+
Py_hash_t hash = PyObject_Hash(key);
426426
if (hash == -1) {
427427
set_unhashable_type(key);
428428
return -1;

Objects/typeobject.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3749,7 +3749,7 @@ solid_base(PyTypeObject *type)
37493749
// or when __bases__ is re-assigned. Since the slots are read without atomic
37503750
// operations and without locking, we can only safely update them while the
37513751
// world is stopped. However, with the world stopped, we are very limited on
3752-
// which APIs can be safely used. For example, calling _PyObject_HashFast()
3752+
// which APIs can be safely used. For example, calling _PyObject_HashDictKey()
37533753
// or _PyDict_GetItemRef_KnownHash() are not safe and can potentially cause
37543754
// deadlocks. Hashing can be re-entrant and _PyDict_GetItemRef_KnownHash can
37553755
// acquire a lock if the dictionary is not owned by the current thread, to
@@ -5898,7 +5898,7 @@ PyObject_GetItemData(PyObject *obj)
58985898
static PyObject *
58995899
find_name_in_mro(PyTypeObject *type, PyObject *name, int *error)
59005900
{
5901-
Py_hash_t hash = _PyObject_HashFast(name);
5901+
Py_hash_t hash = _PyObject_HashDictKey(name);
59025902
if (hash == -1) {
59035903
*error = -1;
59045904
return NULL;

0 commit comments

Comments
 (0)