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