[vm, compiler] Fix high hash collision rate in a large run of sequential double values.

TEST=many_double_literals_test
Change-Id: Ieddaa44ddc0cc67eb8913a62daab44b5579123a2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/506140
Reviewed-by: Tess Strickland <sstrickl@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak
2026-05-26 06:42:00 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 0124cf29fe
commit 58ea063ca8
5 changed files with 31 additions and 37 deletions
@@ -640,16 +640,14 @@ void AssemblerBase::Stop(const char* message) {
uword ObjIndexPair::Hash(Key key) {
switch (key.type()) {
case ObjectPoolBuilderEntry::kImmediate128:
return key.imm128_.int_storage[0] ^ key.imm128_.int_storage[1] ^
key.imm128_.int_storage[2] ^ key.imm128_.int_storage[3];
return HashBytes(&key.imm128_, sizeof(key.imm128_));
#if defined(TARGET_ARCH_IS_32_BIT)
case ObjectPoolBuilderEntry::kImmediate64:
return key.imm64_;
return HashBytes(&key.imm64_, sizeof(key.imm64_));
#endif
case ObjectPoolBuilderEntry::kImmediate:
case ObjectPoolBuilderEntry::kNativeFunction:
return key.imm_;
return HashBytes(&key.imm_, sizeof(key.imm_));
case ObjectPoolBuilderEntry::kTaggedObject:
return ObjectHash(*key.obj_);
}
+14 -7
View File
@@ -28,14 +28,21 @@ inline uint32_t FinalizeHash(uint32_t hash, intptr_t hashbits = kBitsPerInt32) {
return (hash == 0) ? 1 : hash;
}
inline uint32_t HashBytes(const uint8_t* bytes, intptr_t size) {
uint32_t hash = size;
while (size > 0) {
hash = CombineHashes(hash, *bytes);
bytes++;
size--;
inline uint32_t HashBytes(const void* bytes,
intptr_t len,
intptr_t hashbits = kBitsPerInt32) {
if (len == 0) {
return 1;
}
return hash;
uint32_t hash = len;
const intptr_t chunks = len / kInt32Size;
for (intptr_t i = 0; i < chunks; i++) {
hash = CombineHashes(hash, reinterpret_cast<const uint32_t*>(bytes)[i]);
}
for (intptr_t i = chunks * kInt32Size; i < len; i++) {
hash = CombineHashes(hash, reinterpret_cast<const uint8_t*>(bytes)[i]);
}
return FinalizeHash(hash, hashbits);
}
} // namespace dart
+11 -19
View File
@@ -25978,13 +25978,14 @@ float Float32x4::w() const {
}
bool Float32x4::CanonicalizeEquals(const Instance& other) const {
NoSafepointScope no_safepoint;
return memcmp(&untag()->value_, Float32x4::Cast(other).untag()->value_,
sizeof(simd128_value_t)) == 0;
}
uint32_t Float32x4::CanonicalizeHash() const {
return HashBytes(reinterpret_cast<const uint8_t*>(&untag()->value_),
sizeof(simd128_value_t));
NoSafepointScope no_safepoint;
return HashBytes(&untag()->value_, sizeof(simd128_value_t), kHashBits);
}
const char* Float32x4::ToCString() const {
@@ -26062,13 +26063,14 @@ void Int32x4::set_value(simd128_value_t value) const {
}
bool Int32x4::CanonicalizeEquals(const Instance& other) const {
NoSafepointScope no_safepoint;
return memcmp(&untag()->value_, Int32x4::Cast(other).untag()->value_,
sizeof(simd128_value_t)) == 0;
}
uint32_t Int32x4::CanonicalizeHash() const {
return HashBytes(reinterpret_cast<const uint8_t*>(&untag()->value_),
sizeof(simd128_value_t));
NoSafepointScope no_safepoint;
return HashBytes(&untag()->value_, sizeof(simd128_value_t), kHashBits);
}
const char* Int32x4::ToCString() const {
@@ -26122,13 +26124,14 @@ void Float64x2::set_value(simd128_value_t value) const {
}
bool Float64x2::CanonicalizeEquals(const Instance& other) const {
NoSafepointScope no_safepoint;
return memcmp(&untag()->value_, Float64x2::Cast(other).untag()->value_,
sizeof(simd128_value_t)) == 0;
}
uint32_t Float64x2::CanonicalizeHash() const {
return HashBytes(reinterpret_cast<const uint8_t*>(&untag()->value_),
sizeof(simd128_value_t));
NoSafepointScope no_safepoint;
return HashBytes(&untag()->value_, sizeof(simd128_value_t), kHashBits);
}
const char* Float64x2::ToCString() const {
@@ -26181,19 +26184,8 @@ bool TypedData::CanonicalizeEquals(const Instance& other) const {
}
uint32_t TypedData::CanonicalizeHash() const {
const intptr_t len = this->LengthInBytes();
if (len == 0) {
return 1;
}
uint32_t hash = len;
const intptr_t chunks = len / kInt32Size;
for (intptr_t i = 0; i < chunks; i++) {
hash = CombineHashes(hash, GetUint32(i * kInt32Size));
}
for (intptr_t i = chunks * kInt32Size; i < len; i++) {
hash = CombineHashes(hash, GetUint8(i));
}
return FinalizeHash(hash, kHashBits);
NoSafepointScope no_safepoint;
return HashBytes(DataAddr(0), LengthInBytes(), kHashBits);
}
TypedDataPtr TypedData::New(intptr_t class_id,
+1 -1
View File
@@ -5959,7 +5959,7 @@ class Instructions : public Object {
uint32_t Hash() const { return Hash(ptr()); }
static uint32_t Hash(const InstructionsPtr instr) {
return HashBytes(reinterpret_cast<const uint8_t*>(PayloadStart(instr)),
return HashBytes(reinterpret_cast<const void*>(PayloadStart(instr)),
Size(instr));
}
+2 -5
View File
@@ -162,10 +162,7 @@ struct Span {
return memcmp(data, other.data, length * sizeof(T)) == 0;
}
uword Hash() const {
return HashBytes(reinterpret_cast<const uint8_t*>(data),
length * sizeof(T));
}
uword Hash() const { return HashBytes(data, length * sizeof(T)); }
};
template <typename T, typename Allocator>
@@ -197,7 +194,7 @@ struct Interned {
if constexpr (DefinesHashAndEquality<T>) {
return data.Hash();
} else {
return HashBytes(reinterpret_cast<const uint8_t*>(&data), sizeof(T));
return HashBytes(&data, sizeof(T));
}
}