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