• 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_DICTIONARY_H_
6 #define V8_OBJECTS_DICTIONARY_H_
7 
8 #include "src/objects/hash-table.h"
9 
10 #include "src/base/export-template.h"
11 #include "src/globals.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 template <typename T>
20 class Handle;
21 
22 class Isolate;
23 
24 template <typename Derived, typename Shape>
25 class Dictionary : public HashTable<Derived, Shape> {
26   typedef HashTable<Derived, Shape> DerivedHashTable;
27 
28  public:
29   typedef typename Shape::Key Key;
30   // Returns the value at entry.
ValueAt(int entry)31   Object* ValueAt(int entry) {
32     return this->get(DerivedHashTable::EntryToIndex(entry) + 1);
33   }
34 
35   // Set the value for entry.
ValueAtPut(int entry,Object * value)36   void ValueAtPut(int entry, Object* value) {
37     this->set(DerivedHashTable::EntryToIndex(entry) + 1, value);
38   }
39 
40   // Returns the property details for the property at entry.
DetailsAt(int entry)41   PropertyDetails DetailsAt(int entry) {
42     return Shape::DetailsAt(static_cast<Derived*>(this), entry);
43   }
44 
45   // Set the details for entry.
DetailsAtPut(Isolate * isolate,int entry,PropertyDetails value)46   void DetailsAtPut(Isolate* isolate, int entry, PropertyDetails value) {
47     Shape::DetailsAtPut(isolate, static_cast<Derived*>(this), entry, value);
48   }
49 
50   // Delete a property from the dictionary.
51   V8_WARN_UNUSED_RESULT static Handle<Derived> DeleteEntry(
52       Isolate* isolate, Handle<Derived> dictionary, int entry);
53 
54   // Attempt to shrink the dictionary after deletion of key.
Shrink(Isolate * isolate,Handle<Derived> dictionary)55   V8_WARN_UNUSED_RESULT static inline Handle<Derived> Shrink(
56       Isolate* isolate, Handle<Derived> dictionary) {
57     return DerivedHashTable::Shrink(isolate, dictionary);
58   }
59 
60   int NumberOfEnumerableProperties();
61 
62 #ifdef OBJECT_PRINT
63   // For our gdb macros, we should perhaps change these in the future.
64   void Print();
65 
66   void Print(std::ostream& os);  // NOLINT
67 #endif
68   // Returns the key (slow).
69   Object* SlowReverseLookup(Object* value);
70 
71   // Sets the entry to (key, value) pair.
72   inline void ClearEntry(Isolate* isolate, int entry);
73   inline void SetEntry(Isolate* isolate, int entry, Object* key, Object* value,
74                        PropertyDetails details);
75 
76   V8_WARN_UNUSED_RESULT static Handle<Derived> Add(
77       Isolate* isolate, Handle<Derived> dictionary, Key key,
78       Handle<Object> value, PropertyDetails details, int* entry_out = nullptr);
79 
80  protected:
81   // Generic at put operation.
82   V8_WARN_UNUSED_RESULT static Handle<Derived> AtPut(Isolate* isolate,
83                                                      Handle<Derived> dictionary,
84                                                      Key key,
85                                                      Handle<Object> value,
86                                                      PropertyDetails details);
87 };
88 
89 template <typename Key>
90 class BaseDictionaryShape : public BaseShape<Key> {
91  public:
92   static const bool kHasDetails = true;
93   template <typename Dictionary>
DetailsAt(Dictionary * dict,int entry)94   static inline PropertyDetails DetailsAt(Dictionary* dict, int entry) {
95     STATIC_ASSERT(Dictionary::kEntrySize == 3);
96     DCHECK_GE(entry, 0);  // Not found is -1, which is not caught by get().
97     return PropertyDetails(Smi::cast(dict->get(
98         Dictionary::EntryToIndex(entry) + Dictionary::kEntryDetailsIndex)));
99   }
100 
101   template <typename Dictionary>
DetailsAtPut(Isolate * isolate,Dictionary * dict,int entry,PropertyDetails value)102   static inline void DetailsAtPut(Isolate* isolate, Dictionary* dict, int entry,
103                                   PropertyDetails value) {
104     STATIC_ASSERT(Dictionary::kEntrySize == 3);
105     dict->set(Dictionary::EntryToIndex(entry) + Dictionary::kEntryDetailsIndex,
106               value.AsSmi());
107   }
108 };
109 
110 class NameDictionaryShape : public BaseDictionaryShape<Handle<Name>> {
111  public:
112   static inline bool IsMatch(Handle<Name> key, Object* other);
113   static inline uint32_t Hash(Isolate* isolate, Handle<Name> key);
114   static inline uint32_t HashForObject(Isolate* isolate, Object* object);
115   static inline Handle<Object> AsHandle(Isolate* isolate, Handle<Name> key);
116   static inline int GetMapRootIndex();
117   static const int kPrefixSize = 2;
118   static const int kEntrySize = 3;
119   static const int kEntryValueIndex = 1;
120   static const bool kNeedsHoleCheck = false;
121 };
122 
123 template <typename Derived, typename Shape>
124 class BaseNameDictionary : public Dictionary<Derived, Shape> {
125   typedef typename Shape::Key Key;
126 
127  public:
128   static const int kNextEnumerationIndexIndex =
129       HashTableBase::kPrefixStartIndex;
130   static const int kObjectHashIndex = kNextEnumerationIndexIndex + 1;
131   static const int kEntryValueIndex = 1;
132 
133   // Accessors for next enumeration index.
SetNextEnumerationIndex(int index)134   void SetNextEnumerationIndex(int index) {
135     DCHECK_NE(0, index);
136     this->set(kNextEnumerationIndexIndex, Smi::FromInt(index));
137   }
138 
NextEnumerationIndex()139   int NextEnumerationIndex() {
140     return Smi::ToInt(this->get(kNextEnumerationIndexIndex));
141   }
142 
SetHash(int hash)143   void SetHash(int hash) {
144     DCHECK(PropertyArray::HashField::is_valid(hash));
145     this->set(kObjectHashIndex, Smi::FromInt(hash));
146   }
147 
Hash()148   int Hash() const {
149     Object* hash_obj = this->get(kObjectHashIndex);
150     int hash = Smi::ToInt(hash_obj);
151     DCHECK(PropertyArray::HashField::is_valid(hash));
152     return hash;
153   }
154 
155   // Creates a new dictionary.
156   V8_WARN_UNUSED_RESULT static Handle<Derived> New(
157       Isolate* isolate, int at_least_space_for,
158       PretenureFlag pretenure = NOT_TENURED,
159       MinimumCapacity capacity_option = USE_DEFAULT_MINIMUM_CAPACITY);
160 
161   // Collect the keys into the given KeyAccumulator, in ascending chronological
162   // order of property creation.
163   static void CollectKeysTo(Handle<Derived> dictionary, KeyAccumulator* keys);
164 
165   // Return the key indices sorted by its enumeration index.
166   static Handle<FixedArray> IterationIndices(Isolate* isolate,
167                                              Handle<Derived> dictionary);
168 
169   // Copies enumerable keys to preallocated fixed array.
170   // Does not throw for uninitialized exports in module namespace objects, so
171   // this has to be checked separately.
172   static void CopyEnumKeysTo(Isolate* isolate, Handle<Derived> dictionary,
173                              Handle<FixedArray> storage, KeyCollectionMode mode,
174                              KeyAccumulator* accumulator);
175 
176   // Ensure enough space for n additional elements.
177   static Handle<Derived> EnsureCapacity(Isolate* isolate,
178                                         Handle<Derived> dictionary, int n);
179 
180   V8_WARN_UNUSED_RESULT static Handle<Derived> AddNoUpdateNextEnumerationIndex(
181       Isolate* isolate, Handle<Derived> dictionary, Key key,
182       Handle<Object> value, PropertyDetails details, int* entry_out = nullptr);
183 
184   V8_WARN_UNUSED_RESULT static Handle<Derived> Add(
185       Isolate* isolate, Handle<Derived> dictionary, Key key,
186       Handle<Object> value, PropertyDetails details, int* entry_out = nullptr);
187 };
188 
189 class NameDictionary
190     : public BaseNameDictionary<NameDictionary, NameDictionaryShape> {
191  public:
192   DECL_CAST(NameDictionary)
193 
194   static const int kEntryDetailsIndex = 2;
195   static const int kInitialCapacity = 2;
196 
197   inline Name* NameAt(int entry);
198   inline void set_hash(int hash);
199   inline int hash() const;
200 };
201 
202 class GlobalDictionaryShape : public NameDictionaryShape {
203  public:
204   static inline bool IsMatch(Handle<Name> key, Object* other);
205   static inline uint32_t HashForObject(Isolate* isolate, Object* object);
206 
207   static const int kEntrySize = 1;  // Overrides NameDictionaryShape::kEntrySize
208 
209   template <typename Dictionary>
210   static inline PropertyDetails DetailsAt(Dictionary* dict, int entry);
211 
212   template <typename Dictionary>
213   static inline void DetailsAtPut(Isolate* isolate, Dictionary* dict, int entry,
214                                   PropertyDetails value);
215 
216   static inline Object* Unwrap(Object* key);
217   static inline bool IsKey(ReadOnlyRoots roots, Object* k);
218   static inline bool IsLive(ReadOnlyRoots roots, Object* key);
219   static inline int GetMapRootIndex();
220 };
221 
222 class GlobalDictionary
223     : public BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape> {
224  public:
225   DECL_CAST(GlobalDictionary)
226 
227   inline Object* ValueAt(int entry);
228   inline PropertyCell* CellAt(int entry);
229   inline void SetEntry(Isolate* isolate, int entry, Object* key, Object* value,
230                        PropertyDetails details);
231   inline Name* NameAt(int entry);
232   inline void ValueAtPut(int entry, Object* value);
233 };
234 
235 class NumberDictionaryBaseShape : public BaseDictionaryShape<uint32_t> {
236  public:
237   static inline bool IsMatch(uint32_t key, Object* other);
238   static inline Handle<Object> AsHandle(Isolate* isolate, uint32_t key);
239 
240   static inline uint32_t Hash(Isolate* isolate, uint32_t key);
241   static inline uint32_t HashForObject(Isolate* isolate, Object* object);
242 };
243 
244 class NumberDictionaryShape : public NumberDictionaryBaseShape {
245  public:
246   static const int kPrefixSize = 1;
247   static const int kEntrySize = 3;
248 
249   static inline int GetMapRootIndex();
250 };
251 
252 class SimpleNumberDictionaryShape : public NumberDictionaryBaseShape {
253  public:
254   static const bool kHasDetails = false;
255   static const int kPrefixSize = 0;
256   static const int kEntrySize = 2;
257 
258   template <typename Dictionary>
DetailsAt(Dictionary * dict,int entry)259   static inline PropertyDetails DetailsAt(Dictionary* dict, int entry) {
260     UNREACHABLE();
261   }
262 
263   template <typename Dictionary>
DetailsAtPut(Isolate * isolate,Dictionary * dict,int entry,PropertyDetails value)264   static inline void DetailsAtPut(Isolate* isolate, Dictionary* dict, int entry,
265                                   PropertyDetails value) {
266     UNREACHABLE();
267   }
268 
269   static inline int GetMapRootIndex();
270 };
271 
272 extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
273     HashTable<SimpleNumberDictionary, SimpleNumberDictionaryShape>;
274 
275 extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
276     Dictionary<SimpleNumberDictionary, SimpleNumberDictionaryShape>;
277 
278 // SimpleNumberDictionary is used to map number to an entry.
279 class SimpleNumberDictionary
280     : public Dictionary<SimpleNumberDictionary, SimpleNumberDictionaryShape> {
281  public:
282   DECL_CAST(SimpleNumberDictionary)
283   // Type specific at put (default NONE attributes is used when adding).
284   V8_WARN_UNUSED_RESULT static Handle<SimpleNumberDictionary> Set(
285       Isolate* isolate, Handle<SimpleNumberDictionary> dictionary, uint32_t key,
286       Handle<Object> value);
287 
288   static const int kEntryValueIndex = 1;
289 };
290 
291 extern template class EXPORT_TEMPLATE_DECLARE(
292     V8_EXPORT_PRIVATE) HashTable<NumberDictionary, NumberDictionaryShape>;
293 
294 extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
295     Dictionary<NumberDictionary, NumberDictionaryShape>;
296 
297 // NumberDictionary is used as elements backing store and provides a bitfield
298 // and stores property details for every entry.
299 class NumberDictionary
300     : public Dictionary<NumberDictionary, NumberDictionaryShape> {
301  public:
302   DECL_CAST(NumberDictionary)
303   DECL_PRINTER(NumberDictionary)
304 
305   // Type specific at put (default NONE attributes is used when adding).
306   V8_WARN_UNUSED_RESULT static Handle<NumberDictionary> Set(
307       Isolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
308       Handle<Object> value,
309       Handle<JSObject> dictionary_holder = Handle<JSObject>::null(),
310       PropertyDetails details = PropertyDetails::Empty());
311 
312   static const int kMaxNumberKeyIndex = kPrefixStartIndex;
313   void UpdateMaxNumberKey(uint32_t key, Handle<JSObject> dictionary_holder);
314 
315   // Returns true if the dictionary contains any elements that are non-writable,
316   // non-configurable, non-enumerable, or have getters/setters.
317   bool HasComplexElements();
318 
319   // Sorting support
320   void CopyValuesTo(FixedArray* elements);
321 
322   // If slow elements are required we will never go back to fast-case
323   // for the elements kept in this dictionary.  We require slow
324   // elements if an element has been added at an index larger than
325   // kRequiresSlowElementsLimit or set_requires_slow_elements() has been called
326   // when defining a getter or setter with a number key.
327   inline bool requires_slow_elements();
328   inline void set_requires_slow_elements();
329 
330   // Get the value of the max number key that has been added to this
331   // dictionary.  max_number_key can only be called if
332   // requires_slow_elements returns false.
333   inline uint32_t max_number_key();
334 
335   static const int kEntryValueIndex = 1;
336   static const int kEntryDetailsIndex = 2;
337 
338   // Bit masks.
339   static const int kRequiresSlowElementsMask = 1;
340   static const int kRequiresSlowElementsTagSize = 1;
341   static const uint32_t kRequiresSlowElementsLimit = (1 << 29) - 1;
342 
343   // JSObjects prefer dictionary elements if the dictionary saves this much
344   // memory compared to a fast elements backing store.
345   static const uint32_t kPreferFastElementsSizeFactor = 3;
346 };
347 
348 }  // namespace internal
349 }  // namespace v8
350 
351 #include "src/objects/object-macros-undef.h"
352 
353 #endif  // V8_OBJECTS_DICTIONARY_H_
354