v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
hash-table-inl.h
Go to the documentation of this file.
1// Copyright 2017 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#ifndef V8_OBJECTS_HASH_TABLE_INL_H_
6#define V8_OBJECTS_HASH_TABLE_INL_H_
7
9// Include the non-inl header before the rest of the headers.
10
12#include "src/heap/heap.h"
16#include "src/roots/roots-inl.h"
17
18// Has to be the last include (doesn't have include guards):
20
21namespace v8 {
22namespace internal {
23
24void EphemeronHashTable::set_key(int index, Tagged<Object> value) {
25 DCHECK_NE(GetReadOnlyRoots().fixed_cow_array_map(), map());
26 DCHECK(IsEphemeronHashTable(this));
27 DCHECK_GE(index, 0);
28 DCHECK_LT(index, this->length());
29 objects()[index].Relaxed_Store_no_write_barrier(value);
30#ifndef V8_DISABLE_WRITE_BARRIERS
33 Tagged(this), ObjectSlot(&objects()[index]), value, UPDATE_WRITE_BARRIER);
34#endif
35}
36
37void EphemeronHashTable::set_key(int index, Tagged<Object> value,
38 WriteBarrierMode mode) {
39 DCHECK_NE(GetReadOnlyRoots().fixed_cow_array_map(), map());
40 DCHECK(IsEphemeronHashTable(this));
41 DCHECK_GE(index, 0);
42 DCHECK_LT(index, this->length());
43 objects()[index].Relaxed_Store_no_write_barrier(value);
44#ifndef V8_DISABLE_WRITE_BARRIERS
45#if V8_ENABLE_UNCONDITIONAL_WRITE_BARRIERS
47#endif
50 Tagged(this), ObjectSlot(&objects()[index]), value, mode);
51#endif
52}
53
55 return Cast<Smi>(get(kNumberOfElementsIndex)).value();
56}
57
61
63 return Cast<Smi>(get(kCapacityIndex)).value();
64}
65
69
73
78
83
84// static
85int HashTableBase::ComputeCapacity(int at_least_space_for) {
86 // Add 50% slack to make slot collisions sufficiently unlikely.
87 // See matching computation in HashTable::HasSufficientCapacityToAdd().
88 // Must be kept in sync with CodeStubAssembler::HashTableComputeCapacity().
89 int raw_cap = at_least_space_for + (at_least_space_for >> 1);
90 int capacity = base::bits::RoundUpToPowerOfTwo32(raw_cap);
91 return std::max({capacity, kMinCapacity});
92}
93
98
102
106
107// static
108template <typename Derived, typename Shape>
109DirectHandle<Map> HashTable<Derived, Shape>::GetMap(RootsTable& roots) {
110 return roots.hash_table_map();
111}
112
113// static
115 return roots.name_to_index_hash_table_map();
116}
117
118// static
120 return roots.registered_symbol_table_map();
121}
122
123// static
124Handle<Map> EphemeronHashTable::GetMap(RootsTable& roots) {
125 return roots.ephemeron_hash_table_map();
126}
127
128template <typename Derived, typename Shape>
129template <typename IsolateT>
130InternalIndex HashTable<Derived, Shape>::FindEntry(IsolateT* isolate, Key key) {
131 ReadOnlyRoots roots(isolate);
132 return FindEntry(isolate, roots, key, TodoShape::Hash(roots, key));
133}
134
135// Find entry for key otherwise return kNotFound.
136template <typename Derived, typename Shape>
137InternalIndex HashTable<Derived, Shape>::FindEntry(PtrComprCageBase cage_base,
138 ReadOnlyRoots roots, Key key,
139 int32_t hash) {
141 uint32_t capacity = Capacity();
142 uint32_t count = 1;
143 Tagged<Object> undefined = roots.undefined_value();
144 Tagged<Object> the_hole = roots.the_hole_value();
145 DCHECK_EQ(TodoShape::Hash(roots, key), static_cast<uint32_t>(hash));
146 // EnsureCapacity will guarantee the hash table is never full.
147 for (InternalIndex entry = FirstProbe(hash, capacity);;
148 entry = NextProbe(entry, count++, capacity)) {
149 Tagged<Object> element = KeyAt(cage_base, entry);
150 // Empty entry. Uses raw unchecked accessors because it is called by the
151 // string table during bootstrapping.
152 if (element == undefined) return InternalIndex::NotFound();
153 if (TodoShape::kMatchNeedsHoleCheck && element == the_hole) continue;
154 if (TodoShape::IsMatch(key, element)) return entry;
155 }
156}
157
158template <typename Derived, typename Shape>
159template <typename IsolateT>
160InternalIndex HashTable<Derived, Shape>::FindInsertionEntry(IsolateT* isolate,
161 uint32_t hash) {
162 return FindInsertionEntry(isolate, ReadOnlyRoots(isolate), hash);
163}
164
165// static
166template <typename Derived, typename Shape>
167bool HashTable<Derived, Shape>::IsKey(ReadOnlyRoots roots, Tagged<Object> k) {
168 // TODO(leszeks): Dictionaries that don't delete could skip the hole check.
169 return k != roots.unchecked_undefined_value() &&
170 k != roots.unchecked_the_hole_value();
171}
172
173template <typename Derived, typename Shape>
174bool HashTable<Derived, Shape>::ToKey(ReadOnlyRoots roots, InternalIndex entry,
175 Tagged<Object>* out_k) {
176 Tagged<Object> k = KeyAt(entry);
177 if (!IsKey(roots, k)) return false;
178 *out_k = TodoShape::Unwrap(k);
179 return true;
180}
181
182template <typename Derived, typename Shape>
183bool HashTable<Derived, Shape>::ToKey(PtrComprCageBase cage_base,
184 InternalIndex entry,
185 Tagged<Object>* out_k) {
186 Tagged<Object> k = KeyAt(cage_base, entry);
187 if (!IsKey(GetReadOnlyRoots(), k)) return false;
188 *out_k = TodoShape::Unwrap(k);
189 return true;
190}
191
192template <typename Derived, typename Shape>
193Tagged<Object> HashTable<Derived, Shape>::KeyAt(InternalIndex entry) {
194 PtrComprCageBase cage_base = GetPtrComprCageBase();
195 return KeyAt(cage_base, entry);
196}
197
198template <typename Derived, typename Shape>
199Tagged<Object> HashTable<Derived, Shape>::KeyAt(PtrComprCageBase cage_base,
200 InternalIndex entry) {
201 return get(EntryToIndex(entry) + kEntryKeyIndex);
202}
203
204template <typename Derived, typename Shape>
205Tagged<Object> HashTable<Derived, Shape>::KeyAt(InternalIndex entry,
206 RelaxedLoadTag tag) {
207 PtrComprCageBase cage_base = GetPtrComprCageBase();
208 return KeyAt(cage_base, entry, tag);
209}
210
211template <typename Derived, typename Shape>
212Tagged<Object> HashTable<Derived, Shape>::KeyAt(PtrComprCageBase cage_base,
213 InternalIndex entry,
214 RelaxedLoadTag tag) {
215 return get(EntryToIndex(entry) + kEntryKeyIndex, tag);
216}
217
218template <typename Derived, typename Shape>
219void HashTable<Derived, Shape>::SetKeyAt(InternalIndex entry,
220 Tagged<Object> value,
221 WriteBarrierMode mode) {
222 set_key(EntryToIndex(entry), value, mode);
223}
224
225template <typename Derived, typename Shape>
226void HashTable<Derived, Shape>::set_key(int index, Tagged<Object> value) {
227 DCHECK(!IsEphemeronHashTable(this));
228 FixedArray::set(index, value);
229}
230
231template <typename Derived, typename Shape>
232void HashTable<Derived, Shape>::set_key(int index, Tagged<Object> value,
233 WriteBarrierMode mode) {
234 DCHECK(!IsEphemeronHashTable(this));
235 FixedArray::set(index, value, mode);
236}
237
238template <typename Derived, typename Shape>
239void HashTable<Derived, Shape>::SetCapacity(int capacity) {
240 // To scale a computed hash code to fit within the hash table, we
241 // use bit-wise AND with a mask, so the capacity must be positive
242 // and non-zero.
243 DCHECK_GT(capacity, 0);
244 DCHECK_LE(capacity, kMaxCapacity);
245 set(kCapacityIndex, Smi::FromInt(capacity));
246}
247
249 int32_t hash) {
250 return FindEntry(isolate, ReadOnlyRoots(isolate), key, hash).is_found();
251}
252
255 if (!IsSmi(hash)) return false;
256 return FindEntry(isolate, ReadOnlyRoots(isolate), key, Smi::ToInt(hash))
257 .is_found();
258}
259
264
266 Tagged<Object> value) {
267 DCHECK(IsString(value));
268 return key->Equals(Cast<String>(value));
269}
270
273 return key->EnsureHash();
274}
275
277 Tagged<Object> object) {
278 return Cast<String>(object)->EnsureHash();
279}
280
282 return *key == other;
283}
284
286 Tagged<Object> other) {
287 return Cast<Name>(other)->hash();
288}
289
291 return key->hash();
292}
293
298
303
304template <typename IsolateT>
306 IsolateT* isolate, Handle<NameToIndexHashTable> table,
307 DirectHandle<Name> key, int32_t index) {
308 DCHECK_GE(index, 0);
309 // Validate that the key is absent.
310 SLOW_DCHECK(table->FindEntry(isolate, key).is_not_found());
311 // Check whether the dictionary should be extended.
312 table = EnsureCapacity(isolate, table);
314 Tagged<NameToIndexHashTable> raw_table = *table;
315 // Compute the key object.
316 InternalIndex entry = raw_table->FindInsertionEntry(isolate, key->hash());
317 raw_table->set(EntryToIndex(entry), *key);
318 raw_table->set(EntryToValueIndex(entry), Smi::FromInt(index));
319 raw_table->ElementAdded();
320 return table;
321}
322
323} // namespace internal
324} // namespace v8
325
327
328#endif // V8_OBJECTS_HASH_TABLE_INL_H_
#define SLOW_DCHECK(condition)
Definition checks.h:21
uint32_t GetHash()
Definition api.cc:4282
void SetNumberOfDeletedElements(int nod)
static const int kMinCapacity
Definition hash-table.h:100
static const int kCapacityIndex
Definition hash-table.h:96
InternalIndex::Range IterateEntries() const
void SetInitialNumberOfElements(int nof)
static const int kNumberOfDeletedElementsIndex
Definition hash-table.h:95
static int ComputeCapacity(int at_least_space_for)
static const int kNumberOfElementsIndex
Definition hash-table.h:94
static V8_INLINE bool IsOwnedByAnyHeap(Tagged< HeapObject > object)
static InternalIndex NotFound()
static int EntryToValueIndex(InternalIndex entry)
Definition hash-table.h:561
static Handle< NameToIndexHashTable > Add(IsolateT *isolate, Handle< NameToIndexHashTable > table, DirectHandle< Name > key, int32_t value)
static DirectHandle< Map > GetMap(RootsTable &roots)
static uint32_t Hash(ReadOnlyRoots roots, DirectHandle< Name > key)
static bool IsMatch(DirectHandle< Name > key, Tagged< Object > other)
static uint32_t HashForObject(ReadOnlyRoots roots, Tagged< Object > object)
bool Has(Isolate *isolate, DirectHandle< Object > key, int32_t hash)
static uint32_t Hash(ReadOnlyRoots roots, DirectHandle< Object > key)
static uint32_t HashForObject(ReadOnlyRoots roots, Tagged< Object > object)
static bool IsMatch(DirectHandle< Object > key, Tagged< Object > other)
static V8_EXPORT_PRIVATE bool SameValue(Tagged< Object > obj, Tagged< Object > other)
Definition objects.cc:1706
static uint32_t HashForObject(ReadOnlyRoots roots, Tagged< Object > object)
static bool IsMatch(DirectHandle< String > key, Tagged< Object > other)
static uint32_t Hash(ReadOnlyRoots roots, DirectHandle< String > key)
static DirectHandle< Map > GetMap(RootsTable &roots)
static constexpr int ToInt(const Tagged< Object > object)
Definition smi.h:33
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
void set(int index, Tagged< ElementT > value, WriteBarrierMode mode=kDefaultMode)
static void ForEphemeronHashTable(Tagged< EphemeronHashTable > host, ObjectSlot slot, Tagged< Object > value, WriteBarrierMode mode)
std::map< const std::string, const std::string > map
V8_BASE_EXPORT constexpr uint32_t RoundUpToPowerOfTwo32(uint32_t value)
Definition bits.h:219
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
@ UPDATE_WRITE_BARRIER
Definition objects.h:55
SlotTraits::TObjectSlot ObjectSlot
Definition globals.h:1243
ReadOnlyRoots GetReadOnlyRoots()
Definition roots-inl.h:86
Tagged(T object) -> Tagged< T >
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
V8_INLINE PtrComprCageBase GetPtrComprCageBase()
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487