V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
hash-table.h
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_H_
6 #define V8_OBJECTS_HASH_TABLE_H_
7 
8 #include "src/base/compiler-specific.h"
9 #include "src/globals.h"
10 #include "src/objects/fixed-array.h"
11 #include "src/objects/smi.h"
12 
13 // Has to be the last include (doesn't have include guards):
14 #include "src/objects/object-macros.h"
15 
16 namespace v8 {
17 namespace internal {
18 
19 // HashTable is a subclass of FixedArray that implements a hash table
20 // that uses open addressing and quadratic probing.
21 //
22 // In order for the quadratic probing to work, elements that have not
23 // yet been used and elements that have been deleted are
24 // distinguished. Probing continues when deleted elements are
25 // encountered and stops when unused elements are encountered.
26 //
27 // - Elements with key == undefined have not been used yet.
28 // - Elements with key == the_hole have been deleted.
29 //
30 // The hash table class is parameterized with a Shape.
31 // Shape must be a class with the following interface:
32 // class ExampleShape {
33 // public:
34 // // Tells whether key matches other.
35 // static bool IsMatch(Key key, Object* other);
36 // // Returns the hash value for key.
37 // static uint32_t Hash(Isolate* isolate, Key key);
38 // // Returns the hash value for object.
39 // static uint32_t HashForObject(Isolate* isolate, Object* object);
40 // // Convert key to an object.
41 // static inline Handle<Object> AsHandle(Isolate* isolate, Key key);
42 // // The prefix size indicates number of elements in the beginning
43 // // of the backing storage.
44 // static const int kPrefixSize = ..;
45 // // The Element size indicates number of elements per entry.
46 // static const int kEntrySize = ..;
47 // // Indicates whether IsMatch can deal with other being the_hole (a
48 // // deleted entry).
49 // static const bool kNeedsHoleCheck = ..;
50 // };
51 // The prefix size indicates an amount of memory in the
52 // beginning of the backing storage that can be used for non-element
53 // information by subclasses.
54 
55 template <typename KeyT>
56 class BaseShape {
57  public:
58  typedef KeyT Key;
59  static inline RootIndex GetMapRootIndex();
60  static const bool kNeedsHoleCheck = true;
61  static Object* Unwrap(Object* key) { return key; }
62  static inline bool IsKey(ReadOnlyRoots roots, Object* key);
63  static inline bool IsLive(ReadOnlyRoots roots, Object* key);
64 };
65 
66 class V8_EXPORT_PRIVATE HashTableBase : public NON_EXPORTED_BASE(FixedArray) {
67  public:
68  // Returns the number of elements in the hash table.
69  inline int NumberOfElements() const;
70 
71  // Returns the number of deleted elements in the hash table.
72  inline int NumberOfDeletedElements() const;
73 
74  // Returns the capacity of the hash table.
75  inline int Capacity() const;
76 
77  // ElementAdded should be called whenever an element is added to a
78  // hash table.
79  inline void ElementAdded();
80 
81  // ElementRemoved should be called whenever an element is removed from
82  // a hash table.
83  inline void ElementRemoved();
84  inline void ElementsRemoved(int n);
85 
86  // Computes the required capacity for a table holding the given
87  // number of elements. May be more than HashTable::kMaxCapacity.
88  static inline int ComputeCapacity(int at_least_space_for);
89 
90  // Compute the probe offset (quadratic probing).
91  V8_INLINE static uint32_t GetProbeOffset(uint32_t n) {
92  return (n + n * n) >> 1;
93  }
94 
95  static const int kNumberOfElementsIndex = 0;
96  static const int kNumberOfDeletedElementsIndex = 1;
97  static const int kCapacityIndex = 2;
98  static const int kPrefixStartIndex = 3;
99 
100  // Constant used for denoting a absent entry.
101  static const int kNotFound = -1;
102 
103  // Minimum capacity for newly created hash tables.
104  static const int kMinCapacity = 4;
105 
106  protected:
107  // Update the number of elements in the hash table.
108  inline void SetNumberOfElements(int nof);
109 
110  // Update the number of deleted elements in the hash table.
111  inline void SetNumberOfDeletedElements(int nod);
112 
113  // Returns probe entry.
114  static uint32_t GetProbe(uint32_t hash, uint32_t number, uint32_t size) {
115  DCHECK(base::bits::IsPowerOfTwo(size));
116  return (hash + GetProbeOffset(number)) & (size - 1);
117  }
118 
119  inline static uint32_t FirstProbe(uint32_t hash, uint32_t size) {
120  return hash & (size - 1);
121  }
122 
123  inline static uint32_t NextProbe(uint32_t last, uint32_t number,
124  uint32_t size) {
125  return (last + number) & (size - 1);
126  }
127 
128  OBJECT_CONSTRUCTORS(HashTableBase, FixedArray)
129 };
130 
131 template <typename Derived, typename Shape>
132 class HashTable : public HashTableBase {
133  public:
134  typedef Shape ShapeT;
135  typedef typename Shape::Key Key;
136 
137  // Returns a new HashTable object.
138  V8_WARN_UNUSED_RESULT static Handle<Derived> New(
139  Isolate* isolate, int at_least_space_for,
140  PretenureFlag pretenure = NOT_TENURED,
141  MinimumCapacity capacity_option = USE_DEFAULT_MINIMUM_CAPACITY);
142 
143  // Garbage collection support.
144  void IteratePrefix(ObjectVisitor* visitor);
145  void IterateElements(ObjectVisitor* visitor);
146 
147  // Find entry for key otherwise return kNotFound.
148  inline int FindEntry(ReadOnlyRoots roots, Key key, int32_t hash);
149  int FindEntry(Isolate* isolate, Key key);
150 
151  // Rehashes the table in-place.
152  void Rehash(Isolate* isolate);
153 
154  // Tells whether k is a real key. The hole and undefined are not allowed
155  // as keys and can be used to indicate missing or deleted elements.
156  static bool IsKey(ReadOnlyRoots roots, Object* k);
157 
158  inline bool ToKey(ReadOnlyRoots roots, int entry, Object** out_k);
159 
160  // Returns the key at entry.
161  Object* KeyAt(int entry) { return get(EntryToIndex(entry) + kEntryKeyIndex); }
162 
163  static const int kElementsStartIndex = kPrefixStartIndex + Shape::kPrefixSize;
164  static const int kEntrySize = Shape::kEntrySize;
165  STATIC_ASSERT(kEntrySize > 0);
166  static const int kEntryKeyIndex = 0;
167  static const int kElementsStartOffset =
168  kHeaderSize + kElementsStartIndex * kTaggedSize;
169  // Maximal capacity of HashTable. Based on maximal length of underlying
170  // FixedArray. Staying below kMaxCapacity also ensures that EntryToIndex
171  // cannot overflow.
172  static const int kMaxCapacity =
173  (FixedArray::kMaxLength - kElementsStartIndex) / kEntrySize;
174 
175  // Don't shrink a HashTable below this capacity.
176  static const int kMinShrinkCapacity = 16;
177 
178  // Maximum length to create a regular HashTable (aka. non large object).
179  static const int kMaxRegularCapacity = 16384;
180 
181  // Returns the index for an entry (of the key)
182  static constexpr inline int EntryToIndex(int entry) {
183  return (entry * kEntrySize) + kElementsStartIndex;
184  }
185 
186  // Ensure enough space for n additional elements.
187  V8_WARN_UNUSED_RESULT static Handle<Derived> EnsureCapacity(
188  Isolate* isolate, Handle<Derived> table, int n,
189  PretenureFlag pretenure = NOT_TENURED);
190 
191  // Returns true if this table has sufficient capacity for adding n elements.
192  bool HasSufficientCapacityToAdd(int number_of_additional_elements);
193 
194  protected:
195  friend class ObjectHashTable;
196 
197  V8_WARN_UNUSED_RESULT static Handle<Derived> NewInternal(
198  Isolate* isolate, int capacity, PretenureFlag pretenure);
199 
200  // Find the entry at which to insert element with the given key that
201  // has the given hash value.
202  uint32_t FindInsertionEntry(uint32_t hash);
203 
204  // Attempt to shrink hash table after removal of key.
205  V8_WARN_UNUSED_RESULT static Handle<Derived> Shrink(
206  Isolate* isolate, Handle<Derived> table, int additionalCapacity = 0);
207 
208  private:
209  // Ensure that kMaxRegularCapacity yields a non-large object dictionary.
210  STATIC_ASSERT(EntryToIndex(kMaxRegularCapacity) < kMaxRegularLength);
211  STATIC_ASSERT(v8::base::bits::IsPowerOfTwo(kMaxRegularCapacity));
212  static const int kMaxRegularEntry = kMaxRegularCapacity / kEntrySize;
213  static const int kMaxRegularIndex = EntryToIndex(kMaxRegularEntry);
214  STATIC_ASSERT(OffsetOfElementAt(kMaxRegularIndex) <
215  kMaxRegularHeapObjectSize);
216 
217  // Sets the capacity of the hash table.
218  void SetCapacity(int capacity) {
219  // To scale a computed hash code to fit within the hash table, we
220  // use bit-wise AND with a mask, so the capacity must be positive
221  // and non-zero.
222  DCHECK_GT(capacity, 0);
223  DCHECK_LE(capacity, kMaxCapacity);
224  set(kCapacityIndex, Smi::FromInt(capacity));
225  }
226 
227  // Returns _expected_ if one of entries given by the first _probe_ probes is
228  // equal to _expected_. Otherwise, returns the entry given by the probe
229  // number _probe_.
230  uint32_t EntryForProbe(Isolate* isolate, Object* k, int probe,
231  uint32_t expected);
232 
233  void Swap(uint32_t entry1, uint32_t entry2, WriteBarrierMode mode);
234 
235  // Rehashes this hash-table into the new table.
236  void Rehash(Isolate* isolate, Derived new_table);
237 
238  OBJECT_CONSTRUCTORS(HashTable, HashTableBase)
239 };
240 
241 // HashTableKey is an abstract superclass for virtual key behavior.
243  public:
244  explicit HashTableKey(uint32_t hash) : hash_(hash) {}
245 
246  // Returns whether the other object matches this key.
247  virtual bool IsMatch(Object* other) = 0;
248  // Returns the hash value for this key.
249  // Required.
250  virtual ~HashTableKey() = default;
251 
252  uint32_t Hash() const { return hash_; }
253 
254  protected:
255  void set_hash(uint32_t hash) {
256  DCHECK_EQ(0, hash_);
257  hash_ = hash;
258  }
259 
260  private:
261  uint32_t hash_ = 0;
262 };
263 
264 class ObjectHashTableShape : public BaseShape<Handle<Object>> {
265  public:
266  static inline bool IsMatch(Handle<Object> key, Object* other);
267  static inline uint32_t Hash(Isolate* isolate, Handle<Object> key);
268  static inline uint32_t HashForObject(Isolate* isolate, Object* object);
269  static inline Handle<Object> AsHandle(Handle<Object> key);
270  static const int kPrefixSize = 0;
271  static const int kEntryValueIndex = 1;
272  static const int kEntrySize = 2;
273  static const bool kNeedsHoleCheck = false;
274 };
275 
276 template <typename Derived, typename Shape>
277 class ObjectHashTableBase : public HashTable<Derived, Shape> {
278  public:
279  // Looks up the value associated with the given key. The hole value is
280  // returned in case the key is not present.
281  Object* Lookup(Handle<Object> key);
282  Object* Lookup(Handle<Object> key, int32_t hash);
283  Object* Lookup(ReadOnlyRoots roots, Handle<Object> key, int32_t hash);
284 
285  // Returns the value at entry.
286  Object* ValueAt(int entry);
287 
288  // Overwrite all keys and values with the hole value.
289  static void FillEntriesWithHoles(Handle<Derived>);
290 
291  // Adds (or overwrites) the value associated with the given key.
292  static Handle<Derived> Put(Handle<Derived> table, Handle<Object> key,
293  Handle<Object> value);
294  static Handle<Derived> Put(Isolate* isolate, Handle<Derived> table,
295  Handle<Object> key, Handle<Object> value,
296  int32_t hash);
297 
298  // Returns an ObjectHashTable (possibly |table|) where |key| has been removed.
299  static Handle<Derived> Remove(Isolate* isolate, Handle<Derived> table,
300  Handle<Object> key, bool* was_present);
301  static Handle<Derived> Remove(Isolate* isolate, Handle<Derived> table,
302  Handle<Object> key, bool* was_present,
303  int32_t hash);
304 
305  // Returns the index to the value of an entry.
306  static inline int EntryToValueIndex(int entry) {
308  Shape::kEntryValueIndex;
309  }
310 
311  protected:
312  void AddEntry(int entry, Object* key, Object* value);
313  void RemoveEntry(int entry);
314 
315  OBJECT_CONSTRUCTORS(ObjectHashTableBase, HashTable<Derived, Shape>)
316 };
317 
318 // ObjectHashTable maps keys that are arbitrary objects to object values by
319 // using the identity hash of the key for hashing purposes.
321  : public ObjectHashTableBase<ObjectHashTable, ObjectHashTableShape> {
322  public:
323  DECL_CAST2(ObjectHashTable)
324  DECL_PRINTER(ObjectHashTable)
325 
326  OBJECT_CONSTRUCTORS(
329 };
330 
332  public:
333  static inline RootIndex GetMapRootIndex();
334 };
335 
336 // EphemeronHashTable is similar to ObjectHashTable but gets special treatment
337 // by the GC. The GC treats its entries as ephemerons: both key and value are
338 // weak references, however if the key is strongly reachable its corresponding
339 // value is also kept alive.
341  : public ObjectHashTableBase<EphemeronHashTable, EphemeronHashTableShape> {
342  public:
343  DECL_CAST2(EphemeronHashTable)
344  DECL_PRINTER(EphemeronHashTable)
345 
346  protected:
347  friend class MarkCompactCollector;
348 
349  OBJECT_CONSTRUCTORS(
352 };
353 
355  public:
356  static const int kPrefixSize = 0;
357  static const int kEntrySize = 1;
358 };
359 
360 class ObjectHashSet : public HashTable<ObjectHashSet, ObjectHashSetShape> {
361  public:
362  static Handle<ObjectHashSet> Add(Isolate* isolate, Handle<ObjectHashSet> set,
363  Handle<Object> key);
364 
365  inline bool Has(Isolate* isolate, Handle<Object> key, int32_t hash);
366  inline bool Has(Isolate* isolate, Handle<Object> key);
367 
368  DECL_CAST2(ObjectHashSet)
369 
370  OBJECT_CONSTRUCTORS(ObjectHashSet,
372 };
373 
374 } // namespace internal
375 } // namespace v8
376 
377 #include "src/objects/object-macros-undef.h"
378 
379 #endif // V8_OBJECTS_HASH_TABLE_H_
Definition: libplatform.h:13