diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index fb50acd62da5eb..bd153a4f97c697 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -858,9 +858,11 @@ _PyObject_IS_GC(PyObject *obj) && (type->tp_is_gc == NULL || type->tp_is_gc(obj))); } -// Fast inlined version of PyObject_Hash() -static inline Py_hash_t -_PyObject_HashFast(PyObject *op) +// Fast inlined version of PyObject_Hash(). Dictionaries are very +// likely to include string keys (class and instance attributes, +// json, ...) so we include a fast path for strings. +static inline Py_ALWAYS_INLINE Py_hash_t +_PyObject_HashDictKey(PyObject *op) { if (PyUnicode_CheckExact(op)) { Py_hash_t hash = PyUnstable_Unicode_GET_CACHED_HASH(op); diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 3ba48d5d9d3c64..15bc9af3887bfa 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -2565,7 +2565,7 @@ _collections__count_elements_impl(PyObject *module, PyObject *mapping, if (key == NULL) break; - hash = _PyObject_HashFast(key); + hash = _PyObject_HashDictKey(key); if (hash == -1) { goto done; } diff --git a/Objects/dictobject.c b/Objects/dictobject.c index e0eef7b46df4b2..2c512236e431f1 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2285,7 +2285,7 @@ dict_getitem(PyObject *op, PyObject *key, const char *warnmsg) } PyDictObject *mp = (PyDictObject *)op; - Py_hash_t hash = _PyObject_HashFast(key); + Py_hash_t hash = _PyObject_HashDictKey(key); if (hash == -1) { PyErr_FormatUnraisable(warnmsg); return NULL; @@ -2353,7 +2353,7 @@ _PyDict_LookupIndex(PyDictObject *mp, PyObject *key) assert(PyDict_CheckExact((PyObject*)mp)); assert(PyUnicode_CheckExact(key)); - Py_hash_t hash = _PyObject_HashFast(key); + Py_hash_t hash = _PyObject_HashDictKey(key); if (hash == -1) { dict_unhashable_type(key); return -1; @@ -2450,7 +2450,7 @@ PyDict_GetItemRef(PyObject *op, PyObject *key, PyObject **result) return -1; } - Py_hash_t hash = _PyObject_HashFast(key); + Py_hash_t hash = _PyObject_HashDictKey(key); if (hash == -1) { dict_unhashable_type(key); *result = NULL; @@ -2466,7 +2466,7 @@ _PyDict_GetItemRef_Unicode_LockHeld(PyDictObject *op, PyObject *key, PyObject ** ASSERT_DICT_LOCKED(op); assert(PyUnicode_CheckExact(key)); - Py_hash_t hash = _PyObject_HashFast(key); + Py_hash_t hash = _PyObject_HashDictKey(key); if (hash == -1) { dict_unhashable_type(key); *result = NULL; @@ -2504,7 +2504,7 @@ PyDict_GetItemWithError(PyObject *op, PyObject *key) PyErr_BadInternalCall(); return NULL; } - hash = _PyObject_HashFast(key); + hash = _PyObject_HashDictKey(key); if (hash == -1) { dict_unhashable_type(key); return NULL; @@ -2563,7 +2563,7 @@ _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key) Py_hash_t hash; PyObject *value; - hash = _PyObject_HashFast(key); + hash = _PyObject_HashDictKey(key); if (hash == -1) { return NULL; } @@ -2587,7 +2587,7 @@ _PyDict_LoadGlobalStackRef(PyDictObject *globals, PyDictObject *builtins, PyObje Py_ssize_t ix; Py_hash_t hash; - hash = _PyObject_HashFast(key); + hash = _PyObject_HashDictKey(key); if (hash == -1) { *res = PyStackRef_NULL; return; @@ -2650,7 +2650,7 @@ setitem_take2_lock_held(PyDictObject *mp, PyObject *key, PyObject *value) assert(key); assert(value); assert(PyDict_Check(mp)); - Py_hash_t hash = _PyObject_HashFast(key); + Py_hash_t hash = _PyObject_HashDictKey(key); if (hash == -1) { dict_unhashable_type(key); Py_DECREF(key); @@ -2802,7 +2802,7 @@ int PyDict_DelItem(PyObject *op, PyObject *key) { assert(key); - Py_hash_t hash = _PyObject_HashFast(key); + Py_hash_t hash = _PyObject_HashDictKey(key); if (hash == -1) { dict_unhashable_type(key); return -1; @@ -3130,7 +3130,7 @@ pop_lock_held(PyObject *op, PyObject *key, PyObject **result) return 0; } - Py_hash_t hash = _PyObject_HashFast(key); + Py_hash_t hash = _PyObject_HashDictKey(key); if (hash == -1) { dict_unhashable_type(key); if (result) { @@ -3464,7 +3464,7 @@ dict_subscript(PyObject *self, PyObject *key) Py_hash_t hash; PyObject *value; - hash = _PyObject_HashFast(key); + hash = _PyObject_HashDictKey(key); if (hash == -1) { dict_unhashable_type(key); return NULL; @@ -4345,7 +4345,7 @@ dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value) Py_hash_t hash; Py_ssize_t ix; - hash = _PyObject_HashFast(key); + hash = _PyObject_HashDictKey(key); if (hash == -1) { dict_unhashable_type(key); return NULL; @@ -4379,7 +4379,7 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu return -1; } - hash = _PyObject_HashFast(key); + hash = _PyObject_HashDictKey(key); if (hash == -1) { dict_unhashable_type(key); if (result) { @@ -4792,7 +4792,7 @@ static PyMethodDef mapp_methods[] = { int PyDict_Contains(PyObject *op, PyObject *key) { - Py_hash_t hash = _PyObject_HashFast(key); + Py_hash_t hash = _PyObject_HashDictKey(key); if (hash == -1) { dict_unhashable_type(key); return -1; @@ -6841,7 +6841,7 @@ int _PyDict_SetItem_LockHeld(PyDictObject *dict, PyObject *name, PyObject *value) { if (value == NULL) { - Py_hash_t hash = _PyObject_HashFast(name); + Py_hash_t hash = _PyObject_HashDictKey(name); if (hash == -1) { dict_unhashable_type(name); return -1; diff --git a/Objects/setobject.c b/Objects/setobject.c index 85f4d7d403178a..3b0f3968aa3a2f 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -240,7 +240,7 @@ set_unhashable_type(PyObject *key) int _PySet_AddTakeRef(PySetObject *so, PyObject *key) { - Py_hash_t hash = _PyObject_HashFast(key); + Py_hash_t hash = PyObject_Hash(key); if (hash == -1) { set_unhashable_type(key); Py_DECREF(key); @@ -409,7 +409,7 @@ set_discard_entry(PySetObject *so, PyObject *key, Py_hash_t hash) static int set_add_key(PySetObject *so, PyObject *key) { - Py_hash_t hash = _PyObject_HashFast(key); + Py_hash_t hash = PyObject_Hash(key); if (hash == -1) { set_unhashable_type(key); return -1; @@ -420,7 +420,7 @@ set_add_key(PySetObject *so, PyObject *key) static int set_contains_key(PySetObject *so, PyObject *key) { - Py_hash_t hash = _PyObject_HashFast(key); + Py_hash_t hash = PyObject_Hash(key); if (hash == -1) { set_unhashable_type(key); return -1; @@ -431,7 +431,7 @@ set_contains_key(PySetObject *so, PyObject *key) static int set_discard_key(PySetObject *so, PyObject *key) { - Py_hash_t hash = _PyObject_HashFast(key); + Py_hash_t hash = PyObject_Hash(key); if (hash == -1) { set_unhashable_type(key); return -1; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index cbe0215359e29d..bc954add0a3a42 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3780,7 +3780,7 @@ solid_base(PyTypeObject *type) // or when __bases__ is re-assigned. Since the slots are read without atomic // operations and without locking, we can only safely update them while the // world is stopped. However, with the world stopped, we are very limited on -// which APIs can be safely used. For example, calling _PyObject_HashFast() +// which APIs can be safely used. For example, calling _PyObject_HashDictKey() // or _PyDict_GetItemRef_KnownHash() are not safe and can potentially cause // deadlocks. Hashing can be re-entrant and _PyDict_GetItemRef_KnownHash can // acquire a lock if the dictionary is not owned by the current thread, to @@ -5972,7 +5972,7 @@ PyObject_GetItemData(PyObject *obj) static PyObject * find_name_in_mro(PyTypeObject *type, PyObject *name, int *error) { - Py_hash_t hash = _PyObject_HashFast(name); + Py_hash_t hash = _PyObject_HashDictKey(name); if (hash == -1) { *error = -1; return NULL;