v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
lookup.h
Go to the documentation of this file.
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 <optional>
9
10#include "src/common/globals.h"
12#include "src/heap/factory.h"
15#include "src/objects/map.h"
16#include "src/objects/objects.h"
17
18#if V8_ENABLE_WEBASSEMBLY
19#include "src/wasm/value-type.h"
20#endif // V8_ENABLE_WEBASSEMBLY
21
22namespace v8::internal {
23
25 public:
26 inline PropertyKey(Isolate* isolate, double index);
27 // {name} might be a string representation of an element index.
28 template <template <typename> typename HandleType>
29 requires(std::is_convertible_v<HandleType<Name>, DirectHandle<Name>>)
30 inline PropertyKey(Isolate* isolate, HandleType<Name> name);
31 // {valid_key} is a Name or Number.
32 template <typename T, template <typename> typename HandleType>
33 requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>)
34 inline PropertyKey(Isolate* isolate, HandleType<T> valid_key);
35 // {key} could be anything.
36 template <typename T, template <typename> typename HandleType>
37 requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>)
38 PropertyKey(Isolate* isolate, HandleType<T> key, bool* success);
39
40 inline bool is_element() const;
41 DirectHandle<Name> name() const { return name_; }
42 size_t index() const { return index_; }
43 inline DirectHandle<Name> GetName(Isolate* isolate);
44
45 private:
47
48 // Shortcut for constructing PropertyKey from an active LookupIterator.
49 template <template <typename> typename HandleType>
50 requires(std::is_convertible_v<HandleType<Name>, DirectHandle<Name>>)
51 inline PropertyKey(Isolate* isolate, HandleType<Name> name, size_t index);
52
54 size_t index_;
55};
56
58 public:
60 // Configuration bits.
61 kInterceptor = 1 << 0,
62 kPrototypeChain = 1 << 1,
63
64 // Convenience combinations of bits.
65 OWN_SKIP_INTERCEPTOR = 0,
66 OWN = kInterceptor,
67 PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kPrototypeChain,
68 PROTOTYPE_CHAIN = kPrototypeChain | kInterceptor,
69 DEFAULT = PROTOTYPE_CHAIN
70 };
71
72 enum State {
73 // The property was not found by the iterator (this is a terminal state,
74 // iteration should not continue after hitting a not-found state).
76 // Typed arrays have special handling for "canonical numeric index string"
77 // (https://tc39.es/ecma262/#sec-canonicalnumericindexstring), where not
78 // finding such an index (either because of OOB, or because it's not a valid
79 // integer index) immediately returns undefined, without walking the
80 // prototype (https://tc39.es/ecma262/#sec-typedarray-get).
82 // The next lookup requires an access check -- we can continue iteration on
83 // a successful check, otherwise we should abort.
85 // Interceptors are API-level hooks for optionally handling a lookup in
86 // embedder code -- if their handling returns false, then we should continue
87 // the iteration, though we should be conscious that an interceptor may have
88 // side effects despite returning false and might invalidate the lookup
89 // iterator state.
91 // Proxies are user-space hooks for handling lookups in JS code.
92 // https://tc39.es/ecma262/#proxy-exotic-object
94 // Accessors are hooks for property getters/setters -- these can be
95 // user-space accessors (AccessorPair), or API accessors (AccessorInfo).
97 // Data properties are stored as data fields on an object (either properties
98 // or elements).
100 // WasmGC objects are opaque in JS, and appear to have no properties.
102
103 // A LookupIterator in the transition state is in the middle of performing
104 // a data transition (that is, as part of a data property write, updating
105 // the receiver and its map to allow the write).
106 //
107 // This state is not expected to be observed while performing a lookup.
109
110 // Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a
111 // PROPERTY lookup.
112 BEFORE_PROPERTY = INTERCEPTOR
113 };
114
115 // {name} is guaranteed to be a property name (and not e.g. "123").
116 // TODO(leszeks): Port these constructors to use JSAny.
119 Configuration configuration = DEFAULT);
122 DirectHandle<JSAny> lookup_start_object,
123 Configuration configuration = DEFAULT);
124
126 size_t index, Configuration configuration = DEFAULT);
128 size_t index, DirectHandle<JSAny> lookup_start_object,
129 Configuration configuration = DEFAULT);
130
132 const PropertyKey& key,
133 Configuration configuration = DEFAULT);
135 const PropertyKey& key,
136 DirectHandle<JSAny> lookup_start_object,
137 Configuration configuration = DEFAULT);
138
139 // Special case for lookup of the |error_stack_trace| private symbol in
140 // prototype chain (usually private symbols are limited to
141 // OWN_SKIP_INTERCEPTOR lookups).
142 inline LookupIterator(Isolate* isolate, Configuration configuration,
145
146 void Restart() {
147 InterceptorState state = InterceptorState::kUninitialized;
148 IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state);
149 }
150
151 // Checks index validity in a TypedArray again, but doesn't do the whole
152 // lookup anew (holder doesn't change).
153 void RecheckTypedArrayBounds();
154
155 Isolate* isolate() const { return isolate_; }
156 State state() const { return state_; }
157
158 inline DirectHandle<Name> name() const;
159 inline DirectHandle<Name> GetName();
160 size_t index() const { return index_; }
161 uint32_t array_index() const {
162 DCHECK_LE(index_, JSArray::kMaxArrayIndex);
163 return static_cast<uint32_t>(index_);
164 }
165
166 // Helper method for creating a copy of of the iterator.
167 inline PropertyKey GetKey() const;
168
169 // Returns true if this LookupIterator has an index in the range
170 // [0, size_t::max).
171 bool IsElement() const { return index_ != kInvalidIndex; }
172 // Returns true if this LookupIterator has an index that counts as an
173 // element for the given object (up to kMaxArrayIndex for JSArrays,
174 // any integer for JSTypedArrays).
175 inline bool IsElement(Tagged<JSReceiver> object) const;
176
177 inline bool IsPrivateName() const;
178
179 bool IsFound() const { return state_ != NOT_FOUND; }
180 void Next();
181 void NotFound() {
182 has_property_ = false;
183 state_ = NOT_FOUND;
184 }
185
186 Heap* heap() const { return isolate_->heap(); }
187 Factory* factory() const { return isolate_->factory(); }
189
190 template <class T>
191 inline DirectHandle<T> GetStoreTarget() const;
192 inline bool is_dictionary_holder() const;
193 inline DirectHandle<Map> transition_map() const;
194 inline DirectHandle<PropertyCell> transition_cell() const;
195 template <class T>
196 inline DirectHandle<T> GetHolder() const;
197
199 return lookup_start_object_;
200 }
201
202 bool HolderIsReceiver() const;
203 bool HolderIsReceiverOrHiddenPrototype() const;
204
206 return (configuration_ & kPrototypeChain) != 0;
207 }
208
209 /* ACCESS_CHECK */
210 bool HasAccess() const;
211
212 /* PROPERTY */
213 inline bool ExtendingNonExtensible(DirectHandle<JSReceiver> receiver);
214 void PrepareForDataProperty(DirectHandle<Object> value);
215 void PrepareTransitionToDataProperty(DirectHandle<JSReceiver> receiver,
217 PropertyAttributes attributes,
218 StoreOrigin store_origin);
219 inline bool IsCacheableTransition();
220 void ApplyTransitionToDataProperty(DirectHandle<JSReceiver> receiver);
221 void ReconfigureDataProperty(DirectHandle<Object> value,
222 PropertyAttributes attributes);
223 void Delete();
224 void TransitionToAccessorProperty(DirectHandle<Object> getter,
226 PropertyAttributes attributes);
227 void TransitionToAccessorPair(DirectHandle<Object> pair,
228 PropertyAttributes attributes);
230 DCHECK(has_property_);
231 return property_details_;
232 }
234 return property_details().attributes();
235 }
236 bool IsConfigurable() const { return property_details().IsConfigurable(); }
237 bool IsReadOnly() const { return property_details().IsReadOnly(); }
238 bool IsEnumerable() const { return property_details().IsEnumerable(); }
240 return property_details().representation();
241 }
242 PropertyLocation location() const { return property_details().location(); }
243 PropertyConstness constness() const { return property_details().constness(); }
244 FieldIndex GetFieldIndex() const;
245 int GetFieldDescriptorIndex() const;
246 int GetAccessorIndex() const;
247 DirectHandle<PropertyCell> GetPropertyCell() const;
248 DirectHandle<Object> GetAccessors() const;
249 inline DirectHandle<InterceptorInfo> GetInterceptor() const;
250 DirectHandle<InterceptorInfo> GetInterceptorForFailedAccessCheck() const;
251 Handle<Object> GetDataValue(AllocationPolicy allocation_policy =
252 AllocationPolicy::kAllocationAllowed) const;
253 void WriteDataValue(DirectHandle<Object> value, bool initializing_store);
254 DirectHandle<Object> GetDataValue(SeqCstAccessTag tag) const;
255 void WriteDataValue(DirectHandle<Object> value, SeqCstAccessTag tag);
256 DirectHandle<Object> SwapDataValue(DirectHandle<Object> value,
257 SeqCstAccessTag tag);
258 DirectHandle<Object> CompareAndSwapDataValue(DirectHandle<Object> expected,
260 SeqCstAccessTag tag);
261 inline void UpdateProtector();
262 static inline void UpdateProtector(Isolate* isolate,
264 DirectHandle<Name> name);
265
266 // Lookup a 'cached' private property for an accessor.
267 // If not found returns false and leaves the LookupIterator unmodified.
268 bool TryLookupCachedProperty(DirectHandle<AccessorPair> accessor);
269 bool TryLookupCachedProperty();
270
271 // Test whether the object has an internal marker property.
272 static bool HasInternalMarkerProperty(Isolate* isolate,
273 Tagged<JSReceiver> object,
274 DirectHandle<Symbol> marker);
275
276 private:
278
279 static const size_t kInvalidIndex = std::numeric_limits<size_t>::max();
280
281 bool LookupCachedProperty(DirectHandle<AccessorPair> accessor);
283 DirectHandle<Name> name, size_t index,
284 DirectHandle<JSAny> lookup_start_object,
285 Configuration configuration);
286
287 // Lookup private symbol on the prototype chain. Currently used only for
288 // error_stack_symbol and error_message_symbol.
289 inline LookupIterator(Isolate* isolate, Configuration configuration,
291 DirectHandle<JSAny> lookup_start_object);
292
293 static void InternalUpdateProtector(Isolate* isolate,
295 DirectHandle<Name> name);
296
297 enum class InterceptorState {
299 kSkipNonMasking,
300 kProcessNonMasking
301 };
302
303 DirectHandle<Map> GetReceiverMap() const;
304
306
307 bool is_js_array_element(bool is_element) const {
308 return is_element && index_ <= JSArray::kMaxArrayIndex;
309 }
310 template <bool is_element>
312 template <bool is_element>
313 void NextInternal(Tagged<Map> map, Tagged<JSReceiver> holder);
314 template <bool is_element>
316 return IsSpecialReceiverMap(map)
317 ? LookupInSpecialHolder<is_element>(map, holder)
318 : LookupInRegularHolder<is_element>(map, holder);
319 }
320 template <bool is_element>
321 State LookupInRegularHolder(Tagged<Map> map, Tagged<JSReceiver> holder);
322 template <bool is_element>
323 State LookupInSpecialHolder(Tagged<Map> map, Tagged<JSReceiver> holder);
324 template <bool is_element>
326 RestartInternal<is_element>(InterceptorState::kProcessNonMasking);
327 }
328 template <bool is_element>
329 void RestartInternal(InterceptorState interceptor_state);
330 DirectHandle<Object> FetchValue(
331 AllocationPolicy allocation_policy =
332 AllocationPolicy::kAllocationAllowed) const;
333 bool CanStayConst(Tagged<Object> value) const;
334 bool DictCanStayConst(Tagged<Object> value) const;
335
336 template <bool is_element>
337 void ReloadPropertyInformation();
338
339 template <bool is_element>
340 bool SkipInterceptor(Tagged<JSObject> holder);
341 template <bool is_element>
342 inline Tagged<InterceptorInfo> GetInterceptor(Tagged<JSObject> holder) const;
343
344 bool check_interceptor() const {
345 return (configuration_ & kInterceptor) != 0;
346 }
347 inline InternalIndex descriptor_number() const;
348 inline InternalIndex dictionary_entry() const;
349
350 static inline Configuration ComputeConfiguration(Isolate* isolate,
351 Configuration configuration,
352 DirectHandle<Name> name);
353
354 static MaybeDirectHandle<JSReceiver> GetRootForNonJSReceiver(
355 Isolate* isolate, DirectHandle<JSPrimitive> lookup_start_object,
356 size_t index, Configuration configuration);
357 static inline MaybeDirectHandle<JSReceiver> GetRoot(
358 Isolate* isolate, DirectHandle<JSAny> lookup_start_object, size_t index,
359 Configuration configuration);
360
361 State NotFound(Tagged<JSReceiver> const holder) const;
362
363 // If configuration_ becomes mutable, update
364 // HolderIsReceiverOrHiddenPrototype.
366 State state_ = NOT_FOUND;
367 bool has_property_ = false;
368 InterceptorState interceptor_state_ = InterceptorState::kUninitialized;
369 PropertyDetails property_details_ = PropertyDetails::Empty();
376 const size_t index_;
377 InternalIndex number_ = InternalIndex::NotFound();
378};
379
380// Similar to the LookupIterator, but for concurrent accesses from a background
381// thread.
382//
383// Note: This is a work in progress, intended to bundle code related to
384// concurrent lookups here. In its current state, the class is obviously not an
385// 'iterator'. Still, keeping the name for now, with the intent to clarify
386// names and implementation once we've gotten some experience with more
387// involved logic.
388// TODO(jgruber, v8:7790): Consider using a LookupIterator-style interface.
389// TODO(jgruber, v8:7790): Consider merging back into the LookupIterator once
390// functionality and constraints are better known.
392 public:
393 // Tri-state to distinguish between 'not-present' and 'who-knows' failures.
394 enum Result {
395 kPresent, // The value was found.
396 kNotPresent, // No value exists.
397 kGaveUp, // The operation can't be completed.
398 };
399
400 // Implements the own data property lookup for the specialized case of
401 // fixed_cow_array backing stores (these are only in use for array literal
402 // boilerplates). The contract is that the elements, elements kind, and array
403 // length passed to this function should all be read from the same JSArray
404 // instance; but due to concurrency it's possible that they may not be
405 // consistent among themselves (e.g. the elements kind may not match the
406 // given elements backing store). We are thus extra-careful to handle
407 // exceptional situations.
408 V8_EXPORT_PRIVATE static std::optional<Tagged<Object>> TryGetOwnCowElement(
409 Isolate* isolate, Tagged<FixedArray> array_elements,
410 ElementsKind elements_kind, int array_length, size_t index);
411
412 // As above, the contract is that the elements and elements kind should be
413 // read from the same holder, but this function is implemented defensively to
414 // tolerate concurrency issues.
416 Tagged<Object>* result_out, Isolate* isolate, LocalIsolate* local_isolate,
418 ElementsKind elements_kind, size_t index);
419
420 // Implements the own data property lookup for the specialized case of
421 // strings.
423 Isolate* isolate,
424 LocalIsolate* local_isolate,
425 Tagged<String> string,
426 size_t index);
427
428 // This method reimplements the following sequence in a concurrent setting:
429 //
430 // LookupIterator it(holder, isolate, name, LookupIterator::OWN);
431 // it.TryLookupCachedProperty();
432 // if (it.state() == LookupIterator::DATA) it.GetPropertyCell();
433 V8_EXPORT_PRIVATE static std::optional<Tagged<PropertyCell>>
434 TryGetPropertyCell(Isolate* isolate, LocalIsolate* local_isolate,
436 DirectHandle<Name> name);
437};
438
439} // namespace v8::internal
440
441#endif // V8_OBJECTS_LOOKUP_H_
Isolate * isolate_
const char * name
Definition builtins.cc:39
PropertyT * setter
PropertyT * getter
static V8_EXPORT_PRIVATE std::optional< Tagged< Object > > TryGetOwnCowElement(Isolate *isolate, Tagged< FixedArray > array_elements, ElementsKind elements_kind, int array_length, size_t index)
Definition lookup.cc:1492
static V8_EXPORT_PRIVATE Result TryGetOwnChar(Tagged< String > *result_out, Isolate *isolate, LocalIsolate *local_isolate, Tagged< String > string, size_t index)
Definition lookup.cc:1601
static V8_EXPORT_PRIVATE Result TryGetOwnConstantElement(Tagged< Object > *result_out, Isolate *isolate, LocalIsolate *local_isolate, Tagged< JSObject > holder, Tagged< FixedArrayBase > elements, ElementsKind elements_kind, size_t index)
Definition lookup.cc:1537
static V8_EXPORT_PRIVATE std::optional< Tagged< PropertyCell > > TryGetPropertyCell(Isolate *isolate, LocalIsolate *local_isolate, DirectHandle< JSGlobalObject > holder, DirectHandle< Name > name)
Definition lookup.cc:1638
bool is_js_array_element(bool is_element) const
Definition lookup.h:307
const Configuration configuration_
Definition lookup.h:365
PropertyDetails property_details() const
Definition lookup.h:229
DirectHandle< UnionOf< Map, PropertyCell > > transition_
Definition lookup.h:372
uint32_t array_index() const
Definition lookup.h:161
PropertyLocation location() const
Definition lookup.h:242
bool check_interceptor() const
Definition lookup.h:344
LookupIterator(Isolate *isolate, Configuration configuration, DirectHandle< JSAny > receiver, DirectHandle< Symbol > name, DirectHandle< JSAny > lookup_start_object)
Isolate * isolate() const
Definition lookup.h:155
void RestartLookupForNonMaskingInterceptors()
Definition lookup.h:325
PropertyAttributes property_attributes() const
Definition lookup.h:233
DirectHandle< Name > name_
Definition lookup.h:371
DirectHandle< JSReceiver > holder_
Definition lookup.h:374
Isolate *const isolate_
Definition lookup.h:370
DirectHandle< JSAny > GetReceiver() const
Definition lookup.h:188
const DirectHandle< JSAny > receiver_
Definition lookup.h:373
State LookupInHolder(Tagged< Map > map, Tagged< JSReceiver > holder)
Definition lookup.h:315
DirectHandle< JSAny > lookup_start_object() const
Definition lookup.h:198
V8_EXPORT_PRIVATE void Start()
Factory * factory() const
Definition lookup.h:187
bool IsConfigurable() const
Definition lookup.h:236
Representation representation() const
Definition lookup.h:239
bool IsEnumerable() const
Definition lookup.h:238
PropertyConstness constness() const
Definition lookup.h:243
const DirectHandle< JSAny > lookup_start_object_
Definition lookup.h:375
bool check_prototype_chain() const
Definition lookup.h:205
DirectHandle< Name > name_
Definition lookup.h:53
DirectHandle< Name > name() const
Definition lookup.h:41
PropertyKey(Isolate *isolate, double index)
Definition lookup-inl.h:136
size_t index() const
Definition lookup.h:42
DirectHandle< Name > GetName(Isolate *isolate)
Definition lookup-inl.h:233
Register const index_
enum v8::internal::@1270::DeoptimizableCodeIterator::@67 state_
Node * receiver_
TNode< Object > receiver
bool IsSpecialReceiverMap(Tagged< Map > map)
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define DCHECK(condition)
Definition logging.h:482
#define V8_EXPORT_PRIVATE
Definition macros.h:460
#define V8_WARN_UNUSED_RESULT
Definition v8config.h:671
std::unique_ptr< ValueMirror > key