Line data Source code
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/globals.h"
10 : #include "src/isolate.h"
11 : #include "src/objects.h"
12 : #include "src/objects/descriptor-array.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 :
17 : class V8_EXPORT_PRIVATE LookupIterator final BASE_EMBEDDED {
18 : public:
19 : enum Configuration {
20 : // Configuration bits.
21 : kInterceptor = 1 << 0,
22 : kPrototypeChain = 1 << 1,
23 :
24 : // Convience combinations of bits.
25 : OWN_SKIP_INTERCEPTOR = 0,
26 : OWN = kInterceptor,
27 : PROTOTYPE_CHAIN_SKIP_INTERCEPTOR = kPrototypeChain,
28 : PROTOTYPE_CHAIN = kPrototypeChain | kInterceptor,
29 : DEFAULT = PROTOTYPE_CHAIN
30 : };
31 :
32 : enum State {
33 : ACCESS_CHECK,
34 : INTEGER_INDEXED_EXOTIC,
35 : INTERCEPTOR,
36 : JSPROXY,
37 : NOT_FOUND,
38 : ACCESSOR,
39 : DATA,
40 : TRANSITION,
41 : // Set state_ to BEFORE_PROPERTY to ensure that the next lookup will be a
42 : // PROPERTY lookup.
43 : BEFORE_PROPERTY = INTERCEPTOR
44 : };
45 :
46 184578847 : LookupIterator(Handle<Object> receiver, Handle<Name> name,
47 : Configuration configuration = DEFAULT)
48 184578847 : : LookupIterator(name->GetIsolate(), receiver, name, configuration) {}
49 :
50 184579697 : LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
51 : Configuration configuration = DEFAULT)
52 : : LookupIterator(isolate, receiver, name, GetRoot(isolate, receiver),
53 184579697 : configuration) {}
54 :
55 105553849 : LookupIterator(Handle<Object> receiver, Handle<Name> name,
56 : Handle<JSReceiver> holder,
57 : Configuration configuration = DEFAULT)
58 : : LookupIterator(name->GetIsolate(), receiver, name, holder,
59 105553849 : configuration) {}
60 :
61 290133413 : LookupIterator(Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
62 : Handle<JSReceiver> holder,
63 : Configuration configuration = DEFAULT)
64 : : configuration_(ComputeConfiguration(configuration, name)),
65 : interceptor_state_(InterceptorState::kUninitialized),
66 : property_details_(PropertyDetails::Empty()),
67 : isolate_(isolate),
68 : name_(isolate_->factory()->InternalizeName(name)),
69 : receiver_(receiver),
70 : initial_holder_(holder),
71 : // kMaxUInt32 isn't a valid index.
72 : index_(kMaxUInt32),
73 870400147 : number_(static_cast<uint32_t>(DescriptorArray::kNotFound)) {
74 : #ifdef DEBUG
75 : uint32_t index; // Assert that the name is not an array index.
76 : DCHECK(!name->AsArrayIndex(&index));
77 : #endif // DEBUG
78 290133394 : Start<false>();
79 290133490 : }
80 :
81 38138640 : LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
82 : Configuration configuration = DEFAULT)
83 : : LookupIterator(isolate, receiver, index,
84 76277280 : GetRoot(isolate, receiver, index), configuration) {}
85 :
86 381 : LookupIterator(Isolate* isolate, Handle<Object> receiver, uint32_t index,
87 : Handle<JSReceiver> holder,
88 : Configuration configuration = DEFAULT)
89 : : configuration_(configuration),
90 : interceptor_state_(InterceptorState::kUninitialized),
91 : property_details_(PropertyDetails::Empty()),
92 : isolate_(isolate),
93 : receiver_(receiver),
94 : initial_holder_(holder),
95 : index_(index),
96 573296286 : number_(static_cast<uint32_t>(DescriptorArray::kNotFound)) {
97 : // kMaxUInt32 isn't a valid index.
98 : DCHECK_NE(kMaxUInt32, index_);
99 191098762 : Start<true>();
100 381 : }
101 :
102 70676223 : static LookupIterator PropertyOrElement(
103 : Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
104 : Configuration configuration = DEFAULT) {
105 : uint32_t index;
106 70676223 : if (name->AsArrayIndex(&index)) {
107 : LookupIterator it =
108 78184 : LookupIterator(isolate, receiver, index, configuration);
109 78184 : it.name_ = name;
110 78184 : return it;
111 : }
112 70598039 : return LookupIterator(receiver, name, configuration);
113 : }
114 :
115 16734519 : static LookupIterator PropertyOrElement(
116 : Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
117 : Handle<JSReceiver> holder, Configuration configuration = DEFAULT) {
118 : uint32_t index;
119 16734519 : if (name->AsArrayIndex(&index)) {
120 : LookupIterator it =
121 153656 : LookupIterator(isolate, receiver, index, holder, configuration);
122 153656 : it.name_ = name;
123 153656 : return it;
124 : }
125 16580865 : return LookupIterator(receiver, name, holder, configuration);
126 : }
127 :
128 : static LookupIterator PropertyOrElement(
129 : Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
130 : bool* success, Configuration configuration = DEFAULT);
131 :
132 5420671 : void Restart() {
133 : InterceptorState state = InterceptorState::kUninitialized;
134 5420671 : IsElement() ? RestartInternal<true>(state) : RestartInternal<false>(state);
135 5420671 : }
136 :
137 : Isolate* isolate() const { return isolate_; }
138 16680968 : State state() const { return state_; }
139 :
140 154 : Handle<Name> name() const {
141 : DCHECK(!IsElement());
142 154 : return name_;
143 : }
144 3733092 : Handle<Name> GetName() {
145 3551189 : if (name_.is_null()) {
146 : DCHECK(IsElement());
147 363806 : name_ = factory()->Uint32ToString(index_);
148 : }
149 3551189 : return name_;
150 : }
151 : uint32_t index() const { return index_; }
152 :
153 : bool IsElement() const { return index_ != kMaxUInt32; }
154 :
155 5680562 : bool IsFound() const { return state_ != NOT_FOUND; }
156 : void Next();
157 : void NotFound() {
158 635453 : has_property_ = false;
159 635453 : state_ = NOT_FOUND;
160 : }
161 :
162 : Heap* heap() const { return isolate_->heap(); }
163 : Factory* factory() const { return isolate_->factory(); }
164 : Handle<Object> GetReceiver() const { return receiver_; }
165 :
166 59565290 : Handle<JSObject> GetStoreTarget() const {
167 : DCHECK(receiver_->IsJSObject());
168 59565280 : if (receiver_->IsJSGlobalProxy()) {
169 : Map* map = JSGlobalProxy::cast(*receiver_)->map();
170 96860 : if (map->has_hidden_prototype()) {
171 193720 : return handle(JSGlobalObject::cast(map->prototype()), isolate_);
172 : }
173 : }
174 : return Handle<JSObject>::cast(receiver_);
175 : }
176 :
177 3672885 : bool is_dictionary_holder() const { return !holder_->HasFastProperties(); }
178 : Handle<Map> transition_map() const {
179 : DCHECK_EQ(TRANSITION, state_);
180 : return Handle<Map>::cast(transition_);
181 : }
182 : Handle<PropertyCell> transition_cell() const {
183 : DCHECK_EQ(TRANSITION, state_);
184 : return Handle<PropertyCell>::cast(transition_);
185 : }
186 : template <class T>
187 202749 : Handle<T> GetHolder() const {
188 : DCHECK(IsFound());
189 202749 : return Handle<T>::cast(holder_);
190 : }
191 :
192 : bool HolderIsReceiverOrHiddenPrototype() const;
193 :
194 : bool check_prototype_chain() const {
195 406710742 : return (configuration_ & kPrototypeChain) != 0;
196 : }
197 :
198 : /* ACCESS_CHECK */
199 : bool HasAccess() const;
200 :
201 : /* PROPERTY */
202 57604978 : bool ExtendingNonExtensible(Handle<JSObject> receiver) {
203 : DCHECK(receiver.is_identical_to(GetStoreTarget()));
204 57604978 : return !receiver->map()->is_extensible() &&
205 1341 : (IsElement() || !name_->IsPrivate());
206 : }
207 : void PrepareForDataProperty(Handle<Object> value);
208 : void PrepareTransitionToDataProperty(Handle<JSObject> receiver,
209 : Handle<Object> value,
210 : PropertyAttributes attributes,
211 : Object::StoreFromKeyed store_mode);
212 1442640 : bool IsCacheableTransition() {
213 : DCHECK_EQ(TRANSITION, state_);
214 1439918 : return transition_->IsPropertyCell() ||
215 23098 : (transition_map()->is_dictionary_map() &&
216 2910606 : !GetStoreTarget()->HasFastProperties()) ||
217 2864410 : transition_map()->GetBackPointer()->IsMap();
218 : }
219 : void ApplyTransitionToDataProperty(Handle<JSObject> receiver);
220 : void ReconfigureDataProperty(Handle<Object> value,
221 : PropertyAttributes attributes);
222 : void Delete();
223 : void TransitionToAccessorProperty(Handle<Object> getter,
224 : Handle<Object> setter,
225 : PropertyAttributes attributes);
226 : void TransitionToAccessorPair(Handle<Object> pair,
227 : PropertyAttributes attributes);
228 5375903 : PropertyDetails property_details() const {
229 : DCHECK(has_property_);
230 5375903 : return property_details_;
231 : }
232 : PropertyAttributes property_attributes() const {
233 : return property_details().attributes();
234 : }
235 : bool IsConfigurable() const { return property_details().IsConfigurable(); }
236 : bool IsReadOnly() const { return property_details().IsReadOnly(); }
237 : bool IsEnumerable() const { return property_details().IsEnumerable(); }
238 : Representation representation() const {
239 : return property_details().representation();
240 : }
241 : PropertyLocation location() const { return property_details().location(); }
242 : PropertyConstness constness() const { return property_details().constness(); }
243 : Handle<Map> GetFieldOwnerMap() const;
244 : FieldIndex GetFieldIndex() const;
245 : Handle<FieldType> GetFieldType() const;
246 : int GetFieldDescriptorIndex() const;
247 : int GetAccessorIndex() const;
248 : int GetConstantIndex() const;
249 : Handle<PropertyCell> GetPropertyCell() const;
250 : Handle<Object> GetAccessors() const;
251 513290 : inline Handle<InterceptorInfo> GetInterceptor() const {
252 : DCHECK_EQ(INTERCEPTOR, state_);
253 : InterceptorInfo* result =
254 : IsElement() ? GetInterceptor<true>(JSObject::cast(*holder_))
255 513290 : : GetInterceptor<false>(JSObject::cast(*holder_));
256 1026580 : return handle(result, isolate_);
257 : }
258 : Handle<InterceptorInfo> GetInterceptorForFailedAccessCheck() const;
259 : Handle<Object> GetDataValue() const;
260 : void WriteDataValue(Handle<Object> value, bool initializing_store);
261 187373422 : inline void UpdateProtector() {
262 190518463 : if (IsElement()) return;
263 : // This list must be kept in sync with
264 : // CodeStubAssembler::HasAssociatedProtector!
265 276341297 : if (*name_ == heap()->is_concat_spreadable_symbol() ||
266 179314520 : *name_ == heap()->constructor_string() ||
267 266511835 : *name_ == heap()->species_symbol() ||
268 87196039 : *name_ == heap()->iterator_symbol()) {
269 4933311 : InternalUpdateProtector();
270 : }
271 : }
272 :
273 : // Lookup a 'cached' private property for an accessor.
274 : // If not found returns false and leaves the LookupIterator unmodified.
275 : bool TryLookupCachedProperty();
276 : bool LookupCachedProperty();
277 :
278 : private:
279 : void InternalUpdateProtector();
280 :
281 : enum class InterceptorState {
282 : kUninitialized,
283 : kSkipNonMasking,
284 : kProcessNonMasking
285 : };
286 :
287 : Handle<Map> GetReceiverMap() const;
288 :
289 : MUST_USE_RESULT inline JSReceiver* NextHolder(Map* map);
290 :
291 : template <bool is_element>
292 : V8_EXPORT_PRIVATE void Start();
293 : template <bool is_element>
294 : void NextInternal(Map* map, JSReceiver* holder);
295 : template <bool is_element>
296 806840317 : inline State LookupInHolder(Map* map, JSReceiver* holder) {
297 : return map->IsSpecialReceiverMap()
298 : ? LookupInSpecialHolder<is_element>(map, holder)
299 806840317 : : LookupInRegularHolder<is_element>(map, holder);
300 : }
301 : template <bool is_element>
302 : State LookupInRegularHolder(Map* map, JSReceiver* holder);
303 : template <bool is_element>
304 47759723 : State LookupInSpecialHolder(Map* map, JSReceiver* holder);
305 : template <bool is_element>
306 175 : void RestartLookupForNonMaskingInterceptors() {
307 175 : RestartInternal<is_element>(InterceptorState::kProcessNonMasking);
308 175 : }
309 : template <bool is_element>
310 : void RestartInternal(InterceptorState interceptor_state);
311 : Handle<Object> FetchValue() const;
312 : bool IsConstFieldValueEqualTo(Object* value) const;
313 : template <bool is_element>
314 : void ReloadPropertyInformation();
315 :
316 : template <bool is_element>
317 : bool SkipInterceptor(JSObject* holder);
318 : template <bool is_element>
319 : inline InterceptorInfo* GetInterceptor(JSObject* holder) const {
320 : return is_element ? holder->GetIndexedInterceptor()
321 1580216 : : holder->GetNamedInterceptor();
322 : }
323 :
324 : bool check_interceptor() const {
325 47759723 : return (configuration_ & kInterceptor) != 0;
326 : }
327 : int descriptor_number() const {
328 : DCHECK(!IsElement());
329 : DCHECK(has_property_);
330 : DCHECK(holder_->HasFastProperties());
331 50307034 : return number_;
332 : }
333 : int dictionary_entry() const {
334 : DCHECK(!IsElement());
335 : DCHECK(has_property_);
336 : DCHECK(!holder_->HasFastProperties());
337 38267008 : return number_;
338 : }
339 :
340 : static Configuration ComputeConfiguration(
341 : Configuration configuration, Handle<Name> name) {
342 290133413 : return name->IsPrivate() ? OWN_SKIP_INTERCEPTOR : configuration;
343 : }
344 :
345 : static Handle<JSReceiver> GetRootForNonJSReceiver(
346 : Isolate* isolate, Handle<Object> receiver, uint32_t index = kMaxUInt32);
347 222718339 : inline static Handle<JSReceiver> GetRoot(Isolate* isolate,
348 : Handle<Object> receiver,
349 : uint32_t index = kMaxUInt32) {
350 222718345 : if (receiver->IsJSReceiver()) return Handle<JSReceiver>::cast(receiver);
351 252579 : return GetRootForNonJSReceiver(isolate, receiver, index);
352 : }
353 :
354 : State NotFound(JSReceiver* const holder) const;
355 :
356 : // If configuration_ becomes mutable, update
357 : // HolderIsReceiverOrHiddenPrototype.
358 : const Configuration configuration_;
359 : State state_;
360 : bool has_property_;
361 : InterceptorState interceptor_state_;
362 : PropertyDetails property_details_;
363 : Isolate* const isolate_;
364 : Handle<Name> name_;
365 : Handle<Object> transition_;
366 : const Handle<Object> receiver_;
367 : Handle<JSReceiver> holder_;
368 : const Handle<JSReceiver> initial_holder_;
369 : const uint32_t index_;
370 : uint32_t number_;
371 : };
372 :
373 :
374 : } // namespace internal
375 : } // namespace v8
376 :
377 : #endif // V8_LOOKUP_H_
|