• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #include "src/execution/isolate-utils-inl.h"
9 #include "src/heap/heap.h"
10 #include "src/objects/fixed-array-inl.h"
11 #include "src/objects/hash-table.h"
12 #include "src/objects/heap-object-inl.h"
13 #include "src/objects/objects-inl.h"
14 #include "src/roots/roots-inl.h"
15 
16 // Has to be the last include (doesn't have include guards):
17 #include "src/objects/object-macros.h"
18 
19 namespace v8 {
20 namespace internal {
21 
OBJECT_CONSTRUCTORS_IMPL(HashTableBase,FixedArray)22 OBJECT_CONSTRUCTORS_IMPL(HashTableBase, FixedArray)
23 
24 template <typename Derived, typename Shape>
25 HashTable<Derived, Shape>::HashTable(Address ptr) : HashTableBase(ptr) {
26   SLOW_DCHECK(IsHashTable());
27 }
28 
29 template <typename Derived, typename Shape>
ObjectHashTableBase(Address ptr)30 ObjectHashTableBase<Derived, Shape>::ObjectHashTableBase(Address ptr)
31     : HashTable<Derived, Shape>(ptr) {}
32 
ObjectHashTable(Address ptr)33 ObjectHashTable::ObjectHashTable(Address ptr)
34     : ObjectHashTableBase<ObjectHashTable, ObjectHashTableShape>(ptr) {
35   SLOW_DCHECK(IsObjectHashTable());
36 }
37 
RegisteredSymbolTable(Address ptr)38 RegisteredSymbolTable::RegisteredSymbolTable(Address ptr)
39     : HashTable<RegisteredSymbolTable, RegisteredSymbolTableShape>(ptr) {
40   SLOW_DCHECK(IsRegisteredSymbolTable());
41 }
42 
EphemeronHashTable(Address ptr)43 EphemeronHashTable::EphemeronHashTable(Address ptr)
44     : ObjectHashTableBase<EphemeronHashTable, ObjectHashTableShape>(ptr) {
45   SLOW_DCHECK(IsEphemeronHashTable());
46 }
47 
ObjectHashSet(Address ptr)48 ObjectHashSet::ObjectHashSet(Address ptr)
49     : HashTable<ObjectHashSet, ObjectHashSetShape>(ptr) {
50   SLOW_DCHECK(IsObjectHashSet());
51 }
52 
NameToIndexHashTable(Address ptr)53 NameToIndexHashTable::NameToIndexHashTable(Address ptr)
54     : HashTable<NameToIndexHashTable, NameToIndexShape>(ptr) {
55   SLOW_DCHECK(IsNameToIndexHashTable());
56 }
57 
58 CAST_ACCESSOR(ObjectHashTable)
CAST_ACCESSOR(RegisteredSymbolTable)59 CAST_ACCESSOR(RegisteredSymbolTable)
60 CAST_ACCESSOR(EphemeronHashTable)
61 CAST_ACCESSOR(ObjectHashSet)
62 CAST_ACCESSOR(NameToIndexHashTable)
63 
64 void EphemeronHashTable::set_key(int index, Object value) {
65   DCHECK_NE(GetReadOnlyRoots().fixed_cow_array_map(), map());
66   DCHECK(IsEphemeronHashTable());
67   DCHECK_GE(index, 0);
68   DCHECK_LT(index, this->length());
69   int offset = kHeaderSize + index * kTaggedSize;
70   RELAXED_WRITE_FIELD(*this, offset, value);
71   EPHEMERON_KEY_WRITE_BARRIER(*this, offset, value);
72 }
73 
set_key(int index,Object value,WriteBarrierMode mode)74 void EphemeronHashTable::set_key(int index, Object value,
75                                  WriteBarrierMode mode) {
76   DCHECK_NE(GetReadOnlyRoots().fixed_cow_array_map(), map());
77   DCHECK(IsEphemeronHashTable());
78   DCHECK_GE(index, 0);
79   DCHECK_LT(index, this->length());
80   int offset = kHeaderSize + index * kTaggedSize;
81   RELAXED_WRITE_FIELD(*this, offset, value);
82   CONDITIONAL_EPHEMERON_KEY_WRITE_BARRIER(*this, offset, value, mode);
83 }
84 
NumberOfElements()85 int HashTableBase::NumberOfElements() const {
86   return Smi::cast(get(kNumberOfElementsIndex)).value();
87 }
88 
NumberOfDeletedElements()89 int HashTableBase::NumberOfDeletedElements() const {
90   return Smi::cast(get(kNumberOfDeletedElementsIndex)).value();
91 }
92 
Capacity()93 int HashTableBase::Capacity() const {
94   return Smi::cast(get(kCapacityIndex)).value();
95 }
96 
IterateEntries()97 InternalIndex::Range HashTableBase::IterateEntries() const {
98   return InternalIndex::Range(Capacity());
99 }
100 
ElementAdded()101 void HashTableBase::ElementAdded() {
102   SetNumberOfElements(NumberOfElements() + 1);
103 }
104 
ElementRemoved()105 void HashTableBase::ElementRemoved() {
106   SetNumberOfElements(NumberOfElements() - 1);
107   SetNumberOfDeletedElements(NumberOfDeletedElements() + 1);
108 }
109 
ElementsRemoved(int n)110 void HashTableBase::ElementsRemoved(int n) {
111   SetNumberOfElements(NumberOfElements() - n);
112   SetNumberOfDeletedElements(NumberOfDeletedElements() + n);
113 }
114 
115 // static
ComputeCapacity(int at_least_space_for)116 int HashTableBase::ComputeCapacity(int at_least_space_for) {
117   // Add 50% slack to make slot collisions sufficiently unlikely.
118   // See matching computation in HashTable::HasSufficientCapacityToAdd().
119   // Must be kept in sync with CodeStubAssembler::HashTableComputeCapacity().
120   int raw_cap = at_least_space_for + (at_least_space_for >> 1);
121   int capacity = base::bits::RoundUpToPowerOfTwo32(raw_cap);
122   return std::max({capacity, kMinCapacity});
123 }
124 
SetNumberOfElements(int nof)125 void HashTableBase::SetNumberOfElements(int nof) {
126   set(kNumberOfElementsIndex, Smi::FromInt(nof));
127 }
128 
SetNumberOfDeletedElements(int nod)129 void HashTableBase::SetNumberOfDeletedElements(int nod) {
130   set(kNumberOfDeletedElementsIndex, Smi::FromInt(nod));
131 }
132 
133 // static
134 template <typename Derived, typename Shape>
GetMap(ReadOnlyRoots roots)135 Handle<Map> HashTable<Derived, Shape>::GetMap(ReadOnlyRoots roots) {
136   return roots.hash_table_map_handle();
137 }
138 
139 // static
GetMap(ReadOnlyRoots roots)140 Handle<Map> NameToIndexHashTable::GetMap(ReadOnlyRoots roots) {
141   return roots.name_to_index_hash_table_map_handle();
142 }
143 
144 // static
GetMap(ReadOnlyRoots roots)145 Handle<Map> RegisteredSymbolTable::GetMap(ReadOnlyRoots roots) {
146   return roots.registered_symbol_table_map_handle();
147 }
148 
149 // static
GetMap(ReadOnlyRoots roots)150 Handle<Map> EphemeronHashTable::GetMap(ReadOnlyRoots roots) {
151   return roots.ephemeron_hash_table_map_handle();
152 }
153 
154 template <typename Derived, typename Shape>
155 template <typename IsolateT>
FindEntry(IsolateT * isolate,Key key)156 InternalIndex HashTable<Derived, Shape>::FindEntry(IsolateT* isolate, Key key) {
157   ReadOnlyRoots roots(isolate);
158   return FindEntry(isolate, roots, key, Shape::Hash(roots, key));
159 }
160 
161 // Find entry for key otherwise return kNotFound.
162 template <typename Derived, typename Shape>
FindEntry(PtrComprCageBase cage_base,ReadOnlyRoots roots,Key key,int32_t hash)163 InternalIndex HashTable<Derived, Shape>::FindEntry(PtrComprCageBase cage_base,
164                                                    ReadOnlyRoots roots, Key key,
165                                                    int32_t hash) {
166   DisallowGarbageCollection no_gc;
167   uint32_t capacity = Capacity();
168   uint32_t count = 1;
169   Object undefined = roots.undefined_value();
170   Object the_hole = roots.the_hole_value();
171   // EnsureCapacity will guarantee the hash table is never full.
172   for (InternalIndex entry = FirstProbe(hash, capacity);;
173        entry = NextProbe(entry, count++, capacity)) {
174     Object element = KeyAt(cage_base, entry);
175     // Empty entry. Uses raw unchecked accessors because it is called by the
176     // string table during bootstrapping.
177     if (element == undefined) return InternalIndex::NotFound();
178     if (Shape::kMatchNeedsHoleCheck && element == the_hole) continue;
179     if (Shape::IsMatch(key, element)) return entry;
180   }
181 }
182 
183 template <typename Derived, typename Shape>
184 template <typename IsolateT>
FindInsertionEntry(IsolateT * isolate,uint32_t hash)185 InternalIndex HashTable<Derived, Shape>::FindInsertionEntry(IsolateT* isolate,
186                                                             uint32_t hash) {
187   return FindInsertionEntry(isolate, ReadOnlyRoots(isolate), hash);
188 }
189 
190 // static
191 template <typename Derived, typename Shape>
IsKey(ReadOnlyRoots roots,Object k)192 bool HashTable<Derived, Shape>::IsKey(ReadOnlyRoots roots, Object k) {
193   // TODO(leszeks): Dictionaries that don't delete could skip the hole check.
194   return k != roots.undefined_value() && k != roots.the_hole_value();
195 }
196 
197 template <typename Derived, typename Shape>
ToKey(ReadOnlyRoots roots,InternalIndex entry,Object * out_k)198 bool HashTable<Derived, Shape>::ToKey(ReadOnlyRoots roots, InternalIndex entry,
199                                       Object* out_k) {
200   Object k = KeyAt(entry);
201   if (!IsKey(roots, k)) return false;
202   *out_k = Shape::Unwrap(k);
203   return true;
204 }
205 
206 template <typename Derived, typename Shape>
ToKey(PtrComprCageBase cage_base,InternalIndex entry,Object * out_k)207 bool HashTable<Derived, Shape>::ToKey(PtrComprCageBase cage_base,
208                                       InternalIndex entry, Object* out_k) {
209   Object k = KeyAt(cage_base, entry);
210   if (!IsKey(GetReadOnlyRoots(cage_base), k)) return false;
211   *out_k = Shape::Unwrap(k);
212   return true;
213 }
214 
215 template <typename Derived, typename Shape>
KeyAt(InternalIndex entry)216 Object HashTable<Derived, Shape>::KeyAt(InternalIndex entry) {
217   PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
218   return KeyAt(cage_base, entry);
219 }
220 
221 template <typename Derived, typename Shape>
KeyAt(PtrComprCageBase cage_base,InternalIndex entry)222 Object HashTable<Derived, Shape>::KeyAt(PtrComprCageBase cage_base,
223                                         InternalIndex entry) {
224   return get(cage_base, EntryToIndex(entry) + kEntryKeyIndex);
225 }
226 
227 template <typename Derived, typename Shape>
KeyAt(InternalIndex entry,RelaxedLoadTag tag)228 Object HashTable<Derived, Shape>::KeyAt(InternalIndex entry,
229                                         RelaxedLoadTag tag) {
230   PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
231   return KeyAt(cage_base, entry, tag);
232 }
233 
234 template <typename Derived, typename Shape>
KeyAt(PtrComprCageBase cage_base,InternalIndex entry,RelaxedLoadTag tag)235 Object HashTable<Derived, Shape>::KeyAt(PtrComprCageBase cage_base,
236                                         InternalIndex entry,
237                                         RelaxedLoadTag tag) {
238   return get(cage_base, EntryToIndex(entry) + kEntryKeyIndex, tag);
239 }
240 
241 template <typename Derived, typename Shape>
set_key(int index,Object value)242 void HashTable<Derived, Shape>::set_key(int index, Object value) {
243   DCHECK(!IsEphemeronHashTable());
244   FixedArray::set(index, value);
245 }
246 
247 template <typename Derived, typename Shape>
set_key(int index,Object value,WriteBarrierMode mode)248 void HashTable<Derived, Shape>::set_key(int index, Object value,
249                                         WriteBarrierMode mode) {
250   DCHECK(!IsEphemeronHashTable());
251   FixedArray::set(index, value, mode);
252 }
253 
254 template <typename Derived, typename Shape>
SetCapacity(int capacity)255 void HashTable<Derived, Shape>::SetCapacity(int capacity) {
256   // To scale a computed hash code to fit within the hash table, we
257   // use bit-wise AND with a mask, so the capacity must be positive
258   // and non-zero.
259   DCHECK_GT(capacity, 0);
260   DCHECK_LE(capacity, kMaxCapacity);
261   set(kCapacityIndex, Smi::FromInt(capacity));
262 }
263 
Has(Isolate * isolate,Handle<Object> key,int32_t hash)264 bool ObjectHashSet::Has(Isolate* isolate, Handle<Object> key, int32_t hash) {
265   return FindEntry(isolate, ReadOnlyRoots(isolate), key, hash).is_found();
266 }
267 
Has(Isolate * isolate,Handle<Object> key)268 bool ObjectHashSet::Has(Isolate* isolate, Handle<Object> key) {
269   Object hash = key->GetHash();
270   if (!hash.IsSmi()) return false;
271   return FindEntry(isolate, ReadOnlyRoots(isolate), key, Smi::ToInt(hash))
272       .is_found();
273 }
274 
IsMatch(Handle<Object> key,Object other)275 bool ObjectHashTableShape::IsMatch(Handle<Object> key, Object other) {
276   return key->SameValue(other);
277 }
278 
IsMatch(Handle<String> key,Object value)279 bool RegisteredSymbolTableShape::IsMatch(Handle<String> key, Object value) {
280   DCHECK(value.IsString());
281   return key->Equals(String::cast(value));
282 }
283 
Hash(ReadOnlyRoots roots,Handle<String> key)284 uint32_t RegisteredSymbolTableShape::Hash(ReadOnlyRoots roots,
285                                           Handle<String> key) {
286   return key->EnsureHash();
287 }
288 
HashForObject(ReadOnlyRoots roots,Object object)289 uint32_t RegisteredSymbolTableShape::HashForObject(ReadOnlyRoots roots,
290                                                    Object object) {
291   return String::cast(object).EnsureHash();
292 }
293 
IsMatch(Handle<Name> key,Object other)294 bool NameToIndexShape::IsMatch(Handle<Name> key, Object other) {
295   return *key == other;
296 }
297 
HashForObject(ReadOnlyRoots roots,Object other)298 uint32_t NameToIndexShape::HashForObject(ReadOnlyRoots roots, Object other) {
299   return Name::cast(other).hash();
300 }
301 
Hash(ReadOnlyRoots roots,Handle<Name> key)302 uint32_t NameToIndexShape::Hash(ReadOnlyRoots roots, Handle<Name> key) {
303   return key->hash();
304 }
305 
Hash(ReadOnlyRoots roots,Handle<Object> key)306 uint32_t ObjectHashTableShape::Hash(ReadOnlyRoots roots, Handle<Object> key) {
307   return Smi::ToInt(key->GetHash());
308 }
309 
HashForObject(ReadOnlyRoots roots,Object other)310 uint32_t ObjectHashTableShape::HashForObject(ReadOnlyRoots roots,
311                                              Object other) {
312   return Smi::ToInt(other.GetHash());
313 }
314 
315 template <typename IsolateT>
Add(IsolateT * isolate,Handle<NameToIndexHashTable> table,Handle<Name> key,int32_t index)316 Handle<NameToIndexHashTable> NameToIndexHashTable::Add(
317     IsolateT* isolate, Handle<NameToIndexHashTable> table, Handle<Name> key,
318     int32_t index) {
319   DCHECK_GE(index, 0);
320   // Validate that the key is absent.
321   SLOW_DCHECK(table->FindEntry(isolate, key).is_not_found());
322   // Check whether the dictionary should be extended.
323   table = EnsureCapacity(isolate, table);
324 
325   // Compute the key object.
326   InternalIndex entry = table->FindInsertionEntry(isolate, key->hash());
327   table->set(EntryToIndex(entry), *key);
328   table->set(EntryToValueIndex(entry), Smi::FromInt(index));
329   table->ElementAdded();
330   return table;
331 }
332 
333 }  // namespace internal
334 }  // namespace v8
335 
336 #include "src/objects/object-macros-undef.h"
337 
338 #endif  // V8_OBJECTS_HASH_TABLE_INL_H_
339