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