• 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 #if V8_ENABLE_WEBASSEMBLY
17 #include "src/wasm/value-type.h"
18 #endif  // V8_ENABLE_WEBASSEMBLY
19 
20 namespace v8 {
21 namespace internal {
22 
23 class PropertyKey {
24  public:
25   inline PropertyKey(Isolate* isolate, double index);
26   // {name} might be a string representation of an element index.
27   inline PropertyKey(Isolate* isolate, Handle<Name> name);
28   // {valid_key} is a Name or Number.
29   inline PropertyKey(Isolate* isolate, Handle<Object> valid_key);
30   // {key} could be anything.
31   PropertyKey(Isolate* isolate, Handle<Object> key, bool* success);
32 
33   inline bool is_element() const;
name()34   Handle<Name> name() const { return name_; }
index()35   size_t index() const { return index_; }
36   inline Handle<Name> GetName(Isolate* isolate);
37 
38  private:
39   Handle<Name> name_;
40   size_t index_;
41 };
42 
43 class V8_EXPORT_PRIVATE LookupIterator final {
44  public:
45   enum Configuration {
46     // Configuration bits.
47     kInterceptor = 1 << 0,
48     kPrototypeChain = 1 << 1,
49 
50     // Convenience combinations of bits.
51     OWN_SKIP_INTERCEPTOR = 0,
52     OWN = kInterceptor,
53     PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kPrototypeChain,
54     PROTOTYPE_CHAIN = kPrototypeChain | kInterceptor,
55     DEFAULT = PROTOTYPE_CHAIN
56   };
57 
58   enum State {
59     ACCESS_CHECK,
60     INTEGER_INDEXED_EXOTIC,
61     INTERCEPTOR,
62     JSPROXY,
63     NOT_FOUND,
64     ACCESSOR,
65     DATA,
66     TRANSITION,
67     // Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a
68     // PROPERTY lookup.
69     BEFORE_PROPERTY = INTERCEPTOR
70   };
71 
72   // {name} is guaranteed to be a property name (and not e.g. "123").
73   inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
74                         Handle<Name> name,
75                         Configuration configuration = DEFAULT);
76   inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
77                         Handle<Name> name, Handle<Object> lookup_start_object,
78                         Configuration configuration = DEFAULT);
79 
80   inline LookupIterator(Isolate* isolate, Handle<Object> receiver, size_t index,
81                         Configuration configuration = DEFAULT);
82   inline LookupIterator(Isolate* isolate, Handle<Object> receiver, size_t index,
83                         Handle<Object> lookup_start_object,
84                         Configuration configuration = DEFAULT);
85 
86   inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
87                         const PropertyKey& key,
88                         Configuration configuration = DEFAULT);
89   inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
90                         const PropertyKey& key,
91                         Handle<Object> lookup_start_object,
92                         Configuration configuration = DEFAULT);
93 
Restart()94   void Restart() {
95     InterceptorState state = InterceptorState::kUninitialized;
96     IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state);
97   }
98 
isolate()99   Isolate* isolate() const { return isolate_; }
state()100   State state() const { return state_; }
101 
102   inline Handle<Name> name() const;
103   inline Handle<Name> GetName();
index()104   size_t index() const { return index_; }
array_index()105   uint32_t array_index() const {
106     DCHECK_LE(index_, JSArray::kMaxArrayIndex);
107     return static_cast<uint32_t>(index_);
108   }
109 
110   // Returns true if this LookupIterator has an index in the range
111   // [0, size_t::max).
IsElement()112   bool IsElement() const { return index_ != kInvalidIndex; }
113   // Returns true if this LookupIterator has an index that counts as an
114   // element for the given object (up to kMaxArrayIndex for JSArrays,
115   // any integer for JSTypedArrays).
116   inline bool IsElement(JSReceiver object) const;
117 
IsFound()118   bool IsFound() const { return state_ != NOT_FOUND; }
119   void Next();
NotFound()120   void NotFound() {
121     has_property_ = false;
122     state_ = NOT_FOUND;
123   }
124 
heap()125   Heap* heap() const { return isolate_->heap(); }
factory()126   Factory* factory() const { return isolate_->factory(); }
GetReceiver()127   Handle<Object> GetReceiver() const { return receiver_; }
128 
129   template <class T>
130   inline Handle<T> GetStoreTarget() const;
131   inline bool is_dictionary_holder() const;
132   inline Handle<Map> transition_map() const;
133   inline Handle<PropertyCell> transition_cell() const;
134   template <class T>
135   inline Handle<T> GetHolder() const;
136 
lookup_start_object()137   Handle<Object> lookup_start_object() const { return lookup_start_object_; }
138 
139   bool HolderIsReceiver() const;
140   bool HolderIsReceiverOrHiddenPrototype() const;
141 
check_prototype_chain()142   bool check_prototype_chain() const {
143     return (configuration_ & kPrototypeChain) != 0;
144   }
145 
146   /* ACCESS_CHECK */
147   bool HasAccess() const;
148 
149   /* PROPERTY */
150   inline bool ExtendingNonExtensible(Handle<JSReceiver> receiver);
151   void PrepareForDataProperty(Handle<Object> value);
152   void PrepareTransitionToDataProperty(Handle<JSReceiver> receiver,
153                                        Handle<Object> value,
154                                        PropertyAttributes attributes,
155                                        StoreOrigin store_origin);
156   inline bool IsCacheableTransition();
157   void ApplyTransitionToDataProperty(Handle<JSReceiver> receiver);
158   void ReconfigureDataProperty(Handle<Object> value,
159                                PropertyAttributes attributes);
160   void Delete();
161   void TransitionToAccessorProperty(Handle<Object> getter,
162                                     Handle<Object> setter,
163                                     PropertyAttributes attributes);
164   void TransitionToAccessorPair(Handle<Object> pair,
165                                 PropertyAttributes attributes);
property_details()166   PropertyDetails property_details() const {
167     DCHECK(has_property_);
168     return property_details_;
169   }
property_attributes()170   PropertyAttributes property_attributes() const {
171     return property_details().attributes();
172   }
IsConfigurable()173   bool IsConfigurable() const { return property_details().IsConfigurable(); }
IsReadOnly()174   bool IsReadOnly() const { return property_details().IsReadOnly(); }
IsEnumerable()175   bool IsEnumerable() const { return property_details().IsEnumerable(); }
representation()176   Representation representation() const {
177     return property_details().representation();
178   }
location()179   PropertyLocation location() const { return property_details().location(); }
constness()180   PropertyConstness constness() const { return property_details().constness(); }
181   FieldIndex GetFieldIndex() const;
182   int GetFieldDescriptorIndex() const;
183   int GetAccessorIndex() const;
184   Handle<PropertyCell> GetPropertyCell() const;
185   Handle<Object> GetAccessors() const;
186   inline Handle<InterceptorInfo> GetInterceptor() const;
187   Handle<InterceptorInfo> GetInterceptorForFailedAccessCheck() const;
188   Handle<Object> GetDataValue(AllocationPolicy allocation_policy =
189                                   AllocationPolicy::kAllocationAllowed) const;
190   void WriteDataValue(Handle<Object> value, bool initializing_store);
191   Handle<Object> GetDataValue(SeqCstAccessTag tag) const;
192   void WriteDataValue(Handle<Object> value, SeqCstAccessTag tag);
193   Handle<Object> SwapDataValue(Handle<Object> value, SeqCstAccessTag tag);
194   inline void UpdateProtector();
195   static inline void UpdateProtector(Isolate* isolate, Handle<Object> receiver,
196                                      Handle<Name> name);
197 
198 #if V8_ENABLE_WEBASSEMBLY
199   // Fetches type of WasmStruct's field or WasmArray's elements, it
200   // is used for preparing the value for storing into WasmObjects.
201   wasm::ValueType wasm_value_type() const;
202   void WriteDataValueToWasmObject(Handle<Object> value);
203 #endif  // V8_ENABLE_WEBASSEMBLY
204 
205   // Lookup a 'cached' private property for an accessor.
206   // If not found returns false and leaves the LookupIterator unmodified.
207   bool TryLookupCachedProperty(Handle<AccessorPair> accessor);
208   bool TryLookupCachedProperty();
209 
210  private:
211   friend PropertyKey;
212 
213   static const size_t kInvalidIndex = std::numeric_limits<size_t>::max();
214 
215   bool LookupCachedProperty(Handle<AccessorPair> accessor);
216   inline LookupIterator(Isolate* isolate, Handle<Object> receiver,
217                         Handle<Name> name, size_t index,
218                         Handle<Object> lookup_start_object,
219                         Configuration configuration);
220 
221   // For |ForTransitionHandler|.
222   LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
223                  Handle<Map> transition_map, PropertyDetails details,
224                  bool has_property);
225 
226   static void InternalUpdateProtector(Isolate* isolate, Handle<Object> receiver,
227                                       Handle<Name> name);
228 
229   enum class InterceptorState {
230     kUninitialized,
231     kSkipNonMasking,
232     kProcessNonMasking
233   };
234 
235   Handle<Map> GetReceiverMap() const;
236 
237   V8_WARN_UNUSED_RESULT inline JSReceiver NextHolder(Map map);
238 
is_js_array_element(bool is_element)239   bool is_js_array_element(bool is_element) const {
240     return is_element && index_ <= JSArray::kMaxArrayIndex;
241   }
242   template <bool is_element>
243   V8_EXPORT_PRIVATE void Start();
244   template <bool is_element>
245   void NextInternal(Map map, JSReceiver holder);
246   template <bool is_element>
LookupInHolder(Map map,JSReceiver holder)247   inline State LookupInHolder(Map map, JSReceiver holder) {
248     return map.IsSpecialReceiverMap()
249                ? LookupInSpecialHolder<is_element>(map, holder)
250                : LookupInRegularHolder<is_element>(map, holder);
251   }
252   template <bool is_element>
253   State LookupInRegularHolder(Map map, JSReceiver holder);
254   template <bool is_element>
255   State LookupInSpecialHolder(Map map, JSReceiver holder);
256   template <bool is_element>
RestartLookupForNonMaskingInterceptors()257   void RestartLookupForNonMaskingInterceptors() {
258     RestartInternal<is_element>(InterceptorState::kProcessNonMasking);
259   }
260   template <bool is_element>
261   void RestartInternal(InterceptorState interceptor_state);
262   Handle<Object> FetchValue(AllocationPolicy allocation_policy =
263                                 AllocationPolicy::kAllocationAllowed) const;
264   bool IsConstFieldValueEqualTo(Object value) const;
265   bool IsConstDictValueEqualTo(Object value) const;
266 
267   template <bool is_element>
268   void ReloadPropertyInformation();
269 
270   template <bool is_element>
271   bool SkipInterceptor(JSObject holder);
272   template <bool is_element>
273   inline InterceptorInfo GetInterceptor(JSObject holder) const;
274 
check_interceptor()275   bool check_interceptor() const {
276     return (configuration_ & kInterceptor) != 0;
277   }
278   inline InternalIndex descriptor_number() const;
279   inline InternalIndex dictionary_entry() const;
280 
281   static inline Configuration ComputeConfiguration(Isolate* isolate,
282                                                    Configuration configuration,
283                                                    Handle<Name> name);
284 
285   static Handle<JSReceiver> GetRootForNonJSReceiver(
286       Isolate* isolate, Handle<Object> lookup_start_object,
287       size_t index = kInvalidIndex);
288   static inline Handle<JSReceiver> GetRoot(Isolate* isolate,
289                                            Handle<Object> lookup_start_object,
290                                            size_t index = kInvalidIndex);
291 
292   State NotFound(JSReceiver const holder) const;
293 
294   // If configuration_ becomes mutable, update
295   // HolderIsReceiverOrHiddenPrototype.
296   const Configuration configuration_;
297   State state_ = NOT_FOUND;
298   bool has_property_ = false;
299   InterceptorState interceptor_state_ = InterceptorState::kUninitialized;
300   PropertyDetails property_details_ = PropertyDetails::Empty();
301   Isolate* const isolate_;
302   Handle<Name> name_;
303   Handle<Object> transition_;
304   const Handle<Object> receiver_;
305   Handle<JSReceiver> holder_;
306   const Handle<Object> lookup_start_object_;
307   const size_t index_;
308   InternalIndex number_ = InternalIndex::NotFound();
309 };
310 
311 // Similar to the LookupIterator, but for concurrent accesses from a background
312 // thread.
313 //
314 // Note: This is a work in progress, intended to bundle code related to
315 // concurrent lookups here. In its current state, the class is obviously not an
316 // 'iterator'. Still, keeping the name for now, with the intent to clarify
317 // names and implementation once we've gotten some experience with more
318 // involved logic.
319 // TODO(jgruber, v8:7790): Consider using a LookupIterator-style interface.
320 // TODO(jgruber, v8:7790): Consider merging back into the LookupIterator once
321 // functionality and constraints are better known.
322 class ConcurrentLookupIterator final : public AllStatic {
323  public:
324   // Tri-state to distinguish between 'not-present' and 'who-knows' failures.
325   enum Result {
326     kPresent,     // The value was found.
327     kNotPresent,  // No value exists.
328     kGaveUp,      // The operation can't be completed.
329   };
330 
331   // Implements the own data property lookup for the specialized case of
332   // fixed_cow_array backing stores (these are only in use for array literal
333   // boilerplates). The contract is that the elements, elements kind, and array
334   // length passed to this function should all be read from the same JSArray
335   // instance; but due to concurrency it's possible that they may not be
336   // consistent among themselves (e.g. the elements kind may not match the
337   // given elements backing store). We are thus extra-careful to handle
338   // exceptional situations.
339   V8_EXPORT_PRIVATE static base::Optional<Object> TryGetOwnCowElement(
340       Isolate* isolate, FixedArray array_elements, ElementsKind elements_kind,
341       int array_length, size_t index);
342 
343   // As above, the contract is that the elements and elements kind should be
344   // read from the same holder, but this function is implemented defensively to
345   // tolerate concurrency issues.
346   V8_EXPORT_PRIVATE static Result TryGetOwnConstantElement(
347       Object* result_out, Isolate* isolate, LocalIsolate* local_isolate,
348       JSObject holder, FixedArrayBase elements, ElementsKind elements_kind,
349       size_t index);
350 
351   // Implements the own data property lookup for the specialized case of
352   // strings.
353   V8_EXPORT_PRIVATE static Result TryGetOwnChar(String* result_out,
354                                                 Isolate* isolate,
355                                                 LocalIsolate* local_isolate,
356                                                 String string, size_t index);
357 
358   // This method reimplements the following sequence in a concurrent setting:
359   //
360   // LookupIterator it(holder, isolate, name, LookupIterator::OWN);
361   // it.TryLookupCachedProperty();
362   // if (it.state() == LookupIterator::DATA) it.GetPropertyCell();
363   V8_EXPORT_PRIVATE static base::Optional<PropertyCell> TryGetPropertyCell(
364       Isolate* isolate, LocalIsolate* local_isolate,
365       Handle<JSGlobalObject> holder, Handle<Name> name);
366 };
367 
368 }  // namespace internal
369 }  // namespace v8
370 
371 #endif  // V8_OBJECTS_LOOKUP_H_
372