diff --git a/Objects/dictobject.c b/Objects/dictobject.c index b33a273dac3b95..78317740761083 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -129,7 +129,7 @@ As a consequence of this, split keys have a maximum size of 16. #include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_setobject.h" // _PySet_NextEntry() -#include "pycore_tuple.h" // _PyTuple_Recycle() +#include "pycore_tuple.h" // _PyTuple_Recycle(), _PyTuple_HASH_XXPRIME1, _PyTuple_HASH_XXPRIME2, _PyTuple_HASH_XXPRIME5, _PyTuple_HASH_XXROTATE #include "pycore_unicodeobject.h" // _PyUnicode_InternImmortal() #include "stringlib/eq.h" // unicode_eq() @@ -8222,10 +8222,27 @@ frozendict_repr(PyObject *self) return res; } -static Py_uhash_t -_shuffle_bits(Py_uhash_t h) +// Code unrolled from tuple_hash() for 2 values +static inline Py_uhash_t +_tuple2_xxhash(Py_uhash_t h1, Py_uhash_t h2) { - return ((h ^ 89869747UL) ^ (h << 16)) * 3644798167UL; + Py_uhash_t acc = _PyTuple_HASH_XXPRIME_5; + + acc += h1 * _PyTuple_HASH_XXPRIME_2; + acc = _PyTuple_HASH_XXROTATE(acc); + acc *= _PyTuple_HASH_XXPRIME_1; + + acc += h2 * _PyTuple_HASH_XXPRIME_2; + acc = _PyTuple_HASH_XXROTATE(acc); + acc *= _PyTuple_HASH_XXPRIME_1; + + acc += 2 ^ (_PyTuple_HASH_XXPRIME_5 ^ 3527539UL); + + if (acc == (Py_uhash_t)-1) { + acc = 1546275796; + } + + return acc; } // Code copied from frozenset_hash() @@ -8239,7 +8256,7 @@ frozendict_hash(PyObject *op) } PyDictObject *mp = _PyAnyDict_CAST(op); - Py_uhash_t hash = 0; + Py_uhash_t hash = 0xfd1c74; // start at a different value from frozenset to avoid collision with frozenset(frozendict.items()) PyObject *key, *value; // borrowed refs Py_ssize_t pos = 0; @@ -8248,13 +8265,11 @@ frozendict_hash(PyObject *op) if (key_hash == -1) { return -1; } - hash ^= _shuffle_bits(key_hash); - Py_hash_t value_hash = PyObject_Hash(value); if (value_hash == -1) { return -1; } - hash ^= _shuffle_bits(value_hash); + hash ^= _tuple2_xxhash(key_hash, value_hash); } /* Factor in the number of active entries */