v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
dictionary.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_DICTIONARY_H_
6#define V8_OBJECTS_DICTIONARY_H_
7
8#include <optional>
9
11#include "src/common/globals.h"
14#include "src/objects/smi.h"
15#include "src/roots/roots.h"
16
17// Has to be the last include (doesn't have include guards):
19
20namespace v8::internal {
21
22#ifdef V8_ENABLE_SWISS_NAME_DICTIONARY
23class SwissNameDictionary;
24using PropertyDictionary = SwissNameDictionary;
25#else
27#endif
28
29template <typename Derived, typename Shape>
30class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) Dictionary
31 : public HashTable<Derived, Shape> {
32 using DerivedHashTable = HashTable<Derived, Shape>;
33
34 public:
35 using TodoShape = Shape;
36 using Key = typename TodoShape::Key;
37 inline Tagged<Object> ValueAt(InternalIndex entry);
38 inline Tagged<Object> ValueAt(PtrComprCageBase cage_base,
39 InternalIndex entry);
40 inline Tagged<Object> ValueAt(InternalIndex entry, SeqCstAccessTag);
41 inline Tagged<Object> ValueAt(PtrComprCageBase cage_base, InternalIndex entry,
43 // Returns {} if we would be reading out of the bounds of the object.
44 inline std::optional<Tagged<Object>> TryValueAt(InternalIndex entry);
45
46 // Set the value for entry.
47 inline void ValueAtPut(InternalIndex entry, Tagged<Object> value);
48 inline void ValueAtPut(InternalIndex entry, Tagged<Object> value,
50
51 // Swap the value for the entry.
52 inline Tagged<Object> ValueAtSwap(InternalIndex entry, Tagged<Object> value,
54
55 // Compare and swap the value for the entry.
56 inline Tagged<Object> ValueAtCompareAndSwap(InternalIndex entry,
57 Tagged<Object> expected,
58 Tagged<Object> value,
60
61 // Returns the property details for the property at entry.
62 inline PropertyDetails DetailsAt(InternalIndex entry);
63
64 // Set the details for entry.
65 inline void DetailsAtPut(InternalIndex entry, PropertyDetails value);
66
67 static const bool kIsOrderedDictionaryType = false;
68
69 // Delete a property from the dictionary.
70 template <template <typename> typename HandleType>
71 requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
72 V8_WARN_UNUSED_RESULT static HandleType<Derived> DeleteEntry(
73 Isolate* isolate, HandleType<Derived> dictionary, InternalIndex entry);
74
75 // Attempt to shrink the dictionary after deletion of key.
76 template <template <typename> typename HandleType>
77 V8_WARN_UNUSED_RESULT static inline HandleType<Derived> Shrink(
78 Isolate* isolate, HandleType<Derived> dictionary)
79 requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
80 {
81 return DerivedHashTable::Shrink(isolate, dictionary);
82 }
83
84 int NumberOfEnumerableProperties();
85
86 // Returns the key (slow).
87 Tagged<Object> SlowReverseLookup(Tagged<Object> value);
88
89 inline void ClearEntry(InternalIndex entry);
90
91 // Sets the entry to (key, value) pair.
92 inline void SetEntry(InternalIndex entry, Tagged<Object> key,
93 Tagged<Object> value, PropertyDetails details);
94
95 // Garbage collection support.
96 inline ObjectSlot RawFieldOfValueAt(InternalIndex entry);
97
98 template <typename IsolateT, template <typename> typename HandleType,
99 AllocationType key_allocation =
100 std::is_same<IsolateT, Isolate>::value ? AllocationType::kYoung
101 : AllocationType::kOld>
102 requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
103 V8_WARN_UNUSED_RESULT static HandleType<Derived> Add(
104 IsolateT* isolate, HandleType<Derived> dictionary, Key key,
106 InternalIndex* entry_out = nullptr);
107
108 // This method is only safe to use when it is guaranteed that the dictionary
109 // doesn't need to grow.
110 // The number of elements stored is not updated. Use
111 // |SetInitialNumberOfElements| to update the number in one go.
112 template <typename IsolateT, template <typename> typename HandleType,
113 AllocationType key_allocation =
114 std::is_same<IsolateT, Isolate>::value ? AllocationType::kYoung
115 : AllocationType::kOld>
116 requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
117 static void UncheckedAdd(IsolateT* isolate, HandleType<Derived> dictionary,
118 Key key, DirectHandle<Object> value,
119 PropertyDetails details);
120
121 static Handle<Derived> ShallowCopy(
122 Isolate* isolate, DirectHandle<Derived> dictionary,
123 AllocationType allocation = AllocationType::kYoung);
124
125 protected:
126 // Generic at put operation.
127 template <template <typename> typename HandleType>
128 requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
129 V8_WARN_UNUSED_RESULT static HandleType<Derived> AtPut(
130 Isolate* isolate, HandleType<Derived> dictionary, Key key,
132 static void UncheckedAtPut(Isolate* isolate, DirectHandle<Derived> dictionary,
133 Key key, DirectHandle<Object> value,
134 PropertyDetails details);
135};
136
137#define EXTERN_DECLARE_DICTIONARY(DERIVED, SHAPE) \
138 EXTERN_DECLARE_HASH_TABLE(DERIVED, SHAPE) \
139 extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) \
140 Dictionary<DERIVED, SHAPE>;
141
142template <typename Key>
143class BaseDictionaryShape : public BaseShape<Key> {
144 public:
145 static const bool kHasDetails = true;
146 template <typename Dictionary>
147 static inline PropertyDetails DetailsAt(Tagged<Dictionary> dict,
148 InternalIndex entry);
149
150 template <typename Dictionary>
151 static inline void DetailsAtPut(Tagged<Dictionary> dict, InternalIndex entry,
152 PropertyDetails value);
153 static const bool kDoHashSpreading = false;
154 static const uint32_t kHashBits = 0;
155};
156
157class BaseNameDictionaryShape : public BaseDictionaryShape<DirectHandle<Name>> {
158 public:
159 static inline bool IsMatch(DirectHandle<Name> key, Tagged<Object> other);
160 static inline uint32_t Hash(ReadOnlyRoots roots, DirectHandle<Name> key);
161 static inline uint32_t HashForObject(ReadOnlyRoots roots,
162 Tagged<Object> object);
163 template <AllocationType allocation = AllocationType::kYoung>
164 static inline DirectHandle<Object> AsHandle(Isolate* isolate,
166 template <AllocationType allocation = AllocationType::kOld>
167 static inline DirectHandle<Object> AsHandle(LocalIsolate* isolate,
169 static const int kEntryValueIndex = 1;
170};
171
173 public:
174 static const int kPrefixSize = 3;
175 static const int kEntrySize = 3;
176 static const bool kMatchNeedsHoleCheck = false;
177};
178
179template <typename Derived, typename Shape>
180class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) BaseNameDictionary
181 : public Dictionary<Derived, Shape> {
182 using Key = typename Shape::Key;
183
184 public:
185 static const int kNextEnumerationIndexIndex =
186 HashTableBase::kPrefixStartIndex;
187 static const int kObjectHashIndex = kNextEnumerationIndexIndex + 1;
188 static const int kEntryValueIndex = 1;
189
190 inline void SetHash(int hash);
191 inline int Hash() const;
192
193 // Creates a new dictionary.
194 template <typename IsolateT>
196 IsolateT* isolate, int at_least_space_for,
197 AllocationType allocation = AllocationType::kYoung,
199
200 // Allocate the next enumeration index. Possibly updates all enumeration
201 // indices in the table.
202 static int NextEnumerationIndex(Isolate* isolate,
203 DirectHandle<Derived> dictionary);
204 // Accessors for next enumeration index.
205 inline int next_enumeration_index();
206 inline void set_next_enumeration_index(int index);
207
208 // Return the key indices sorted by its enumeration index.
209 static DirectHandle<FixedArray> IterationIndices(
210 Isolate* isolate, DirectHandle<Derived> dictionary);
211
212 template <typename IsolateT, template <typename> typename HandleType>
213 requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
214 V8_WARN_UNUSED_RESULT static HandleType<Derived>
215 AddNoUpdateNextEnumerationIndex(IsolateT* isolate,
216 HandleType<Derived> dictionary, Key key,
218 PropertyDetails details,
219 InternalIndex* entry_out = nullptr);
220
221 template <template <typename> typename HandleType>
222 requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
223 V8_WARN_UNUSED_RESULT static HandleType<Derived> Add(
224 Isolate* isolate, HandleType<Derived> dictionary, Key key,
226 InternalIndex* entry_out = nullptr);
227
228 // Exposed for NameDictionaryLookupForwardedString slow path for forwarded
229 // strings.
230 using Dictionary<Derived, Shape>::FindInsertionEntry;
231};
232
233#define EXTERN_DECLARE_BASE_NAME_DICTIONARY(DERIVED, SHAPE) \
234 EXTERN_DECLARE_DICTIONARY(DERIVED, SHAPE) \
235 extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) \
236 BaseNameDictionary<DERIVED, SHAPE>;
237
238EXTERN_DECLARE_BASE_NAME_DICTIONARY(NameDictionary, NameDictionaryShape)
239
241 : public BaseNameDictionary<NameDictionary, NameDictionaryShape> {
242 public:
243 static inline DirectHandle<Map> GetMap(RootsTable& roots);
244
246
247 static const int kFlagsIndex = kObjectHashIndex + 1;
248 static const int kEntryValueIndex = 1;
249 static const int kEntryDetailsIndex = 2;
250 static const int kInitialCapacity = 2;
251
252 inline Tagged<Name> NameAt(InternalIndex entry);
253 inline Tagged<Name> NameAt(PtrComprCageBase cage_base, InternalIndex entry);
254
255 inline void set_hash(int hash);
256 inline int hash() const;
257
258 // Note: Flags are stored as smi, so only 31 bits are usable.
259 using MayHaveInterestingPropertiesBit = base::BitField<bool, 0, 1, uint32_t>;
260 DECL_BOOLEAN_ACCESSORS(may_have_interesting_properties)
261
262 static constexpr int kFlagsDefault = 0;
263
264 inline uint32_t flags() const;
265 inline void set_flags(uint32_t flags);
266
267 // Creates a new NameDictionary.
268 template <typename IsolateT>
270 IsolateT* isolate, int at_least_space_for,
271 AllocationType allocation = AllocationType::kYoung,
272 MinimumCapacity capacity_option = USE_DEFAULT_MINIMUM_CAPACITY);
273};
274
276 public:
277 static inline bool IsMatch(DirectHandle<Name> key, Tagged<Object> other);
278 static inline uint32_t HashForObject(ReadOnlyRoots roots,
279 Tagged<Object> object);
280
281 static const bool kMatchNeedsHoleCheck = true;
282 static const int kPrefixSize = 2;
283 static const int kEntrySize = 1;
284
285 template <typename Dictionary>
286 static inline PropertyDetails DetailsAt(Tagged<Dictionary> dict,
287 InternalIndex entry);
288
289 template <typename Dictionary>
290 static inline void DetailsAtPut(Tagged<Dictionary> dict, InternalIndex entry,
291 PropertyDetails value);
292
293 static inline Tagged<Object> Unwrap(Tagged<Object> key);
294};
295
297
299 : public BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape> {
300 public:
301 static inline DirectHandle<Map> GetMap(RootsTable& roots);
302
304
305 inline Tagged<Object> ValueAt(InternalIndex entry);
306 inline Tagged<Object> ValueAt(PtrComprCageBase cage_base,
307 InternalIndex entry);
309 inline Tagged<PropertyCell> CellAt(PtrComprCageBase cage_base,
310 InternalIndex entry);
311 inline void SetEntry(InternalIndex entry, Tagged<Object> key,
312 Tagged<Object> value, PropertyDetails details);
313 inline void ClearEntry(InternalIndex entry);
314 inline Tagged<Name> NameAt(InternalIndex entry);
315 inline Tagged<Name> NameAt(PtrComprCageBase cage_base, InternalIndex entry);
316 inline void ValueAtPut(InternalIndex entry, Tagged<Object> value);
317
318 std::optional<Tagged<PropertyCell>>
319 TryFindPropertyCellForConcurrentLookupIterator(Isolate* isolate,
321 RelaxedLoadTag tag);
322};
323
325 public:
326 static inline bool IsMatch(uint32_t key, Tagged<Object> other);
327 template <AllocationType allocation = AllocationType::kYoung>
328 static inline DirectHandle<Object> AsHandle(Isolate* isolate, uint32_t key);
329 template <AllocationType allocation = AllocationType::kOld>
330 static inline DirectHandle<Object> AsHandle(LocalIsolate* isolate,
331 uint32_t key);
332
333 static inline uint32_t Hash(ReadOnlyRoots roots, uint32_t key);
334 static inline uint32_t HashForObject(ReadOnlyRoots roots,
335 Tagged<Object> object);
336
337 static const bool kMatchNeedsHoleCheck = true;
338};
339
341 public:
342 static const int kPrefixSize = 1;
343 static const int kEntrySize = 3;
344};
345
347 public:
348 static const bool kHasDetails = false;
349 static const int kPrefixSize = 0;
350 static const int kEntrySize = 2;
351
352 template <typename Dictionary>
354 InternalIndex entry) {
355 UNREACHABLE();
356 }
357
358 template <typename Dictionary>
359 static inline void DetailsAtPut(Tagged<Dictionary> dict, InternalIndex entry,
360 PropertyDetails value) {
361 UNREACHABLE();
362 }
363};
364
365EXTERN_DECLARE_DICTIONARY(SimpleNumberDictionary, SimpleNumberDictionaryShape)
366
367// SimpleNumberDictionary is used to map number to an entry.
370 public:
371 static inline DirectHandle<Map> GetMap(RootsTable& roots);
372
373 // Type specific at put (default NONE attributes is used when adding).
375 Set(Isolate* isolate, Handle<SimpleNumberDictionary> dictionary, uint32_t key,
377
378 static const int kEntryValueIndex = 1;
379};
380
382
383// NumberDictionary is used as elements backing store and provides a bitfield
384// and stores property details for every entry.
386 : public Dictionary<NumberDictionary, NumberDictionaryShape> {
387 public:
388 static inline DirectHandle<Map> GetMap(RootsTable& roots);
389
391
392 // Type specific at put (default NONE attributes is used when adding).
393 template <template <typename> typename HandleType>
394 requires(std::is_convertible_v<HandleType<NumberDictionary>,
396 V8_WARN_UNUSED_RESULT static HandleType<NumberDictionary> Set(
397 Isolate* isolate, HandleType<NumberDictionary> dictionary, uint32_t key,
400 PropertyDetails details = PropertyDetails::Empty());
401 // This method is only safe to use when it is guaranteed that the dictionary
402 // doesn't need to grow.
403 // The number of elements stored and the maximum index is not updated. Use
404 // |SetInitialNumberOfElements| and |UpdateMaxNumberKey| to update the number
405 // in one go.
406 static void UncheckedSet(Isolate* isolate,
408 uint32_t key, DirectHandle<Object> value);
409
410 static const int kMaxNumberKeyIndex = kPrefixStartIndex;
411 void UpdateMaxNumberKey(uint32_t key,
412 DirectHandle<JSObject> dictionary_holder);
413
414 // Sorting support
415 void CopyValuesTo(Tagged<FixedArray> elements);
416
417 // If slow elements are required we will never go back to fast-case
418 // for the elements kept in this dictionary. We require slow
419 // elements if an element has been added at an index larger than
420 // kRequiresSlowElementsLimit or set_requires_slow_elements() has been called
421 // when defining a getter or setter with a number key.
422 inline bool requires_slow_elements();
423 inline void set_requires_slow_elements();
424
425 // Get the value of the max number key that has been added to this
426 // dictionary. max_number_key can only be called if
427 // requires_slow_elements returns false.
428 inline uint32_t max_number_key();
429
430 static const int kEntryValueIndex = 1;
431 static const int kEntryDetailsIndex = 2;
432
433 // Bit masks.
434 static const int kRequiresSlowElementsMask = 1;
435 static const int kRequiresSlowElementsTagSize = 1;
436 static const uint32_t kRequiresSlowElementsLimit = (1 << 29) - 1;
437
438 // JSObjects prefer dictionary elements if the dictionary saves this much
439 // memory compared to a fast elements backing store.
440 static const uint32_t kPreferFastElementsSizeFactor = 3;
441};
442
443// The comparator is passed two indices |a| and |b|, and it returns < 0 when the
444// property at index |a| comes before the property at index |b| in the
445// enumeration order.
446template <typename Dictionary>
448 explicit EnumIndexComparator(Tagged<Dictionary> dict) : dict(dict) {}
450 PropertyDetails details_a(dict->DetailsAt(
451 InternalIndex(Tagged<Smi>(static_cast<Address>(a)).value())));
452 PropertyDetails details_b(dict->DetailsAt(
453 InternalIndex(Tagged<Smi>(static_cast<Address>(b)).value())));
454 return details_a.dictionary_index() < details_b.dictionary_index();
455 }
457};
458
459} // namespace v8::internal
460
462
463#endif // V8_OBJECTS_DICTIONARY_H_
Tagged< PropertyCell > CellAt(InternalIndex entry)
static V8_WARN_UNUSED_RESULT HandleType< NumberDictionary > Set(Isolate *isolate, HandleType< NumberDictionary > dictionary, uint32_t key, DirectHandle< Object > value, DirectHandle< JSObject > dictionary_holder=DirectHandle< JSObject >::null(), PropertyDetails details=PropertyDetails::Empty())
static PropertyDetails DetailsAt(Tagged< Dictionary > dict, InternalIndex entry)
Definition dictionary.h:353
static void DetailsAtPut(Tagged< Dictionary > dict, InternalIndex entry, PropertyDetails value)
Definition dictionary.h:359
#define EXTERN_DECLARE_DICTIONARY(DERIVED, SHAPE)
Definition dictionary.h:137
#define EXTERN_DECLARE_BASE_NAME_DICTIONARY(DERIVED, SHAPE)
Definition dictionary.h:233
@ USE_DEFAULT_MINIMUM_CAPACITY
Definition globals.h:1567
Address Tagged_t
Definition globals.h:547
NameDictionary PropertyDictionary
Definition dictionary.h:26
#define DECL_BOOLEAN_ACCESSORS(name)
#define DECL_PRINTER(Name)
#define UNREACHABLE()
Definition logging.h:67
#define V8_EXPORT_PRIVATE
Definition macros.h:460
bool operator()(Tagged_t a, Tagged_t b)
Definition dictionary.h:449
EnumIndexComparator(Tagged< Dictionary > dict)
Definition dictionary.h:448
#define V8_WARN_UNUSED_RESULT
Definition v8config.h:671
std::unique_ptr< ValueMirror > value
std::unique_ptr< ValueMirror > key