• 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      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