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