diff --git a/src/ic/accessor-assembler.cc b/src/ic/accessor-assembler.cc index 98c7b39913..0989c61dea 100644 --- a/src/ic/accessor-assembler.cc +++ b/src/ic/accessor-assembler.cc @@ -2769,14 +2769,17 @@ TNode AccessorAssembler::StubCachePrimaryOffset(TNode name, return Signed(result); } -TNode AccessorAssembler::StubCacheSecondaryOffset( - TNode name, TNode seed) { +TNode AccessorAssembler::StubCacheSecondaryOffset(TNode name, + TNode map) { // See v8::internal::StubCache::SecondaryOffset(). // Use the seed from the primary cache in the secondary cache. TNode name32 = TruncateIntPtrToInt32(BitcastTaggedToWord(name)); - TNode hash = Int32Sub(TruncateIntPtrToInt32(seed), name32); - hash = Int32Add(hash, Int32Constant(StubCache::kSecondaryMagic)); + TNode map32 = TruncateIntPtrToInt32(BitcastTaggedToWord(map)); + // Base the offset on a simple combination of name and map. + TNode hash_a = Int32Add(map32, name32); + TNode hash_b = Word32Shr(hash_a, StubCache::kSecondaryKeyShift); + TNode hash = Int32Add(hash_a, hash_b); int32_t mask = (StubCache::kSecondaryTableSize - 1) << StubCache::kCacheIndexShift; TNode result = @@ -2846,7 +2849,7 @@ void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, { // Probe the secondary table. TNode secondary_offset = - StubCacheSecondaryOffset(name, primary_offset); + StubCacheSecondaryOffset(name, lookup_start_object_map); TryProbeStubCacheTable(stub_cache, kSecondary, secondary_offset, name, lookup_start_object_map, if_handler, var_handler, &miss); diff --git a/src/ic/accessor-assembler.h b/src/ic/accessor-assembler.h index 733559755d..3afcaa22f1 100644 --- a/src/ic/accessor-assembler.h +++ b/src/ic/accessor-assembler.h @@ -83,8 +83,8 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { return StubCachePrimaryOffset(name, map); } TNode StubCacheSecondaryOffsetForTesting(TNode name, - TNode seed) { - return StubCacheSecondaryOffset(name, seed); + TNode map) { + return StubCacheSecondaryOffset(name, map); } struct LoadICParameters { @@ -512,8 +512,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { enum StubCacheTable : int; TNode StubCachePrimaryOffset(TNode name, TNode map); - TNode StubCacheSecondaryOffset(TNode name, - TNode seed); + TNode StubCacheSecondaryOffset(TNode name, TNode map); void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id, TNode entry_offset, TNode name, diff --git a/src/ic/stub-cache.cc b/src/ic/stub-cache.cc index 8a58e7b32f..9cb242b38d 100644 --- a/src/ic/stub-cache.cc +++ b/src/ic/stub-cache.cc @@ -44,12 +44,14 @@ int StubCache::PrimaryOffset(Name name, Map map) { } // Hash algorithm for the secondary table. This algorithm is replicated in -// assembler for every architecture. Returns an index into the table that -// is scaled by 1 << kCacheIndexShift. -int StubCache::SecondaryOffset(Name name, int seed) { - // Use the seed from the primary cache in the secondary cache. +// assembler. This hash should be sufficiently different from the primary one +// in order to avoid collisions for minified code with short names. +// Returns an index into the table that is scaled by 1 << kCacheIndexShift. +int StubCache::SecondaryOffset(Name name, Map old_map) { uint32_t name_low32bits = static_cast(name.ptr()); - uint32_t key = (seed - name_low32bits) + kSecondaryMagic; + uint32_t map_low32bits = static_cast(old_map.ptr()); + uint32_t key = (map_low32bits + name_low32bits); + key = key + (key >> kSecondaryKeyShift); return key & ((kSecondaryTableSize - 1) << kCacheIndexShift); } @@ -57,8 +59,8 @@ int StubCache::PrimaryOffsetForTesting(Name name, Map map) { return PrimaryOffset(name, map); } -int StubCache::SecondaryOffsetForTesting(Name name, int seed) { - return SecondaryOffset(name, seed); +int StubCache::SecondaryOffsetForTesting(Name name, Map map) { + return SecondaryOffset(name, map); } #ifdef DEBUG @@ -93,11 +95,9 @@ void StubCache::Set(Name name, Map map, MaybeObject handler) { !primary->map.IsSmi()) { Map old_map = Map::cast(StrongTaggedValue::ToObject(isolate(), primary->map)); - int seed = PrimaryOffset( - Name::cast(StrongTaggedValue::ToObject(isolate(), primary->key)), - old_map); - int secondary_offset = SecondaryOffset( - Name::cast(StrongTaggedValue::ToObject(isolate(), primary->key)), seed); + Name old_name = + Name::cast(StrongTaggedValue::ToObject(isolate(), primary->key)); + int secondary_offset = SecondaryOffset(old_name, old_map); Entry* secondary = entry(secondary_, secondary_offset); *secondary = *primary; } @@ -116,7 +116,7 @@ MaybeObject StubCache::Get(Name name, Map map) { if (primary->key == name && primary->map == map) { return TaggedValue::ToMaybeObject(isolate(), primary->value); } - int secondary_offset = SecondaryOffset(name, primary_offset); + int secondary_offset = SecondaryOffset(name, map); Entry* secondary = entry(secondary_, secondary_offset); if (secondary->key == name && secondary->map == map) { return TaggedValue::ToMaybeObject(isolate(), secondary->value); diff --git a/src/ic/stub-cache.h b/src/ic/stub-cache.h index f8b3a3cdf2..a9e10f1311 100644 --- a/src/ic/stub-cache.h +++ b/src/ic/stub-cache.h @@ -90,15 +90,13 @@ class V8_EXPORT_PRIVATE StubCache { static const int kSecondaryTableBits = 9; static const int kSecondaryTableSize = (1 << kSecondaryTableBits); - // We compute the hash code for a map as follows: - // =
^ (
>> kMapKeyShift) + // Used to introduce more entropy from the higher bits of the Map address. + // This should fill in the masked out kCacheIndexShift-bits. static const int kMapKeyShift = kPrimaryTableBits + kCacheIndexShift; - - // Some magic number used in the secondary hash computation. - static const int kSecondaryMagic = 0xb16ca6e5; + static const int kSecondaryKeyShift = kSecondaryTableBits + kCacheIndexShift; static int PrimaryOffsetForTesting(Name name, Map map); - static int SecondaryOffsetForTesting(Name name, int seed); + static int SecondaryOffsetForTesting(Name name, Map map); // The constructor is made public only for the purposes of testing. explicit StubCache(Isolate* isolate); @@ -121,7 +119,7 @@ class V8_EXPORT_PRIVATE StubCache { // Hash algorithm for the secondary table. This algorithm is replicated in // assembler for every architecture. Returns an index into the table that // is scaled by 1 << kCacheIndexShift. - static int SecondaryOffset(Name name, int seed); + static int SecondaryOffset(Name name, Map map); // Compute the entry for a given offset in exactly the same way as // we do in generated code. We generate an hash code that already diff --git a/test/cctest/test-accessor-assembler.cc b/test/cctest/test-accessor-assembler.cc index 6e33cd1d02..9bb2d02af2 100644 --- a/test/cctest/test-accessor-assembler.cc +++ b/test/cctest/test-accessor-assembler.cc @@ -37,7 +37,7 @@ void TestStubCacheOffsetCalculation(StubCache::Table table) { result = primary_offset; } else { CHECK_EQ(StubCache::kSecondary, table); - result = m.StubCacheSecondaryOffsetForTesting(name, primary_offset); + result = m.StubCacheSecondaryOffsetForTesting(name, map); } m.Return(m.SmiTag(result)); } @@ -83,8 +83,7 @@ void TestStubCacheOffsetCalculation(StubCache::Table table) { if (table == StubCache::kPrimary) { expected_result = primary_offset; } else { - expected_result = - StubCache::SecondaryOffsetForTesting(*name, primary_offset); + expected_result = StubCache::SecondaryOffsetForTesting(*name, *map); } } Handle result = ft.Call(name, map).ToHandleChecked();