• 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_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<Object> lookup_start_object,
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<Object> lookup_start_object,
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<Object> lookup_start_object,
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 
lookup_start_object()131   Handle<Object> lookup_start_object() const { return lookup_start_object_; }
132 
133   bool HolderIsReceiver() const;
134   bool HolderIsReceiverOrHiddenPrototype() const;
135 
check_prototype_chain()136   bool check_prototype_chain() const {
137     return (configuration_ & kPrototypeChain) != 0;
138   }
139 
140   /* ACCESS_CHECK */
141   bool HasAccess() const;
142 
143   /* PROPERTY */
144   inline bool ExtendingNonExtensible(Handle<JSReceiver> receiver);
145   void PrepareForDataProperty(Handle<Object> value);
146   void PrepareTransitionToDataProperty(Handle<JSReceiver> receiver,
147                                        Handle<Object> value,
148                                        PropertyAttributes attributes,
149                                        StoreOrigin store_origin);
150   inline bool IsCacheableTransition();
151   void ApplyTransitionToDataProperty(Handle<JSReceiver> receiver);
152   void ReconfigureDataProperty(Handle<Object> value,
153                                PropertyAttributes attributes);
154   void Delete();
155   void TransitionToAccessorProperty(Handle<Object> getter,
156                                     Handle<Object> setter,
157                                     PropertyAttributes attributes);
158   void TransitionToAccessorPair(Handle<Object> pair,
159                                 PropertyAttributes attributes);
property_details()160   PropertyDetails property_details() const {
161     DCHECK(has_property_);
162     return property_details_;
163   }
property_attributes()164   PropertyAttributes property_attributes() const {
165     return property_details().attributes();
166   }
IsConfigurable()167   bool IsConfigurable() const { return property_details().IsConfigurable(); }
IsReadOnly()168   bool IsReadOnly() const { return property_details().IsReadOnly(); }
IsEnumerable()169   bool IsEnumerable() const { return property_details().IsEnumerable(); }
representation()170   Representation representation() const {
171     return property_details().representation();
172   }
location()173   PropertyLocation location() const { return property_details().location(); }
constness()174   PropertyConstness constness() const { return property_details().constness(); }
175   Handle<Map> GetFieldOwnerMap() const;
176   FieldIndex GetFieldIndex() const;
177   Handle<FieldType> GetFieldType() const;
178   int GetFieldDescriptorIndex() const;
179   int GetAccessorIndex() const;
180   Handle<PropertyCell> GetPropertyCell() const;
181   Handle<Object> GetAccessors() const;
182   inline Handle<InterceptorInfo> GetInterceptor() const;
183   Handle<InterceptorInfo> GetInterceptorForFailedAccessCheck() const;
184   Handle<Object> GetDataValue(AllocationPolicy allocation_policy =
185                                   AllocationPolicy::kAllocationAllowed) const;
186   void WriteDataValue(Handle<Object> value, bool initializing_store);
187   inline void UpdateProtector();
188   static inline void UpdateProtector(Isolate* isolate, Handle<Object> receiver,
189                                      Handle<Name> name);
190 
191   // Lookup a 'cached' private property for an accessor.
192   // If not found returns false and leaves the LookupIterator unmodified.
193   bool TryLookupCachedProperty();
194   bool LookupCachedProperty();
195 
196  private:
197   static const size_t kInvalidIndex = std::numeric_limits<size_t>::max();
198 
199   inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
200                         Handle<Name> name, size_t index,
201                         Handle<Object> lookup_start_object,
202                         Configuration configuration);
203 
204   // For |ForTransitionHandler|.
205   LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
206                  Handle<Map> transition_map, PropertyDetails details,
207                  bool has_property);
208 
209   static void InternalUpdateProtector(Isolate* isolate, Handle<Object> receiver,
210                                       Handle<Name> name);
211 
212   enum class InterceptorState {
213     kUninitialized,
214     kSkipNonMasking,
215     kProcessNonMasking
216   };
217 
218   Handle<Map> GetReceiverMap() const;
219 
220   V8_WARN_UNUSED_RESULT inline JSReceiver NextHolder(Map map);
221 
is_js_array_element(bool is_element)222   bool is_js_array_element(bool is_element) const {
223     return is_element && index_ <= JSArray::kMaxArrayIndex;
224   }
225   template <bool is_element>
226   V8_EXPORT_PRIVATE void Start();
227   template <bool is_element>
228   void NextInternal(Map map, JSReceiver holder);
229   template <bool is_element>
LookupInHolder(Map map,JSReceiver holder)230   inline State LookupInHolder(Map map, JSReceiver holder) {
231     return map.IsSpecialReceiverMap()
232                ? LookupInSpecialHolder<is_element>(map, holder)
233                : LookupInRegularHolder<is_element>(map, holder);
234   }
235   template <bool is_element>
236   State LookupInRegularHolder(Map map, JSReceiver holder);
237   template <bool is_element>
238   State LookupInSpecialHolder(Map map, JSReceiver holder);
239   template <bool is_element>
RestartLookupForNonMaskingInterceptors()240   void RestartLookupForNonMaskingInterceptors() {
241     RestartInternal<is_element>(InterceptorState::kProcessNonMasking);
242   }
243   template <bool is_element>
244   void RestartInternal(InterceptorState interceptor_state);
245   Handle<Object> FetchValue(AllocationPolicy allocation_policy =
246                                 AllocationPolicy::kAllocationAllowed) const;
247   bool IsConstFieldValueEqualTo(Object value) const;
248   template <bool is_element>
249   void ReloadPropertyInformation();
250 
251   template <bool is_element>
252   bool SkipInterceptor(JSObject holder);
253   template <bool is_element>
254   inline InterceptorInfo GetInterceptor(JSObject holder) const;
255 
check_interceptor()256   bool check_interceptor() const {
257     return (configuration_ & kInterceptor) != 0;
258   }
259   inline InternalIndex descriptor_number() const;
260   inline InternalIndex dictionary_entry() const;
261 
262   static inline Configuration ComputeConfiguration(Isolate* isolate,
263                                                    Configuration configuration,
264                                                    Handle<Name> name);
265 
266   static Handle<JSReceiver> GetRootForNonJSReceiver(
267       Isolate* isolate, Handle<Object> lookup_start_object,
268       size_t index = kInvalidIndex);
269   static inline Handle<JSReceiver> GetRoot(Isolate* isolate,
270                                            Handle<Object> lookup_start_object,
271                                            size_t index = kInvalidIndex);
272 
273   State NotFound(JSReceiver const holder) const;
274 
275   // If configuration_ becomes mutable, update
276   // HolderIsReceiverOrHiddenPrototype.
277   const Configuration configuration_;
278   State state_ = NOT_FOUND;
279   bool has_property_ = false;
280   InterceptorState interceptor_state_ = InterceptorState::kUninitialized;
281   PropertyDetails property_details_ = PropertyDetails::Empty();
282   Isolate* const isolate_;
283   Handle<Name> name_;
284   Handle<Object> transition_;
285   const Handle<Object> receiver_;
286   Handle<JSReceiver> holder_;
287   const Handle<Object> lookup_start_object_;
288   const size_t index_;
289   InternalIndex number_ = InternalIndex::NotFound();
290 };
291 
292 }  // namespace internal
293 }  // namespace v8
294 
295 #endif  // V8_OBJECTS_LOOKUP_H_
296