5 #include "src/lookup.h" 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" 19 LookupIterator LookupIterator::PropertyOrElement(
20 Isolate* isolate, Handle<Object> receiver, Handle<Object> key,
21 bool* success, Handle<JSReceiver> holder, Configuration configuration) {
23 if (key->ToArrayIndex(&index)) {
25 return LookupIterator(isolate, receiver, index, holder, configuration);
29 *success = Object::ToName(isolate, key).ToHandle(&name);
31 DCHECK(isolate->has_pending_exception());
33 return LookupIterator(isolate, receiver,
34 isolate->factory()->empty_string());
37 if (name->AsArrayIndex(&index)) {
38 LookupIterator it(isolate, receiver, index, holder, configuration);
45 return LookupIterator(receiver, name, holder, configuration);
49 LookupIterator LookupIterator::PropertyOrElement(Isolate* isolate,
50 Handle<Object> receiver,
53 Configuration configuration) {
56 if (key->ToArrayIndex(&index)) {
58 return LookupIterator(isolate, receiver, index, configuration);
62 *success = Object::ToName(isolate, key).ToHandle(&name);
64 DCHECK(isolate->has_pending_exception());
66 return LookupIterator(isolate, receiver,
67 isolate->factory()->empty_string());
70 if (name->AsArrayIndex(&index)) {
71 LookupIterator it(isolate, receiver, index, configuration);
78 return LookupIterator(isolate, receiver, name, configuration);
83 LookupIterator LookupIterator::ForTransitionHandler(
84 Isolate* isolate, Handle<Object> receiver, Handle<Name> name,
85 Handle<Object> value, MaybeHandle<Map> maybe_transition_map) {
86 Handle<Map> transition_map;
87 if (!maybe_transition_map.ToHandle(&transition_map) ||
88 !transition_map->IsPrototypeValidityCellValid()) {
90 return LookupIterator(isolate, receiver, name);
93 PropertyDetails details = PropertyDetails::Empty();
95 if (transition_map->is_dictionary_map()) {
96 details = PropertyDetails(kData, NONE, PropertyCellType::kNoCell);
99 details = transition_map->GetLastDescriptorDetails();
103 if (name->IsPrivate()) {
104 DCHECK_EQ(DONT_ENUM, details.attributes());
106 DCHECK_EQ(NONE, details.attributes());
109 LookupIterator it(isolate, receiver, name, transition_map, details,
112 if (!transition_map->is_dictionary_map()) {
113 int descriptor_number = transition_map->LastAdded();
114 Handle<Map> new_map =
115 Map::PrepareForDataProperty(isolate, transition_map, descriptor_number,
116 PropertyConstness::kConst, value);
118 it.property_details_ =
119 new_map->instance_descriptors()->GetDetails(descriptor_number);
120 it.transition_ = new_map;
125 LookupIterator::LookupIterator(Isolate* isolate, Handle<Object> receiver,
126 Handle<Name> name, Handle<Map> transition_map,
127 PropertyDetails details,
bool has_property)
128 : configuration_(DEFAULT),
130 has_property_(has_property),
131 interceptor_state_(InterceptorState::kUninitialized),
132 property_details_(details),
135 transition_(transition_map),
137 initial_holder_(GetRoot(isolate, receiver)),
139 number_(static_cast<
uint32_t>(DescriptorArray::kNotFound)) {
140 holder_ = initial_holder_;
143 template <
bool is_element>
144 void LookupIterator::Start() {
145 DisallowHeapAllocation no_gc;
147 has_property_ =
false;
149 holder_ = initial_holder_;
151 JSReceiver* holder = *holder_;
152 Map map = holder->map();
154 state_ = LookupInHolder<is_element>(map, holder);
155 if (IsFound())
return;
157 NextInternal<is_element>(map, holder);
160 template void LookupIterator::Start<true>();
161 template void LookupIterator::Start<false>();
163 void LookupIterator::Next() {
164 DCHECK_NE(JSPROXY, state_);
165 DCHECK_NE(TRANSITION, state_);
166 DisallowHeapAllocation no_gc;
167 has_property_ =
false;
169 JSReceiver* holder = *holder_;
170 Map map = holder->map();
172 if (map->IsSpecialReceiverMap()) {
173 state_ = IsElement() ? LookupInSpecialHolder<true>(map, holder)
174 : LookupInSpecialHolder<false>(map, holder);
175 if (IsFound())
return;
178 IsElement() ? NextInternal<true>(map, holder)
179 : NextInternal<false>(map, holder);
182 template <
bool is_element>
183 void LookupIterator::NextInternal(Map map, JSReceiver* holder) {
185 JSReceiver* maybe_holder = NextHolder(map);
186 if (maybe_holder ==
nullptr) {
187 if (interceptor_state_ == InterceptorState::kSkipNonMasking) {
188 RestartLookupForNonMaskingInterceptors<is_element>();
192 if (holder != *holder_) holder_ = handle(holder, isolate_);
195 holder = maybe_holder;
197 state_ = LookupInHolder<is_element>(map, holder);
198 }
while (!IsFound());
200 holder_ = handle(holder, isolate_);
203 template <
bool is_element>
204 void LookupIterator::RestartInternal(InterceptorState interceptor_state) {
205 interceptor_state_ = interceptor_state;
206 property_details_ = PropertyDetails::Empty();
207 number_ =
static_cast<uint32_t>(DescriptorArray::kNotFound);
211 template void LookupIterator::RestartInternal<true>(InterceptorState);
212 template void LookupIterator::RestartInternal<false>(InterceptorState);
215 Handle<JSReceiver> LookupIterator::GetRootForNonJSReceiver(
216 Isolate* isolate, Handle<Object> receiver,
uint32_t index) {
219 if (index != kMaxUInt32 && receiver->IsString() &&
220 index < static_cast<uint32_t>(String::cast(*receiver)->length())) {
223 Handle<JSFunction> constructor = isolate->string_function();
224 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
225 Handle<JSValue>::cast(result)->set_value(*receiver);
229 handle(receiver->GetPrototypeChainRootMap(isolate)->prototype(), isolate);
230 if (root->IsNull(isolate)) {
231 isolate->PushStackTraceAndDie(*receiver);
233 return Handle<JSReceiver>::cast(root);
237 Handle<Map> LookupIterator::GetReceiverMap()
const {
238 if (receiver_->IsNumber())
return factory()->heap_number_map();
239 return handle(Handle<HeapObject>::cast(receiver_)->map(), isolate_);
242 bool LookupIterator::HasAccess()
const {
243 DCHECK_EQ(ACCESS_CHECK, state_);
244 return isolate_->MayAccess(handle(isolate_->context(), isolate_),
245 GetHolder<JSObject>());
248 template <
bool is_element>
249 void LookupIterator::ReloadPropertyInformation() {
250 state_ = BEFORE_PROPERTY;
251 interceptor_state_ = InterceptorState::kUninitialized;
252 state_ = LookupInHolder<is_element>(holder_->map(), *holder_);
253 DCHECK(IsFound() || !holder_->HasFastProperties());
258 bool IsTypedArrayFunctionInAnyContext(Isolate* isolate, JSReceiver* holder) {
260 #define TYPED_ARRAY_CONTEXT_SLOTS(Type, type, TYPE, ctype) \ 261 Context::TYPE##_ARRAY_FUN_INDEX, 263 TYPED_ARRAYS(TYPED_ARRAY_CONTEXT_SLOTS)
264 #undef TYPED_ARRAY_CONTEXT_SLOTS 267 if (!holder->IsJSFunction())
return false;
270 std::begin(context_slots), std::end(context_slots),
271 [=](
uint32_t slot) {
return isolate->IsInAnyContext(holder, slot); });
276 void LookupIterator::InternalUpdateProtector() {
277 if (isolate_->bootstrapper()->IsActive())
return;
279 ReadOnlyRoots roots(heap());
280 if (*name_ == roots.constructor_string()) {
281 if (!isolate_->IsArraySpeciesLookupChainIntact() &&
282 !isolate_->IsPromiseSpeciesLookupChainIntact() &&
283 !isolate_->IsRegExpSpeciesLookupChainIntact() &&
284 !isolate_->IsTypedArraySpeciesLookupChainIntact()) {
288 if (holder_->IsJSArray()) {
289 if (!isolate_->IsArraySpeciesLookupChainIntact())
return;
290 isolate_->CountUsage(
291 v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified);
292 isolate_->InvalidateArraySpeciesProtector();
294 }
else if (holder_->IsJSPromise()) {
295 if (!isolate_->IsPromiseSpeciesLookupChainIntact())
return;
296 isolate_->InvalidatePromiseSpeciesProtector();
298 }
else if (holder_->IsJSRegExp()) {
299 if (!isolate_->IsRegExpSpeciesLookupChainIntact())
return;
300 isolate_->InvalidateRegExpSpeciesProtector();
302 }
else if (holder_->IsJSTypedArray()) {
303 if (!isolate_->IsTypedArraySpeciesLookupChainIntact())
return;
304 isolate_->InvalidateTypedArraySpeciesProtector();
307 if (holder_->map()->is_prototype_map()) {
308 DisallowHeapAllocation no_gc;
314 if (isolate_->IsInAnyContext(*holder_,
315 Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) {
316 if (!isolate_->IsArraySpeciesLookupChainIntact())
return;
317 isolate_->CountUsage(
318 v8::Isolate::UseCounterFeature::kArrayPrototypeConstructorModified);
319 isolate_->InvalidateArraySpeciesProtector();
320 }
else if (isolate_->IsInAnyContext(*holder_,
321 Context::PROMISE_PROTOTYPE_INDEX)) {
322 if (!isolate_->IsPromiseSpeciesLookupChainIntact())
return;
323 isolate_->InvalidatePromiseSpeciesProtector();
324 }
else if (isolate_->IsInAnyContext(*holder_,
325 Context::REGEXP_PROTOTYPE_INDEX)) {
326 if (!isolate_->IsRegExpSpeciesLookupChainIntact())
return;
327 isolate_->InvalidateRegExpSpeciesProtector();
328 }
else if (isolate_->IsInAnyContext(
329 holder_->map()->prototype(),
330 Context::TYPED_ARRAY_PROTOTYPE_INDEX)) {
331 if (!isolate_->IsTypedArraySpeciesLookupChainIntact())
return;
332 isolate_->InvalidateTypedArraySpeciesProtector();
335 }
else if (*name_ == roots.next_string()) {
336 if (isolate_->IsInAnyContext(
337 *holder_, Context::INITIAL_ARRAY_ITERATOR_PROTOTYPE_INDEX)) {
340 if (!isolate_->IsArrayIteratorLookupChainIntact())
return;
341 isolate_->InvalidateArrayIteratorProtector();
342 }
else if (isolate_->IsInAnyContext(
343 *holder_, Context::INITIAL_MAP_ITERATOR_PROTOTYPE_INDEX)) {
344 if (!isolate_->IsMapIteratorLookupChainIntact())
return;
345 isolate_->InvalidateMapIteratorProtector();
346 }
else if (isolate_->IsInAnyContext(
347 *holder_, Context::INITIAL_SET_ITERATOR_PROTOTYPE_INDEX)) {
348 if (!isolate_->IsSetIteratorLookupChainIntact())
return;
349 isolate_->InvalidateSetIteratorProtector();
350 }
else if (isolate_->IsInAnyContext(
352 Context::INITIAL_STRING_ITERATOR_PROTOTYPE_INDEX)) {
355 if (!isolate_->IsStringIteratorLookupChainIntact())
return;
356 isolate_->InvalidateStringIteratorProtector();
358 }
else if (*name_ == roots.species_symbol()) {
359 if (!isolate_->IsArraySpeciesLookupChainIntact() &&
360 !isolate_->IsPromiseSpeciesLookupChainIntact() &&
361 !isolate_->IsRegExpSpeciesLookupChainIntact() &&
362 !isolate_->IsTypedArraySpeciesLookupChainIntact()) {
367 if (isolate_->IsInAnyContext(*holder_, Context::ARRAY_FUNCTION_INDEX)) {
368 if (!isolate_->IsArraySpeciesLookupChainIntact())
return;
369 isolate_->CountUsage(
370 v8::Isolate::UseCounterFeature::kArraySpeciesModified);
371 isolate_->InvalidateArraySpeciesProtector();
372 }
else if (isolate_->IsInAnyContext(*holder_,
373 Context::PROMISE_FUNCTION_INDEX)) {
374 if (!isolate_->IsPromiseSpeciesLookupChainIntact())
return;
375 isolate_->InvalidatePromiseSpeciesProtector();
376 }
else if (isolate_->IsInAnyContext(*holder_,
377 Context::REGEXP_FUNCTION_INDEX)) {
378 if (!isolate_->IsRegExpSpeciesLookupChainIntact())
return;
379 isolate_->InvalidateRegExpSpeciesProtector();
380 }
else if (IsTypedArrayFunctionInAnyContext(isolate_, *holder_)) {
381 if (!isolate_->IsTypedArraySpeciesLookupChainIntact())
return;
382 isolate_->InvalidateTypedArraySpeciesProtector();
384 }
else if (*name_ == roots.is_concat_spreadable_symbol()) {
385 if (!isolate_->IsIsConcatSpreadableLookupChainIntact())
return;
386 isolate_->InvalidateIsConcatSpreadableProtector();
387 }
else if (*name_ == roots.iterator_symbol()) {
388 if (holder_->IsJSArray()) {
389 if (!isolate_->IsArrayIteratorLookupChainIntact())
return;
390 isolate_->InvalidateArrayIteratorProtector();
391 }
else if (isolate_->IsInAnyContext(
392 *holder_, Context::INITIAL_ITERATOR_PROTOTYPE_INDEX)) {
393 if (isolate_->IsMapIteratorLookupChainIntact()) {
394 isolate_->InvalidateMapIteratorProtector();
396 if (isolate_->IsSetIteratorLookupChainIntact()) {
397 isolate_->InvalidateSetIteratorProtector();
399 }
else if (isolate_->IsInAnyContext(*holder_,
400 Context::INITIAL_SET_PROTOTYPE_INDEX)) {
401 if (!isolate_->IsSetIteratorLookupChainIntact())
return;
402 isolate_->InvalidateSetIteratorProtector();
403 }
else if (isolate_->IsInAnyContext(
404 *receiver_, Context::INITIAL_STRING_PROTOTYPE_INDEX)) {
409 if (!isolate_->IsStringIteratorLookupChainIntact())
return;
410 isolate_->InvalidateStringIteratorProtector();
412 }
else if (*name_ == roots.resolve_string()) {
413 if (!isolate_->IsPromiseResolveLookupChainIntact())
return;
416 if (isolate_->IsInAnyContext(*holder_, Context::PROMISE_FUNCTION_INDEX)) {
417 isolate_->InvalidatePromiseResolveProtector();
419 }
else if (*name_ == roots.then_string()) {
420 if (!isolate_->IsPromiseThenLookupChainIntact())
return;
428 if (holder_->IsJSPromise() ||
429 isolate_->IsInAnyContext(*holder_,
430 Context::INITIAL_OBJECT_PROTOTYPE_INDEX) ||
431 isolate_->IsInAnyContext(*holder_, Context::PROMISE_PROTOTYPE_INDEX)) {
432 isolate_->InvalidatePromiseThenProtector();
437 void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
438 DCHECK(state_ == DATA || state_ == ACCESSOR);
439 DCHECK(HolderIsReceiverOrHiddenPrototype());
441 Handle<JSReceiver> holder = GetHolder<JSReceiver>();
443 DCHECK_IMPLIES(holder->IsJSProxy(), !holder->HasFastProperties());
444 DCHECK_IMPLIES(holder->IsJSProxy(), name()->IsPrivate());
445 if (holder->IsJSProxy())
return;
447 Handle<JSObject> holder_obj = Handle<JSObject>::cast(holder);
450 ElementsKind kind = holder_obj->GetElementsKind();
451 ElementsKind to = value->OptimalElementsKind();
452 if (IsHoleyElementsKind(kind)) to = GetHoleyElementsKind(to);
453 to = GetMoreGeneralElementsKind(kind, to);
456 JSObject::TransitionElementsKind(holder_obj, to);
460 if (IsSmiOrObjectElementsKind(to)) {
461 JSObject::EnsureWritableFastElements(holder_obj);
466 if (holder_obj->IsJSGlobalObject()) {
467 Handle<GlobalDictionary> dictionary(
468 JSGlobalObject::cast(*holder_obj)->global_dictionary(), isolate());
469 Handle<PropertyCell> cell(dictionary->CellAt(dictionary_entry()),
471 property_details_ = cell->property_details();
472 PropertyCell::PrepareForValue(isolate(), dictionary, dictionary_entry(),
473 value, property_details_);
476 if (!holder_obj->HasFastProperties())
return;
478 PropertyConstness new_constness = PropertyConstness::kConst;
479 if (FLAG_track_constant_fields) {
480 if (constness() == PropertyConstness::kConst) {
481 DCHECK_EQ(kData, property_details_.kind());
484 if (!IsConstFieldValueEqualTo(*value))
485 new_constness = PropertyConstness::kMutable;
488 new_constness = PropertyConstness::kMutable;
491 Handle<Map> old_map(holder_obj->map(), isolate_);
492 Handle<Map> new_map = Map::PrepareForDataProperty(
493 isolate(), old_map, descriptor_number(), new_constness, value);
495 if (old_map.is_identical_to(new_map)) {
497 if (constness() != new_constness || representation().IsNone()) {
499 new_map->instance_descriptors()->GetDetails(descriptor_number());
504 JSObject::MigrateToMap(holder_obj, new_map);
505 ReloadPropertyInformation<false>();
509 void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
510 PropertyAttributes attributes) {
511 DCHECK(state_ == DATA || state_ == ACCESSOR);
512 DCHECK(HolderIsReceiverOrHiddenPrototype());
514 Handle<JSReceiver> holder = GetHolder<JSReceiver>();
517 if (holder->IsJSProxy()) {
518 DCHECK(name()->IsPrivate());
522 Handle<JSObject> holder_obj = Handle<JSObject>::cast(holder);
524 DCHECK(!holder_obj->HasFixedTypedArrayElements());
525 DCHECK(attributes != NONE || !holder_obj->HasFastElements());
526 Handle<FixedArrayBase> elements(holder_obj->elements(), isolate());
527 holder_obj->GetElementsAccessor()->Reconfigure(holder_obj, elements,
528 number_, value, attributes);
529 ReloadPropertyInformation<true>();
530 }
else if (holder_obj->HasFastProperties()) {
531 Handle<Map> old_map(holder_obj->map(), isolate_);
532 Handle<Map> new_map = Map::ReconfigureExistingProperty(
533 isolate_, old_map, descriptor_number(), i::kData, attributes);
537 Map::PrepareForDataProperty(isolate(), new_map, descriptor_number(),
538 PropertyConstness::kMutable, value);
539 JSObject::MigrateToMap(holder_obj, new_map);
540 ReloadPropertyInformation<false>();
543 if (!IsElement() && !holder_obj->HasFastProperties()) {
544 PropertyDetails details(kData, attributes, PropertyCellType::kMutable);
545 if (holder_obj->map()->is_prototype_map() &&
546 (property_details_.attributes() & READ_ONLY) == 0 &&
547 (attributes & READ_ONLY) != 0) {
551 JSObject::InvalidatePrototypeChains(holder->map());
553 if (holder_obj->IsJSGlobalObject()) {
554 Handle<GlobalDictionary> dictionary(
555 JSGlobalObject::cast(*holder_obj)->global_dictionary(), isolate());
557 Handle<PropertyCell> cell = PropertyCell::PrepareForValue(
558 isolate(), dictionary, dictionary_entry(), value, details);
559 cell->set_value(*value);
560 property_details_ = cell->property_details();
562 Handle<NameDictionary> dictionary(holder_obj->property_dictionary(),
564 PropertyDetails original_details =
565 dictionary->DetailsAt(dictionary_entry());
566 int enumeration_index = original_details.dictionary_index();
567 DCHECK_GT(enumeration_index, 0);
568 details = details.set_index(enumeration_index);
569 dictionary->SetEntry(isolate(), dictionary_entry(), *name(), *value,
571 property_details_ = details;
576 WriteDataValue(value,
true);
579 if (FLAG_verify_heap) {
580 holder->HeapObjectVerify(isolate());
587 void LookupIterator::PrepareTransitionToDataProperty(
588 Handle<JSReceiver> receiver, Handle<Object> value,
589 PropertyAttributes attributes, StoreOrigin store_origin) {
590 DCHECK_IMPLIES(receiver->IsJSProxy(), name()->IsPrivate());
591 DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>()));
592 if (state_ == TRANSITION)
return;
594 if (!IsElement() && name()->IsPrivate()) {
595 attributes =
static_cast<PropertyAttributes
>(attributes | DONT_ENUM);
598 DCHECK(state_ != LookupIterator::ACCESSOR ||
599 (GetAccessors()->IsAccessorInfo() &&
600 AccessorInfo::cast(*GetAccessors())->is_special_data_property()));
601 DCHECK_NE(INTEGER_INDEXED_EXOTIC, state_);
602 DCHECK(state_ == NOT_FOUND || !HolderIsReceiverOrHiddenPrototype());
604 Handle<Map> map(receiver->map(), isolate_);
607 if (map->is_dictionary_map()) {
609 if (map->IsJSGlobalObjectMap()) {
611 Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(receiver);
613 Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
614 global, name(), PropertyCellType::kUninitialized, &entry);
615 Handle<GlobalDictionary> dictionary(global->global_dictionary(),
617 DCHECK(cell->value()->IsTheHole(isolate_));
618 DCHECK(!value->IsTheHole(isolate_));
622 int index = dictionary->NextEnumerationIndex();
623 dictionary->SetNextEnumerationIndex(index + 1);
624 property_details_ = PropertyDetails(
625 kData, attributes, PropertyCellType::kUninitialized, index);
626 PropertyCellType new_type =
627 PropertyCell::UpdatedType(isolate(), cell, value, property_details_);
628 property_details_ = property_details_.set_cell_type(new_type);
629 cell->set_property_details(property_details_);
631 has_property_ =
true;
635 PropertyDetails(kData, attributes, PropertyCellType::kNoCell);
641 Handle<Map> transition =
642 Map::TransitionToDataProperty(isolate_, map, name_, value, attributes,
643 kDefaultFieldConstness, store_origin);
645 transition_ = transition;
647 if (transition->is_dictionary_map()) {
650 PropertyDetails(kData, attributes, PropertyCellType::kNoCell);
652 property_details_ = transition->GetLastDescriptorDetails();
653 has_property_ =
true;
657 void LookupIterator::ApplyTransitionToDataProperty(
658 Handle<JSReceiver> receiver) {
659 DCHECK_EQ(TRANSITION, state_);
661 DCHECK(receiver.is_identical_to(GetStoreTarget<JSReceiver>()));
663 if (receiver->IsJSGlobalObject()) {
664 JSObject::InvalidatePrototypeChains(receiver->map());
668 Handle<Map> transition = transition_map();
669 bool simple_transition = transition->GetBackPointer() == receiver->map();
671 if (configuration_ == DEFAULT && !transition->is_dictionary_map() &&
672 !transition->IsPrototypeValidityCellValid()) {
675 Handle<Object> validity_cell =
676 Map::GetOrCreatePrototypeChainValidityCell(transition, isolate());
677 transition->set_prototype_validity_cell(*validity_cell);
680 if (!receiver->IsJSProxy()) {
681 JSObject::MigrateToMap(Handle<JSObject>::cast(receiver), transition);
684 if (simple_transition) {
685 int number = transition->LastAdded();
686 number_ =
static_cast<uint32_t>(number);
687 property_details_ = transition->GetLastDescriptorDetails();
689 }
else if (receiver->map()->is_dictionary_map()) {
690 Handle<NameDictionary> dictionary(receiver->property_dictionary(),
693 if (receiver->map()->is_prototype_map() && receiver->IsJSObject()) {
694 JSObject::InvalidatePrototypeChains(receiver->map());
696 dictionary = NameDictionary::Add(isolate(), dictionary, name(),
697 isolate_->factory()->uninitialized_value(),
698 property_details_, &entry);
699 receiver->SetProperties(*dictionary);
701 property_details_ = dictionary->DetailsAt(entry);
703 has_property_ =
true;
707 ReloadPropertyInformation<false>();
712 void LookupIterator::Delete() {
713 Handle<JSReceiver> holder = Handle<JSReceiver>::cast(holder_);
715 Handle<JSObject>
object = Handle<JSObject>::cast(holder);
716 ElementsAccessor* accessor =
object->GetElementsAccessor();
717 accessor->Delete(
object, number_);
719 DCHECK(!name()->IsPrivateName());
720 bool is_prototype_map = holder->map()->is_prototype_map();
721 RuntimeCallTimerScope stats_scope(
722 isolate_, is_prototype_map
723 ? RuntimeCallCounterId::kPrototypeObject_DeleteProperty
724 : RuntimeCallCounterId::kObject_DeleteProperty);
726 PropertyNormalizationMode mode =
727 is_prototype_map ? KEEP_INOBJECT_PROPERTIES : CLEAR_INOBJECT_PROPERTIES;
729 if (holder->HasFastProperties()) {
730 JSObject::NormalizeProperties(Handle<JSObject>::cast(holder), mode, 0,
732 ReloadPropertyInformation<false>();
734 JSReceiver::DeleteNormalizedProperty(holder, number_);
735 if (holder->IsJSObject()) {
736 JSObject::ReoptimizeIfPrototype(Handle<JSObject>::cast(holder));
742 void LookupIterator::TransitionToAccessorProperty(
743 Handle<Object> getter, Handle<Object> setter,
744 PropertyAttributes attributes) {
745 DCHECK(!getter->IsNull(isolate_) || !setter->IsNull(isolate_));
749 Handle<JSObject> receiver = GetStoreTarget<JSObject>();
750 if (!IsElement() && name()->IsPrivate()) {
751 attributes =
static_cast<PropertyAttributes
>(attributes | DONT_ENUM);
754 if (!IsElement() && !receiver->map()->is_dictionary_map()) {
755 Handle<Map> old_map(receiver->map(), isolate_);
757 if (!holder_.is_identical_to(receiver)) {
760 }
else if (state_ == INTERCEPTOR) {
761 LookupInRegularHolder<false>(*old_map, *holder_);
764 IsFound() ?
static_cast<int>(number_) : DescriptorArray::kNotFound;
766 Handle<Map> new_map = Map::TransitionToAccessorProperty(
767 isolate_, old_map, name_, descriptor, getter, setter, attributes);
768 bool simple_transition = new_map->GetBackPointer() == receiver->map();
769 JSObject::MigrateToMap(receiver, new_map);
771 if (simple_transition) {
772 int number = new_map->LastAdded();
773 number_ =
static_cast<uint32_t>(number);
774 property_details_ = new_map->GetLastDescriptorDetails();
779 ReloadPropertyInformation<false>();
780 if (!new_map->is_dictionary_map())
return;
783 Handle<AccessorPair> pair;
784 if (state() == ACCESSOR && GetAccessors()->IsAccessorPair()) {
785 pair = Handle<AccessorPair>::cast(GetAccessors());
787 if (pair->Equals(*getter, *setter)) {
788 if (property_details().attributes() == attributes) {
789 if (!IsElement()) JSObject::ReoptimizeIfPrototype(receiver);
793 pair = AccessorPair::Copy(isolate(), pair);
794 pair->SetComponents(*getter, *setter);
797 pair = factory()->NewAccessorPair();
798 pair->SetComponents(*getter, *setter);
801 TransitionToAccessorPair(pair, attributes);
804 if (FLAG_verify_heap) {
805 receiver->JSObjectVerify(isolate());
811 void LookupIterator::TransitionToAccessorPair(Handle<Object> pair,
812 PropertyAttributes attributes) {
813 Handle<JSObject> receiver = GetStoreTarget<JSObject>();
816 PropertyDetails details(kAccessor, attributes, PropertyCellType::kMutable);
820 isolate_->CountUsage(v8::Isolate::kIndexAccessor);
821 Handle<NumberDictionary> dictionary = JSObject::NormalizeElements(receiver);
823 dictionary = NumberDictionary::Set(isolate_, dictionary, index_, pair,
825 receiver->RequireSlowElements(*dictionary);
827 if (receiver->HasSlowArgumentsElements()) {
828 FixedArray parameter_map = FixedArray::cast(receiver->elements());
829 uint32_t length = parameter_map->length() - 2;
830 if (number_ < length) {
831 parameter_map->set(number_ + 2, ReadOnlyRoots(heap()).the_hole_value());
833 FixedArray::cast(receiver->elements())->
set(1, *dictionary);
835 receiver->set_elements(*dictionary);
838 ReloadPropertyInformation<true>();
840 PropertyNormalizationMode mode = CLEAR_INOBJECT_PROPERTIES;
841 if (receiver->map()->is_prototype_map()) {
842 JSObject::InvalidatePrototypeChains(receiver->map());
843 mode = KEEP_INOBJECT_PROPERTIES;
847 JSObject::NormalizeProperties(receiver, mode, 0,
848 "TransitionToAccessorPair");
850 JSObject::SetNormalizedProperty(receiver, name_, pair, details);
851 JSObject::ReoptimizeIfPrototype(receiver);
853 ReloadPropertyInformation<false>();
857 bool LookupIterator::HolderIsReceiver()
const {
858 DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
860 if (!check_prototype_chain())
return true;
861 return *receiver_ == *holder_;
864 bool LookupIterator::HolderIsReceiverOrHiddenPrototype()
const {
865 DCHECK(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
867 if (!check_prototype_chain())
return true;
868 DisallowHeapAllocation no_gc;
869 if (*receiver_ == *holder_)
return true;
870 if (!receiver_->IsJSReceiver())
return false;
871 JSReceiver* current = JSReceiver::cast(*receiver_);
872 JSReceiver*
object = *holder_;
873 if (!current->map()->has_hidden_prototype())
return false;
875 if (object->IsJSProxy())
return false;
876 PrototypeIterator iter(isolate(), current, kStartAtPrototype,
877 PrototypeIterator::END_AT_NON_HIDDEN);
878 while (!iter.IsAtEnd()) {
879 if (iter.GetCurrent<JSReceiver>() == object)
return true;
886 Handle<Object> LookupIterator::FetchValue()
const {
887 Object* result =
nullptr;
889 Handle<JSObject> holder = GetHolder<JSObject>();
890 ElementsAccessor* accessor = holder->GetElementsAccessor();
891 return accessor->Get(holder, number_);
892 }
else if (holder_->IsJSGlobalObject()) {
893 Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>();
894 result = holder->global_dictionary()->ValueAt(number_);
895 }
else if (!holder_->HasFastProperties()) {
896 result = holder_->property_dictionary()->ValueAt(number_);
897 }
else if (property_details_.location() == kField) {
898 DCHECK_EQ(kData, property_details_.kind());
899 Handle<JSObject> holder = GetHolder<JSObject>();
900 FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_);
901 return JSObject::FastPropertyAt(holder, property_details_.representation(),
904 result = holder_->map()->instance_descriptors()->GetStrongValue(number_);
906 return handle(result, isolate_);
909 bool LookupIterator::IsConstFieldValueEqualTo(Object* value)
const {
910 DCHECK(!IsElement());
911 DCHECK(holder_->HasFastProperties());
912 DCHECK_EQ(kField, property_details_.location());
913 DCHECK_EQ(PropertyConstness::kConst, property_details_.constness());
914 Handle<JSObject> holder = GetHolder<JSObject>();
915 FieldIndex field_index = FieldIndex::ForDescriptor(holder->map(), number_);
916 if (property_details_.representation().IsDouble()) {
917 if (!value->IsNumber())
return false;
919 if (holder->IsUnboxedDoubleField(field_index)) {
920 bits = holder->RawFastDoublePropertyAsBitsAt(field_index);
922 Object* current_value = holder->RawFastPropertyAt(field_index);
923 DCHECK(current_value->IsMutableHeapNumber());
924 bits = MutableHeapNumber::cast(current_value)->value_as_bits();
931 if (bits == kHoleNanInt64) {
935 return bit_cast<
double>(bits) == value->Number();
937 Object* current_value = holder->RawFastPropertyAt(field_index);
938 return current_value->IsUninitialized(isolate()) || current_value == value;
942 int LookupIterator::GetFieldDescriptorIndex()
const {
943 DCHECK(has_property_);
944 DCHECK(holder_->HasFastProperties());
945 DCHECK_EQ(kField, property_details_.location());
946 DCHECK_EQ(kData, property_details_.kind());
947 return descriptor_number();
950 int LookupIterator::GetAccessorIndex()
const {
951 DCHECK(has_property_);
952 DCHECK(holder_->HasFastProperties());
953 DCHECK_EQ(kDescriptor, property_details_.location());
954 DCHECK_EQ(kAccessor, property_details_.kind());
955 return descriptor_number();
959 int LookupIterator::GetConstantIndex()
const {
960 DCHECK(has_property_);
961 DCHECK(holder_->HasFastProperties());
962 DCHECK_EQ(kDescriptor, property_details_.location());
963 DCHECK_EQ(kData, property_details_.kind());
964 DCHECK(!FLAG_track_constant_fields);
965 DCHECK(!IsElement());
966 return descriptor_number();
969 Handle<Map> LookupIterator::GetFieldOwnerMap()
const {
970 DCHECK(has_property_);
971 DCHECK(holder_->HasFastProperties());
972 DCHECK_EQ(kField, property_details_.location());
973 DCHECK(!IsElement());
974 Map holder_map = holder_->map();
975 return handle(holder_map->FindFieldOwner(isolate(), descriptor_number()),
979 FieldIndex LookupIterator::GetFieldIndex()
const {
980 DCHECK(has_property_);
981 DCHECK(holder_->HasFastProperties());
982 DCHECK_EQ(kField, property_details_.location());
983 DCHECK(!IsElement());
984 return FieldIndex::ForDescriptor(holder_->map(), descriptor_number());
987 Handle<FieldType> LookupIterator::GetFieldType()
const {
988 DCHECK(has_property_);
989 DCHECK(holder_->HasFastProperties());
990 DCHECK_EQ(kField, property_details_.location());
992 holder_->map()->instance_descriptors()->GetFieldType(descriptor_number()),
997 Handle<PropertyCell> LookupIterator::GetPropertyCell()
const {
998 DCHECK(!IsElement());
999 Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>();
1000 return handle(holder->global_dictionary()->CellAt(dictionary_entry()),
1005 Handle<Object> LookupIterator::GetAccessors()
const {
1006 DCHECK_EQ(ACCESSOR, state_);
1007 return FetchValue();
1011 Handle<Object> LookupIterator::GetDataValue()
const {
1012 DCHECK_EQ(DATA, state_);
1013 Handle<Object> value = FetchValue();
1017 void LookupIterator::WriteDataValue(Handle<Object> value,
1018 bool initializing_store) {
1019 DCHECK_EQ(DATA, state_);
1020 Handle<JSReceiver> holder = GetHolder<JSReceiver>();
1022 Handle<JSObject>
object = Handle<JSObject>::cast(holder);
1023 ElementsAccessor* accessor =
object->GetElementsAccessor();
1024 accessor->Set(
object, number_, *value);
1025 }
else if (holder->HasFastProperties()) {
1026 if (property_details_.location() == kField) {
1029 DCHECK_IMPLIES(!initializing_store && property_details_.constness() ==
1030 PropertyConstness::kConst,
1031 IsConstFieldValueEqualTo(*value));
1032 JSObject::cast(*holder)->WriteToField(descriptor_number(),
1033 property_details_, *value);
1035 DCHECK_EQ(kDescriptor, property_details_.location());
1036 DCHECK_EQ(PropertyConstness::kConst, property_details_.constness());
1038 }
else if (holder->IsJSGlobalObject()) {
1039 GlobalDictionary dictionary =
1040 JSGlobalObject::cast(*holder)->global_dictionary();
1041 dictionary->CellAt(dictionary_entry())->set_value(*value);
1043 DCHECK_IMPLIES(holder->IsJSProxy(), name()->IsPrivate());
1044 NameDictionary dictionary = holder->property_dictionary();
1045 dictionary->ValueAtPut(dictionary_entry(), *value);
1049 template <
bool is_element>
1050 bool LookupIterator::SkipInterceptor(JSObject* holder) {
1051 auto info = GetInterceptor<is_element>(holder);
1052 if (!is_element && name_->IsSymbol() && !info->can_intercept_symbols()) {
1055 if (info->non_masking()) {
1056 switch (interceptor_state_) {
1057 case InterceptorState::kUninitialized:
1058 interceptor_state_ = InterceptorState::kSkipNonMasking;
1060 case InterceptorState::kSkipNonMasking:
1062 case InterceptorState::kProcessNonMasking:
1066 return interceptor_state_ == InterceptorState::kProcessNonMasking;
1069 JSReceiver* LookupIterator::NextHolder(Map map) {
1070 DisallowHeapAllocation no_gc;
1071 if (map->prototype() == ReadOnlyRoots(heap()).null_value())
return nullptr;
1072 if (!check_prototype_chain() && !map->has_hidden_prototype())
return nullptr;
1073 return JSReceiver::cast(map->prototype());
1076 LookupIterator::State LookupIterator::NotFound(JSReceiver*
const holder)
const {
1077 DCHECK(!IsElement());
1078 if (!holder->IsJSTypedArray() || !name_->IsString())
return NOT_FOUND;
1080 Handle<String> name_string = Handle<String>::cast(name_);
1081 if (name_string->length() == 0)
return NOT_FOUND;
1083 return IsSpecialIndex(*name_string) ? INTEGER_INDEXED_EXOTIC : NOT_FOUND;
1088 template <
bool is_element>
1089 bool HasInterceptor(Map map) {
1090 return is_element ? map->has_indexed_interceptor()
1091 : map->has_named_interceptor();
1096 template <
bool is_element>
1097 LookupIterator::State LookupIterator::LookupInSpecialHolder(
1098 Map
const map, JSReceiver*
const holder) {
1099 STATIC_ASSERT(INTERCEPTOR == BEFORE_PROPERTY);
1102 if (map->IsJSProxyMap()) {
1103 if (is_element || !name_->IsPrivate())
return JSPROXY;
1105 if (map->is_access_check_needed()) {
1106 if (is_element || !name_->IsPrivate())
return ACCESS_CHECK;
1110 if (check_interceptor() && HasInterceptor<is_element>(map) &&
1111 !SkipInterceptor<is_element>(JSObject::cast(holder))) {
1112 if (is_element || !name_->IsPrivate())
return INTERCEPTOR;
1116 if (!is_element && map->IsJSGlobalObjectMap()) {
1117 GlobalDictionary dict =
1118 JSGlobalObject::cast(holder)->global_dictionary();
1119 int number = dict->FindEntry(isolate(), name_);
1120 if (number == GlobalDictionary::kNotFound)
return NOT_FOUND;
1121 number_ =
static_cast<uint32_t>(number);
1122 PropertyCell* cell = dict->CellAt(number_);
1123 if (cell->value()->IsTheHole(isolate_))
return NOT_FOUND;
1124 property_details_ = cell->property_details();
1125 has_property_ =
true;
1126 switch (property_details_.kind()) {
1127 case v8::internal::kData:
1129 case v8::internal::kAccessor:
1133 return LookupInRegularHolder<is_element>(map, holder);
1137 case INTEGER_INDEXED_EXOTIC:
1145 template <
bool is_element>
1146 LookupIterator::State LookupIterator::LookupInRegularHolder(
1147 Map
const map, JSReceiver*
const holder) {
1148 DisallowHeapAllocation no_gc;
1149 if (interceptor_state_ == InterceptorState::kProcessNonMasking) {
1154 JSObject* js_object = JSObject::cast(holder);
1155 ElementsAccessor* accessor = js_object->GetElementsAccessor();
1156 FixedArrayBase backing_store = js_object->elements();
1158 accessor->GetEntryForIndex(isolate_, js_object, backing_store, index_);
1159 if (number_ == kMaxUInt32) {
1160 return holder->IsJSTypedArray() ? INTEGER_INDEXED_EXOTIC : NOT_FOUND;
1162 property_details_ = accessor->GetDetails(js_object, number_);
1163 }
else if (!map->is_dictionary_map()) {
1164 DescriptorArray* descriptors = map->instance_descriptors();
1165 int number = descriptors->SearchWithCache(isolate_, *name_, map);
1166 if (number == DescriptorArray::kNotFound)
return NotFound(holder);
1167 number_ =
static_cast<uint32_t>(number);
1168 property_details_ = descriptors->GetDetails(number_);
1170 DCHECK_IMPLIES(holder->IsJSProxy(), name()->IsPrivate());
1171 NameDictionary dict = holder->property_dictionary();
1172 int number = dict->FindEntry(isolate(), name_);
1173 if (number == NameDictionary::kNotFound)
return NotFound(holder);
1174 number_ =
static_cast<uint32_t>(number);
1175 property_details_ = dict->DetailsAt(number_);
1177 has_property_ =
true;
1178 switch (property_details_.kind()) {
1179 case v8::internal::kData:
1181 case v8::internal::kAccessor:
1188 Handle<InterceptorInfo> LookupIterator::GetInterceptorForFailedAccessCheck()
1190 DCHECK_EQ(ACCESS_CHECK, state_);
1191 DisallowHeapAllocation no_gc;
1192 AccessCheckInfo* access_check_info =
1193 AccessCheckInfo::Get(isolate_, Handle<JSObject>::cast(holder_));
1194 if (access_check_info) {
1195 Object* interceptor = IsElement() ? access_check_info->indexed_interceptor()
1196 : access_check_info->named_interceptor();
1198 return handle(InterceptorInfo::cast(interceptor), isolate_);
1201 return Handle<InterceptorInfo>();
1204 bool LookupIterator::TryLookupCachedProperty() {
1205 return state() == LookupIterator::ACCESSOR &&
1206 GetAccessors()->IsAccessorPair() && LookupCachedProperty();
1209 bool LookupIterator::LookupCachedProperty() {
1210 DCHECK_EQ(state(), LookupIterator::ACCESSOR);
1211 DCHECK(GetAccessors()->IsAccessorPair());
1213 AccessorPair* accessor_pair = AccessorPair::cast(*GetAccessors());
1214 Handle<Object> getter(accessor_pair->getter(), isolate());
1215 MaybeHandle<Name> maybe_name =
1216 FunctionTemplateInfo::TryGetCachedPropertyName(isolate(), getter);
1217 if (maybe_name.is_null())
return false;
1220 name_ = maybe_name.ToHandleChecked();
1222 CHECK_EQ(state(), LookupIterator::DATA);