5 #include "src/ic/keyed-store-generic.h" 7 #include "src/code-factory.h" 8 #include "src/code-stub-assembler.h" 9 #include "src/contexts.h" 10 #include "src/feedback-vector.h" 11 #include "src/ic/accessor-assembler.h" 12 #include "src/interface-descriptors.h" 13 #include "src/isolate.h" 14 #include "src/objects-inl.h" 19 using Node = compiler::Node;
21 using TNode = compiler::TNode<T>;
23 enum class StoreMode { kOrdinary, kInLiteral };
31 void KeyedStoreGeneric();
33 void StoreIC_Uninitialized();
47 LanguageMode language_mode);
54 kIncrementLengthByOne,
58 enum UseStubCache { kUseStubCache, kDontUseStubCache };
66 void EmitGenericElementStore(
Node* receiver,
Node* receiver_map,
67 Node* instance_type,
Node* intptr_index,
82 EmitGenericPropertyStore(receiver, receiver_map, p, &direct_exit, slow,
83 Nothing<LanguageMode>());
86 void BranchIfPrototypesHaveNonFastElements(
Node* receiver_map,
87 Label* non_fast_elements,
88 Label* only_fast_elements);
90 void TryRewriteElements(
Node* receiver,
Node* receiver_map,
Node* elements,
91 Node* native_context, ElementsKind from_kind,
92 ElementsKind to_kind,
Label* bailout);
94 void StoreElementWithCapacity(
Node* receiver,
Node* receiver_map,
97 Label* slow, UpdateLength update_length);
99 void MaybeUpdateLengthAndReturn(
Node* receiver,
Node* index,
Node* value,
100 UpdateLength update_length);
102 void TryChangeToHoleyMapHelper(
Node* receiver,
Node* receiver_map,
103 Node* native_context, ElementsKind packed_kind,
104 ElementsKind holey_kind,
Label* done,
106 void TryChangeToHoleyMap(
Node* receiver,
Node* receiver_map,
107 Node* current_elements_kind,
Node* context,
108 ElementsKind packed_kind,
Label* bailout);
109 void TryChangeToHoleyMapMulti(
Node* receiver,
Node* receiver_map,
110 Node* current_elements_kind,
Node* context,
111 ElementsKind packed_kind,
112 ElementsKind packed_kind_2,
Label* bailout);
114 void LookupPropertyOnPrototypeChain(
Node* receiver_map,
Node* name,
124 bool IsKeyedStore()
const {
return mode_ == StoreMode::kOrdinary; }
125 bool IsStoreInLiteral()
const {
return mode_ == StoreMode::kInLiteral; }
127 bool ShouldCheckPrototype()
const {
return IsKeyedStore(); }
128 bool ShouldReconfigureExisting()
const {
return IsStoreInLiteral(); }
129 bool ShouldCallSetter()
const {
return IsKeyedStore(); }
130 bool ShouldCheckPrototypeValidity()
const {
133 return !IsStoreInLiteral();
139 assembler.KeyedStoreGeneric();
142 void StoreICUninitializedGenerator::Generate(
143 compiler::CodeAssemblerState* state) {
144 KeyedStoreGenericAssembler assembler(state, StoreMode::kOrdinary);
145 assembler.StoreIC_Uninitialized();
148 void KeyedStoreGenericGenerator::SetProperty(
149 compiler::CodeAssemblerState* state, TNode<Context> context,
150 TNode<JSReceiver> receiver, TNode<BoolT> is_simple_receiver,
151 TNode<Name> name, TNode<Object> value, LanguageMode language_mode) {
152 KeyedStoreGenericAssembler assembler(state, StoreMode::kOrdinary);
153 assembler.SetProperty(context, receiver, is_simple_receiver, name, value,
157 void KeyedStoreGenericGenerator::SetProperty(
158 compiler::CodeAssemblerState* state, TNode<Context> context,
159 TNode<Object> receiver, TNode<Object> key, TNode<Object> value,
160 LanguageMode language_mode) {
161 KeyedStoreGenericAssembler assembler(state, StoreMode::kOrdinary);
162 assembler.SetProperty(context, receiver, key, value, language_mode);
165 void KeyedStoreGenericGenerator::SetPropertyInLiteral(
166 compiler::CodeAssemblerState* state, TNode<Context> context,
167 TNode<JSObject> receiver, TNode<Object> key, TNode<Object> value) {
168 KeyedStoreGenericAssembler assembler(state, StoreMode::kInLiteral);
169 assembler.SetProperty(context, receiver, key, value, LanguageMode::kStrict);
172 void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements(
173 Node* receiver_map, Label* non_fast_elements, Label* only_fast_elements) {
174 VARIABLE(var_map, MachineRepresentation::kTagged);
175 var_map.Bind(receiver_map);
176 Label loop_body(
this, &var_map);
181 Node* map = var_map.value();
182 Node* prototype = LoadMapPrototype(map);
183 GotoIf(IsNull(prototype), only_fast_elements);
184 Node* prototype_map = LoadMap(prototype);
185 var_map.Bind(prototype_map);
186 TNode<Int32T> instance_type = LoadMapInstanceType(prototype_map);
187 GotoIf(IsCustomElementsReceiverInstanceType(instance_type),
189 Node* elements_kind = LoadMapElementsKind(prototype_map);
190 GotoIf(IsFastElementsKind(elements_kind), &loop_body);
191 GotoIf(Word32Equal(elements_kind, Int32Constant(NO_ELEMENTS)), &loop_body);
192 Goto(non_fast_elements);
196 void KeyedStoreGenericAssembler::TryRewriteElements(
197 Node* receiver, Node* receiver_map, Node* elements, Node* native_context,
198 ElementsKind from_kind, ElementsKind to_kind, Label* bailout) {
199 DCHECK(IsFastPackedElementsKind(from_kind));
200 ElementsKind holey_from_kind = GetHoleyElementsKind(from_kind);
201 ElementsKind holey_to_kind = GetHoleyElementsKind(to_kind);
202 if (AllocationSite::ShouldTrack(from_kind, to_kind)) {
203 TrapAllocationMemento(receiver, bailout);
205 Label perform_transition(
this), check_holey_map(
this);
206 VARIABLE(var_target_map, MachineRepresentation::kTagged);
209 Node* packed_map = LoadJSArrayElementsMap(from_kind, native_context);
210 GotoIf(WordNotEqual(receiver_map, packed_map), &check_holey_map);
212 LoadContextElement(native_context, Context::ArrayMapIndex(to_kind)));
213 Goto(&perform_transition);
217 BIND(&check_holey_map);
219 Node* holey_map = LoadContextElement(
220 native_context, Context::ArrayMapIndex(holey_from_kind));
221 GotoIf(WordNotEqual(receiver_map, holey_map), bailout);
222 var_target_map.Bind(LoadContextElement(
223 native_context, Context::ArrayMapIndex(holey_to_kind)));
224 Goto(&perform_transition);
228 BIND(&perform_transition);
230 if (IsDoubleElementsKind(from_kind) != IsDoubleElementsKind(to_kind)) {
231 Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
232 GrowElementsCapacity(receiver, elements, from_kind, to_kind, capacity,
233 capacity, INTPTR_PARAMETERS, bailout);
235 StoreMap(receiver, var_target_map.value());
239 void KeyedStoreGenericAssembler::TryChangeToHoleyMapHelper(
240 Node* receiver, Node* receiver_map, Node* native_context,
241 ElementsKind packed_kind, ElementsKind holey_kind, Label* done,
242 Label* map_mismatch, Label* bailout) {
243 Node* packed_map = LoadJSArrayElementsMap(packed_kind, native_context);
244 GotoIf(WordNotEqual(receiver_map, packed_map), map_mismatch);
245 if (AllocationSite::ShouldTrack(packed_kind, holey_kind)) {
246 TrapAllocationMemento(receiver, bailout);
249 LoadContextElement(native_context, Context::ArrayMapIndex(holey_kind));
250 StoreMap(receiver, holey_map);
254 void KeyedStoreGenericAssembler::TryChangeToHoleyMap(
255 Node* receiver, Node* receiver_map, Node* current_elements_kind,
256 Node* context, ElementsKind packed_kind, Label* bailout) {
257 ElementsKind holey_kind = GetHoleyElementsKind(packed_kind);
258 Label already_holey(
this);
260 GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind)),
262 Node* native_context = LoadNativeContext(context);
263 TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind,
264 holey_kind, &already_holey, bailout, bailout);
265 BIND(&already_holey);
268 void KeyedStoreGenericAssembler::TryChangeToHoleyMapMulti(
269 Node* receiver, Node* receiver_map, Node* current_elements_kind,
270 Node* context, ElementsKind packed_kind, ElementsKind packed_kind_2,
272 ElementsKind holey_kind = GetHoleyElementsKind(packed_kind);
273 ElementsKind holey_kind_2 = GetHoleyElementsKind(packed_kind_2);
274 Label already_holey(
this), check_other_kind(
this);
276 GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind)),
278 GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind_2)),
281 Node* native_context = LoadNativeContext(context);
282 TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind,
283 holey_kind, &already_holey, &check_other_kind,
285 BIND(&check_other_kind);
286 TryChangeToHoleyMapHelper(receiver, receiver_map, native_context,
287 packed_kind_2, holey_kind_2, &already_holey,
289 BIND(&already_holey);
292 void KeyedStoreGenericAssembler::MaybeUpdateLengthAndReturn(
293 Node* receiver, Node* index, Node* value, UpdateLength update_length) {
294 if (update_length != kDontChangeLength) {
295 Node* new_length = SmiTag(Signed(IntPtrAdd(index, IntPtrConstant(1))));
296 StoreObjectFieldNoWriteBarrier(receiver, JSArray::kLengthOffset, new_length,
297 MachineRepresentation::kTagged);
302 void KeyedStoreGenericAssembler::StoreElementWithCapacity(
303 Node* receiver, Node* receiver_map, Node* elements, Node* elements_kind,
304 Node* intptr_index, Node* value, Node* context, Label* slow,
305 UpdateLength update_length) {
306 if (update_length != kDontChangeLength) {
307 CSA_ASSERT(
this, InstanceTypeEqual(LoadMapInstanceType(receiver_map),
311 GotoIf(IsDictionaryMap(receiver_map), slow);
314 TNode<DescriptorArray> descriptors = LoadMapDescriptors(receiver_map);
315 TNode<Uint32T> details = LoadDetailsByDescriptorEntry(descriptors, 0);
316 GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask),
319 STATIC_ASSERT(FixedArray::kHeaderSize == FixedDoubleArray::kHeaderSize);
320 const int kHeaderSize = FixedArray::kHeaderSize - kHeapObjectTag;
322 Label check_double_elements(
this), check_cow_elements(
this);
323 Node* elements_map = LoadMap(elements);
324 GotoIf(WordNotEqual(elements_map, LoadRoot(RootIndex::kFixedArrayMap)),
325 &check_double_elements);
329 Node* offset = ElementOffsetFromIndex(intptr_index, PACKED_ELEMENTS,
330 INTPTR_PARAMETERS, kHeaderSize);
336 Label hole_check_passed(
this);
337 if (update_length == kDontChangeLength) {
338 Node* element = Load(MachineType::AnyTagged(), elements, offset);
339 GotoIf(WordNotEqual(element, TheHoleConstant()), &hole_check_passed);
341 BranchIfPrototypesHaveNonFastElements(receiver_map, slow,
343 BIND(&hole_check_passed);
349 Label non_smi_value(
this);
350 GotoIfNot(TaggedIsSmi(value), &non_smi_value);
352 if (update_length == kBumpLengthWithGap) {
353 TryChangeToHoleyMapMulti(receiver, receiver_map, elements_kind, context,
354 PACKED_SMI_ELEMENTS, PACKED_ELEMENTS, slow);
356 StoreNoWriteBarrier(MachineRepresentation::kTagged, elements, offset,
358 MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
360 BIND(&non_smi_value);
365 Label must_transition(
this);
366 STATIC_ASSERT(PACKED_SMI_ELEMENTS == 0);
367 STATIC_ASSERT(HOLEY_SMI_ELEMENTS == 1);
368 GotoIf(Int32LessThanOrEqual(elements_kind,
369 Int32Constant(HOLEY_SMI_ELEMENTS)),
371 if (update_length == kBumpLengthWithGap) {
372 TryChangeToHoleyMap(receiver, receiver_map, elements_kind, context,
373 PACKED_ELEMENTS, slow);
375 Store(elements, offset, value);
376 MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
378 BIND(&must_transition);
383 Label transition_to_double(
this), transition_to_object(
this);
384 Node* native_context = LoadNativeContext(context);
385 Branch(WordEqual(LoadMap(value), LoadRoot(RootIndex::kHeapNumberMap)),
386 &transition_to_double, &transition_to_object);
387 BIND(&transition_to_double);
391 ElementsKind target_kind = update_length == kBumpLengthWithGap
392 ? HOLEY_DOUBLE_ELEMENTS
393 : PACKED_DOUBLE_ELEMENTS;
394 TryRewriteElements(receiver, receiver_map, elements, native_context,
395 PACKED_SMI_ELEMENTS, target_kind, slow);
397 Node* double_elements = LoadElements(receiver);
398 Node* double_offset =
399 ElementOffsetFromIndex(intptr_index, PACKED_DOUBLE_ELEMENTS,
400 INTPTR_PARAMETERS, kHeaderSize);
402 Node* double_value = Float64SilenceNaN(LoadHeapNumberValue(value));
403 StoreNoWriteBarrier(MachineRepresentation::kFloat64, double_elements,
404 double_offset, double_value);
405 MaybeUpdateLengthAndReturn(receiver, intptr_index, value,
409 BIND(&transition_to_object);
413 ElementsKind target_kind = update_length == kBumpLengthWithGap
416 TryRewriteElements(receiver, receiver_map, elements, native_context,
417 PACKED_SMI_ELEMENTS, target_kind, slow);
419 CSA_ASSERT(
this, WordEqual(elements, LoadElements(receiver)));
420 Store(elements, offset, value);
421 MaybeUpdateLengthAndReturn(receiver, intptr_index, value,
427 BIND(&check_double_elements);
428 Node* fixed_double_array_map = LoadRoot(RootIndex::kFixedDoubleArrayMap);
429 GotoIf(WordNotEqual(elements_map, fixed_double_array_map),
430 &check_cow_elements);
433 Node* offset = ElementOffsetFromIndex(intptr_index, PACKED_DOUBLE_ELEMENTS,
434 INTPTR_PARAMETERS, kHeaderSize);
438 Label hole_check_passed(
this);
441 if (update_length == kDontChangeLength) {
442 Label found_hole(
this);
443 LoadDoubleWithHoleCheck(elements, offset, &found_hole,
444 MachineType::None());
445 Goto(&hole_check_passed);
448 BranchIfPrototypesHaveNonFastElements(receiver_map, slow,
450 BIND(&hole_check_passed);
455 Label non_number_value(
this);
456 Node* double_value = TryTaggedToFloat64(value, &non_number_value);
459 double_value = Float64SilenceNaN(double_value);
461 if (update_length == kBumpLengthWithGap) {
462 TryChangeToHoleyMap(receiver, receiver_map, elements_kind, context,
463 PACKED_DOUBLE_ELEMENTS, slow);
465 StoreNoWriteBarrier(MachineRepresentation::kFloat64, elements, offset,
467 MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
469 BIND(&non_number_value);
474 Node* native_context = LoadNativeContext(context);
475 ElementsKind target_kind = update_length == kBumpLengthWithGap
478 TryRewriteElements(receiver, receiver_map, elements, native_context,
479 PACKED_DOUBLE_ELEMENTS, target_kind, slow);
481 Node* fast_elements = LoadElements(receiver);
482 Node* fast_offset = ElementOffsetFromIndex(
483 intptr_index, PACKED_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize);
484 Store(fast_elements, fast_offset, value);
485 MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
489 BIND(&check_cow_elements);
496 void KeyedStoreGenericAssembler::EmitGenericElementStore(
497 Node* receiver, Node* receiver_map, Node* instance_type, Node* intptr_index,
498 Node* value, Node* context, Label* slow) {
499 Label if_fast(
this), if_in_bounds(
this), if_out_of_bounds(
this),
500 if_increment_length_by_one(
this), if_bump_length_with_gap(
this),
501 if_grow(
this), if_nonfast(
this), if_typed_array(
this),
503 Node* elements = LoadElements(receiver);
504 Node* elements_kind = LoadMapElementsKind(receiver_map);
505 Branch(IsFastElementsKind(elements_kind), &if_fast, &if_nonfast);
508 Label if_array(
this);
509 GotoIf(InstanceTypeEqual(instance_type, JS_ARRAY_TYPE), &if_array);
511 Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
512 Branch(UintPtrLessThan(intptr_index, capacity), &if_in_bounds,
517 Node* length = SmiUntag(LoadFastJSArrayLength(receiver));
518 GotoIf(UintPtrLessThan(intptr_index, length), &if_in_bounds);
519 Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
520 GotoIf(UintPtrGreaterThanOrEqual(intptr_index, capacity), &if_grow);
521 Branch(WordEqual(intptr_index, length), &if_increment_length_by_one,
522 &if_bump_length_with_gap);
527 StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
528 intptr_index, value, context, slow,
532 BIND(&if_out_of_bounds);
538 GotoIfNot(InstanceTypeEqual(instance_type, JS_TYPED_ARRAY_TYPE), &if_grow);
542 BIND(&if_increment_length_by_one);
544 StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
545 intptr_index, value, context, slow,
546 kIncrementLengthByOne);
549 BIND(&if_bump_length_with_gap);
551 StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
552 intptr_index, value, context, slow,
562 Comment(
"Grow backing store");
571 STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
572 GotoIf(Int32GreaterThanOrEqual(
574 Int32Constant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)),
576 GotoIf(Word32Equal(elements_kind, Int32Constant(DICTIONARY_ELEMENTS)),
581 BIND(&if_dictionary);
583 Comment(
"Dictionary");
588 BIND(&if_typed_array);
590 Comment(
"Typed array");
596 void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
597 Node* receiver_map, Node* name, Label* accessor,
598 Variable* var_accessor_pair, Variable* var_accessor_holder, Label* readonly,
600 Label ok_to_write(
this);
601 VARIABLE(var_holder, MachineRepresentation::kTagged);
602 var_holder.Bind(LoadMapPrototype(receiver_map));
603 VARIABLE(var_holder_map, MachineRepresentation::kTagged);
604 var_holder_map.Bind(LoadMap(var_holder.value()));
606 Variable* merged_variables[] = {&var_holder, &var_holder_map};
607 Label loop(
this, arraysize(merged_variables), merged_variables);
611 Node* holder = var_holder.value();
612 GotoIf(IsNull(holder), &ok_to_write);
613 Node* holder_map = var_holder_map.value();
614 Node* instance_type = LoadMapInstanceType(holder_map);
615 Label next_proto(
this);
617 Label found(
this), found_fast(
this), found_dict(
this), found_global(
this);
618 TVARIABLE(HeapObject, var_meta_storage);
619 TVARIABLE(IntPtrT, var_entry);
620 TryLookupProperty(holder, holder_map, instance_type, name, &found_fast,
621 &found_dict, &found_global, &var_meta_storage,
622 &var_entry, &next_proto, bailout);
625 TNode<DescriptorArray> descriptors = CAST(var_meta_storage.value());
626 TNode<IntPtrT> name_index = var_entry.value();
627 Node* details = LoadDetailsByKeyIndex(descriptors, name_index);
628 JumpIfDataProperty(details, &ok_to_write, readonly);
633 VARIABLE(var_details, MachineRepresentation::kWord32);
634 LoadPropertyFromFastObject(holder, holder_map, descriptors, name_index,
635 &var_details, var_accessor_pair);
636 var_accessor_holder->Bind(holder);
642 Node* dictionary = var_meta_storage.value();
643 Node* entry = var_entry.value();
645 LoadDetailsByKeyIndex<NameDictionary>(dictionary, entry);
646 JumpIfDataProperty(details, &ok_to_write, readonly);
648 if (accessor !=
nullptr) {
650 var_accessor_pair->Bind(
651 LoadValueByKeyIndex<NameDictionary>(dictionary, entry));
652 var_accessor_holder->Bind(holder);
661 Node* dictionary = var_meta_storage.value();
662 Node* entry = var_entry.value();
663 Node* property_cell =
664 LoadValueByKeyIndex<GlobalDictionary>(dictionary, entry);
666 LoadObjectField(property_cell, PropertyCell::kValueOffset);
667 GotoIf(WordEqual(value, TheHoleConstant()), &next_proto);
668 Node* details = LoadAndUntagToWord32ObjectField(
669 property_cell, PropertyCell::kDetailsOffset);
670 JumpIfDataProperty(details, &ok_to_write, readonly);
672 if (accessor !=
nullptr) {
674 var_accessor_pair->Bind(value);
675 var_accessor_holder->Bind(holder);
685 GotoIf(InstanceTypeEqual(instance_type, JS_TYPED_ARRAY_TYPE), bailout);
686 Node* proto = LoadMapPrototype(holder_map);
687 GotoIf(IsNull(proto), &ok_to_write);
688 var_holder.Bind(proto);
689 var_holder_map.Bind(LoadMap(proto));
695 TNode<Map> KeyedStoreGenericAssembler::FindCandidateStoreICTransitionMapHandler(
696 TNode<Map> map, TNode<Name> name, Label* slow) {
697 TVARIABLE(Map, var_transition_map);
698 Label simple_transition(
this), transition_array(
this),
699 found_handler_candidate(
this);
701 TNode<MaybeObject> maybe_handler =
702 LoadMaybeWeakObjectField(map, Map::kTransitionsOrPrototypeInfoOffset);
708 TVARIABLE(Object, var_transition_map_or_array);
709 DispatchMaybeObject(maybe_handler, slow, slow, &simple_transition,
710 &transition_array, &var_transition_map_or_array);
712 BIND(&simple_transition);
714 var_transition_map = CAST(var_transition_map_or_array.value());
715 Goto(&found_handler_candidate);
718 BIND(&transition_array);
720 TNode<Map> maybe_handler_map =
721 LoadMap(CAST(var_transition_map_or_array.value()));
722 GotoIfNot(IsTransitionArrayMap(maybe_handler_map), slow);
724 TVARIABLE(IntPtrT, var_name_index);
725 Label if_found_candidate(
this);
726 TNode<TransitionArray> transitions =
727 CAST(var_transition_map_or_array.value());
728 TransitionLookup(name, transitions, &if_found_candidate, &var_name_index,
731 BIND(&if_found_candidate);
744 STATIC_ASSERT(kData == 0);
745 STATIC_ASSERT(NONE == 0);
746 const int kKeyToTargetOffset = (TransitionArray::kEntryTargetIndex -
747 TransitionArray::kEntryKeyIndex) *
749 var_transition_map = CAST(GetHeapObjectAssumeWeak(
750 LoadArrayElement(transitions, WeakFixedArray::kHeaderSize,
751 var_name_index.value(), kKeyToTargetOffset)));
752 Goto(&found_handler_candidate);
756 BIND(&found_handler_candidate);
757 return var_transition_map.value();
760 void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
761 TNode<JSReceiver> receiver, TNode<Map> receiver_map,
762 const StoreICParameters* p, ExitPoint* exit_point, Label* slow,
763 Maybe<LanguageMode> maybe_language_mode) {
764 CSA_ASSERT(
this, IsSimpleObjectMap(receiver_map));
765 VARIABLE(var_accessor_pair, MachineRepresentation::kTagged);
766 VARIABLE(var_accessor_holder, MachineRepresentation::kTagged);
767 Label fast_properties(
this), dictionary_properties(
this), accessor(
this),
769 Node* bitfield3 = LoadMapBitField3(receiver_map);
770 Branch(IsSetWord32<Map::IsDictionaryMapBit>(bitfield3),
771 &dictionary_properties, &fast_properties);
773 BIND(&fast_properties);
775 Comment(
"fast property store");
776 TNode<DescriptorArray> descriptors = LoadMapDescriptors(receiver_map);
777 Label descriptor_found(
this), lookup_transition(
this);
778 TVARIABLE(IntPtrT, var_name_index);
779 DescriptorLookup(p->name, descriptors, bitfield3, &descriptor_found,
780 &var_name_index, &lookup_transition);
782 BIND(&descriptor_found);
784 TNode<IntPtrT> name_index = var_name_index.value();
785 Node* details = LoadDetailsByKeyIndex(descriptors, name_index);
786 Label data_property(
this);
787 JumpIfDataProperty(details, &data_property,
788 ShouldReconfigureExisting() ?
nullptr : &readonly);
790 if (ShouldCallSetter()) {
793 VARIABLE(var_details, MachineRepresentation::kWord32);
794 LoadPropertyFromFastObject(receiver, receiver_map, descriptors,
795 name_index, &var_details,
797 var_accessor_holder.Bind(receiver);
800 Goto(&data_property);
803 BIND(&data_property);
805 CheckForAssociatedProtector(p->name, slow);
806 OverwriteExistingFastDataProperty(receiver, receiver_map, descriptors,
807 name_index, details, p->value, slow,
809 exit_point->Return(p->value);
812 BIND(&lookup_transition);
814 Comment(
"lookup transition");
815 TNode<Map> transition_map = FindCandidateStoreICTransitionMapHandler(
816 receiver_map, CAST(p->name), slow);
819 StoreTransitionMapFlags flags = kValidateTransitionHandler;
820 if (ShouldCheckPrototypeValidity()) {
821 flags = StoreTransitionMapFlags(flags | kCheckPrototypeValidity);
823 HandleStoreICTransitionMapHandlerCase(p, transition_map, slow, flags);
824 exit_point->Return(p->value);
828 BIND(&dictionary_properties);
830 Comment(
"dictionary property store");
834 TVARIABLE(IntPtrT, var_name_index);
835 Label dictionary_found(
this, &var_name_index), not_found(
this);
836 TNode<NameDictionary> properties = CAST(LoadSlowProperties(CAST(receiver)));
837 NameDictionaryLookup<NameDictionary>(properties, CAST(p->name),
838 &dictionary_found, &var_name_index,
840 BIND(&dictionary_found);
842 Label overwrite(
this);
843 TNode<Uint32T> details = LoadDetailsByKeyIndex<NameDictionary>(
844 properties, var_name_index.value());
845 JumpIfDataProperty(details, &overwrite,
846 ShouldReconfigureExisting() ?
nullptr : &readonly);
848 if (ShouldCallSetter()) {
850 var_accessor_pair.Bind(LoadValueByKeyIndex<NameDictionary>(
851 properties, var_name_index.value()));
852 var_accessor_holder.Bind(receiver);
860 CheckForAssociatedProtector(p->name, slow);
861 StoreValueByKeyIndex<NameDictionary>(properties, var_name_index.value(),
863 exit_point->Return(p->value);
869 CheckForAssociatedProtector(p->name, slow);
870 Label extensible(
this);
871 Node* bitfield2 = LoadMapBitField2(receiver_map);
872 GotoIf(IsPrivateSymbol(p->name), &extensible);
873 Branch(IsSetWord32<Map::IsExtensibleBit>(bitfield2), &extensible, slow);
876 if (ShouldCheckPrototype()) {
877 DCHECK(ShouldCallSetter());
878 LookupPropertyOnPrototypeChain(
879 receiver_map, p->name, &accessor, &var_accessor_pair,
880 &var_accessor_holder,
881 ShouldReconfigureExisting() ?
nullptr : &readonly, slow);
883 Label add_dictionary_property_slow(
this);
884 InvalidateValidityCellIfPrototype(receiver_map, bitfield2);
885 Add<NameDictionary>(properties, CAST(p->name), p->value,
886 &add_dictionary_property_slow);
887 exit_point->Return(p->value);
889 BIND(&add_dictionary_property_slow);
890 exit_point->ReturnCallRuntime(Runtime::kAddDictionaryProperty, p->context,
891 p->receiver, p->name, p->value);
895 if (ShouldCallSetter()) {
898 Label not_callable(
this);
899 Node* accessor_pair = var_accessor_pair.value();
900 GotoIf(IsAccessorInfoMap(LoadMap(accessor_pair)), slow);
901 CSA_ASSERT(
this, HasInstanceType(accessor_pair, ACCESSOR_PAIR_TYPE));
903 LoadObjectField(accessor_pair, AccessorPair::kSetterOffset);
904 Node* setter_map = LoadMap(setter);
906 GotoIf(IsFunctionTemplateInfoMap(setter_map), slow);
907 GotoIfNot(IsCallableMap(setter_map), ¬_callable);
909 Callable callable = CodeFactory::Call(isolate());
910 CallJS(callable, p->context, setter, receiver, p->value);
911 exit_point->Return(p->value);
915 bool handle_strict =
true;
917 LanguageMode language_mode;
918 if (maybe_language_mode.To(&language_mode)) {
919 if (language_mode == LanguageMode::kStrict) {
922 handle_strict =
false;
923 exit_point->Return(p->value);
926 BranchIfStrictMode(p->vector, p->slot, &strict);
927 exit_point->Return(p->value);
933 exit_point->ReturnCallRuntime(
934 Runtime::kThrowTypeError, p->context,
935 SmiConstant(MessageTemplate::kNoSetterInCallback), p->name,
936 var_accessor_holder.value());
943 if (!ShouldReconfigureExisting()) {
946 bool handle_strict =
true;
948 LanguageMode language_mode;
949 if (maybe_language_mode.To(&language_mode)) {
950 if (language_mode == LanguageMode::kStrict) {
953 handle_strict =
false;
954 exit_point->Return(p->value);
957 BranchIfStrictMode(p->vector, p->slot, &strict);
958 exit_point->Return(p->value);
963 Node* type = Typeof(p->receiver);
964 ThrowTypeError(p->context, MessageTemplate::kStrictReadOnlyProperty,
965 p->name, type, p->receiver);
973 void KeyedStoreGenericAssembler::KeyedStoreGeneric(
974 TNode<Context> context, TNode<Object> receiver, TNode<Object> key,
975 TNode<Object> value, Maybe<LanguageMode> language_mode, TNode<Smi> slot,
976 TNode<FeedbackVector> vector) {
977 TVARIABLE(IntPtrT, var_index);
978 TVARIABLE(Object, var_unique, key);
979 Label if_index(
this), if_unique_name(
this), not_internalized(
this),
982 GotoIf(TaggedIsSmi(receiver), &slow);
983 TNode<Map> receiver_map = LoadMap(CAST(receiver));
984 TNode<Int32T> instance_type = LoadMapInstanceType(receiver_map);
987 GotoIf(IsCustomElementsReceiverInstanceType(instance_type), &slow);
989 TryToName(key, &if_index, &var_index, &if_unique_name, &var_unique, &slow,
994 Comment(
"integer index");
995 EmitGenericElementStore(receiver, receiver_map, instance_type,
996 var_index.value(), value, context, &slow);
999 BIND(&if_unique_name);
1001 Comment(
"key is unique name");
1002 StoreICParameters p(context, receiver, var_unique.value(), value, slot,
1004 ExitPoint direct_exit(
this);
1005 EmitGenericPropertyStore(CAST(receiver), receiver_map, &p, &direct_exit,
1006 &slow, language_mode);
1009 BIND(¬_internalized);
1011 if (FLAG_internalize_on_the_fly) {
1012 TryInternalizeString(key, &if_index, &var_index, &if_unique_name,
1013 &var_unique, &slow, &slow);
1021 if (IsKeyedStore()) {
1022 Comment(
"KeyedStoreGeneric_slow");
1023 if (language_mode.IsJust()) {
1024 TailCallRuntime(Runtime::kSetKeyedProperty, context, receiver, key,
1025 value, SmiConstant(language_mode.FromJust()));
1027 TVARIABLE(Smi, var_language_mode, SmiConstant(LanguageMode::kStrict));
1028 Label call_runtime(
this);
1029 BranchIfStrictMode(vector, slot, &call_runtime);
1030 var_language_mode = SmiConstant(LanguageMode::kSloppy);
1031 Goto(&call_runtime);
1032 BIND(&call_runtime);
1033 TailCallRuntime(Runtime::kSetKeyedProperty, context, receiver, key,
1034 value, var_language_mode.value());
1037 DCHECK(IsStoreInLiteral());
1038 TailCallRuntime(Runtime::kStoreDataPropertyInLiteral, context, receiver,
1044 void KeyedStoreGenericAssembler::KeyedStoreGeneric() {
1045 typedef StoreWithVectorDescriptor Descriptor;
1047 TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
1048 TNode<Object> name = CAST(Parameter(Descriptor::kName));
1049 TNode<Object> value = CAST(Parameter(Descriptor::kValue));
1050 TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
1051 TNode<FeedbackVector> vector = CAST(Parameter(Descriptor::kVector));
1052 TNode<Context> context = CAST(Parameter(Descriptor::kContext));
1054 KeyedStoreGeneric(context, receiver, name, value, Nothing<LanguageMode>(),
1058 void KeyedStoreGenericAssembler::SetProperty(TNode<Context> context,
1059 TNode<Object> receiver,
1061 TNode<Object> value,
1062 LanguageMode language_mode) {
1063 KeyedStoreGeneric(context, receiver, key, value, Just(language_mode),
1064 TNode<Smi>(), TNode<FeedbackVector>());
1067 void KeyedStoreGenericAssembler::StoreIC_Uninitialized() {
1068 typedef StoreWithVectorDescriptor Descriptor;
1070 Node* receiver = Parameter(Descriptor::kReceiver);
1071 Node* name = Parameter(Descriptor::kName);
1072 Node* value = Parameter(Descriptor::kValue);
1073 Node* slot = Parameter(Descriptor::kSlot);
1074 Node* vector = Parameter(Descriptor::kVector);
1075 Node* context = Parameter(Descriptor::kContext);
1079 GotoIf(TaggedIsSmi(receiver), &miss);
1080 Node* receiver_map = LoadMap(receiver);
1081 TNode<Int32T> instance_type = LoadMapInstanceType(receiver_map);
1084 GotoIf(IsSpecialReceiverInstanceType(instance_type), &miss);
1087 StoreFeedbackVectorSlot(vector, slot,
1088 LoadRoot(RootIndex::kpremonomorphic_symbol),
1089 SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
1091 StoreICParameters p(context, receiver, name, value, slot, vector);
1092 EmitGenericPropertyStore(receiver, receiver_map, &p, &miss);
1097 StoreFeedbackVectorSlot(vector, slot,
1098 LoadRoot(RootIndex::kuninitialized_symbol),
1099 SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
1100 TailCallRuntime(Runtime::kStoreIC_Miss, context, value, slot, vector,
1105 void KeyedStoreGenericAssembler::SetProperty(TNode<Context> context,
1106 TNode<JSReceiver> receiver,
1107 TNode<BoolT> is_simple_receiver,
1108 TNode<Name> unique_name,
1109 TNode<Object> value,
1110 LanguageMode language_mode) {
1111 StoreICParameters p(context, receiver, unique_name, value,
nullptr,
nullptr);
1113 Label done(
this), slow(
this, Label::kDeferred);
1114 ExitPoint exit_point(
this, [&](Node* result) { Goto(&done); });
1116 CSA_ASSERT(
this, Word32Equal(is_simple_receiver,
1117 IsSimpleObjectMap(LoadMap(receiver))));
1118 GotoIfNot(is_simple_receiver, &slow);
1120 EmitGenericPropertyStore(receiver, LoadMap(receiver), &p, &exit_point, &slow,
1121 Just(language_mode));
1125 if (IsStoreInLiteral()) {
1126 CallRuntime(Runtime::kStoreDataPropertyInLiteral, context, receiver,
1127 unique_name, value);
1129 CallRuntime(Runtime::kSetKeyedProperty, context, receiver, unique_name,
1130 value, SmiConstant(language_mode));