Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions Include/internal/pycore_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -836,9 +836,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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe explain that this function should not be used in a collection if str is not very likely, since this function is slower than PyObject_Hash() on types other than str.

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);
Expand Down
2 changes: 1 addition & 1 deletion Modules/_collectionsmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2583,7 +2583,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;
}
Expand Down
30 changes: 15 additions & 15 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2357,7 +2357,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;
Expand Down Expand Up @@ -2429,7 +2429,7 @@ _PyDict_LookupIndexAndValue(PyDictObject *mp, PyObject *key, PyObject **value)
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((PyObject*)mp, key);
return -1;
Expand Down Expand Up @@ -2533,7 +2533,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(op, key);
*result = NULL;
Expand All @@ -2549,7 +2549,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((PyObject*)op, key);
*result = NULL;
Expand Down Expand Up @@ -2587,7 +2587,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(op, key);
return NULL;
Expand Down Expand Up @@ -2646,7 +2646,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;
}
Expand All @@ -2670,7 +2670,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;
Expand Down Expand Up @@ -2747,7 +2747,7 @@ setitem_take2_lock_held_known_hash(PyDictObject *mp, PyObject *key, PyObject *va
static int
setitem_take2_lock_held(PyDictObject *mp, PyObject *key, PyObject *value)
{
Py_hash_t hash = _PyObject_HashFast(key);
Py_hash_t hash = _PyObject_HashDictKey(key);
if (hash == -1) {
dict_unhashable_type((PyObject*)mp, key);
Py_DECREF(key);
Expand Down Expand Up @@ -2925,7 +2925,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(op, key);
return -1;
Expand Down Expand Up @@ -3269,7 +3269,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(op, key);
if (result) {
Expand Down Expand Up @@ -3707,7 +3707,7 @@ _PyDict_SubscriptKnownHash(PyObject *self, PyObject *key, Py_hash_t hash)
PyObject *
_PyDict_Subscript(PyObject *self, PyObject *key)
{
Py_hash_t hash = _PyObject_HashFast(key);
Py_hash_t hash = _PyObject_HashDictKey(key);
if (hash == -1) {
dict_unhashable_type(self, key);
return NULL;
Expand Down Expand Up @@ -4659,7 +4659,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((PyObject*)self, key);
return NULL;
Expand Down Expand Up @@ -4696,7 +4696,7 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
Py_hash_t hash;
Py_ssize_t ix;

hash = _PyObject_HashFast(key);
hash = _PyObject_HashDictKey(key);
if (hash == -1) {
dict_unhashable_type(d, key);
if (result) {
Expand Down Expand Up @@ -5137,7 +5137,7 @@ static PyMethodDef mapp_methods[] = {
static int
dict_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(op, key);
return -1;
Expand Down Expand Up @@ -7243,7 +7243,7 @@ _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((PyObject*)dict, name);
return -1;
Expand Down
14 changes: 7 additions & 7 deletions Objects/setobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,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);
Expand Down Expand Up @@ -600,7 +600,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;
Expand All @@ -611,7 +611,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;
Expand All @@ -622,7 +622,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;
Expand Down Expand Up @@ -2514,7 +2514,7 @@ _PySet_Contains(PySetObject *so, PyObject *key)
{
assert(so);

Py_hash_t hash = _PyObject_HashFast(key);
Py_hash_t hash = PyObject_Hash(key);
if (hash == -1) {
if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) {
set_unhashable_type(key);
Expand Down Expand Up @@ -2574,7 +2574,7 @@ static PyObject *
frozenset___contains___impl(PySetObject *so, PyObject *key)
/*[clinic end generated code: output=2301ed91bc3a6dd5 input=2f04922a98d8bab7]*/
{
Py_hash_t hash = _PyObject_HashFast(key);
Py_hash_t hash = PyObject_Hash(key);
if (hash == -1) {
if (!PySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) {
set_unhashable_type(key);
Expand Down Expand Up @@ -3037,7 +3037,7 @@ PySet_Contains(PyObject *anyset, PyObject *key)
}

PySetObject *so = (PySetObject *)anyset;
Py_hash_t hash = _PyObject_HashFast(key);
Py_hash_t hash = PyObject_Hash(key);
if (hash == -1) {
set_unhashable_type(key);
return -1;
Expand Down
4 changes: 2 additions & 2 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -3788,7 +3788,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
Expand Down Expand Up @@ -6129,7 +6129,7 @@ PyObject_GetItemData(PyObject *obj)
static int
find_name_in_mro(PyTypeObject *type, PyObject *name, _PyStackRef *out)
{
Py_hash_t hash = _PyObject_HashFast(name);
Py_hash_t hash = _PyObject_HashDictKey(name);
if (hash == -1) {
PyErr_Clear();
return -1;
Expand Down
Loading