11cb0ef41Sopenharmony_ci// Copyright 2012 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/ic/stub-cache.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include "src/ast/ast.h" 81cb0ef41Sopenharmony_ci#include "src/base/bits.h" 91cb0ef41Sopenharmony_ci#include "src/heap/heap-inl.h" // For InYoungGeneration(). 101cb0ef41Sopenharmony_ci#include "src/ic/ic-inl.h" 111cb0ef41Sopenharmony_ci#include "src/logging/counters.h" 121cb0ef41Sopenharmony_ci#include "src/objects/tagged-value-inl.h" 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_cinamespace v8 { 151cb0ef41Sopenharmony_cinamespace internal { 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ciStubCache::StubCache(Isolate* isolate) : isolate_(isolate) { 181cb0ef41Sopenharmony_ci // Ensure the nullptr (aka Smi::zero()) which StubCache::Get() returns 191cb0ef41Sopenharmony_ci // when the entry is not found is not considered as a handler. 201cb0ef41Sopenharmony_ci DCHECK(!IC::IsHandler(MaybeObject())); 211cb0ef41Sopenharmony_ci} 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_civoid StubCache::Initialize() { 241cb0ef41Sopenharmony_ci DCHECK(base::bits::IsPowerOfTwo(kPrimaryTableSize)); 251cb0ef41Sopenharmony_ci DCHECK(base::bits::IsPowerOfTwo(kSecondaryTableSize)); 261cb0ef41Sopenharmony_ci Clear(); 271cb0ef41Sopenharmony_ci} 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ci// Hash algorithm for the primary table. This algorithm is replicated in 301cb0ef41Sopenharmony_ci// the AccessorAssembler. Returns an index into the table that 311cb0ef41Sopenharmony_ci// is scaled by 1 << kCacheIndexShift. 321cb0ef41Sopenharmony_ciint StubCache::PrimaryOffset(Name name, Map map) { 331cb0ef41Sopenharmony_ci // Compute the hash of the name (use entire hash field). 341cb0ef41Sopenharmony_ci DCHECK(name.HasHashCode()); 351cb0ef41Sopenharmony_ci uint32_t field = name.raw_hash_field(); 361cb0ef41Sopenharmony_ci // Using only the low bits in 64-bit mode is unlikely to increase the 371cb0ef41Sopenharmony_ci // risk of collision even if the heap is spread over an area larger than 381cb0ef41Sopenharmony_ci // 4Gb (and not at all if it isn't). 391cb0ef41Sopenharmony_ci uint32_t map_low32bits = 401cb0ef41Sopenharmony_ci static_cast<uint32_t>(map.ptr() ^ (map.ptr() >> kMapKeyShift)); 411cb0ef41Sopenharmony_ci // Base the offset on a simple combination of name and map. 421cb0ef41Sopenharmony_ci uint32_t key = map_low32bits + field; 431cb0ef41Sopenharmony_ci return key & ((kPrimaryTableSize - 1) << kCacheIndexShift); 441cb0ef41Sopenharmony_ci} 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci// Hash algorithm for the secondary table. This algorithm is replicated in 471cb0ef41Sopenharmony_ci// assembler. This hash should be sufficiently different from the primary one 481cb0ef41Sopenharmony_ci// in order to avoid collisions for minified code with short names. 491cb0ef41Sopenharmony_ci// Returns an index into the table that is scaled by 1 << kCacheIndexShift. 501cb0ef41Sopenharmony_ciint StubCache::SecondaryOffset(Name name, Map old_map) { 511cb0ef41Sopenharmony_ci uint32_t name_low32bits = static_cast<uint32_t>(name.ptr()); 521cb0ef41Sopenharmony_ci uint32_t map_low32bits = static_cast<uint32_t>(old_map.ptr()); 531cb0ef41Sopenharmony_ci uint32_t key = (map_low32bits + name_low32bits); 541cb0ef41Sopenharmony_ci key = key + (key >> kSecondaryKeyShift); 551cb0ef41Sopenharmony_ci return key & ((kSecondaryTableSize - 1) << kCacheIndexShift); 561cb0ef41Sopenharmony_ci} 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_ciint StubCache::PrimaryOffsetForTesting(Name name, Map map) { 591cb0ef41Sopenharmony_ci return PrimaryOffset(name, map); 601cb0ef41Sopenharmony_ci} 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ciint StubCache::SecondaryOffsetForTesting(Name name, Map map) { 631cb0ef41Sopenharmony_ci return SecondaryOffset(name, map); 641cb0ef41Sopenharmony_ci} 651cb0ef41Sopenharmony_ci 661cb0ef41Sopenharmony_ci#ifdef DEBUG 671cb0ef41Sopenharmony_cinamespace { 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_cibool CommonStubCacheChecks(StubCache* stub_cache, Name name, Map map, 701cb0ef41Sopenharmony_ci MaybeObject handler) { 711cb0ef41Sopenharmony_ci // Validate that the name and handler do not move on scavenge, and that we 721cb0ef41Sopenharmony_ci // can use identity checks instead of structural equality checks. 731cb0ef41Sopenharmony_ci DCHECK(!Heap::InYoungGeneration(name)); 741cb0ef41Sopenharmony_ci DCHECK(!Heap::InYoungGeneration(handler)); 751cb0ef41Sopenharmony_ci DCHECK(name.IsUniqueName()); 761cb0ef41Sopenharmony_ci if (handler->ptr() != kNullAddress) DCHECK(IC::IsHandler(handler)); 771cb0ef41Sopenharmony_ci return true; 781cb0ef41Sopenharmony_ci} 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_ci} // namespace 811cb0ef41Sopenharmony_ci#endif 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_civoid StubCache::Set(Name name, Map map, MaybeObject handler) { 841cb0ef41Sopenharmony_ci DCHECK(CommonStubCacheChecks(this, name, map, handler)); 851cb0ef41Sopenharmony_ci 861cb0ef41Sopenharmony_ci // Compute the primary entry. 871cb0ef41Sopenharmony_ci int primary_offset = PrimaryOffset(name, map); 881cb0ef41Sopenharmony_ci Entry* primary = entry(primary_, primary_offset); 891cb0ef41Sopenharmony_ci MaybeObject old_handler( 901cb0ef41Sopenharmony_ci TaggedValue::ToMaybeObject(isolate(), primary->value)); 911cb0ef41Sopenharmony_ci // If the primary entry has useful data in it, we retire it to the 921cb0ef41Sopenharmony_ci // secondary cache before overwriting it. 931cb0ef41Sopenharmony_ci if (old_handler != MaybeObject::FromObject( 941cb0ef41Sopenharmony_ci isolate()->builtins()->code(Builtin::kIllegal)) && 951cb0ef41Sopenharmony_ci !primary->map.IsSmi()) { 961cb0ef41Sopenharmony_ci Map old_map = 971cb0ef41Sopenharmony_ci Map::cast(StrongTaggedValue::ToObject(isolate(), primary->map)); 981cb0ef41Sopenharmony_ci Name old_name = 991cb0ef41Sopenharmony_ci Name::cast(StrongTaggedValue::ToObject(isolate(), primary->key)); 1001cb0ef41Sopenharmony_ci int secondary_offset = SecondaryOffset(old_name, old_map); 1011cb0ef41Sopenharmony_ci Entry* secondary = entry(secondary_, secondary_offset); 1021cb0ef41Sopenharmony_ci *secondary = *primary; 1031cb0ef41Sopenharmony_ci } 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ci // Update primary cache. 1061cb0ef41Sopenharmony_ci primary->key = StrongTaggedValue(name); 1071cb0ef41Sopenharmony_ci primary->value = TaggedValue(handler); 1081cb0ef41Sopenharmony_ci primary->map = StrongTaggedValue(map); 1091cb0ef41Sopenharmony_ci isolate()->counters()->megamorphic_stub_cache_updates()->Increment(); 1101cb0ef41Sopenharmony_ci} 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ciMaybeObject StubCache::Get(Name name, Map map) { 1131cb0ef41Sopenharmony_ci DCHECK(CommonStubCacheChecks(this, name, map, MaybeObject())); 1141cb0ef41Sopenharmony_ci int primary_offset = PrimaryOffset(name, map); 1151cb0ef41Sopenharmony_ci Entry* primary = entry(primary_, primary_offset); 1161cb0ef41Sopenharmony_ci if (primary->key == name && primary->map == map) { 1171cb0ef41Sopenharmony_ci return TaggedValue::ToMaybeObject(isolate(), primary->value); 1181cb0ef41Sopenharmony_ci } 1191cb0ef41Sopenharmony_ci int secondary_offset = SecondaryOffset(name, map); 1201cb0ef41Sopenharmony_ci Entry* secondary = entry(secondary_, secondary_offset); 1211cb0ef41Sopenharmony_ci if (secondary->key == name && secondary->map == map) { 1221cb0ef41Sopenharmony_ci return TaggedValue::ToMaybeObject(isolate(), secondary->value); 1231cb0ef41Sopenharmony_ci } 1241cb0ef41Sopenharmony_ci return MaybeObject(); 1251cb0ef41Sopenharmony_ci} 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_civoid StubCache::Clear() { 1281cb0ef41Sopenharmony_ci MaybeObject empty = 1291cb0ef41Sopenharmony_ci MaybeObject::FromObject(isolate_->builtins()->code(Builtin::kIllegal)); 1301cb0ef41Sopenharmony_ci Name empty_string = ReadOnlyRoots(isolate()).empty_string(); 1311cb0ef41Sopenharmony_ci for (int i = 0; i < kPrimaryTableSize; i++) { 1321cb0ef41Sopenharmony_ci primary_[i].key = StrongTaggedValue(empty_string); 1331cb0ef41Sopenharmony_ci primary_[i].map = StrongTaggedValue(Smi::zero()); 1341cb0ef41Sopenharmony_ci primary_[i].value = TaggedValue(empty); 1351cb0ef41Sopenharmony_ci } 1361cb0ef41Sopenharmony_ci for (int j = 0; j < kSecondaryTableSize; j++) { 1371cb0ef41Sopenharmony_ci secondary_[j].key = StrongTaggedValue(empty_string); 1381cb0ef41Sopenharmony_ci secondary_[j].map = StrongTaggedValue(Smi::zero()); 1391cb0ef41Sopenharmony_ci secondary_[j].value = TaggedValue(empty); 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci} 1421cb0ef41Sopenharmony_ci 1431cb0ef41Sopenharmony_ci} // namespace internal 1441cb0ef41Sopenharmony_ci} // namespace v8 145