1 // Copyright 2018 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_INL_H_
6 #define V8_OBJECTS_DICTIONARY_INL_H_
7 
8 #include "src/base/optional.h"
9 #include "src/execution/isolate-utils-inl.h"
10 #include "src/numbers/hash-seed-inl.h"
11 #include "src/objects/dictionary.h"
12 #include "src/objects/hash-table-inl.h"
13 #include "src/objects/objects-inl.h"
14 #include "src/objects/oddball.h"
15 #include "src/objects/property-cell-inl.h"
16 
17 // Has to be the last include (doesn't have include guards):
18 #include "src/objects/object-macros.h"
19 
20 namespace v8 {
21 namespace internal {
22 
23 CAST_ACCESSOR(GlobalDictionary)
CAST_ACCESSOR(NameDictionary)24 CAST_ACCESSOR(NameDictionary)
25 CAST_ACCESSOR(NumberDictionary)
26 CAST_ACCESSOR(SimpleNumberDictionary)
27 
28 template <typename Derived, typename Shape>
29 Dictionary<Derived, Shape>::Dictionary(Address ptr)
30     : HashTable<Derived, Shape>(ptr) {}
31 
32 template <typename Derived, typename Shape>
ValueAt(InternalIndex entry)33 Object Dictionary<Derived, Shape>::ValueAt(InternalIndex entry) {
34   PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
35   return ValueAt(cage_base, entry);
36 }
37 
38 template <typename Derived, typename Shape>
ValueAt(PtrComprCageBase cage_base,InternalIndex entry)39 Object Dictionary<Derived, Shape>::ValueAt(PtrComprCageBase cage_base,
40                                            InternalIndex entry) {
41   return this->get(cage_base, DerivedHashTable::EntryToIndex(entry) +
42                                   Derived::kEntryValueIndex);
43 }
44 
45 template <typename Derived, typename Shape>
TryValueAt(InternalIndex entry)46 base::Optional<Object> Dictionary<Derived, Shape>::TryValueAt(
47     InternalIndex entry) {
48 #if DEBUG
49   Isolate* isolate;
50   GetIsolateFromHeapObject(*this, &isolate);
51   DCHECK_NE(isolate, nullptr);
52   SLOW_DCHECK(!isolate->heap()->IsPendingAllocation(*this));
53 #endif  // DEBUG
54   // We can read length() in a non-atomic way since we are reading an
55   // initialized object which is not pending allocation.
56   if (DerivedHashTable::EntryToIndex(entry) + Derived::kEntryValueIndex >=
57       this->length()) {
58     return {};
59   }
60   return ValueAt(entry);
61 }
62 
63 template <typename Derived, typename Shape>
ValueAtPut(InternalIndex entry,Object value)64 void Dictionary<Derived, Shape>::ValueAtPut(InternalIndex entry, Object value) {
65   this->set(DerivedHashTable::EntryToIndex(entry) + Derived::kEntryValueIndex,
66             value);
67 }
68 
69 template <typename Derived, typename Shape>
DetailsAt(InternalIndex entry)70 PropertyDetails Dictionary<Derived, Shape>::DetailsAt(InternalIndex entry) {
71   return Shape::DetailsAt(Derived::cast(*this), entry);
72 }
73 
74 template <typename Derived, typename Shape>
DetailsAtPut(InternalIndex entry,PropertyDetails value)75 void Dictionary<Derived, Shape>::DetailsAtPut(InternalIndex entry,
76                                               PropertyDetails value) {
77   Shape::DetailsAtPut(Derived::cast(*this), entry, value);
78 }
79 
80 template <typename Derived, typename Shape>
BaseNameDictionary(Address ptr)81 BaseNameDictionary<Derived, Shape>::BaseNameDictionary(Address ptr)
82     : Dictionary<Derived, Shape>(ptr) {}
83 
84 template <typename Derived, typename Shape>
set_next_enumeration_index(int index)85 void BaseNameDictionary<Derived, Shape>::set_next_enumeration_index(int index) {
86   DCHECK_LT(0, index);
87   this->set(kNextEnumerationIndexIndex, Smi::FromInt(index));
88 }
89 
90 template <typename Derived, typename Shape>
next_enumeration_index()91 int BaseNameDictionary<Derived, Shape>::next_enumeration_index() {
92   return Smi::ToInt(this->get(kNextEnumerationIndexIndex));
93 }
94 
95 template <typename Derived, typename Shape>
SetHash(int hash)96 void BaseNameDictionary<Derived, Shape>::SetHash(int hash) {
97   DCHECK(PropertyArray::HashField::is_valid(hash));
98   this->set(kObjectHashIndex, Smi::FromInt(hash));
99 }
100 
101 template <typename Derived, typename Shape>
Hash()102 int BaseNameDictionary<Derived, Shape>::Hash() const {
103   Object hash_obj = this->get(kObjectHashIndex);
104   int hash = Smi::ToInt(hash_obj);
105   DCHECK(PropertyArray::HashField::is_valid(hash));
106   return hash;
107 }
108 
GlobalDictionary(Address ptr)109 GlobalDictionary::GlobalDictionary(Address ptr)
110     : BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape>(ptr) {
111   SLOW_DCHECK(IsGlobalDictionary());
112 }
113 
NameDictionary(Address ptr)114 NameDictionary::NameDictionary(Address ptr)
115     : BaseNameDictionary<NameDictionary, NameDictionaryShape>(ptr) {
116   SLOW_DCHECK(IsNameDictionary());
117 }
118 
NumberDictionary(Address ptr)119 NumberDictionary::NumberDictionary(Address ptr)
120     : Dictionary<NumberDictionary, NumberDictionaryShape>(ptr) {
121   SLOW_DCHECK(IsNumberDictionary());
122 }
123 
SimpleNumberDictionary(Address ptr)124 SimpleNumberDictionary::SimpleNumberDictionary(Address ptr)
125     : Dictionary<SimpleNumberDictionary, SimpleNumberDictionaryShape>(ptr) {
126   SLOW_DCHECK(IsSimpleNumberDictionary());
127 }
128 
requires_slow_elements()129 bool NumberDictionary::requires_slow_elements() {
130   Object max_index_object = get(kMaxNumberKeyIndex);
131   if (!max_index_object.IsSmi()) return false;
132   return 0 != (Smi::ToInt(max_index_object) & kRequiresSlowElementsMask);
133 }
134 
max_number_key()135 uint32_t NumberDictionary::max_number_key() {
136   DCHECK(!requires_slow_elements());
137   Object max_index_object = get(kMaxNumberKeyIndex);
138   if (!max_index_object.IsSmi()) return 0;
139   uint32_t value = static_cast<uint32_t>(Smi::ToInt(max_index_object));
140   return value >> kRequiresSlowElementsTagSize;
141 }
142 
set_requires_slow_elements()143 void NumberDictionary::set_requires_slow_elements() {
144   set(kMaxNumberKeyIndex, Smi::FromInt(kRequiresSlowElementsMask));
145 }
146 
147 template <typename Derived, typename Shape>
ClearEntry(InternalIndex entry)148 void Dictionary<Derived, Shape>::ClearEntry(InternalIndex entry) {
149   Object the_hole = this->GetReadOnlyRoots().the_hole_value();
150   PropertyDetails details = PropertyDetails::Empty();
151   Derived::cast(*this).SetEntry(entry, the_hole, the_hole, details);
152 }
153 
154 template <typename Derived, typename Shape>
SetEntry(InternalIndex entry,Object key,Object value,PropertyDetails details)155 void Dictionary<Derived, Shape>::SetEntry(InternalIndex entry, Object key,
156                                           Object value,
157                                           PropertyDetails details) {
158   DCHECK(Dictionary::kEntrySize == 2 || Dictionary::kEntrySize == 3);
159   DCHECK(!key.IsName() || details.dictionary_index() > 0);
160   int index = DerivedHashTable::EntryToIndex(entry);
161   DisallowGarbageCollection no_gc;
162   WriteBarrierMode mode = this->GetWriteBarrierMode(no_gc);
163   this->set(index + Derived::kEntryKeyIndex, key, mode);
164   this->set(index + Derived::kEntryValueIndex, value, mode);
165   if (Shape::kHasDetails) DetailsAtPut(entry, details);
166 }
167 
168 template <typename Derived, typename Shape>
RawFieldOfValueAt(InternalIndex entry)169 ObjectSlot Dictionary<Derived, Shape>::RawFieldOfValueAt(InternalIndex entry) {
170   return this->RawFieldOfElementAt(DerivedHashTable::EntryToIndex(entry) +
171                                    Derived::kEntryValueIndex);
172 }
173 
174 template <typename Key>
175 template <typename Dictionary>
DetailsAt(Dictionary dict,InternalIndex entry)176 PropertyDetails BaseDictionaryShape<Key>::DetailsAt(Dictionary dict,
177                                                     InternalIndex entry) {
178   STATIC_ASSERT(Dictionary::kEntrySize == 3);
179   DCHECK(entry.is_found());
180   return PropertyDetails(Smi::cast(dict.get(Dictionary::EntryToIndex(entry) +
181                                             Dictionary::kEntryDetailsIndex)));
182 }
183 
184 template <typename Key>
185 template <typename Dictionary>
DetailsAtPut(Dictionary dict,InternalIndex entry,PropertyDetails value)186 void BaseDictionaryShape<Key>::DetailsAtPut(Dictionary dict,
187                                             InternalIndex entry,
188                                             PropertyDetails value) {
189   STATIC_ASSERT(Dictionary::kEntrySize == 3);
190   dict.set(Dictionary::EntryToIndex(entry) + Dictionary::kEntryDetailsIndex,
191            value.AsSmi());
192 }
193 
Unwrap(Object object)194 Object GlobalDictionaryShape::Unwrap(Object object) {
195   return PropertyCell::cast(object).name();
196 }
197 
GetMap(ReadOnlyRoots roots)198 Handle<Map> GlobalDictionary::GetMap(ReadOnlyRoots roots) {
199   return roots.global_dictionary_map_handle();
200 }
201 
NameAt(InternalIndex entry)202 Name NameDictionary::NameAt(InternalIndex entry) {
203   PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
204   return NameAt(cage_base, entry);
205 }
206 
NameAt(PtrComprCageBase cage_base,InternalIndex entry)207 Name NameDictionary::NameAt(PtrComprCageBase cage_base, InternalIndex entry) {
208   return Name::cast(KeyAt(cage_base, entry));
209 }
210 
GetMap(ReadOnlyRoots roots)211 Handle<Map> NameDictionary::GetMap(ReadOnlyRoots roots) {
212   return roots.name_dictionary_map_handle();
213 }
214 
CellAt(InternalIndex entry)215 PropertyCell GlobalDictionary::CellAt(InternalIndex entry) {
216   PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
217   return CellAt(cage_base, entry);
218 }
219 
CellAt(PtrComprCageBase cage_base,InternalIndex entry)220 PropertyCell GlobalDictionary::CellAt(PtrComprCageBase cage_base,
221                                       InternalIndex entry) {
222   DCHECK(KeyAt(cage_base, entry).IsPropertyCell(cage_base));
223   return PropertyCell::cast(KeyAt(cage_base, entry));
224 }
225 
NameAt(InternalIndex entry)226 Name GlobalDictionary::NameAt(InternalIndex entry) {
227   PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
228   return NameAt(cage_base, entry);
229 }
230 
NameAt(PtrComprCageBase cage_base,InternalIndex entry)231 Name GlobalDictionary::NameAt(PtrComprCageBase cage_base, InternalIndex entry) {
232   return CellAt(cage_base, entry).name(cage_base);
233 }
234 
ValueAt(InternalIndex entry)235 Object GlobalDictionary::ValueAt(InternalIndex entry) {
236   PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
237   return ValueAt(cage_base, entry);
238 }
239 
ValueAt(PtrComprCageBase cage_base,InternalIndex entry)240 Object GlobalDictionary::ValueAt(PtrComprCageBase cage_base,
241                                  InternalIndex entry) {
242   return CellAt(cage_base, entry).value(cage_base);
243 }
244 
SetEntry(InternalIndex entry,Object key,Object value,PropertyDetails details)245 void GlobalDictionary::SetEntry(InternalIndex entry, Object key, Object value,
246                                 PropertyDetails details) {
247   DCHECK_EQ(key, PropertyCell::cast(value).name());
248   set(EntryToIndex(entry) + kEntryKeyIndex, value);
249   DetailsAtPut(entry, details);
250 }
251 
ClearEntry(InternalIndex entry)252 void GlobalDictionary::ClearEntry(InternalIndex entry) {
253   Object the_hole = this->GetReadOnlyRoots().the_hole_value();
254   set(EntryToIndex(entry) + kEntryKeyIndex, the_hole);
255 }
256 
ValueAtPut(InternalIndex entry,Object value)257 void GlobalDictionary::ValueAtPut(InternalIndex entry, Object value) {
258   set(EntryToIndex(entry), value);
259 }
260 
IsMatch(uint32_t key,Object other)261 bool NumberDictionaryBaseShape::IsMatch(uint32_t key, Object other) {
262   DCHECK(other.IsNumber());
263   return key == static_cast<uint32_t>(other.Number());
264 }
265 
Hash(ReadOnlyRoots roots,uint32_t key)266 uint32_t NumberDictionaryBaseShape::Hash(ReadOnlyRoots roots, uint32_t key) {
267   return ComputeSeededHash(key, HashSeed(roots));
268 }
269 
HashForObject(ReadOnlyRoots roots,Object other)270 uint32_t NumberDictionaryBaseShape::HashForObject(ReadOnlyRoots roots,
271                                                   Object other) {
272   DCHECK(other.IsNumber());
273   return ComputeSeededHash(static_cast<uint32_t>(other.Number()),
274                            HashSeed(roots));
275 }
276 
AsHandle(Isolate * isolate,uint32_t key)277 Handle<Object> NumberDictionaryBaseShape::AsHandle(Isolate* isolate,
278                                                    uint32_t key) {
279   return isolate->factory()->NewNumberFromUint(key);
280 }
281 
AsHandle(LocalIsolate * isolate,uint32_t key)282 Handle<Object> NumberDictionaryBaseShape::AsHandle(LocalIsolate* isolate,
283                                                    uint32_t key) {
284   return isolate->factory()->NewNumberFromUint<AllocationType::kOld>(key);
285 }
286 
GetMap(ReadOnlyRoots roots)287 Handle<Map> NumberDictionary::GetMap(ReadOnlyRoots roots) {
288   return roots.number_dictionary_map_handle();
289 }
290 
GetMap(ReadOnlyRoots roots)291 Handle<Map> SimpleNumberDictionary::GetMap(ReadOnlyRoots roots) {
292   return roots.simple_number_dictionary_map_handle();
293 }
294 
IsMatch(Handle<Name> key,Object other)295 bool NameDictionaryShape::IsMatch(Handle<Name> key, Object other) {
296   DCHECK(other.IsTheHole() || Name::cast(other).IsUniqueName());
297   DCHECK(key->IsUniqueName());
298   return *key == other;
299 }
300 
Hash(ReadOnlyRoots roots,Handle<Name> key)301 uint32_t NameDictionaryShape::Hash(ReadOnlyRoots roots, Handle<Name> key) {
302   DCHECK(key->IsUniqueName());
303   return key->hash();
304 }
305 
HashForObject(ReadOnlyRoots roots,Object other)306 uint32_t NameDictionaryShape::HashForObject(ReadOnlyRoots roots, Object other) {
307   DCHECK(other.IsUniqueName());
308   return Name::cast(other).hash();
309 }
310 
IsMatch(Handle<Name> key,Object other)311 bool GlobalDictionaryShape::IsMatch(Handle<Name> key, Object other) {
312   DCHECK(key->IsUniqueName());
313   DCHECK(PropertyCell::cast(other).name().IsUniqueName());
314   return *key == PropertyCell::cast(other).name();
315 }
316 
HashForObject(ReadOnlyRoots roots,Object other)317 uint32_t GlobalDictionaryShape::HashForObject(ReadOnlyRoots roots,
318                                               Object other) {
319   return PropertyCell::cast(other).name().hash();
320 }
321 
AsHandle(Isolate * isolate,Handle<Name> key)322 Handle<Object> NameDictionaryShape::AsHandle(Isolate* isolate,
323                                              Handle<Name> key) {
324   DCHECK(key->IsUniqueName());
325   return key;
326 }
327 
AsHandle(LocalIsolate * isolate,Handle<Name> key)328 Handle<Object> NameDictionaryShape::AsHandle(LocalIsolate* isolate,
329                                              Handle<Name> key) {
330   DCHECK(key->IsUniqueName());
331   return key;
332 }
333 
334 template <typename Dictionary>
DetailsAt(Dictionary dict,InternalIndex entry)335 PropertyDetails GlobalDictionaryShape::DetailsAt(Dictionary dict,
336                                                  InternalIndex entry) {
337   DCHECK(entry.is_found());
338   return dict.CellAt(entry).property_details();
339 }
340 
341 template <typename Dictionary>
DetailsAtPut(Dictionary dict,InternalIndex entry,PropertyDetails value)342 void GlobalDictionaryShape::DetailsAtPut(Dictionary dict, InternalIndex entry,
343                                          PropertyDetails value) {
344   DCHECK(entry.is_found());
345   dict.CellAt(entry).UpdatePropertyDetailsExceptCellType(value);
346 }
347 
348 }  // namespace internal
349 }  // namespace v8
350 
351 #include "src/objects/object-macros-undef.h"
352 
353 #endif  // V8_OBJECTS_DICTIONARY_INL_H_
354