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_OBJECTS_LOOKUP_H_
6 #define V8_OBJECTS_LOOKUP_H_
7 
8 #include "src/common/globals.h"
9 #include "src/execution/isolate.h"
10 #include "src/heap/factory.h"
11 #include "src/objects/descriptor-array.h"
12 #include "src/objects/js-objects.h"
13 #include "src/objects/map.h"
14 #include "src/objects/objects.h"
15 
16 namespace v8 {
17 namespace internal {
18 
19 class V8_EXPORT_PRIVATE LookupIterator final {
20  public:
21   enum Configuration {
22     // Configuration bits.
23     kInterceptor = 1 << 0,
24     kPrototypeChain = 1 << 1,
25 
26     // Convenience combinations of bits.
27     OWN_SKIP_INTERCEPTOR = 0,
28     OWN = kInterceptor,
29     PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kPrototypeChain,
30     PROTOTYPE_CHAIN = kPrototypeChain | kInterceptor,
31     DEFAULT = PROTOTYPE_CHAIN
32   };
33 
34   enum State {
35     ACCESS_CHECK,
36     INTEGER_INDEXED_EXOTIC,
37     INTERCEPTOR,
38     JSPROXY,
39     NOT_FOUND,
40     ACCESSOR,
41     DATA,
42     TRANSITION,
43     // Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a
44     // PROPERTY lookup.
45     BEFORE_PROPERTY = INTERCEPTOR
46   };
47 
48   class Key {
49    public:
50     inline Key(Isolate* isolate, double index);
51     // {name} might be a string representation of an element index.
52     inline Key(Isolate* isolate, Handle<Name> name);
53     // {valid_key} is a Name or Number.
54     inline Key(Isolate* isolate, Handle<Object> valid_key);
55     // {key} could be anything.
56     Key(Isolate* isolate, Handle<Object> key, bool* success);
57 
is_element()58     bool is_element() { return index_ != LookupIterator::kInvalidIndex; }
name()59     Handle<Name> name() const { return name_; }
index()60     size_t index() const { return index_; }
61     inline Handle<Name> GetName(Isolate* isolate);
62 
63    private:
64     Handle<Name> name_;
65     size_t index_;
66   };
67 
68   // {name} is guaranteed to be a property name (and not e.g. "123").
69   inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
70                         Handle<Name> name,
71                         Configuration configuration = DEFAULT);
72   inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
73                         Handle<Name> name, Handle<JSReceiver> holder,
74                         Configuration configuration = DEFAULT);
75 
76   inline LookupIterator(Isolate* isolate, Handle<Object> receiver, size_t index,
77                         Configuration configuration = DEFAULT);
78   inline LookupIterator(Isolate* isolate, Handle<Object> receiver, size_t index,
79                         Handle<JSReceiver> holder,
80                         Configuration configuration = DEFAULT);
81 
82   inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
83                         const Key& key, Configuration configuration = DEFAULT);
84   inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
85                         const Key& key, Handle<JSReceiver> holder,
86                         Configuration configuration = DEFAULT);
87 
Restart()88   void Restart() {
89     InterceptorState state = InterceptorState::kUninitialized;
90     IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state);
91   }
92 
isolate()93   Isolate* isolate() const { return isolate_; }
state()94   State state() const { return state_; }
95 
96   inline Handle<Name> name() const;
97   inline Handle<Name> GetName();
index()98   size_t index() const { return index_; }
array_index()99   uint32_t array_index() const {
100     DCHECK_LE(index_, JSArray::kMaxArrayIndex);
101     return static_cast<uint32_t>(index_);
102   }
103 
104   // Returns true if this LookupIterator has an index in the range
105   // [0, size_t::max).
IsElement()106   bool IsElement() const { return index_ != kInvalidIndex; }
107   // Returns true if this LookupIterator has an index that counts as an
108   // element for the given object (up to kMaxArrayIndex for JSArrays,
109   // any integer for JSTypedArrays).
110   inline bool IsElement(JSReceiver object) const;
111 
IsFound()112   bool IsFound() const { return state_ != NOT_FOUND; }
113   void Next();
NotFound()114   void NotFound() {
115     has_property_ = false;
116     state_ = NOT_FOUND;
117   }
118 
heap()119   Heap* heap() const { return isolate_->heap(); }
factory()120   Factory* factory() const { return isolate_->factory(); }
GetReceiver()121   Handle<Object> GetReceiver() const { return receiver_; }
122 
123   template <class T>
124   inline Handle<T> GetStoreTarget() const;
125   inline bool is_dictionary_holder() const;
126   inline Handle<Map> transition_map() const;
127   inline Handle<PropertyCell> transition_cell() const;
128   template <class T>
129   inline Handle<T> GetHolder() const;
130 
131   bool HolderIsReceiver() const;
132   bool HolderIsReceiverOrHiddenPrototype() const;
133 
check_prototype_chain()134   bool check_prototype_chain() const {
135     return (configuration_ & kPrototypeChain) != 0;
136   }
137 
138   /* ACCESS_CHECK */
139   bool HasAccess() const;
140 
141   /* PROPERTY */
142   inline bool ExtendingNonExtensible(Handle<JSReceiver> receiver);
143   void PrepareForDataProperty(Handle<Object> value);
144   void PrepareTransitionToDataProperty(Handle<JSReceiver> receiver,
145                                        Handle<Object> value,
146                                        PropertyAttributes attributes,
147                                        StoreOrigin store_origin);
148   inline bool IsCacheableTransition();
149   void ApplyTransitionToDataProperty(Handle<JSReceiver> receiver);
150   void ReconfigureDataProperty(Handle<Object> value,
151                                PropertyAttributes attributes);
152   void Delete();
153   void TransitionToAccessorProperty(Handle<Object> getter,
154                                     Handle<Object> setter,
155                                     PropertyAttributes attributes);
156   void TransitionToAccessorPair(Handle<Object> pair,
157                                 PropertyAttributes attributes);
property_details()158   PropertyDetails property_details() const {
159     DCHECK(has_property_);
160     return property_details_;
161   }
property_attributes()162   PropertyAttributes property_attributes() const {
163     return property_details().attributes();
164   }
IsConfigurable()165   bool IsConfigurable() const { return property_details().IsConfigurable(); }
IsReadOnly()166   bool IsReadOnly() const { return property_details().IsReadOnly(); }
IsEnumerable()167   bool IsEnumerable() const { return property_details().IsEnumerable(); }
representation()168   Representation representation() const {
169     return property_details().representation();
170   }
location()171   PropertyLocation location() const { return property_details().location(); }
constness()172   PropertyConstness constness() const { return property_details().constness(); }
173   Handle<Map> GetFieldOwnerMap() const;
174   FieldIndex GetFieldIndex() const;
175   Handle<FieldType> GetFieldType() const;
176   int GetFieldDescriptorIndex() const;
177   int GetAccessorIndex() const;
178   Handle<PropertyCell> GetPropertyCell() const;
179   Handle<Object> GetAccessors() const;
180   inline Handle<InterceptorInfo> GetInterceptor() const;
181   Handle<InterceptorInfo> GetInterceptorForFailedAccessCheck() const;
182   Handle<Object> GetDataValue(AllocationPolicy allocation_policy =
183                                   AllocationPolicy::kAllocationAllowed) const;
184   void WriteDataValue(Handle<Object> value, bool initializing_store);
185   inline void UpdateProtector();
186   static inline void UpdateProtector(Isolate* isolate, Handle<Object> receiver,
187                                      Handle<Name> name);
188 
189   // Lookup a 'cached' private property for an accessor.
190   // If not found returns false and leaves the LookupIterator unmodified.
191   bool TryLookupCachedProperty();
192   bool LookupCachedProperty();
193 
194  private:
195   static const size_t kInvalidIndex = std::numeric_limits<size_t>::max();
196 
197   inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
198                         Handle<Name> name, size_t index,
199                         Handle<JSReceiver> holder, Configuration configuration);
200 
201   // For |ForTransitionHandler|.
202   LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
203                  Handle<Map> transition_map, PropertyDetails details,
204                  bool has_property);
205 
206   static void InternalUpdateProtector(Isolate* isolate, Handle<Object> receiver,
207                                       Handle<Name> name);
208 
209   enum class InterceptorState {
210     kUninitialized,
211     kSkipNonMasking,
212     kProcessNonMasking
213   };
214 
215   Handle<Map> GetReceiverMap() const;
216 
217   V8_WARN_UNUSED_RESULT inline JSReceiver NextHolder(Map map);
218 
is_js_array_element(bool is_element)219   bool is_js_array_element(bool is_element) const {
220     return is_element && index_ <= JSArray::kMaxArrayIndex;
221   }
222   template <bool is_element>
223   V8_EXPORT_PRIVATE void Start();
224   template <bool is_element>
225   void NextInternal(Map map, JSReceiver holder);
226   template <bool is_element>
LookupInHolder(Map map,JSReceiver holder)227   inline State LookupInHolder(Map map, JSReceiver holder) {
228     return map.IsSpecialReceiverMap()
229                ? LookupInSpecialHolder<is_element>(map, holder)
230                : LookupInRegularHolder<is_element>(map, holder);
231   }
232   template <bool is_element>
233   State LookupInRegularHolder(Map map, JSReceiver holder);
234   template <bool is_element>
235   State LookupInSpecialHolder(Map map, JSReceiver holder);
236   template <bool is_element>
RestartLookupForNonMaskingInterceptors()237   void RestartLookupForNonMaskingInterceptors() {
238     RestartInternal<is_element>(InterceptorState::kProcessNonMasking);
239   }
240   template <bool is_element>
241   void RestartInternal(InterceptorState interceptor_state);
242   Handle<Object> FetchValue(AllocationPolicy allocation_policy =
243                                 AllocationPolicy::kAllocationAllowed) const;
244   bool IsConstFieldValueEqualTo(Object value) const;
245   template <bool is_element>
246   void ReloadPropertyInformation();
247 
248   template <bool is_element>
249   bool SkipInterceptor(JSObject holder);
250   template <bool is_element>
251   inline InterceptorInfo GetInterceptor(JSObject holder) const;
252 
check_interceptor()253   bool check_interceptor() const {
254     return (configuration_ & kInterceptor) != 0;
255   }
256   inline InternalIndex descriptor_number() const;
257   inline InternalIndex dictionary_entry() const;
258 
259   static inline Configuration ComputeConfiguration(Isolate* isolate,
260                                                    Configuration configuration,
261                                                    Handle<Name> name);
262 
263   static Handle<JSReceiver> GetRootForNonJSReceiver(
264       Isolate* isolate, Handle<Object> receiver, size_t index = kInvalidIndex);
265   static inline Handle<JSReceiver> GetRoot(Isolate* isolate,
266                                            Handle<Object> receiver,
267                                            size_t index = kInvalidIndex);
268 
269   State NotFound(JSReceiver const holder) const;
270 
271   // If configuration_ becomes mutable, update
272   // HolderIsReceiverOrHiddenPrototype.
273   const Configuration configuration_;
274   State state_ = NOT_FOUND;
275   bool has_property_ = false;
276   InterceptorState interceptor_state_ = InterceptorState::kUninitialized;
277   PropertyDetails property_details_ = PropertyDetails::Empty();
278   Isolate* const isolate_;
279   Handle<Name> name_;
280   Handle<Object> transition_;
281   const Handle<Object> receiver_;
282   Handle<JSReceiver> holder_;
283   const Handle<JSReceiver> initial_holder_;
284   const size_t index_;
285   InternalIndex number_ = InternalIndex::NotFound();
286 };
287 
288 }  // namespace internal
289 }  // namespace v8
290 
291 #endif  // V8_OBJECTS_LOOKUP_H_
292