Skip to content

GH-137759:Limit _PyObject_HashFast to dicts keys, rename it, and mark it as Py_ALWAYS_INLINE #137828

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
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 @@ -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 = FT_ATOMIC_LOAD_SSIZE_RELAXED(
Expand Down
2 changes: 1 addition & 1 deletion Modules/_collectionsmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
30 changes: 15 additions & 15 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2281,7 +2281,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 @@ -2349,7 +2349,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;
Expand Down Expand Up @@ -2446,7 +2446,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;
Expand All @@ -2462,7 +2462,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;
Expand Down Expand Up @@ -2500,7 +2500,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;
Expand Down Expand Up @@ -2571,7 +2571,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 @@ -2595,7 +2595,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 @@ -2658,7 +2658,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);
Expand Down Expand Up @@ -2810,7 +2810,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;
Expand Down Expand Up @@ -3138,7 +3138,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) {
Expand Down Expand Up @@ -3472,7 +3472,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;
Expand Down Expand Up @@ -4353,7 +4353,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;
Expand Down Expand Up @@ -4386,7 +4386,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) {
Expand Down Expand Up @@ -4816,7 +4816,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;
Expand Down Expand Up @@ -6903,7 +6903,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;
Expand Down
8 changes: 4 additions & 4 deletions Objects/setobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,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 @@ -400,7 +400,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 @@ -411,7 +411,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 @@ -422,7 +422,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
4 changes: 2 additions & 2 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -3749,7 +3749,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 @@ -5898,7 +5898,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;
Expand Down
Loading