Line data Source code
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_LOOKUP_H_
6 : #define V8_LOOKUP_H_
7 :
8 : #include "src/factory.h"
9 : #include "src/globals.h"
10 : #include "src/isolate.h"
11 : #include "src/objects.h"
12 : #include "src/objects/descriptor-array.h"
13 : #include "src/objects/map.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 :
18 : class V8_EXPORT_PRIVATE LookupIterator final BASE_EMBEDDED {
19 : public:
20 : enum Configuration {
21 : // Configuration bits.
22 : kInterceptor = 1 << 0,
23 : kPrototypeChain = 1 << 1,
24 :
25 : // Convenience combinations of bits.
26 : OWN_SKIP_INTERCEPTOR = 0,
27 : OWN = kInterceptor,
28 : PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kPrototypeChain,
29 : PROTOTYPE_CHAIN = kPrototypeChain | kInterceptor,
30 : DEFAULT = PROTOTYPE_CHAIN
31 : };
32 :
33 : enum State {
34 : ACCESS_CHECK,
35 : INTEGER_INDEXED_EXOTIC,
36 : INTERCEPTOR,
37 : JSPROXY,
38 : NOT_FOUND,
39 : ACCESSOR,
40 : DATA,
41 : TRANSITION,
42 : // Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a
43 : // PROPERTY lookup.
44 : BEFORE_PROPERTY = INTERCEPTOR
45 : };
46 :
47 108171261 : LookupIterator(Handle<Object> receiver, Handle<Name> name,
48 : Configuration configuration = DEFAULT)
49 108171261 : : LookupIterator(name->GetIsolate(), receiver, name, configuration) {}
50 :
51 108171726 : LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
52 : Configuration configuration = DEFAULT)
53 : : LookupIterator(isolate, receiver, name, GetRoot(isolate, receiver),
54 108171726 : configuration) {}
55 :
56 71413519 : LookupIterator(Handle<Object> receiver, Handle<Name> name,
57 : Handle<JSReceiver> holder,
58 : Configuration configuration = DEFAULT)
59 : : LookupIterator(name->GetIsolate(), receiver, name, holder,
60 71413519 : configuration) {}
61 :
62 179585242 : LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
63 : Handle<JSReceiver> holder,
64 : Configuration configuration = DEFAULT)
65 : : configuration_(ComputeConfiguration(configuration, name)),
66 : interceptor_state_(InterceptorState::kUninitialized),
67 : property_details_(PropertyDetails::Empty()),
68 : isolate_(isolate),
69 : name_(isolate_->factory()->InternalizeName(name)),
70 : receiver_(receiver),
71 : initial_holder_(holder),
72 : // kMaxUInt32 isn't a valid index.
73 : index_(kMaxUInt32),
74 538755729 : number_(static_cast<uint32_t>(DescriptorArray::kNotFound)) {
75 : #ifdef DEBUG
76 : uint32_t index; // Assert that the name is not an array index.
77 : DCHECK(!name->AsArrayIndex(&index));
78 : #endif // DEBUG
79 179585245 : Start<false>();
80 179585250 : }
81 :
82 26874515 : LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
83 : Configuration configuration = DEFAULT)
84 : : LookupIterator(isolate, receiver, index,
85 53749030 : GetRoot(isolate, receiver, index), configuration) {}
86 :
87 255 : LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
88 : Handle<JSReceiver> holder,
89 : Configuration configuration = DEFAULT)
90 : : configuration_(configuration),
91 : interceptor_state_(InterceptorState::kUninitialized),
92 : property_details_(PropertyDetails::Empty()),
93 : isolate_(isolate),
94 : receiver_(receiver),
95 : initial_holder_(holder),
96 : index_(index),
97 382903269 : number_(static_cast<uint32_t>(DescriptorArray::kNotFound)) {
98 : // kMaxUInt32 isn't a valid index.
99 : DCHECK_NE(kMaxUInt32, index_);
100 127634423 : Start<true>();
101 255 : }
102 :
103 46453862 : static LookupIterator PropertyOrElement(
104 : Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
105 : Configuration configuration = DEFAULT) {
106 : uint32_t index;
107 46453862 : if (name->AsArrayIndex(&index)) {
108 : LookupIterator it =
109 76164 : LookupIterator(isolate, receiver, index, configuration);
110 76164 : it.name_ = name;
111 76164 : return it;
112 : }
113 46377698 : return LookupIterator(receiver, name, configuration);
114 : }
115 :
116 11940671 : static LookupIterator PropertyOrElement(
117 : Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
118 : Handle<JSReceiver> holder, Configuration configuration = DEFAULT) {
119 : uint32_t index;
120 11940671 : if (name->AsArrayIndex(&index)) {
121 : LookupIterator it =
122 13086 : LookupIterator(isolate, receiver, index, holder, configuration);
123 13086 : it.name_ = name;
124 13086 : return it;
125 : }
126 11927585 : return LookupIterator(receiver, name, holder, configuration);
127 : }
128 :
129 : static LookupIterator PropertyOrElement(
130 : Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
131 : bool* success, Handle<JSReceiver> holder,
132 : Configuration configuration = DEFAULT);
133 :
134 : static LookupIterator PropertyOrElement(
135 : Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
136 : bool* success, Configuration configuration = DEFAULT);
137 :
138 : static LookupIterator ForTransitionHandler(Isolate* isolate,
139 : Handle<Object> receiver,
140 : Handle<Name> name,
141 : Handle<Object> value,
142 : MaybeHandle<Object> handler,
143 : Handle<Map> transition_map);
144 :
145 4703052 : void Restart() {
146 : InterceptorState state = InterceptorState::kUninitialized;
147 4703052 : IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state);
148 4703052 : }
149 :
150 : Isolate* isolate() const { return isolate_; }
151 501282 : State state() const { return state_; }
152 :
153 132 : Handle<Name> name() const {
154 : DCHECK(!IsElement());
155 132 : return name_;
156 : }
157 1663821 : Handle<Name> GetName() {
158 1542374 : if (name_.is_null()) {
159 : DCHECK(IsElement());
160 242894 : name_ = factory()->Uint32ToString(index_);
161 : }
162 1542374 : return name_;
163 : }
164 : uint32_t index() const { return index_; }
165 :
166 : bool IsElement() const { return index_ != kMaxUInt32; }
167 :
168 281475 : bool IsFound() const { return state_ != NOT_FOUND; }
169 : void Next();
170 : void NotFound() {
171 464385 : has_property_ = false;
172 464385 : state_ = NOT_FOUND;
173 : }
174 :
175 : Heap* heap() const { return isolate_->heap(); }
176 : Factory* factory() const { return isolate_->factory(); }
177 : Handle<Object> GetReceiver() const { return receiver_; }
178 :
179 44112010 : Handle<JSObject> GetStoreTarget() const {
180 : DCHECK(receiver_->IsJSObject());
181 44112010 : if (receiver_->IsJSGlobalProxy()) {
182 : Map* map = JSGlobalProxy::cast(*receiver_)->map();
183 72164 : if (map->has_hidden_prototype()) {
184 144328 : return handle(JSGlobalObject::cast(map->prototype()), isolate_);
185 : }
186 : }
187 : return Handle<JSObject>::cast(receiver_);
188 : }
189 :
190 1403636 : bool is_dictionary_holder() const { return !holder_->HasFastProperties(); }
191 : Handle<Map> transition_map() const {
192 : DCHECK_EQ(TRANSITION, state_);
193 : return Handle<Map>::cast(transition_);
194 : }
195 : Handle<PropertyCell> transition_cell() const {
196 : DCHECK_EQ(TRANSITION, state_);
197 : return Handle<PropertyCell>::cast(transition_);
198 : }
199 : template <class T>
200 200610 : Handle<T> GetHolder() const {
201 : DCHECK(IsFound());
202 200610 : return Handle<T>::cast(holder_);
203 : }
204 :
205 : bool HolderIsReceiver() const;
206 : bool HolderIsReceiverOrHiddenPrototype() const;
207 :
208 : bool check_prototype_chain() const {
209 272502717 : return (configuration_ & kPrototypeChain) != 0;
210 : }
211 :
212 : /* ACCESS_CHECK */
213 : bool HasAccess() const;
214 :
215 : /* PROPERTY */
216 42920970 : bool ExtendingNonExtensible(Handle<JSObject> receiver) {
217 : DCHECK(receiver.is_identical_to(GetStoreTarget()));
218 42920970 : return !receiver->map()->is_extensible() &&
219 914 : (IsElement() || !name_->IsPrivate());
220 : }
221 : void PrepareForDataProperty(Handle<Object> value);
222 : bool PrepareTransitionToDataProperty(Handle<JSObject> receiver,
223 : Handle<Object> value,
224 : PropertyAttributes attributes,
225 : Object::StoreFromKeyed store_mode);
226 600533 : bool IsCacheableTransition() {
227 : DCHECK_EQ(TRANSITION, state_);
228 598743 : return transition_->IsPropertyCell() ||
229 13956 : (transition_map()->is_dictionary_map() &&
230 1213348 : !GetStoreTarget()->HasFastProperties()) ||
231 1185436 : transition_map()->GetBackPointer()->IsMap();
232 : }
233 : void ApplyTransitionToDataProperty(Handle<JSObject> receiver);
234 : void ReconfigureDataProperty(Handle<Object> value,
235 : PropertyAttributes attributes);
236 : void Delete();
237 : void TransitionToAccessorProperty(Handle<Object> getter,
238 : Handle<Object> setter,
239 : PropertyAttributes attributes);
240 : void TransitionToAccessorPair(Handle<Object> pair,
241 : PropertyAttributes attributes);
242 80 : PropertyDetails property_details() const {
243 : DCHECK(has_property_);
244 80 : return property_details_;
245 : }
246 : PropertyAttributes property_attributes() const {
247 : return property_details().attributes();
248 : }
249 : bool IsConfigurable() const { return property_details().IsConfigurable(); }
250 : bool IsReadOnly() const { return property_details().IsReadOnly(); }
251 : bool IsEnumerable() const { return property_details().IsEnumerable(); }
252 : Representation representation() const {
253 : return property_details().representation();
254 : }
255 : PropertyLocation location() const { return property_details().location(); }
256 : PropertyConstness constness() const { return property_details().constness(); }
257 : Handle<Map> GetFieldOwnerMap() const;
258 : FieldIndex GetFieldIndex() const;
259 : Handle<FieldType> GetFieldType() const;
260 : int GetFieldDescriptorIndex() const;
261 : int GetAccessorIndex() const;
262 : int GetConstantIndex() const;
263 : Handle<PropertyCell> GetPropertyCell() const;
264 : Handle<Object> GetAccessors() const;
265 459246 : inline Handle<InterceptorInfo> GetInterceptor() const {
266 : DCHECK_EQ(INTERCEPTOR, state_);
267 : InterceptorInfo* result =
268 : IsElement() ? GetInterceptor<true>(JSObject::cast(*holder_))
269 459246 : : GetInterceptor<false>(JSObject::cast(*holder_));
270 918492 : return handle(result, isolate_);
271 : }
272 : Handle<InterceptorInfo> GetInterceptorForFailedAccessCheck() const;
273 : Handle<Object> GetDataValue() const;
274 : void WriteDataValue(Handle<Object> value, bool initializing_store);
275 122176415 : inline void UpdateProtector() {
276 127824914 : if (IsElement()) return;
277 : // This list must be kept in sync with
278 : // CodeStubAssembler::HasAssociatedProtector!
279 174790885 : if (*name_ == heap()->is_concat_spreadable_symbol() ||
280 112932067 : *name_ == heap()->constructor_string() ||
281 167597238 : *name_ == heap()->species_symbol() ||
282 54664182 : *name_ == heap()->iterator_symbol()) {
283 3615441 : InternalUpdateProtector();
284 : }
285 : }
286 :
287 : // Lookup a 'cached' private property for an accessor.
288 : // If not found returns false and leaves the LookupIterator unmodified.
289 : bool TryLookupCachedProperty();
290 : bool LookupCachedProperty();
291 :
292 : private:
293 : // For |ForTransitionHandler|.
294 : LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
295 : Handle<Map> transition_map, PropertyDetails details,
296 : bool has_property);
297 :
298 : void InternalUpdateProtector();
299 :
300 : enum class InterceptorState {
301 : kUninitialized,
302 : kSkipNonMasking,
303 : kProcessNonMasking
304 : };
305 :
306 : Handle<Map> GetReceiverMap() const;
307 :
308 : MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map);
309 :
310 : template <bool is_element>
311 : V8_EXPORT_PRIVATE void Start();
312 : template <bool is_element>
313 : void NextInternal(Map* map, JSReceiver* holder);
314 : template <bool is_element>
315 527204071 : inline State LookupInHolder(Map* map, JSReceiver* holder) {
316 : return map->IsSpecialReceiverMap()
317 : ? LookupInSpecialHolder<is_element>(map, holder)
318 527204071 : : LookupInRegularHolder<is_element>(map, holder);
319 : }
320 : template <bool is_element>
321 : State LookupInRegularHolder(Map* map, JSReceiver* holder);
322 : template <bool is_element>
323 35373751 : State LookupInSpecialHolder(Map* map, JSReceiver* holder);
324 : template <bool is_element>
325 0 : void RestartLookupForNonMaskingInterceptors() {
326 150 : RestartInternal<is_element>(InterceptorState::kProcessNonMasking);
327 0 : }
328 : template <bool is_element>
329 : void RestartInternal(InterceptorState interceptor_state);
330 : Handle<Object> FetchValue() const;
331 : bool IsConstFieldValueEqualTo(Object* value) const;
332 : template <bool is_element>
333 : void ReloadPropertyInformation();
334 :
335 : template <bool is_element>
336 : bool SkipInterceptor(JSObject* holder);
337 : template <bool is_element>
338 : inline InterceptorInfo* GetInterceptor(JSObject* holder) const {
339 : return is_element ? holder->GetIndexedInterceptor()
340 1419642 : : holder->GetNamedInterceptor();
341 : }
342 :
343 : bool check_interceptor() const {
344 35373751 : return (configuration_ & kInterceptor) != 0;
345 : }
346 : int descriptor_number() const {
347 : DCHECK(!IsElement());
348 : DCHECK(has_property_);
349 : DCHECK(holder_->HasFastProperties());
350 25453354 : return number_;
351 : }
352 : int dictionary_entry() const {
353 : DCHECK(!IsElement());
354 : DCHECK(has_property_);
355 : DCHECK(!holder_->HasFastProperties());
356 26568820 : return number_;
357 : }
358 :
359 : static Configuration ComputeConfiguration(
360 : Configuration configuration, Handle<Name> name) {
361 179585242 : return name->IsPrivate() ? OWN_SKIP_INTERCEPTOR : configuration;
362 : }
363 :
364 : static Handle<JSReceiver> GetRootForNonJSReceiver(
365 : Isolate* isolate, Handle<Object> receiver, uint32_t index = kMaxUInt32);
366 135049325 : inline static Handle<JSReceiver> GetRoot(Isolate* isolate,
367 : Handle<Object> receiver,
368 : uint32_t index = kMaxUInt32) {
369 135049323 : if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver);
370 165137 : return GetRootForNonJSReceiver(isolate, receiver, index);
371 : }
372 :
373 : State NotFound(JSReceiver* const holder) const;
374 :
375 : // If configuration_ becomes mutable, update
376 : // HolderIsReceiverOrHiddenPrototype.
377 : const Configuration configuration_;
378 : State state_;
379 : bool has_property_;
380 : InterceptorState interceptor_state_;
381 : PropertyDetails property_details_;
382 : Isolate* const isolate_;
383 : Handle<Name> name_;
384 : Handle<Object> transition_;
385 : const Handle<Object> receiver_;
386 : Handle<JSReceiver> holder_;
387 : const Handle<JSReceiver> initial_holder_;
388 : const uint32_t index_;
389 : uint32_t number_;
390 : };
391 :
392 :
393 : } // namespace internal
394 : } // namespace v8
395 :
396 : #endif // V8_LOOKUP_H_
|