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