Bug 1718516 - Fix AddToHash of 64-bits numbers on 32-bits platforms. r=nika,anba

Differential Revision: https://phabricator.services.mozilla.com/D197302
This commit is contained in:
Mike Hommey 2024-01-09 01:48:31 +00:00
parent 4bb1a054be
commit 6e1293b5f7
2 changed files with 15 additions and 25 deletions

View File

@ -7639,18 +7639,7 @@ void MacroAssembler::prepareHashNonGCThing(ValueOperand value, Register result,
move64(value.toRegister64(), r64);
rshift64Arithmetic(Imm32(32), r64);
#else
// TODO: This seems like a bug in mozilla::detail::AddUintptrToHash().
// The uint64_t input is first converted to uintptr_t and then back to
// uint64_t. But |uint64_t(uintptr_t(bits))| actually only clears the high
// bits, so this computation:
//
// aValue = uintptr_t(bits)
// v2 = static_cast<uint32_t>(static_cast<uint64_t>(aValue) >> 32)
//
// really just sets |v2 = 0|. And that means the xor-operation in AddU32ToHash
// can be optimized away, because |x ^ 0 = x|.
//
// Filed as bug 1718516.
move32(value.typeReg(), temp);
#endif
// mozilla::WrappingMultiply(kGoldenRatioU32, RotateLeft5(aHash) ^ aValue);
@ -7660,9 +7649,7 @@ void MacroAssembler::prepareHashNonGCThing(ValueOperand value, Register result,
// mozilla::WrappingMultiply(kGoldenRatioU32, RotateLeft5(aHash) ^ aValue);
// with |aHash = <above hash>| and |aValue = v2|.
rotateLeft(Imm32(5), result, result);
#ifdef JS_PUNBOX64
xor32(temp, result);
#endif
// Combine |mul32| and |scrambleHashCode| by directly multiplying with
// |kGoldenRatioU32 * kGoldenRatioU32|.

View File

@ -153,17 +153,20 @@ constexpr HashNumber AddU32ToHash(HashNumber aHash, uint32_t aValue) {
}
/**
* AddUintptrToHash takes sizeof(uintptr_t) as a template parameter.
* AddUintNToHash takes sizeof(int_type) as a template parameter.
* Changes to these functions need to be propagated to
* MacroAssembler::prepareHashNonGCThing, which inlines them manually for
* the JIT.
*/
template <size_t PtrSize>
constexpr HashNumber AddUintptrToHash(HashNumber aHash, uintptr_t aValue) {
template <size_t Size>
constexpr HashNumber AddUintNToHash(HashNumber aHash, uint64_t aValue) {
return AddU32ToHash(aHash, static_cast<uint32_t>(aValue));
}
template <>
inline HashNumber AddUintptrToHash<8>(HashNumber aHash, uintptr_t aValue) {
inline HashNumber AddUintNToHash<8>(HashNumber aHash, uint64_t aValue) {
uint32_t v1 = static_cast<uint32_t>(aValue);
uint32_t v2 = static_cast<uint32_t>(static_cast<uint64_t>(aValue) >> 32);
uint32_t v2 = static_cast<uint32_t>(aValue >> 32);
return AddU32ToHash(AddU32ToHash(aHash, v1), v2);
}
@ -196,23 +199,23 @@ template <typename A>
static_assert(sizeof(aA) == sizeof(uintptr_t), "Strange pointer!");
return detail::AddUintptrToHash<sizeof(uintptr_t)>(aHash, uintptr_t(aA));
return detail::AddUintNToHash<sizeof(uintptr_t)>(aHash, uintptr_t(aA));
}
// We use AddUintptrToHash() for hashing all integral types. 8-byte integral
// We use AddUintNToHash() for hashing all integral types. 8-byte integral
// types are treated the same as 64-bit pointers, and smaller integral types are
// first implicitly converted to 32 bits and then passed to AddUintptrToHash()
// first implicitly converted to 32 bits and then passed to AddUintNToHash()
// to be hashed.
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
[[nodiscard]] constexpr HashNumber AddToHash(HashNumber aHash, T aA) {
return detail::AddUintptrToHash<sizeof(T)>(aHash, aA);
return detail::AddUintNToHash<sizeof(T)>(aHash, aA);
}
template <typename T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
[[nodiscard]] constexpr HashNumber AddToHash(HashNumber aHash, T aA) {
// Hash using AddUintptrToHash with the underlying type of the enum type
// Hash using AddUintNToHash with the underlying type of the enum type
using UnderlyingType = typename std::underlying_type<T>::type;
return detail::AddUintptrToHash<sizeof(UnderlyingType)>(
return detail::AddUintNToHash<sizeof(UnderlyingType)>(
aHash, static_cast<UnderlyingType>(aA));
}