v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
stub-cache.cc
Go to the documentation of this file.
1// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/ic/stub-cache.h"
6
7#include "src/ast/ast.h"
8#include "src/base/bits.h"
9#include "src/heap/heap-inl.h" // For InYoungGeneration().
10#include "src/ic/ic-inl.h"
13
14namespace v8 {
15namespace internal {
16
18 // Ensure the nullptr (aka Smi::zero()) which StubCache::Get() returns
19 // when the entry is not found is not considered as a handler.
21}
22
28
29// Hash algorithm for the primary table. This algorithm is replicated in
30// the AccessorAssembler. Returns an index into the table that
31// is scaled by 1 << kCacheIndexShift.
33 // Compute the hash of the name (use entire hash field).
34 uint32_t field = name->RawHash();
36 // Using only the low bits in 64-bit mode is unlikely to increase the
37 // risk of collision even if the heap is spread over an area larger than
38 // 4Gb (and not at all if it isn't).
39 uint32_t map_low32bits =
40 static_cast<uint32_t>(map.ptr() ^ (map.ptr() >> kPrimaryTableBits));
41 // Base the offset on a simple combination of name and map.
42 uint32_t key = map_low32bits + field;
43 return key & ((kPrimaryTableSize - 1) << kCacheIndexShift);
44}
45
46// Hash algorithm for the secondary table. This algorithm is replicated in
47// assembler. This hash should be sufficiently different from the primary one
48// in order to avoid collisions for minified code with short names.
49// Returns an index into the table that is scaled by 1 << kCacheIndexShift.
51 uint32_t name_low32bits = static_cast<uint32_t>(name.ptr());
52 uint32_t map_low32bits = static_cast<uint32_t>(old_map.ptr());
53 uint32_t key = (map_low32bits + name_low32bits);
55 return key & ((kSecondaryTableSize - 1) << kCacheIndexShift);
56}
57
61
65
66#ifdef DEBUG
67namespace {
68
69bool CommonStubCacheChecks(StubCache* stub_cache, Tagged<Name> name,
70 Tagged<Map> map, Tagged<MaybeObject> handler) {
71 // Validate that the name and handler do not move on scavenge, and that we
72 // can use identity checks instead of structural equality checks.
75#ifdef V8_COMPRESS_POINTERS
76 // If the handler is a heap object, it is expected to live in the regular
77 // cage, not the code cage. No cage information is stored in the cache and
78 // StubCache::Get() assumes that this is true.
79 DCHECK(handler.IsSmi() || handler.IsInMainCageBase());
80#endif // V8_COMPRESS_POINTERS
81 DCHECK(IsUniqueName(name));
82 if (handler.ptr() != kNullAddress) DCHECK(IC::IsHandler(handler));
83 return true;
84}
85
86} // namespace
87#endif
88
90 Tagged<MaybeObject> handler) {
91 DCHECK(CommonStubCacheChecks(this, name, map, handler));
92
93 // Compute the primary entry.
94 int primary_offset = PrimaryOffset(name, map);
95 Entry* primary = entry(primary_, primary_offset);
96 Tagged<MaybeObject> old_handler(
98 // If the primary entry has useful data in it, we retire it to the
99 // secondary cache before overwriting it.
100 // We need SafeEquals here while Builtin Code objects still live in the RO
101 // space inside the sandbox.
102 static_assert(!kAllCodeObjectsLiveInTrustedSpace);
103 if (!old_handler.SafeEquals(isolate()->builtins()->code(Builtin::kIllegal)) &&
104 !primary->map.IsSmi()) {
105 Tagged<Map> old_map =
107 Tagged<Name> old_name =
109 int secondary_offset = SecondaryOffset(old_name, old_map);
110 Entry* secondary = entry(secondary_, secondary_offset);
111 *secondary = *primary;
112 }
113
114 // Update primary cache.
115 primary->key = StrongTaggedValue(name);
116 primary->value = TaggedValue(handler);
117 primary->map = StrongTaggedValue(map);
118 isolate()->counters()->megamorphic_stub_cache_updates()->Increment();
119}
120
122 DCHECK(CommonStubCacheChecks(this, name, map, Tagged<MaybeObject>()));
123 int primary_offset = PrimaryOffset(name, map);
124 Entry* primary = entry(primary_, primary_offset);
125 if (primary->key == name && primary->map == map) {
126 return TaggedValue::ToMaybeObject(isolate(), primary->value);
127 }
128 int secondary_offset = SecondaryOffset(name, map);
129 Entry* secondary = entry(secondary_, secondary_offset);
130 if (secondary->key == name && secondary->map == map) {
131 return TaggedValue::ToMaybeObject(isolate(), secondary->value);
132 }
133 return Tagged<MaybeObject>();
134}
135
137 Tagged<MaybeObject> empty = isolate_->builtins()->code(Builtin::kIllegal);
138 Tagged<Name> empty_string = ReadOnlyRoots(isolate()).empty_string();
139 for (int i = 0; i < kPrimaryTableSize; i++) {
140 primary_[i].key = StrongTaggedValue(empty_string);
142 primary_[i].value = TaggedValue(empty);
143 }
144 for (int j = 0; j < kSecondaryTableSize; j++) {
145 secondary_[j].key = StrongTaggedValue(empty_string);
147 secondary_[j].value = TaggedValue(empty);
148 }
149}
150
151} // namespace internal
152} // namespace v8
Isolate * isolate_
V8_EXPORT_PRIVATE Tagged< Code > code(Builtin builtin)
Definition builtins.cc:149
static V8_INLINE bool InYoungGeneration(Tagged< Object > object)
static bool IsHandler(Tagged< MaybeObject > object)
Definition ic-inl.h:29
Counters * counters()
Definition isolate.h:1180
Builtins * builtins()
Definition isolate.h:1443
static bool IsHashFieldComputed(uint32_t raw_hash_field)
Definition name-inl.h:96
static constexpr Tagged< Smi > zero()
Definition smi.h:99
static Tagged< Object > ToObject(Isolate *isolate, StrongTaggedValue object)
static const int kCacheIndexShift
Definition stub-cache.h:86
static const int kPrimaryTableBits
Definition stub-cache.h:88
static int SecondaryOffsetForTesting(Tagged< Name > name, Tagged< Map > map)
Definition stub-cache.cc:62
static int SecondaryOffset(Tagged< Name > name, Tagged< Map > map)
Definition stub-cache.cc:50
Entry secondary_[kSecondaryTableSize]
Definition stub-cache.h:135
static const int kSecondaryTableBits
Definition stub-cache.h:90
StubCache(Isolate *isolate)
Definition stub-cache.cc:17
static int PrimaryOffset(Tagged< Name > name, Tagged< Map > map)
Definition stub-cache.cc:32
static const int kSecondaryTableSize
Definition stub-cache.h:91
static const int kPrimaryTableSize
Definition stub-cache.h:89
Entry primary_[kPrimaryTableSize]
Definition stub-cache.h:134
static Entry * entry(Entry *table, int offset)
Definition stub-cache.h:124
void Set(Tagged< Name > name, Tagged< Map > map, Tagged< MaybeObject > handler)
Definition stub-cache.cc:89
Tagged< MaybeObject > Get(Tagged< Name > name, Tagged< Map > map)
static int PrimaryOffsetForTesting(Tagged< Name > name, Tagged< Map > map)
Definition stub-cache.cc:58
V8_INLINE constexpr StorageType ptr() const
constexpr bool SafeEquals(TaggedImpl< kOtherRefType, StorageType > other) const
Definition tagged-impl.h:93
constexpr bool IsSmi() const
static Tagged< MaybeObject > ToMaybeObject(Isolate *isolate, TaggedValue object)
Handle< Code > code
constexpr bool IsPowerOfTwo(T value)
Definition bits.h:187
Tagged(T object) -> Tagged< T >
bool IsUniqueName(Tagged< Name > obj)
constexpr bool kAllCodeObjectsLiveInTrustedSpace
static constexpr Address kNullAddress
Definition v8-internal.h:53
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define DCHECK(condition)
Definition logging.h:482