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   };
31 
32   enum State {
33     ACCESS_CHECK,
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 = PROTOTYPE_CHAIN)
configuration_(ComputeConfiguration (configuration,name))47       : configuration_(ComputeConfiguration(configuration, name)),
48         state_(NOT_FOUND),
49         property_details_(NONE, NORMAL, Representation::None()),
50         isolate_(name->GetIsolate()),
51         name_(name),
52         receiver_(receiver),
53         number_(DescriptorArray::kNotFound) {
54     holder_ = GetRoot();
55     holder_map_ = handle(holder_->map(), isolate_);
56     Next();
57   }
58 
59   LookupIterator(Handle<Object> receiver, Handle<Name> name,
60                  Handle<JSReceiver> holder,
61                  Configuration configuration = PROTOTYPE_CHAIN)
configuration_(ComputeConfiguration (configuration,name))62       : configuration_(ComputeConfiguration(configuration, name)),
63         state_(NOT_FOUND),
64         property_details_(NONE, NORMAL, Representation::None()),
65         isolate_(name->GetIsolate()),
66         name_(name),
67         holder_map_(holder->map(), isolate_),
68         receiver_(receiver),
69         holder_(holder),
70         number_(DescriptorArray::kNotFound) {
71     Next();
72   }
73 
isolate()74   Isolate* isolate() const { return isolate_; }
state()75   State state() const { return state_; }
name()76   Handle<Name> name() const { return name_; }
77 
IsFound()78   bool IsFound() const { return state_ != NOT_FOUND; }
79   void Next();
NotFound()80   void NotFound() {
81     has_property_ = false;
82     state_ = NOT_FOUND;
83   }
84 
factory()85   Factory* factory() const { return isolate_->factory(); }
GetReceiver()86   Handle<Object> GetReceiver() const { return receiver_; }
87   Handle<JSObject> GetStoreTarget() const;
is_dictionary_holder()88   bool is_dictionary_holder() const { return holder_map_->is_dictionary_map(); }
transition_map()89   Handle<Map> transition_map() const {
90     DCHECK_EQ(TRANSITION, state_);
91     return transition_map_;
92   }
93   template <class T>
GetHolder()94   Handle<T> GetHolder() const {
95     DCHECK(IsFound());
96     return Handle<T>::cast(holder_);
97   }
98   Handle<JSReceiver> GetRoot() const;
99   bool HolderIsReceiverOrHiddenPrototype() const;
100 
101   /* ACCESS_CHECK */
102   bool HasAccess(v8::AccessType access_type) const;
103 
104   /* PROPERTY */
105   void PrepareForDataProperty(Handle<Object> value);
106   void PrepareTransitionToDataProperty(Handle<Object> value,
107                                        PropertyAttributes attributes,
108                                        Object::StoreFromKeyed store_mode);
IsCacheableTransition()109   bool IsCacheableTransition() {
110     bool cacheable =
111         state_ == TRANSITION && transition_map()->GetBackPointer()->IsMap();
112     if (cacheable) {
113       property_details_ = transition_map_->GetLastDescriptorDetails();
114       has_property_ = true;
115     }
116     return cacheable;
117   }
118   void ApplyTransitionToDataProperty();
119   void ReconfigureDataProperty(Handle<Object> value,
120                                PropertyAttributes attributes);
121   void TransitionToAccessorProperty(AccessorComponent component,
122                                     Handle<Object> accessor,
123                                     PropertyAttributes attributes);
property_details()124   PropertyDetails property_details() const {
125     DCHECK(has_property_);
126     return property_details_;
127   }
IsConfigurable()128   bool IsConfigurable() const { return property_details().IsConfigurable(); }
IsReadOnly()129   bool IsReadOnly() const { return property_details().IsReadOnly(); }
representation()130   Representation representation() const {
131     return property_details().representation();
132   }
133   FieldIndex GetFieldIndex() const;
134   Handle<HeapType> GetFieldType() const;
135   int GetConstantIndex() const;
136   Handle<PropertyCell> GetPropertyCell() const;
137   Handle<Object> GetAccessors() const;
138   Handle<Object> GetDataValue() const;
139   void WriteDataValue(Handle<Object> value);
140 
141   void InternalizeName();
142 
143  private:
144   Handle<Map> GetReceiverMap() const;
145 
146   MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map);
147   inline State LookupInHolder(Map* map, JSReceiver* holder);
148   Handle<Object> FetchValue() const;
149   void ReloadPropertyInformation();
150 
151   bool IsBootstrapping() const;
152 
check_hidden()153   bool check_hidden() const { return (configuration_ & kHidden) != 0; }
check_interceptor()154   bool check_interceptor() const {
155     return !IsBootstrapping() && (configuration_ & kInterceptor) != 0;
156   }
check_prototype_chain()157   bool check_prototype_chain() const {
158     return (configuration_ & kPrototypeChain) != 0;
159   }
descriptor_number()160   int descriptor_number() const {
161     DCHECK(has_property_);
162     DCHECK(!holder_map_->is_dictionary_map());
163     return number_;
164   }
dictionary_entry()165   int dictionary_entry() const {
166     DCHECK(has_property_);
167     DCHECK(holder_map_->is_dictionary_map());
168     return number_;
169   }
170 
ComputeConfiguration(Configuration configuration,Handle<Name> name)171   static Configuration ComputeConfiguration(
172       Configuration configuration, Handle<Name> name) {
173     if (name->IsOwn()) {
174       return static_cast<Configuration>(configuration & HIDDEN);
175     } else {
176       return configuration;
177     }
178   }
179 
180   // If configuration_ becomes mutable, update
181   // HolderIsReceiverOrHiddenPrototype.
182   Configuration configuration_;
183   State state_;
184   bool has_property_;
185   PropertyDetails property_details_;
186   Isolate* isolate_;
187   Handle<Name> name_;
188   Handle<Map> holder_map_;
189   Handle<Map> transition_map_;
190   Handle<Object> receiver_;
191   Handle<JSReceiver> holder_;
192 
193   int number_;
194 };
195 
196 
197 } }  // namespace v8::internal
198 
199 #endif  // V8_LOOKUP_H_
200