• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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_LOOKUP_INL_H_
6 #define V8_OBJECTS_LOOKUP_INL_H_
7 
8 #include "src/objects/lookup.h"
9 
10 #include "src/handles/handles-inl.h"
11 #include "src/heap/factory-inl.h"
12 #include "src/objects/api-callbacks.h"
13 #include "src/objects/internal-index.h"
14 #include "src/objects/map-inl.h"
15 #include "src/objects/name-inl.h"
16 #include "src/objects/objects-inl.h"
17 
18 namespace v8 {
19 namespace internal {
20 
LookupIterator(Isolate * isolate,Handle<Object> receiver,Handle<Name> name,Configuration configuration)21 LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
22                                Handle<Name> name, Configuration configuration)
23     : LookupIterator(isolate, receiver, name, kInvalidIndex, receiver,
24                      configuration) {}
25 
LookupIterator(Isolate * isolate,Handle<Object> receiver,Handle<Name> name,Handle<Object> lookup_start_object,Configuration configuration)26 LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
27                                Handle<Name> name,
28                                Handle<Object> lookup_start_object,
29                                Configuration configuration)
30     : LookupIterator(isolate, receiver, name, kInvalidIndex,
31                      lookup_start_object, configuration) {}
32 
LookupIterator(Isolate * isolate,Handle<Object> receiver,size_t index,Configuration configuration)33 LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
34                                size_t index, Configuration configuration)
35     : LookupIterator(isolate, receiver, Handle<Name>(), index, receiver,
36                      configuration) {
37   DCHECK_NE(index, kInvalidIndex);
38 }
39 
LookupIterator(Isolate * isolate,Handle<Object> receiver,size_t index,Handle<Object> lookup_start_object,Configuration configuration)40 LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
41                                size_t index, Handle<Object> lookup_start_object,
42                                Configuration configuration)
43     : LookupIterator(isolate, receiver, Handle<Name>(), index,
44                      lookup_start_object, configuration) {
45   DCHECK_NE(index, kInvalidIndex);
46 }
47 
LookupIterator(Isolate * isolate,Handle<Object> receiver,const Key & key,Configuration configuration)48 LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
49                                const Key& key, Configuration configuration)
50     : LookupIterator(isolate, receiver, key.name(), key.index(), receiver,
51                      configuration) {}
52 
LookupIterator(Isolate * isolate,Handle<Object> receiver,const Key & key,Handle<Object> lookup_start_object,Configuration configuration)53 LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
54                                const Key& key,
55                                Handle<Object> lookup_start_object,
56                                Configuration configuration)
57     : LookupIterator(isolate, receiver, key.name(), key.index(),
58                      lookup_start_object, configuration) {}
59 
60 // This private constructor is the central bottleneck that all the other
61 // constructors use.
LookupIterator(Isolate * isolate,Handle<Object> receiver,Handle<Name> name,size_t index,Handle<Object> lookup_start_object,Configuration configuration)62 LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
63                                Handle<Name> name, size_t index,
64                                Handle<Object> lookup_start_object,
65                                Configuration configuration)
66     : configuration_(ComputeConfiguration(isolate, configuration, name)),
67       isolate_(isolate),
68       name_(name),
69       receiver_(receiver),
70       lookup_start_object_(lookup_start_object),
71       index_(index) {
72   if (IsElement()) {
73     // If we're not looking at a TypedArray, we will need the key represented
74     // as an internalized string.
75     if (index_ > JSArray::kMaxArrayIndex &&
76         !lookup_start_object->IsJSTypedArray()) {
77       if (name_.is_null()) {
78         name_ = isolate->factory()->SizeToString(index_);
79       }
80       name_ = isolate->factory()->InternalizeName(name_);
81     } else if (!name_.is_null() && !name_->IsInternalizedString()) {
82       // Maintain the invariant that if name_ is present, it is internalized.
83       name_ = Handle<Name>();
84     }
85     Start<true>();
86   } else {
87     name_ = isolate->factory()->InternalizeName(name_);
88 #ifdef DEBUG
89     // Assert that the name is not an index.
90     // If we're not looking at the prototype chain and the lookup start object
91     // is not a typed array, then this means "array index", otherwise we need to
92     // ensure the full generality so that typed arrays are handled correctly.
93     if (!check_prototype_chain() && !lookup_start_object->IsJSTypedArray()) {
94       uint32_t index;
95       DCHECK(!name_->AsArrayIndex(&index));
96     } else {
97       size_t index;
98       DCHECK(!name_->AsIntegerIndex(&index));
99     }
100 #endif  // DEBUG
101     Start<false>();
102   }
103 }
104 
Key(Isolate * isolate,double index)105 LookupIterator::Key::Key(Isolate* isolate, double index) {
106   DCHECK_EQ(index, static_cast<uint64_t>(index));
107 #if V8_TARGET_ARCH_32_BIT
108   if (index <= JSArray::kMaxArrayIndex) {
109     index_ = static_cast<size_t>(index);
110   } else {
111     index_ = LookupIterator::kInvalidIndex;
112     name_ = isolate->factory()->InternalizeString(
113         isolate->factory()->HeapNumberToString(
114             isolate->factory()->NewHeapNumber(index), index));
115   }
116 #else
117   index_ = static_cast<size_t>(index);
118 #endif
119 }
120 
Key(Isolate * isolate,Handle<Name> name)121 LookupIterator::Key::Key(Isolate* isolate, Handle<Name> name) {
122   if (name->AsIntegerIndex(&index_)) {
123     name_ = name;
124   } else {
125     index_ = LookupIterator::kInvalidIndex;
126     name_ = isolate->factory()->InternalizeName(name);
127   }
128 }
129 
Key(Isolate * isolate,Handle<Object> valid_key)130 LookupIterator::Key::Key(Isolate* isolate, Handle<Object> valid_key) {
131   DCHECK(valid_key->IsName() || valid_key->IsNumber());
132   if (valid_key->ToIntegerIndex(&index_)) return;
133   if (valid_key->IsNumber()) {
134     // Negative or out of range -> treat as named property.
135     valid_key = isolate->factory()->NumberToString(valid_key);
136   }
137   DCHECK(valid_key->IsName());
138   name_ = Handle<Name>::cast(valid_key);
139   if (!name_->AsIntegerIndex(&index_)) {
140     index_ = LookupIterator::kInvalidIndex;
141     name_ = isolate->factory()->InternalizeName(name_);
142   }
143 }
144 
GetName(Isolate * isolate)145 Handle<Name> LookupIterator::Key::GetName(Isolate* isolate) {
146   if (name_.is_null()) {
147     DCHECK(is_element());
148     name_ = isolate->factory()->SizeToString(index_);
149   }
150   return name_;
151 }
152 
name()153 Handle<Name> LookupIterator::name() const {
154   DCHECK(!IsElement(*holder_));
155   return name_;
156 }
157 
GetName()158 Handle<Name> LookupIterator::GetName() {
159   if (name_.is_null()) {
160     DCHECK(IsElement());
161     name_ = factory()->SizeToString(index_);
162   }
163   return name_;
164 }
165 
IsElement(JSReceiver object)166 bool LookupIterator::IsElement(JSReceiver object) const {
167   return index_ <= JSArray::kMaxArrayIndex ||
168          (index_ != kInvalidIndex && object.map().has_typed_array_elements());
169 }
170 
is_dictionary_holder()171 bool LookupIterator::is_dictionary_holder() const {
172   return !holder_->HasFastProperties(isolate_);
173 }
174 
transition_map()175 Handle<Map> LookupIterator::transition_map() const {
176   DCHECK_EQ(TRANSITION, state_);
177   return Handle<Map>::cast(transition_);
178 }
179 
transition_cell()180 Handle<PropertyCell> LookupIterator::transition_cell() const {
181   DCHECK_EQ(TRANSITION, state_);
182   return Handle<PropertyCell>::cast(transition_);
183 }
184 
185 template <class T>
GetHolder()186 Handle<T> LookupIterator::GetHolder() const {
187   DCHECK(IsFound());
188   return Handle<T>::cast(holder_);
189 }
190 
ExtendingNonExtensible(Handle<JSReceiver> receiver)191 bool LookupIterator::ExtendingNonExtensible(Handle<JSReceiver> receiver) {
192   DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>()));
193   return !receiver->map(isolate_).is_extensible() &&
194          (IsElement() || !name_->IsPrivate(isolate_));
195 }
196 
IsCacheableTransition()197 bool LookupIterator::IsCacheableTransition() {
198   DCHECK_EQ(TRANSITION, state_);
199   return transition_->IsPropertyCell(isolate_) ||
200          (transition_map()->is_dictionary_map() &&
201           !GetStoreTarget<JSReceiver>()->HasFastProperties(isolate_)) ||
202          transition_map()->GetBackPointer(isolate_).IsMap(isolate_);
203 }
204 
205 // static
UpdateProtector(Isolate * isolate,Handle<Object> receiver,Handle<Name> name)206 void LookupIterator::UpdateProtector(Isolate* isolate, Handle<Object> receiver,
207                                      Handle<Name> name) {
208   // This list must be kept in sync with
209   // CodeStubAssembler::CheckForAssociatedProtector!
210   ReadOnlyRoots roots(isolate);
211   if (*name == roots.is_concat_spreadable_symbol() ||
212       *name == roots.constructor_string() || *name == roots.next_string() ||
213       *name == roots.species_symbol() || *name == roots.iterator_symbol() ||
214       *name == roots.resolve_string() || *name == roots.then_string()) {
215     InternalUpdateProtector(isolate, receiver, name);
216   }
217 }
218 
UpdateProtector()219 void LookupIterator::UpdateProtector() {
220   if (IsElement()) return;
221   UpdateProtector(isolate_, receiver_, name_);
222 }
223 
descriptor_number()224 InternalIndex LookupIterator::descriptor_number() const {
225   DCHECK(!IsElement(*holder_));
226   DCHECK(has_property_);
227   DCHECK(holder_->HasFastProperties(isolate_));
228   return number_;
229 }
230 
dictionary_entry()231 InternalIndex LookupIterator::dictionary_entry() const {
232   DCHECK(!IsElement(*holder_));
233   DCHECK(has_property_);
234   DCHECK(!holder_->HasFastProperties(isolate_));
235   return number_;
236 }
237 
238 // static
ComputeConfiguration(Isolate * isolate,Configuration configuration,Handle<Name> name)239 LookupIterator::Configuration LookupIterator::ComputeConfiguration(
240     Isolate* isolate, Configuration configuration, Handle<Name> name) {
241   return (!name.is_null() && name->IsPrivate(isolate)) ? OWN_SKIP_INTERCEPTOR
242                                                        : configuration;
243 }
244 
245 // static
GetRoot(Isolate * isolate,Handle<Object> lookup_start_object,size_t index)246 Handle<JSReceiver> LookupIterator::GetRoot(Isolate* isolate,
247                                            Handle<Object> lookup_start_object,
248                                            size_t index) {
249   if (lookup_start_object->IsJSReceiver(isolate)) {
250     return Handle<JSReceiver>::cast(lookup_start_object);
251   }
252   return GetRootForNonJSReceiver(isolate, lookup_start_object, index);
253 }
254 
255 template <class T>
GetStoreTarget()256 Handle<T> LookupIterator::GetStoreTarget() const {
257   DCHECK(receiver_->IsJSReceiver(isolate_));
258   if (receiver_->IsJSGlobalProxy(isolate_)) {
259     HeapObject prototype =
260         JSGlobalProxy::cast(*receiver_).map(isolate_).prototype(isolate_);
261     if (prototype.IsJSGlobalObject(isolate_)) {
262       return handle(JSGlobalObject::cast(prototype), isolate_);
263     }
264   }
265   return Handle<T>::cast(receiver_);
266 }
267 
268 template <bool is_element>
GetInterceptor(JSObject holder)269 InterceptorInfo LookupIterator::GetInterceptor(JSObject holder) const {
270   if (is_element && index_ <= JSArray::kMaxArrayIndex) {
271     return holder.GetIndexedInterceptor(isolate_);
272   } else {
273     return holder.GetNamedInterceptor(isolate_);
274   }
275 }
276 
GetInterceptor()277 inline Handle<InterceptorInfo> LookupIterator::GetInterceptor() const {
278   DCHECK_EQ(INTERCEPTOR, state_);
279   JSObject holder = JSObject::cast(*holder_);
280   InterceptorInfo result = IsElement(holder) ? GetInterceptor<true>(holder)
281                                              : GetInterceptor<false>(holder);
282   return handle(result, isolate_);
283 }
284 
285 }  // namespace internal
286 }  // namespace v8
287 
288 #endif  // V8_OBJECTS_LOOKUP_INL_H_
289