&& (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.
+// This function should not be used in a collection if str is not
+// very likely, since it is slower than PyObject_Hash() on types
+// other than str. See gh-137759.
+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);
if (key == NULL)
break;
- hash = _PyObject_HashFast(key);
+ hash = _PyObject_HashDictKey(key);
if (hash == -1) {
goto done;
}
}
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;
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;
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;
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;
PyErr_BadInternalCall();
return NULL;
}
- hash = _PyObject_HashFast(key);
+ hash = _PyObject_HashDictKey(key);
if (hash == -1) {
dict_unhashable_type(op, key);
return NULL;
Py_hash_t hash;
PyObject *value;
- hash = _PyObject_HashFast(key);
+ hash = _PyObject_HashDictKey(key);
if (hash == -1) {
return NULL;
}
Py_ssize_t ix;
Py_hash_t hash;
- hash = _PyObject_HashFast(key);
+ hash = _PyObject_HashDictKey(key);
if (hash == -1) {
*res = PyStackRef_NULL;
return;
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);
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;
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) {
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;
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;
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) {
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;
}
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;
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);
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;
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;
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;
{
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);
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);
}
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;
// 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
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;