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 : #include "src/lookup.h"
6 :
7 : #include "src/bootstrapper.h"
8 : #include "src/counters.h"
9 : #include "src/deoptimizer.h"
10 : #include "src/elements.h"
11 : #include "src/field-type.h"
12 : #include "src/isolate-inl.h"
13 : #include "src/objects/hash-table-inl.h"
14 : #include "src/objects/heap-number-inl.h"
15 : #include "src/objects/struct-inl.h"
16 :
17 : namespace v8 {
18 : namespace internal {
19 :
20 : // static
21 4751 : LookupIterator LookupIterator::PropertyOrElement(
22 : Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
23 : bool* success, Handle<JSReceiver> holder, Configuration configuration) {
24 4751 : uint32_t index = 0;
25 9502 : if (key->ToArrayIndex(&index)) {
26 1881 : *success = true;
27 1881 : return LookupIterator(isolate, receiver, index, holder, configuration);
28 : }
29 :
30 : Handle<Name> name;
31 5740 : *success = Object::ToName(isolate, key).ToHandle(&name);
32 2870 : if (!*success) {
33 : DCHECK(isolate->has_pending_exception());
34 : // Return an unusable dummy.
35 : return LookupIterator(isolate, receiver,
36 18 : isolate->factory()->empty_string());
37 : }
38 :
39 2852 : if (name->AsArrayIndex(&index)) {
40 306 : LookupIterator it(isolate, receiver, index, holder, configuration);
41 : // Here we try to avoid having to rebuild the string later
42 : // by storing it on the indexed LookupIterator.
43 306 : it.name_ = name;
44 306 : return it;
45 : }
46 :
47 2546 : return LookupIterator(receiver, name, holder, configuration);
48 : }
49 :
50 : // static
51 39541521 : LookupIterator LookupIterator::PropertyOrElement(Isolate* isolate,
52 : Handle<Object> receiver,
53 : Handle<Object> key,
54 : bool* success,
55 : Configuration configuration) {
56 : // TODO(mslekova): come up with better way to avoid duplication
57 39541521 : uint32_t index = 0;
58 79083064 : if (key->ToArrayIndex(&index)) {
59 33219845 : *success = true;
60 33219845 : return LookupIterator(isolate, receiver, index, configuration);
61 : }
62 :
63 : Handle<Name> name;
64 12643379 : *success = Object::ToName(isolate, key).ToHandle(&name);
65 6321687 : if (!*success) {
66 : DCHECK(isolate->has_pending_exception());
67 : // Return an unusable dummy.
68 : return LookupIterator(isolate, receiver,
69 49 : isolate->factory()->empty_string());
70 : }
71 :
72 6321640 : if (name->AsArrayIndex(&index)) {
73 349636 : LookupIterator it(isolate, receiver, index, configuration);
74 : // Here we try to avoid having to rebuild the string later
75 : // by storing it on the indexed LookupIterator.
76 349636 : it.name_ = name;
77 349636 : return it;
78 : }
79 :
80 5972002 : return LookupIterator(isolate, receiver, name, configuration);
81 : }
82 :
83 : // TODO(ishell): Consider removing this way of LookupIterator creation.
84 : // static
85 0 : LookupIterator LookupIterator::ForTransitionHandler(
86 : Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
87 : Handle<Object> value, MaybeHandle<Map> maybe_transition_map) {
88 : Handle<Map> transition_map;
89 0 : if (!maybe_transition_map.ToHandle(&transition_map) ||
90 0 : !transition_map->IsPrototypeValidityCellValid()) {
91 : // This map is not a valid transition handler, so full lookup is required.
92 0 : return LookupIterator(isolate, receiver, name);
93 : }
94 :
95 0 : PropertyDetails details = PropertyDetails::Empty();
96 : bool has_property;
97 0 : if (transition_map->is_dictionary_map()) {
98 : details = PropertyDetails(kData, NONE, PropertyCellType::kNoCell);
99 : has_property = false;
100 : } else {
101 0 : details = transition_map->GetLastDescriptorDetails();
102 : has_property = true;
103 : }
104 : #ifdef DEBUG
105 : if (name->IsPrivate()) {
106 : DCHECK_EQ(DONT_ENUM, details.attributes());
107 : } else {
108 : DCHECK_EQ(NONE, details.attributes());
109 : }
110 : #endif
111 : LookupIterator it(isolate, receiver, name, transition_map, details,
112 0 : has_property);
113 :
114 0 : if (!transition_map->is_dictionary_map()) {
115 0 : int descriptor_number = transition_map->LastAdded();
116 : Handle<Map> new_map =
117 : Map::PrepareForDataProperty(isolate, transition_map, descriptor_number,
118 0 : PropertyConstness::kConst, value);
119 : // Reload information; this is no-op if nothing changed.
120 : it.property_details_ =
121 0 : new_map->instance_descriptors()->GetDetails(descriptor_number);
122 0 : it.transition_ = new_map;
123 : }
124 0 : return it;
125 : }
126 :
127 0 : LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
128 : Handle<Name> name, Handle<Map> transition_map,
129 : PropertyDetails details, bool has_property)
130 : : configuration_(DEFAULT),
131 : state_(TRANSITION),
132 : has_property_(has_property),
133 : interceptor_state_(InterceptorState::kUninitialized),
134 : property_details_(details),
135 : isolate_(isolate),
136 : name_(name),
137 : transition_(transition_map),
138 : receiver_(receiver),
139 : initial_holder_(GetRoot(isolate, receiver)),
140 : index_(kMaxUInt32),
141 0 : number_(static_cast<uint32_t>(DescriptorArray::kNotFound)) {
142 0 : holder_ = initial_holder_;
143 0 : }
144 :
145 : template <bool is_element>
146 191623953 : void LookupIterator::Start() {
147 : DisallowHeapAllocation no_gc;
148 :
149 191623953 : has_property_ = false;
150 191623953 : state_ = NOT_FOUND;
151 191623953 : holder_ = initial_holder_;
152 :
153 : JSReceiver holder = *holder_;
154 191623965 : Map map = holder->map();
155 :
156 191623965 : state_ = LookupInHolder<is_element>(map, holder);
157 232132663 : if (IsFound()) return;
158 :
159 151115333 : NextInternal<is_element>(map, holder);
160 : }
161 :
162 : template void LookupIterator::Start<true>();
163 : template void LookupIterator::Start<false>();
164 :
165 20539263 : void LookupIterator::Next() {
166 : DCHECK_NE(JSPROXY, state_);
167 : DCHECK_NE(TRANSITION, state_);
168 : DisallowHeapAllocation no_gc;
169 7095400 : has_property_ = false;
170 :
171 : JSReceiver holder = *holder_;
172 : Map map = holder->map();
173 :
174 7095400 : if (map->IsSpecialReceiverMap()) {
175 : state_ = IsElement() ? LookupInSpecialHolder<true>(map, holder)
176 6911879 : : LookupInSpecialHolder<false>(map, holder);
177 14007279 : if (IsFound()) return;
178 : }
179 :
180 112200 : IsElement() ? NextInternal<true>(map, holder)
181 12951768 : : NextInternal<false>(map, holder);
182 : }
183 :
184 : template <bool is_element>
185 157647301 : void LookupIterator::NextInternal(Map map, JSReceiver holder) {
186 187483867 : do {
187 332915327 : JSReceiver maybe_holder = NextHolder(map);
188 332915347 : if (maybe_holder.is_null()) {
189 145431483 : if (interceptor_state_ == InterceptorState::kSkipNonMasking) {
190 0 : RestartLookupForNonMaskingInterceptors<is_element>();
191 60608718 : return;
192 : }
193 145431327 : state_ = NOT_FOUND;
194 235968689 : if (holder != *holder_) holder_ = handle(holder, isolate_);
195 : return;
196 : }
197 : holder = maybe_holder;
198 187483864 : map = holder->map();
199 187483864 : state_ = LookupInHolder<is_element>(map, holder);
200 : } while (!IsFound());
201 :
202 24431679 : holder_ = handle(holder, isolate_);
203 : }
204 :
205 : template <bool is_element>
206 1478655 : void LookupIterator::RestartInternal(InterceptorState interceptor_state) {
207 1478655 : interceptor_state_ = interceptor_state;
208 1478655 : property_details_ = PropertyDetails::Empty();
209 1478655 : number_ = static_cast<uint32_t>(DescriptorArray::kNotFound);
210 1478655 : Start<is_element>();
211 1478680 : }
212 :
213 : template void LookupIterator::RestartInternal<true>(InterceptorState);
214 : template void LookupIterator::RestartInternal<false>(InterceptorState);
215 :
216 : // static
217 369733 : Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
218 : Isolate* isolate, Handle<Object> receiver, uint32_t index) {
219 : // Strings are the only objects with properties (only elements) directly on
220 : // the wrapper. Hence we can skip generating the wrapper for all other cases.
221 400410 : if (index != kMaxUInt32 && receiver->IsString() &&
222 3387 : index < static_cast<uint32_t>(String::cast(*receiver)->length())) {
223 : // TODO(verwaest): Speed this up. Perhaps use a cached wrapper on the native
224 : // context, ensuring that we don't leak it into JS?
225 1301 : Handle<JSFunction> constructor = isolate->string_function();
226 1301 : Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
227 2602 : Handle<JSValue>::cast(result)->set_value(*receiver);
228 1301 : return result;
229 : }
230 : auto root =
231 736866 : handle(receiver->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
232 736868 : if (root->IsNull(isolate)) {
233 0 : isolate->PushStackTraceAndDie(reinterpret_cast<void*>(receiver->ptr()));
234 : }
235 368434 : return Handle<JSReceiver>::cast(root);
236 : }
237 :
238 :
239 0 : Handle<Map> LookupIterator::GetReceiverMap() const {
240 0 : if (receiver_->IsNumber()) return factory()->heap_number_map();
241 0 : return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_);
242 : }
243 :
244 6003821 : bool LookupIterator::HasAccess() const {
245 : DCHECK_EQ(ACCESS_CHECK, state_);
246 : return isolate_->MayAccess(handle(isolate_->context(), isolate_),
247 12007642 : GetHolder<JSObject>());
248 : }
249 :
250 : template <bool is_element>
251 12010781 : void LookupIterator::ReloadPropertyInformation() {
252 12010781 : state_ = BEFORE_PROPERTY;
253 12010781 : interceptor_state_ = InterceptorState::kUninitialized;
254 12010780 : state_ = LookupInHolder<is_element>(holder_->map(), *holder_);
255 : DCHECK(IsFound() || !holder_->HasFastProperties());
256 12010782 : }
257 :
258 : namespace {
259 :
260 3252 : bool IsTypedArrayFunctionInAnyContext(Isolate* isolate, JSReceiver holder) {
261 : static uint32_t context_slots[] = {
262 : #define TYPED_ARRAY_CONTEXT_SLOTS(Type, type, TYPE, ctype) \
263 : Context::TYPE##_ARRAY_FUN_INDEX,
264 :
265 : TYPED_ARRAYS(TYPED_ARRAY_CONTEXT_SLOTS)
266 : #undef TYPED_ARRAY_CONTEXT_SLOTS
267 : };
268 :
269 3252 : if (!holder->IsJSFunction()) return false;
270 :
271 : return std::any_of(
272 : std::begin(context_slots), std::end(context_slots),
273 1348 : [=](uint32_t slot) { return isolate->IsInAnyContext(holder, slot); });
274 : }
275 :
276 : } // namespace
277 :
278 4319574 : void LookupIterator::InternalUpdateProtector() {
279 4319574 : if (isolate_->bootstrapper()->IsActive()) return;
280 :
281 134735 : ReadOnlyRoots roots(heap());
282 134735 : if (*name_ == roots.constructor_string()) {
283 251371 : if (!isolate_->IsArraySpeciesLookupChainIntact() &&
284 16365 : !isolate_->IsPromiseSpeciesLookupChainIntact() &&
285 130173 : !isolate_->IsRegExpSpeciesLookupChainIntact() &&
286 5068 : !isolate_->IsTypedArraySpeciesLookupChainIntact()) {
287 : return;
288 : }
289 : // Setting the constructor property could change an instance's @@species
290 229938 : if (holder_->IsJSArray()) {
291 282 : if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
292 : isolate_->CountUsage(
293 95 : v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified);
294 95 : isolate_->InvalidateArraySpeciesProtector();
295 95 : return;
296 229374 : } else if (holder_->IsJSPromise()) {
297 5 : if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
298 5 : isolate_->InvalidatePromiseSpeciesProtector();
299 5 : return;
300 229364 : } else if (holder_->IsJSRegExp()) {
301 0 : if (!isolate_->IsRegExpSpeciesLookupChainIntact()) return;
302 0 : isolate_->InvalidateRegExpSpeciesProtector();
303 0 : return;
304 229364 : } else if (holder_->IsJSTypedArray()) {
305 55 : if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
306 55 : isolate_->InvalidateTypedArraySpeciesProtector();
307 55 : return;
308 : }
309 114627 : if (holder_->map()->is_prototype_map()) {
310 : DisallowHeapAllocation no_gc;
311 : // Setting the constructor of any prototype with the @@species protector
312 : // (of any realm) also needs to invalidate the protector.
313 : // For typed arrays, we check a prototype of this holder since TypedArrays
314 : // have different prototypes for each type, and their parent prototype is
315 : // pointing the same TYPED_ARRAY_PROTOTYPE.
316 18600 : if (isolate_->IsInAnyContext(*holder_,
317 18600 : Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) {
318 0 : if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
319 : isolate_->CountUsage(
320 0 : v8::Isolate::UseCounterFeature::kArrayPrototypeConstructorModified);
321 0 : isolate_->InvalidateArraySpeciesProtector();
322 18600 : } else if (isolate_->IsInAnyContext(*holder_,
323 18600 : Context::PROMISE_PROTOTYPE_INDEX)) {
324 81 : if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
325 25 : isolate_->InvalidatePromiseSpeciesProtector();
326 18438 : } else if (isolate_->IsInAnyContext(*holder_,
327 18438 : Context::REGEXP_PROTOTYPE_INDEX)) {
328 55 : if (!isolate_->IsRegExpSpeciesLookupChainIntact()) return;
329 15 : isolate_->InvalidateRegExpSpeciesProtector();
330 9164 : } else if (isolate_->IsInAnyContext(
331 : holder_->map()->prototype(),
332 9164 : Context::TYPED_ARRAY_PROTOTYPE_INDEX)) {
333 623 : if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
334 135 : isolate_->InvalidateTypedArraySpeciesProtector();
335 : }
336 : }
337 14698 : } else if (*name_ == roots.next_string()) {
338 7582 : if (isolate_->IsInAnyContext(
339 7582 : *holder_, Context::INITIAL_ARRAY_ITERATOR_PROTOTYPE_INDEX)) {
340 : // Setting the next property of %ArrayIteratorPrototype% also needs to
341 : // invalidate the array iterator protector.
342 505 : if (!isolate_->IsArrayIteratorLookupChainIntact()) return;
343 25 : isolate_->InvalidateArrayIteratorProtector();
344 6572 : } else if (isolate_->IsInAnyContext(
345 6572 : *holder_, Context::INITIAL_MAP_ITERATOR_PROTOTYPE_INDEX)) {
346 30 : if (!isolate_->IsMapIteratorLookupChainIntact()) return;
347 25 : isolate_->InvalidateMapIteratorProtector();
348 6512 : } else if (isolate_->IsInAnyContext(
349 6512 : *holder_, Context::INITIAL_SET_ITERATOR_PROTOTYPE_INDEX)) {
350 30 : if (!isolate_->IsSetIteratorLookupChainIntact()) return;
351 25 : isolate_->InvalidateSetIteratorProtector();
352 3226 : } else if (isolate_->IsInAnyContext(
353 : *receiver_,
354 3226 : Context::INITIAL_STRING_ITERATOR_PROTOTYPE_INDEX)) {
355 : // Setting the next property of %StringIteratorPrototype% invalidates the
356 : // string iterator protector.
357 5 : if (!isolate_->IsStringIteratorLookupChainIntact()) return;
358 5 : isolate_->InvalidateStringIteratorProtector();
359 : }
360 10907 : } else if (*name_ == roots.species_symbol()) {
361 6841 : if (!isolate_->IsArraySpeciesLookupChainIntact() &&
362 121 : !isolate_->IsPromiseSpeciesLookupChainIntact() &&
363 3360 : !isolate_->IsRegExpSpeciesLookupChainIntact() &&
364 0 : !isolate_->IsTypedArraySpeciesLookupChainIntact()) {
365 : return;
366 : }
367 : // Setting the Symbol.species property of any Array, Promise or TypedArray
368 : // constructor invalidates the @@species protector
369 3360 : if (isolate_->IsInAnyContext(*holder_, Context::ARRAY_FUNCTION_INDEX)) {
370 45 : if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
371 : isolate_->CountUsage(
372 25 : v8::Isolate::UseCounterFeature::kArraySpeciesModified);
373 25 : isolate_->InvalidateArraySpeciesProtector();
374 6630 : } else if (isolate_->IsInAnyContext(*holder_,
375 6630 : Context::PROMISE_FUNCTION_INDEX)) {
376 45 : if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
377 25 : isolate_->InvalidatePromiseSpeciesProtector();
378 6540 : } else if (isolate_->IsInAnyContext(*holder_,
379 6540 : Context::REGEXP_FUNCTION_INDEX)) {
380 18 : if (!isolate_->IsRegExpSpeciesLookupChainIntact()) return;
381 10 : isolate_->InvalidateRegExpSpeciesProtector();
382 3252 : } else if (IsTypedArrayFunctionInAnyContext(isolate_, *holder_)) {
383 110 : if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
384 55 : isolate_->InvalidateTypedArraySpeciesProtector();
385 : }
386 7547 : } else if (*name_ == roots.is_concat_spreadable_symbol()) {
387 864 : if (!isolate_->IsIsConcatSpreadableLookupChainIntact()) return;
388 65 : isolate_->InvalidateIsConcatSpreadableProtector();
389 6683 : } else if (*name_ == roots.iterator_symbol()) {
390 6496 : if (holder_->IsJSArray()) {
391 783 : if (!isolate_->IsArrayIteratorLookupChainIntact()) return;
392 80 : isolate_->InvalidateArrayIteratorProtector();
393 4930 : } else if (isolate_->IsInAnyContext(
394 4930 : *holder_, Context::INITIAL_ITERATOR_PROTOTYPE_INDEX)) {
395 50 : if (isolate_->IsMapIteratorLookupChainIntact()) {
396 30 : isolate_->InvalidateMapIteratorProtector();
397 : }
398 50 : if (isolate_->IsSetIteratorLookupChainIntact()) {
399 30 : isolate_->InvalidateSetIteratorProtector();
400 : }
401 4830 : } else if (isolate_->IsInAnyContext(*holder_,
402 4830 : Context::INITIAL_SET_PROTOTYPE_INDEX)) {
403 15 : if (!isolate_->IsSetIteratorLookupChainIntact()) return;
404 10 : isolate_->InvalidateSetIteratorProtector();
405 2400 : } else if (isolate_->IsInAnyContext(
406 2400 : *receiver_, Context::INITIAL_STRING_PROTOTYPE_INDEX)) {
407 : // Setting the Symbol.iterator property of String.prototype invalidates
408 : // the string iterator protector. Symbol.iterator can also be set on a
409 : // String wrapper, but not on a primitive string. We only support
410 : // protector for primitive strings.
411 24 : if (!isolate_->IsStringIteratorLookupChainIntact()) return;
412 20 : isolate_->InvalidateStringIteratorProtector();
413 : }
414 3435 : } else if (*name_ == roots.resolve_string()) {
415 1747 : if (!isolate_->IsPromiseResolveLookupChainIntact()) return;
416 : // Setting the "resolve" property on any %Promise% intrinsic object
417 : // invalidates the Promise.resolve protector.
418 1747 : if (isolate_->IsInAnyContext(*holder_, Context::PROMISE_FUNCTION_INDEX)) {
419 0 : isolate_->InvalidatePromiseResolveProtector();
420 : }
421 1688 : } else if (*name_ == roots.then_string()) {
422 1688 : if (!isolate_->IsPromiseThenLookupChainIntact()) return;
423 : // Setting the "then" property on any JSPromise instance or on the
424 : // initial %PromisePrototype% invalidates the Promise#then protector.
425 : // Also setting the "then" property on the initial %ObjectPrototype%
426 : // invalidates the Promise#then protector, since we use this protector
427 : // to guard the fast-path in AsyncGeneratorResolve, where we can skip
428 : // the ResolvePromise step and go directly to FulfillPromise if we
429 : // know that the Object.prototype doesn't contain a "then" method.
430 3386 : if (holder_->IsJSPromise() ||
431 : isolate_->IsInAnyContext(*holder_,
432 4463 : Context::INITIAL_OBJECT_PROTOTYPE_INDEX) ||
433 2209 : isolate_->IsInAnyContext(*holder_, Context::PROMISE_PROTOTYPE_INDEX)) {
434 105 : isolate_->InvalidatePromiseThenProtector();
435 : }
436 : }
437 : }
438 :
439 33927705 : void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
440 : DCHECK(state_ == DATA || state_ == ACCESSOR);
441 : DCHECK(HolderIsReceiverOrHiddenPrototype());
442 :
443 : Handle<JSReceiver> holder = GetHolder<JSReceiver>();
444 : // JSProxy does not have fast properties so we do an early return.
445 : DCHECK_IMPLIES(holder->IsJSProxy(), !holder->HasFastProperties());
446 : DCHECK_IMPLIES(holder->IsJSProxy(), name()->IsPrivate());
447 20006800 : if (holder->IsJSProxy()) return;
448 :
449 6672517 : Handle<JSObject> holder_obj = Handle<JSObject>::cast(holder);
450 :
451 6672516 : if (IsElement()) {
452 908265 : ElementsKind kind = holder_obj->GetElementsKind();
453 908265 : ElementsKind to = value->OptimalElementsKind();
454 908266 : if (IsHoleyElementsKind(kind)) to = GetHoleyElementsKind(to);
455 : to = GetMoreGeneralElementsKind(kind, to);
456 :
457 908266 : if (kind != to) {
458 18624 : JSObject::TransitionElementsKind(holder_obj, to);
459 : }
460 :
461 : // Copy the backing store if it is copy-on-write.
462 908264 : if (IsSmiOrObjectElementsKind(to)) {
463 176386 : JSObject::EnsureWritableFastElements(holder_obj);
464 : }
465 : return;
466 : }
467 :
468 11528500 : if (holder_obj->IsJSGlobalObject()) {
469 : Handle<GlobalDictionary> dictionary(
470 8997906 : JSGlobalObject::cast(*holder_obj)->global_dictionary(), isolate());
471 : Handle<PropertyCell> cell(dictionary->CellAt(dictionary_entry()),
472 8997906 : isolate());
473 4498953 : property_details_ = cell->property_details();
474 : PropertyCell::PrepareForValue(isolate(), dictionary, dictionary_entry(),
475 4498953 : value, property_details_);
476 : return;
477 : }
478 1265296 : if (!holder_obj->HasFastProperties()) return;
479 :
480 : PropertyConstness new_constness = PropertyConstness::kConst;
481 : if (FLAG_track_constant_fields) {
482 : if (constness() == PropertyConstness::kConst) {
483 : DCHECK_EQ(kData, property_details_.kind());
484 : // Check that current value matches new value otherwise we should make
485 : // the property mutable.
486 : if (!IsConstFieldValueEqualTo(*value))
487 : new_constness = PropertyConstness::kMutable;
488 : }
489 : } else {
490 : new_constness = PropertyConstness::kMutable;
491 : }
492 :
493 1202365 : Handle<Map> old_map(holder_obj->map(), isolate_);
494 : Handle<Map> new_map = Map::PrepareForDataProperty(
495 1202370 : isolate(), old_map, descriptor_number(), new_constness, value);
496 :
497 1202368 : if (old_map.is_identical_to(new_map)) {
498 : // Update the property details if the representation was None.
499 2381887 : if (constness() != new_constness || representation().IsNone()) {
500 : property_details_ =
501 182105 : new_map->instance_descriptors()->GetDetails(descriptor_number());
502 : }
503 : return;
504 : }
505 :
506 10830 : JSObject::MigrateToMap(holder_obj, new_map);
507 10830 : ReloadPropertyInformation<false>();
508 : }
509 :
510 :
511 37333 : void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
512 147937 : PropertyAttributes attributes) {
513 : DCHECK(state_ == DATA || state_ == ACCESSOR);
514 : DCHECK(HolderIsReceiverOrHiddenPrototype());
515 :
516 : Handle<JSReceiver> holder = GetHolder<JSReceiver>();
517 :
518 : // Property details can never change for private properties.
519 74666 : if (holder->IsJSProxy()) {
520 : DCHECK(name()->IsPrivate());
521 37333 : return;
522 : }
523 :
524 37333 : Handle<JSObject> holder_obj = Handle<JSObject>::cast(holder);
525 37333 : if (IsElement()) {
526 : DCHECK(!holder_obj->HasFixedTypedArrayElements());
527 : DCHECK(attributes != NONE || !holder_obj->HasFastElements());
528 38728 : Handle<FixedArrayBase> elements(holder_obj->elements(), isolate());
529 38728 : holder_obj->GetElementsAccessor()->Reconfigure(holder_obj, elements,
530 19364 : number_, value, attributes);
531 19364 : ReloadPropertyInformation<true>();
532 17969 : } else if (holder_obj->HasFastProperties()) {
533 16395 : Handle<Map> old_map(holder_obj->map(), isolate_);
534 : Handle<Map> new_map = Map::ReconfigureExistingProperty(
535 16395 : isolate_, old_map, descriptor_number(), i::kData, attributes);
536 : // Force mutable to avoid changing constant value by reconfiguring
537 : // kData -> kAccessor -> kData.
538 : new_map =
539 : Map::PrepareForDataProperty(isolate(), new_map, descriptor_number(),
540 16395 : PropertyConstness::kMutable, value);
541 16395 : JSObject::MigrateToMap(holder_obj, new_map);
542 16395 : ReloadPropertyInformation<false>();
543 : }
544 :
545 55302 : if (!IsElement() && !holder_obj->HasFastProperties()) {
546 : PropertyDetails details(kData, attributes, PropertyCellType::kMutable);
547 2039 : if (holder_obj->map()->is_prototype_map() &&
548 2495 : (property_details_.attributes() & READ_ONLY) == 0 &&
549 456 : (attributes & READ_ONLY) != 0) {
550 : // Invalidate prototype validity cell when a property is reconfigured
551 : // from writable to read-only as this may invalidate transitioning store
552 : // IC handlers.
553 87 : JSObject::InvalidatePrototypeChains(holder->map());
554 : }
555 3148 : if (holder_obj->IsJSGlobalObject()) {
556 : Handle<GlobalDictionary> dictionary(
557 860 : JSGlobalObject::cast(*holder_obj)->global_dictionary(), isolate());
558 :
559 : Handle<PropertyCell> cell = PropertyCell::PrepareForValue(
560 430 : isolate(), dictionary, dictionary_entry(), value, details);
561 430 : cell->set_value(*value);
562 430 : property_details_ = cell->property_details();
563 : } else {
564 2288 : Handle<NameDictionary> dictionary(holder_obj->property_dictionary(),
565 1144 : isolate());
566 : PropertyDetails original_details =
567 1144 : dictionary->DetailsAt(dictionary_entry());
568 : int enumeration_index = original_details.dictionary_index();
569 : DCHECK_GT(enumeration_index, 0);
570 : details = details.set_index(enumeration_index);
571 2288 : dictionary->SetEntry(isolate(), dictionary_entry(), *name(), *value,
572 3432 : details);
573 1144 : property_details_ = details;
574 : }
575 1574 : state_ = DATA;
576 : }
577 :
578 37333 : WriteDataValue(value, true);
579 :
580 : #if VERIFY_HEAP
581 : if (FLAG_verify_heap) {
582 : holder->HeapObjectVerify(isolate());
583 : }
584 : #endif
585 : }
586 :
587 : // Can only be called when the receiver is a JSObject. JSProxy has to be handled
588 : // via a trap. Adding properties to primitive values is not observable.
589 34138864 : void LookupIterator::PrepareTransitionToDataProperty(
590 : Handle<JSReceiver> receiver, Handle<Object> value,
591 41901865 : PropertyAttributes attributes, StoreOrigin store_origin) {
592 : DCHECK_IMPLIES(receiver->IsJSProxy(), name()->IsPrivate());
593 : DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>()));
594 34138864 : if (state_ == TRANSITION) return;
595 :
596 67327514 : if (!IsElement() && name()->IsPrivate()) {
597 2541156 : attributes = static_cast<PropertyAttributes>(attributes | DONT_ENUM);
598 : }
599 :
600 : DCHECK(state_ != LookupIterator::ACCESSOR ||
601 : (GetAccessors()->IsAccessorInfo() &&
602 : AccessorInfo::cast(*GetAccessors())->is_special_data_property()));
603 : DCHECK_NE(INTEGER_INDEXED_EXOTIC, state_);
604 : DCHECK(state_ == NOT_FOUND || !HolderIsReceiverOrHiddenPrototype());
605 :
606 33663752 : Handle<Map> map(receiver->map(), isolate_);
607 :
608 : // Dictionary maps can always have additional data properties.
609 33663755 : if (map->is_dictionary_map()) {
610 11294971 : state_ = TRANSITION;
611 11294970 : if (map->IsJSGlobalObjectMap()) {
612 : // Install a property cell.
613 8238110 : Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(receiver);
614 : int entry;
615 : Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
616 8238111 : global, name(), PropertyCellType::kUninitialized, &entry);
617 : Handle<GlobalDictionary> dictionary(global->global_dictionary(),
618 24714342 : isolate_);
619 : DCHECK(cell->value()->IsTheHole(isolate_));
620 : DCHECK(!value->IsTheHole(isolate_));
621 8238115 : transition_ = cell;
622 : // Assign an enumeration index to the property and update
623 : // SetNextEnumerationIndex.
624 8238114 : int index = dictionary->NextEnumerationIndex();
625 8238114 : dictionary->SetNextEnumerationIndex(index + 1);
626 : property_details_ = PropertyDetails(
627 8238113 : kData, attributes, PropertyCellType::kUninitialized, index);
628 : PropertyCellType new_type =
629 8238113 : PropertyCell::UpdatedType(isolate(), cell, value, property_details_);
630 8238117 : property_details_ = property_details_.set_cell_type(new_type);
631 16476235 : cell->set_property_details(property_details_);
632 8238118 : number_ = entry;
633 8238118 : has_property_ = true;
634 : } else {
635 : // Don't set enumeration index (it will be set during value store).
636 : property_details_ =
637 3056860 : PropertyDetails(kData, attributes, PropertyCellType::kNoCell);
638 3056860 : transition_ = map;
639 : }
640 : return;
641 : }
642 :
643 : Handle<Map> transition =
644 : Map::TransitionToDataProperty(isolate_, map, name_, value, attributes,
645 22368812 : kDefaultFieldConstness, store_origin);
646 22368777 : state_ = TRANSITION;
647 22368777 : transition_ = transition;
648 :
649 22368790 : if (transition->is_dictionary_map()) {
650 : // Don't set enumeration index (it will be set during value store).
651 : property_details_ =
652 25615 : PropertyDetails(kData, attributes, PropertyCellType::kNoCell);
653 : } else {
654 22343179 : property_details_ = transition->GetLastDescriptorDetails();
655 22343185 : has_property_ = true;
656 : }
657 : }
658 :
659 33663194 : void LookupIterator::ApplyTransitionToDataProperty(
660 563355 : Handle<JSReceiver> receiver) {
661 : DCHECK_EQ(TRANSITION, state_);
662 :
663 : DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>()));
664 33663194 : holder_ = receiver;
665 67326428 : if (receiver->IsJSGlobalObject()) {
666 8237567 : JSObject::InvalidatePrototypeChains(receiver->map());
667 8237563 : state_ = DATA;
668 33663236 : return;
669 : }
670 : Handle<Map> transition = transition_map();
671 50851324 : bool simple_transition = transition->GetBackPointer() == receiver->map();
672 :
673 53175044 : if (configuration_ == DEFAULT && !transition->is_dictionary_map() &&
674 26361574 : !transition->IsPrototypeValidityCellValid()) {
675 : // Only LookupIterator instances with DEFAULT (full prototype chain)
676 : // configuration can produce valid transition handler maps.
677 : Handle<Object> validity_cell =
678 563355 : Map::GetOrCreatePrototypeChainValidityCell(transition, isolate());
679 563361 : transition->set_prototype_validity_cell(*validity_cell);
680 : }
681 :
682 50851329 : if (!receiver->IsJSProxy()) {
683 25425620 : JSObject::MigrateToMap(Handle<JSObject>::cast(receiver), transition);
684 : }
685 :
686 25425658 : if (simple_transition) {
687 11461099 : int number = transition->LastAdded();
688 11461101 : number_ = static_cast<uint32_t>(number);
689 11461106 : property_details_ = transition->GetLastDescriptorDetails();
690 11461114 : state_ = DATA;
691 13964562 : } else if (receiver->map()->is_dictionary_map()) {
692 : Handle<NameDictionary> dictionary(receiver->property_dictionary(),
693 9247425 : isolate_);
694 : int entry;
695 3645037 : if (receiver->map()->is_prototype_map() && receiver->IsJSObject()) {
696 281281 : JSObject::InvalidatePrototypeChains(receiver->map());
697 : }
698 : dictionary = NameDictionary::Add(isolate(), dictionary, name(),
699 : isolate_->factory()->uninitialized_value(),
700 6164950 : property_details_, &entry);
701 6164950 : receiver->SetProperties(*dictionary);
702 : // Reload details containing proper enumeration index value.
703 6164950 : property_details_ = dictionary->DetailsAt(entry);
704 3082475 : number_ = entry;
705 3082475 : has_property_ = true;
706 3082475 : state_ = DATA;
707 :
708 : } else {
709 10882085 : ReloadPropertyInformation<false>();
710 : }
711 : }
712 :
713 :
714 315372 : void LookupIterator::Delete() {
715 157686 : Handle<JSReceiver> holder = Handle<JSReceiver>::cast(holder_);
716 157686 : if (IsElement()) {
717 103411 : Handle<JSObject> object = Handle<JSObject>::cast(holder);
718 103411 : ElementsAccessor* accessor = object->GetElementsAccessor();
719 103411 : accessor->Delete(object, number_);
720 : } else {
721 : DCHECK(!name()->IsPrivateName());
722 : bool is_prototype_map = holder->map()->is_prototype_map();
723 : RuntimeCallTimerScope stats_scope(
724 : isolate_, is_prototype_map
725 : ? RuntimeCallCounterId::kPrototypeObject_DeleteProperty
726 54275 : : RuntimeCallCounterId::kObject_DeleteProperty);
727 :
728 : PropertyNormalizationMode mode =
729 54275 : is_prototype_map ? KEEP_INOBJECT_PROPERTIES : CLEAR_INOBJECT_PROPERTIES;
730 :
731 54275 : if (holder->HasFastProperties()) {
732 : JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0,
733 40555 : "DeletingProperty");
734 40555 : ReloadPropertyInformation<false>();
735 : }
736 54275 : JSReceiver::DeleteNormalizedProperty(holder, number_);
737 108550 : if (holder->IsJSObject()) {
738 54269 : JSObject::ReoptimizeIfPrototype(Handle<JSObject>::cast(holder));
739 : }
740 : }
741 157686 : state_ = NOT_FOUND;
742 157686 : }
743 :
744 768782 : void LookupIterator::TransitionToAccessorProperty(
745 : Handle<Object> getter, Handle<Object> setter,
746 2809104 : PropertyAttributes attributes) {
747 : DCHECK(!getter->IsNull(isolate_) || !setter->IsNull(isolate_));
748 : // Can only be called when the receiver is a JSObject. JSProxy has to be
749 : // handled via a trap. Adding properties to primitive values is not
750 : // observable.
751 768782 : Handle<JSObject> receiver = GetStoreTarget<JSObject>();
752 1510004 : if (!IsElement() && name()->IsPrivate()) {
753 5 : attributes = static_cast<PropertyAttributes>(attributes | DONT_ENUM);
754 : }
755 :
756 1510003 : if (!IsElement() && !receiver->map()->is_dictionary_map()) {
757 727725 : Handle<Map> old_map(receiver->map(), isolate_);
758 :
759 727726 : if (!holder_.is_identical_to(receiver)) {
760 0 : holder_ = receiver;
761 0 : state_ = NOT_FOUND;
762 727726 : } else if (state_ == INTERCEPTOR) {
763 37 : LookupInRegularHolder<false>(*old_map, *holder_);
764 : }
765 : int descriptor =
766 727725 : IsFound() ? static_cast<int>(number_) : DescriptorArray::kNotFound;
767 :
768 : Handle<Map> new_map = Map::TransitionToAccessorProperty(
769 727725 : isolate_, old_map, name_, descriptor, getter, setter, attributes);
770 1455454 : bool simple_transition = new_map->GetBackPointer() == receiver->map();
771 727727 : JSObject::MigrateToMap(receiver, new_map);
772 :
773 727727 : if (simple_transition) {
774 19568 : int number = new_map->LastAdded();
775 19568 : number_ = static_cast<uint32_t>(number);
776 19568 : property_details_ = new_map->GetLastDescriptorDetails();
777 19568 : state_ = ACCESSOR;
778 19568 : return;
779 : }
780 :
781 708159 : ReloadPropertyInformation<false>();
782 708159 : if (!new_map->is_dictionary_map()) return;
783 : }
784 :
785 : Handle<AccessorPair> pair;
786 294016 : if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) {
787 10899 : pair = Handle<AccessorPair>::cast(GetAccessors());
788 : // If the component and attributes are identical, nothing has to be done.
789 10899 : if (pair->Equals(*getter, *setter)) {
790 27 : if (property_details().attributes() == attributes) {
791 0 : if (!IsElement()) JSObject::ReoptimizeIfPrototype(receiver);
792 : return;
793 : }
794 : } else {
795 10872 : pair = AccessorPair::Copy(isolate(), pair);
796 10872 : pair->SetComponents(*getter, *setter);
797 : }
798 : } else {
799 261021 : pair = factory()->NewAccessorPair();
800 261021 : pair->SetComponents(*getter, *setter);
801 : }
802 :
803 271920 : TransitionToAccessorPair(pair, attributes);
804 :
805 : #if VERIFY_HEAP
806 : if (FLAG_verify_heap) {
807 : receiver->JSObjectVerify(isolate());
808 : }
809 : #endif
810 : }
811 :
812 :
813 333396 : void LookupIterator::TransitionToAccessorPair(Handle<Object> pair,
814 333468 : PropertyAttributes attributes) {
815 333396 : Handle<JSObject> receiver = GetStoreTarget<JSObject>();
816 333396 : holder_ = receiver;
817 :
818 : PropertyDetails details(kAccessor, attributes, PropertyCellType::kMutable);
819 :
820 333396 : if (IsElement()) {
821 : // TODO(verwaest): Move code into the element accessor.
822 27574 : isolate_->CountUsage(v8::Isolate::kIndexAccessor);
823 27574 : Handle<NumberDictionary> dictionary = JSObject::NormalizeElements(receiver);
824 :
825 : dictionary = NumberDictionary::Set(isolate_, dictionary, index_, pair,
826 27574 : receiver, details);
827 27574 : receiver->RequireSlowElements(*dictionary);
828 :
829 55148 : if (receiver->HasSlowArgumentsElements()) {
830 198 : FixedArray parameter_map = FixedArray::cast(receiver->elements());
831 99 : uint32_t length = parameter_map->length() - 2;
832 99 : if (number_ < length) {
833 144 : parameter_map->set(number_ + 2, ReadOnlyRoots(heap()).the_hole_value());
834 : }
835 297 : FixedArray::cast(receiver->elements())->set(1, *dictionary);
836 : } else {
837 54950 : receiver->set_elements(*dictionary);
838 : }
839 :
840 27574 : ReloadPropertyInformation<true>();
841 : } else {
842 : PropertyNormalizationMode mode = CLEAR_INOBJECT_PROPERTIES;
843 305822 : if (receiver->map()->is_prototype_map()) {
844 13207 : JSObject::InvalidatePrototypeChains(receiver->map());
845 : mode = KEEP_INOBJECT_PROPERTIES;
846 : }
847 :
848 : // Normalize object to make this operation simple.
849 : JSObject::NormalizeProperties(receiver, mode, 0,
850 305822 : "TransitionToAccessorPair");
851 :
852 305822 : JSObject::SetNormalizedProperty(receiver, name_, pair, details);
853 305822 : JSObject::ReoptimizeIfPrototype(receiver);
854 :
855 305822 : ReloadPropertyInformation<false>();
856 : }
857 333396 : }
858 :
859 339 : bool LookupIterator::HolderIsReceiver() const {
860 : DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
861 : // Optimization that only works if configuration_ is not mutable.
862 339 : if (!check_prototype_chain()) return true;
863 : return *receiver_ == *holder_;
864 : }
865 :
866 4994932 : bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
867 : DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
868 : // Optimization that only works if configuration_ is not mutable.
869 4987426 : if (!check_prototype_chain()) return true;
870 : DisallowHeapAllocation no_gc;
871 4972982 : if (*receiver_ == *holder_) return true;
872 402976 : if (!receiver_->IsJSReceiver()) return false;
873 : JSReceiver current = JSReceiver::cast(*receiver_);
874 199473 : JSReceiver object = *holder_;
875 199473 : if (!current->map()->has_hidden_prototype()) return false;
876 : // JSProxy do not occur as hidden prototypes.
877 7506 : if (object->IsJSProxy()) return false;
878 : PrototypeIterator iter(isolate(), current, kStartAtPrototype,
879 : PrototypeIterator::END_AT_NON_HIDDEN);
880 8008 : while (!iter.IsAtEnd()) {
881 15012 : if (iter.GetCurrent<JSReceiver>() == object) return true;
882 502 : iter.Advance();
883 : }
884 : return false;
885 : }
886 :
887 :
888 29544790 : Handle<Object> LookupIterator::FetchValue() const {
889 : Object result;
890 29544790 : if (IsElement()) {
891 : Handle<JSObject> holder = GetHolder<JSObject>();
892 5965633 : ElementsAccessor* accessor = holder->GetElementsAccessor();
893 5965633 : return accessor->Get(holder, number_);
894 47158334 : } else if (holder_->IsJSGlobalObject()) {
895 : Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>();
896 21201306 : result = holder->global_dictionary()->ValueAt(number_);
897 16512078 : } else if (!holder_->HasFastProperties()) {
898 1814434 : result = holder_->property_dictionary()->ValueAt(number_);
899 15604859 : } else if (property_details_.location() == kField) {
900 : DCHECK_EQ(kData, property_details_.kind());
901 : Handle<JSObject> holder = GetHolder<JSObject>();
902 10917282 : FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_);
903 : return JSObject::FastPropertyAt(holder, property_details_.representation(),
904 5458643 : field_index);
905 : } else {
906 20292432 : result = holder_->map()->instance_descriptors()->GetStrongValue(number_);
907 : }
908 18120533 : return handle(result, isolate_);
909 : }
910 :
911 0 : bool LookupIterator::IsConstFieldValueEqualTo(Object value) const {
912 : DCHECK(!IsElement());
913 : DCHECK(holder_->HasFastProperties());
914 : DCHECK_EQ(kField, property_details_.location());
915 : DCHECK_EQ(PropertyConstness::kConst, property_details_.constness());
916 : Handle<JSObject> holder = GetHolder<JSObject>();
917 0 : FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_);
918 0 : if (property_details_.representation().IsDouble()) {
919 0 : if (!value->IsNumber()) return false;
920 : uint64_t bits;
921 0 : if (holder->IsUnboxedDoubleField(field_index)) {
922 : bits = holder->RawFastDoublePropertyAsBitsAt(field_index);
923 : } else {
924 0 : Object current_value = holder->RawFastPropertyAt(field_index);
925 : DCHECK(current_value->IsMutableHeapNumber());
926 : bits = MutableHeapNumber::cast(current_value)->value_as_bits();
927 : }
928 : // Use bit representation of double to to check for hole double, since
929 : // manipulating the signaling NaN used for the hole in C++, e.g. with
930 : // bit_cast or value(), will change its value on ia32 (the x87 stack is
931 : // used to return values and stores to the stack silently clear the
932 : // signalling bit).
933 0 : if (bits == kHoleNanInt64) {
934 : // Uninitialized double field.
935 : return true;
936 : }
937 0 : return bit_cast<double>(bits) == value->Number();
938 : } else {
939 0 : Object current_value = holder->RawFastPropertyAt(field_index);
940 0 : return current_value->IsUninitialized(isolate()) || current_value == value;
941 : }
942 : }
943 :
944 165689 : int LookupIterator::GetFieldDescriptorIndex() const {
945 : DCHECK(has_property_);
946 : DCHECK(holder_->HasFastProperties());
947 : DCHECK_EQ(kField, property_details_.location());
948 : DCHECK_EQ(kData, property_details_.kind());
949 165689 : return descriptor_number();
950 : }
951 :
952 284238 : int LookupIterator::GetAccessorIndex() const {
953 : DCHECK(has_property_);
954 : DCHECK(holder_->HasFastProperties());
955 : DCHECK_EQ(kDescriptor, property_details_.location());
956 : DCHECK_EQ(kAccessor, property_details_.kind());
957 284238 : return descriptor_number();
958 : }
959 :
960 :
961 421271 : int LookupIterator::GetConstantIndex() const {
962 : DCHECK(has_property_);
963 : DCHECK(holder_->HasFastProperties());
964 : DCHECK_EQ(kDescriptor, property_details_.location());
965 : DCHECK_EQ(kData, property_details_.kind());
966 : DCHECK(!FLAG_track_constant_fields);
967 : DCHECK(!IsElement());
968 421271 : return descriptor_number();
969 : }
970 :
971 0 : Handle<Map> LookupIterator::GetFieldOwnerMap() const {
972 : DCHECK(has_property_);
973 : DCHECK(holder_->HasFastProperties());
974 : DCHECK_EQ(kField, property_details_.location());
975 : DCHECK(!IsElement());
976 0 : Map holder_map = holder_->map();
977 : return handle(holder_map->FindFieldOwner(isolate(), descriptor_number()),
978 0 : isolate_);
979 : }
980 :
981 728841 : FieldIndex LookupIterator::GetFieldIndex() const {
982 : DCHECK(has_property_);
983 : DCHECK(holder_->HasFastProperties());
984 : DCHECK_EQ(kField, property_details_.location());
985 : DCHECK(!IsElement());
986 728845 : return FieldIndex::ForDescriptor(holder_->map(), descriptor_number());
987 : }
988 :
989 0 : Handle<FieldType> LookupIterator::GetFieldType() const {
990 : DCHECK(has_property_);
991 : DCHECK(holder_->HasFastProperties());
992 : DCHECK_EQ(kField, property_details_.location());
993 : return handle(
994 0 : holder_->map()->instance_descriptors()->GetFieldType(descriptor_number()),
995 0 : isolate_);
996 : }
997 :
998 :
999 12315938 : Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
1000 : DCHECK(!IsElement());
1001 : Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>();
1002 12315944 : return handle(holder->global_dictionary()->CellAt(dictionary_entry()),
1003 24631887 : isolate_);
1004 : }
1005 :
1006 :
1007 2466481 : Handle<Object> LookupIterator::GetAccessors() const {
1008 : DCHECK_EQ(ACCESSOR, state_);
1009 3184738 : return FetchValue();
1010 : }
1011 :
1012 :
1013 26360058 : Handle<Object> LookupIterator::GetDataValue() const {
1014 : DCHECK_EQ(DATA, state_);
1015 26360058 : Handle<Object> value = FetchValue();
1016 26360060 : return value;
1017 : }
1018 :
1019 38598164 : void LookupIterator::WriteDataValue(Handle<Object> value,
1020 66498405 : bool initializing_store) {
1021 : DCHECK_EQ(DATA, state_);
1022 : Handle<JSReceiver> holder = GetHolder<JSReceiver>();
1023 38598185 : if (IsElement()) {
1024 927627 : Handle<JSObject> object = Handle<JSObject>::cast(holder);
1025 927628 : ElementsAccessor* accessor = object->GetElementsAccessor();
1026 1855259 : accessor->Set(object, number_, *value);
1027 37670556 : } else if (holder->HasFastProperties()) {
1028 23396220 : if (property_details_.location() == kField) {
1029 : // Check that in case of VariableMode::kConst field the existing value is
1030 : // equal to |value|.
1031 : DCHECK_IMPLIES(!initializing_store && property_details_.constness() ==
1032 : PropertyConstness::kConst,
1033 : IsConstFieldValueEqualTo(*value));
1034 : JSObject::cast(*holder)->WriteToField(descriptor_number(),
1035 13625874 : property_details_, *value);
1036 : } else {
1037 : DCHECK_EQ(kDescriptor, property_details_.location());
1038 : DCHECK_EQ(PropertyConstness::kConst, property_details_.constness());
1039 : }
1040 28548690 : } else if (holder->IsJSGlobalObject()) {
1041 : GlobalDictionary dictionary =
1042 11133305 : JSGlobalObject::cast(*holder)->global_dictionary();
1043 11133306 : dictionary->CellAt(dictionary_entry())->set_value(*value);
1044 : } else {
1045 : DCHECK_IMPLIES(holder->IsJSProxy(), name()->IsPrivate());
1046 3141039 : NameDictionary dictionary = holder->property_dictionary();
1047 : dictionary->ValueAtPut(dictionary_entry(), *value);
1048 : }
1049 38598197 : }
1050 :
1051 : template <bool is_element>
1052 914561 : bool LookupIterator::SkipInterceptor(JSObject holder) {
1053 914561 : auto info = GetInterceptor<is_element>(holder);
1054 1210990 : if (!is_element && name_->IsSymbol() && !info->can_intercept_symbols()) {
1055 : return true;
1056 : }
1057 914549 : if (info->non_masking()) {
1058 414 : switch (interceptor_state_) {
1059 : case InterceptorState::kUninitialized:
1060 258 : interceptor_state_ = InterceptorState::kSkipNonMasking;
1061 : V8_FALLTHROUGH;
1062 : case InterceptorState::kSkipNonMasking:
1063 : return true;
1064 : case InterceptorState::kProcessNonMasking:
1065 : return false;
1066 : }
1067 : }
1068 914135 : return interceptor_state_ == InterceptorState::kProcessNonMasking;
1069 : }
1070 :
1071 566903334 : JSReceiver LookupIterator::NextHolder(Map map) {
1072 : DisallowHeapAllocation no_gc;
1073 665830678 : if (map->prototype() == ReadOnlyRoots(heap()).null_value()) {
1074 98927344 : return JSReceiver();
1075 : }
1076 233988014 : if (!check_prototype_chain() && !map->has_hidden_prototype()) {
1077 46504147 : return JSReceiver();
1078 : }
1079 : return JSReceiver::cast(map->prototype());
1080 : }
1081 :
1082 84799314 : LookupIterator::State LookupIterator::NotFound(JSReceiver const holder) const {
1083 : DCHECK(!IsElement());
1084 84982904 : if (!holder->IsJSTypedArray() || !name_->IsString()) return NOT_FOUND;
1085 :
1086 83800 : Handle<String> name_string = Handle<String>::cast(name_);
1087 83800 : if (name_string->length() == 0) return NOT_FOUND;
1088 :
1089 83800 : return IsSpecialIndex(*name_string) ? INTEGER_INDEXED_EXOTIC : NOT_FOUND;
1090 : }
1091 :
1092 : namespace {
1093 :
1094 : template <bool is_element>
1095 : bool HasInterceptor(Map map) {
1096 : return is_element ? map->has_indexed_interceptor()
1097 : : map->has_named_interceptor();
1098 : }
1099 :
1100 : } // namespace
1101 :
1102 : template <bool is_element>
1103 50466112 : LookupIterator::State LookupIterator::LookupInSpecialHolder(
1104 : Map const map, JSReceiver const holder) {
1105 : STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY);
1106 50466112 : switch (state_) {
1107 : case NOT_FOUND:
1108 43544296 : if (map->IsJSProxyMap()) {
1109 317445 : if (is_element || !name_->IsPrivate()) return JSPROXY;
1110 : }
1111 43216539 : if (map->is_access_check_needed()) {
1112 8288380 : if (is_element || !name_->IsPrivate()) return ACCESS_CHECK;
1113 : }
1114 : V8_FALLTHROUGH;
1115 : case ACCESS_CHECK:
1116 65791993 : if (check_interceptor() && HasInterceptor<is_element>(map) &&
1117 914561 : !SkipInterceptor<is_element>(JSObject::cast(holder))) {
1118 605225 : if (is_element || !name_->IsPrivate()) return INTERCEPTOR;
1119 : }
1120 : V8_FALLTHROUGH;
1121 : case INTERCEPTOR:
1122 40609522 : if (!is_element && map->IsJSGlobalObjectMap()) {
1123 : GlobalDictionary dict =
1124 33742165 : JSGlobalObject::cast(holder)->global_dictionary();
1125 33742168 : int number = dict->FindEntry(isolate(), name_);
1126 67484301 : if (number == GlobalDictionary::kNotFound) return NOT_FOUND;
1127 16492554 : number_ = static_cast<uint32_t>(number);
1128 16492554 : PropertyCell cell = dict->CellAt(number_);
1129 32985108 : if (cell->value()->IsTheHole(isolate_)) return NOT_FOUND;
1130 16458791 : property_details_ = cell->property_details();
1131 16458790 : has_property_ = true;
1132 16458790 : switch (property_details_.kind()) {
1133 : case v8::internal::kData:
1134 : return DATA;
1135 : case v8::internal::kAccessor:
1136 40608 : return ACCESSOR;
1137 : }
1138 : }
1139 7187087 : return LookupInRegularHolder<is_element>(map, holder);
1140 : case ACCESSOR:
1141 : case DATA:
1142 : return NOT_FOUND;
1143 : case INTEGER_INDEXED_EXOTIC:
1144 : case JSPROXY:
1145 : case TRANSITION:
1146 0 : UNREACHABLE();
1147 : }
1148 0 : UNREACHABLE();
1149 : }
1150 :
1151 : template <bool is_element>
1152 354751475 : LookupIterator::State LookupIterator::LookupInRegularHolder(
1153 : Map const map, JSReceiver const holder) {
1154 : DisallowHeapAllocation no_gc;
1155 354751475 : if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
1156 : return NOT_FOUND;
1157 : }
1158 :
1159 : if (is_element) {
1160 238708135 : JSObject js_object = JSObject::cast(holder);
1161 238708135 : ElementsAccessor* accessor = js_object->GetElementsAccessor();
1162 238708136 : FixedArrayBase backing_store = js_object->elements();
1163 238708135 : number_ =
1164 238708136 : accessor->GetEntryForIndex(isolate_, js_object, backing_store, index_);
1165 238708135 : if (number_ == kMaxUInt32) {
1166 231023676 : return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND;
1167 : }
1168 7684461 : property_details_ = accessor->GetDetails(js_object, number_);
1169 116043242 : } else if (!map->is_dictionary_map()) {
1170 110783491 : DescriptorArray descriptors = map->instance_descriptors();
1171 110783509 : int number = descriptors->SearchWithCache(isolate_, *name_, map);
1172 110783590 : if (number == DescriptorArray::kNotFound) return NotFound(holder);
1173 29979692 : number_ = static_cast<uint32_t>(number);
1174 29979692 : property_details_ = descriptors->GetDetails(number_);
1175 : } else {
1176 : DCHECK_IMPLIES(holder->IsJSProxy(), name()->IsPrivate());
1177 5259750 : NameDictionary dict = holder->property_dictionary();
1178 5259750 : int number = dict->FindEntry(isolate(), name_);
1179 5259750 : if (number == NameDictionary::kNotFound) return NotFound(holder);
1180 1264312 : number_ = static_cast<uint32_t>(number);
1181 1264312 : property_details_ = dict->DetailsAt(number_);
1182 : }
1183 38928465 : has_property_ = true;
1184 38928465 : switch (property_details_.kind()) {
1185 : case v8::internal::kData:
1186 : return DATA;
1187 : case v8::internal::kAccessor:
1188 2953771 : return ACCESSOR;
1189 : }
1190 :
1191 0 : UNREACHABLE();
1192 : }
1193 :
1194 1398 : Handle<InterceptorInfo> LookupIterator::GetInterceptorForFailedAccessCheck()
1195 1102 : const {
1196 : DCHECK_EQ(ACCESS_CHECK, state_);
1197 : DisallowHeapAllocation no_gc;
1198 : AccessCheckInfo access_check_info =
1199 1398 : AccessCheckInfo::Get(isolate_, Handle<JSObject>::cast(holder_));
1200 1398 : if (!access_check_info.is_null()) {
1201 : Object interceptor = IsElement() ? access_check_info->indexed_interceptor()
1202 1102 : : access_check_info->named_interceptor();
1203 1102 : if (interceptor != Object()) {
1204 290 : return handle(InterceptorInfo::cast(interceptor), isolate_);
1205 : }
1206 : }
1207 1253 : return Handle<InterceptorInfo>();
1208 : }
1209 :
1210 3395598 : bool LookupIterator::TryLookupCachedProperty() {
1211 348484 : return state() == LookupIterator::ACCESSOR &&
1212 4091908 : GetAccessors()->IsAccessorPair() && LookupCachedProperty();
1213 : }
1214 :
1215 1043559 : bool LookupIterator::LookupCachedProperty() {
1216 : DCHECK_EQ(state(), LookupIterator::ACCESSOR);
1217 : DCHECK(GetAccessors()->IsAccessorPair());
1218 :
1219 347826 : AccessorPair accessor_pair = AccessorPair::cast(*GetAccessors());
1220 347826 : Handle<Object> getter(accessor_pair->getter(), isolate());
1221 : MaybeHandle<Name> maybe_name =
1222 347826 : FunctionTemplateInfo::TryGetCachedPropertyName(isolate(), getter);
1223 347826 : if (maybe_name.is_null()) return false;
1224 :
1225 : // We have found a cached property! Modify the iterator accordingly.
1226 81 : name_ = maybe_name.ToHandleChecked();
1227 81 : Restart();
1228 81 : CHECK_EQ(state(), LookupIterator::DATA);
1229 : return true;
1230 : }
1231 :
1232 : } // namespace internal
1233 183867 : } // namespace v8
|