OLD | NEW |
---|---|
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/ic/keyed-store-generic.h" | 5 #include "src/ic/keyed-store-generic.h" |
6 | 6 |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/code-stub-assembler.h" | 8 #include "src/code-stub-assembler.h" |
9 #include "src/contexts.h" | 9 #include "src/contexts.h" |
10 #include "src/ic/accessor-assembler.h" | 10 #include "src/ic/accessor-assembler.h" |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
65 Node* current_elements_kind, Node* context, | 65 Node* current_elements_kind, Node* context, |
66 ElementsKind packed_kind, | 66 ElementsKind packed_kind, |
67 ElementsKind packed_kind_2, Label* bailout); | 67 ElementsKind packed_kind_2, Label* bailout); |
68 | 68 |
69 void JumpIfDataProperty(Node* details, Label* writable, Label* readonly); | 69 void JumpIfDataProperty(Node* details, Label* writable, Label* readonly); |
70 void LookupPropertyOnPrototypeChain(Node* receiver_map, Node* name, | 70 void LookupPropertyOnPrototypeChain(Node* receiver_map, Node* name, |
71 Label* accessor, | 71 Label* accessor, |
72 Variable* var_accessor_pair, | 72 Variable* var_accessor_pair, |
73 Variable* var_accessor_holder, | 73 Variable* var_accessor_holder, |
74 Label* readonly, Label* bailout); | 74 Label* readonly, Label* bailout); |
75 | |
76 void CheckFieldType(Node* descriptors, Node* name_index, Node* representation, | |
77 Node* value, Label* bailout); | |
78 void OverwriteExistingFastProperty(Node* object, Node* object_map, | |
79 Node* properties, Node* descriptors, | |
80 Node* descriptor_name_index, Node* details, | |
81 Node* value, Label* slow); | |
75 }; | 82 }; |
76 | 83 |
77 void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state, | 84 void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state, |
78 LanguageMode language_mode) { | 85 LanguageMode language_mode) { |
79 KeyedStoreGenericAssembler assembler(state); | 86 KeyedStoreGenericAssembler assembler(state); |
80 assembler.KeyedStoreGeneric(language_mode); | 87 assembler.KeyedStoreGeneric(language_mode); |
81 } | 88 } |
82 | 89 |
83 void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements( | 90 void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements( |
84 Node* receiver_map, Label* non_fast_elements, Label* only_fast_elements) { | 91 Node* receiver_map, Label* non_fast_elements, Label* only_fast_elements) { |
(...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
537 &var_entry, &next_proto, bailout); | 544 &var_entry, &next_proto, bailout); |
538 Bind(&found_fast); | 545 Bind(&found_fast); |
539 { | 546 { |
540 Node* descriptors = var_meta_storage.value(); | 547 Node* descriptors = var_meta_storage.value(); |
541 Node* name_index = var_entry.value(); | 548 Node* name_index = var_entry.value(); |
542 Node* details = | 549 Node* details = |
543 LoadDetailsByKeyIndex<DescriptorArray>(descriptors, name_index); | 550 LoadDetailsByKeyIndex<DescriptorArray>(descriptors, name_index); |
544 JumpIfDataProperty(details, &ok_to_write, readonly); | 551 JumpIfDataProperty(details, &ok_to_write, readonly); |
545 | 552 |
546 // Accessor case. | 553 // Accessor case. |
554 // TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject. | |
547 Variable var_details(this, MachineRepresentation::kWord32); | 555 Variable var_details(this, MachineRepresentation::kWord32); |
548 LoadPropertyFromFastObject(holder, holder_map, descriptors, name_index, | 556 LoadPropertyFromFastObject(holder, holder_map, descriptors, name_index, |
549 &var_details, var_accessor_pair); | 557 &var_details, var_accessor_pair); |
550 var_accessor_holder->Bind(holder); | 558 var_accessor_holder->Bind(holder); |
551 Goto(accessor); | 559 Goto(accessor); |
552 } | 560 } |
553 | 561 |
554 Bind(&found_dict); | 562 Bind(&found_dict); |
555 { | 563 { |
556 Node* dictionary = var_meta_storage.value(); | 564 Node* dictionary = var_meta_storage.value(); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
592 bailout); | 600 bailout); |
593 Node* proto = LoadMapPrototype(holder_map); | 601 Node* proto = LoadMapPrototype(holder_map); |
594 GotoIf(WordEqual(proto, NullConstant()), &ok_to_write); | 602 GotoIf(WordEqual(proto, NullConstant()), &ok_to_write); |
595 var_holder.Bind(proto); | 603 var_holder.Bind(proto); |
596 var_holder_map.Bind(LoadMap(proto)); | 604 var_holder_map.Bind(LoadMap(proto)); |
597 Goto(&loop); | 605 Goto(&loop); |
598 } | 606 } |
599 Bind(&ok_to_write); | 607 Bind(&ok_to_write); |
600 } | 608 } |
601 | 609 |
610 void KeyedStoreGenericAssembler::CheckFieldType(Node* descriptors, | |
611 Node* name_index, | |
612 Node* representation, | |
613 Node* value, Label* bailout) { | |
614 Label r_smi(this), r_double(this), r_heapobject(this), all_fine(this); | |
615 if (FLAG_track_fields) { | |
616 GotoIf(Word32Equal(representation, Int32Constant(Representation::kSmi)), | |
617 &r_smi); | |
618 } | |
619 if (FLAG_track_double_fields) { | |
620 GotoIf(Word32Equal(representation, Int32Constant(Representation::kDouble)), | |
621 &r_double); | |
622 } | |
623 if (FLAG_track_heap_object_fields) { | |
624 GotoIf( | |
625 Word32Equal(representation, Int32Constant(Representation::kHeapObject)), | |
626 &r_heapobject); | |
627 } | |
628 if (FLAG_track_fields) { | |
629 GotoIf(Word32Equal(representation, Int32Constant(Representation::kNone)), | |
630 bailout); | |
631 } | |
Igor Sheludko
2017/02/16 16:04:37
CSA_ASSERT(representation == kTagged)?
Jakob Kummerow
2017/02/16 18:24:27
Done.
| |
632 Goto(&all_fine); | |
633 | |
634 Bind(&r_smi); | |
Igor Sheludko
2017/02/16 16:04:37
1) "if (FLAG_track_fields) {" or we will have an u
Jakob Kummerow
2017/02/16 18:24:27
I agree, but as discussed, that unfortunately does
| |
635 { Branch(TaggedIsSmi(value), &all_fine, bailout); } | |
636 | |
637 Bind(&r_double); | |
Igor Sheludko
2017/02/16 16:04:37
Same here.
| |
638 { | |
639 GotoIf(TaggedIsSmi(value), &all_fine); | |
640 Node* value_map = LoadMap(value); | |
641 // While supporting mutable HeapNumbers would be straightforward, such | |
642 // objects should not end up here anyway. | |
643 CSA_ASSERT(this, | |
644 WordNotEqual(value_map, | |
645 LoadRoot(Heap::kMutableHeapNumberMapRootIndex))); | |
646 Branch(IsHeapNumberMap(value_map), &all_fine, bailout); | |
647 } | |
648 | |
649 Bind(&r_heapobject); | |
Igor Sheludko
2017/02/16 16:04:37
Same here.
| |
650 { | |
651 GotoIf(TaggedIsSmi(value), bailout); | |
652 Node* field_type = | |
653 LoadValueByKeyIndex<DescriptorArray>(descriptors, name_index); | |
654 intptr_t kNoneType = reinterpret_cast<intptr_t>(FieldType::None()); | |
655 intptr_t kAnyType = reinterpret_cast<intptr_t>(FieldType::Any()); | |
656 // FieldType::None can't hold any value. | |
657 GotoIf(WordEqual(field_type, IntPtrConstant(kNoneType)), bailout); | |
658 // FieldType::Any can hold any value. | |
659 GotoIf(WordEqual(field_type, IntPtrConstant(kAnyType)), &all_fine); | |
660 CSA_ASSERT(this, IsWeakCell(field_type)); | |
661 // Cleared WeakCells count as FieldType::None, which can't hold any value. | |
662 field_type = LoadWeakCellValue(field_type, bailout); | |
663 // FieldType::Class(...) performs a map check. | |
664 CSA_ASSERT(this, IsMap(field_type)); | |
665 Branch(WordEqual(LoadMap(value), field_type), &all_fine, bailout); | |
666 } | |
667 | |
668 Bind(&all_fine); | |
669 } | |
670 | |
671 void KeyedStoreGenericAssembler::OverwriteExistingFastProperty( | |
672 Node* object, Node* object_map, Node* properties, Node* descriptors, | |
673 Node* descriptor_name_index, Node* details, Node* value, Label* slow) { | |
674 // Properties in descriptors can't be overwritten without map transition. | |
675 GotoIf(Word32NotEqual(DecodeWord32<PropertyDetails::LocationField>(details), | |
676 Int32Constant(kField)), | |
677 slow); | |
678 | |
679 if (FLAG_track_constant_fields) { | |
680 // TODO(ishell): Taking the slow path is not necessary if new and old | |
681 // values are identical. | |
682 GotoIf(Word32Equal(DecodeWord32<PropertyDetails::ConstnessField>(details), | |
683 Int32Constant(kConst)), | |
684 slow); | |
685 } | |
686 | |
687 Label done(this); | |
688 Node* representation = | |
689 DecodeWord32<PropertyDetails::RepresentationField>(details); | |
690 | |
691 CheckFieldType(descriptors, descriptor_name_index, representation, value, | |
692 slow); | |
693 Node* field_index = | |
694 DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details); | |
695 Node* inobject_properties = LoadMapInobjectProperties(object_map); | |
696 | |
697 Label inobject(this), backing_store(this); | |
698 Branch(UintPtrLessThan(field_index, inobject_properties), &inobject, | |
699 &backing_store); | |
700 | |
701 Bind(&inobject); | |
702 { | |
703 Node* field_offset = | |
704 IntPtrMul(IntPtrSub(LoadMapInstanceSize(object_map), | |
705 IntPtrSub(inobject_properties, field_index)), | |
706 IntPtrConstant(kPointerSize)); | |
707 Label tagged_rep(this), double_rep(this); | |
708 Branch(Word32Equal(representation, Int32Constant(Representation::kDouble)), | |
709 &double_rep, &tagged_rep); | |
710 Bind(&double_rep); | |
711 { | |
712 Node* double_value = ChangeNumberToFloat64(value); | |
713 if (FLAG_unbox_double_fields) { | |
714 StoreObjectFieldNoWriteBarrier(object, field_offset, double_value, | |
715 MachineRepresentation::kFloat64); | |
716 } else { | |
717 Node* mutable_heap_number = LoadObjectField(object, field_offset); | |
718 StoreHeapNumberValue(mutable_heap_number, double_value); | |
719 } | |
720 Goto(&done); | |
721 } | |
722 | |
723 Bind(&tagged_rep); | |
724 { | |
725 StoreObjectField(object, field_offset, value); | |
726 Goto(&done); | |
727 } | |
728 } | |
729 | |
730 Bind(&backing_store); | |
731 { | |
732 Node* backing_store_index = IntPtrSub(field_index, inobject_properties); | |
733 Label tagged_rep(this), double_rep(this); | |
734 Branch(Word32Equal(representation, Int32Constant(Representation::kDouble)), | |
735 &double_rep, &tagged_rep); | |
736 Bind(&double_rep); | |
737 { | |
738 Node* double_value = ChangeNumberToFloat64(value); | |
739 Node* mutable_heap_number = | |
740 LoadFixedArrayElement(properties, backing_store_index); | |
741 StoreHeapNumberValue(mutable_heap_number, double_value); | |
742 Goto(&done); | |
743 } | |
744 Bind(&tagged_rep); | |
745 { | |
746 StoreFixedArrayElement(properties, backing_store_index, value); | |
747 Goto(&done); | |
748 } | |
749 } | |
750 Bind(&done); | |
751 } | |
752 | |
602 void KeyedStoreGenericAssembler::EmitGenericPropertyStore( | 753 void KeyedStoreGenericAssembler::EmitGenericPropertyStore( |
603 Node* receiver, Node* receiver_map, const StoreICParameters* p, Label* slow, | 754 Node* receiver, Node* receiver_map, const StoreICParameters* p, Label* slow, |
604 LanguageMode language_mode) { | 755 LanguageMode language_mode) { |
605 Variable var_accessor_pair(this, MachineRepresentation::kTagged); | 756 Variable var_accessor_pair(this, MachineRepresentation::kTagged); |
606 Variable var_accessor_holder(this, MachineRepresentation::kTagged); | 757 Variable var_accessor_holder(this, MachineRepresentation::kTagged); |
607 Label stub_cache(this), fast_properties(this), dictionary_properties(this), | 758 Label stub_cache(this), fast_properties(this), dictionary_properties(this), |
608 accessor(this), readonly(this); | 759 accessor(this), readonly(this); |
609 Node* properties = LoadProperties(receiver); | 760 Node* properties = LoadProperties(receiver); |
610 Node* properties_map = LoadMap(properties); | 761 Node* properties_map = LoadMap(properties); |
611 Branch(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)), | 762 Branch(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)), |
612 &dictionary_properties, &fast_properties); | 763 &dictionary_properties, &fast_properties); |
613 | 764 |
614 Bind(&fast_properties); | 765 Bind(&fast_properties); |
615 { | 766 { |
616 // TODO(jkummerow): Does it make sense to support some cases here inline? | 767 Comment("fast property store"); |
617 // Maybe overwrite existing writable properties? | 768 Node* bitfield3 = LoadMapBitField3(receiver_map); |
618 // Maybe support map transitions? | 769 Node* descriptors = LoadMapDescriptors(receiver_map); |
619 Goto(&stub_cache); | 770 Label descriptor_found(this); |
771 Variable var_name_index(this, MachineType::PointerRepresentation()); | |
772 // TODO(jkummerow): Maybe look for existing map transitions? | |
773 Label* notfound = &stub_cache; | |
774 DescriptorLookup(p->name, descriptors, bitfield3, &descriptor_found, | |
775 &var_name_index, notfound); | |
776 | |
777 Bind(&descriptor_found); | |
778 { | |
779 Node* name_index = var_name_index.value(); | |
780 Node* details = | |
781 LoadDetailsByKeyIndex<DescriptorArray>(descriptors, name_index); | |
782 Label data_property(this); | |
783 JumpIfDataProperty(details, &data_property, &readonly); | |
784 | |
785 // Accessor case. | |
786 // TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject. | |
787 Variable var_details(this, MachineRepresentation::kWord32); | |
788 LoadPropertyFromFastObject(receiver, receiver_map, descriptors, | |
789 name_index, &var_details, &var_accessor_pair); | |
790 var_accessor_holder.Bind(receiver); | |
791 Goto(&accessor); | |
792 | |
793 Bind(&data_property); | |
794 { | |
795 OverwriteExistingFastProperty(receiver, receiver_map, properties, | |
796 descriptors, name_index, details, | |
797 p->value, slow); | |
798 Return(p->value); | |
799 } | |
800 } | |
620 } | 801 } |
621 | 802 |
622 Bind(&dictionary_properties); | 803 Bind(&dictionary_properties); |
623 { | 804 { |
624 Comment("dictionary property store"); | 805 Comment("dictionary property store"); |
625 // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out | 806 // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out |
626 // seeing global objects here (which would need special handling). | 807 // seeing global objects here (which would need special handling). |
627 | 808 |
628 Variable var_name_index(this, MachineType::PointerRepresentation()); | 809 Variable var_name_index(this, MachineType::PointerRepresentation()); |
629 Label dictionary_found(this, &var_name_index), not_found(this); | 810 Label dictionary_found(this, &var_name_index), not_found(this); |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
769 Bind(&slow); | 950 Bind(&slow); |
770 { | 951 { |
771 Comment("KeyedStoreGeneric_slow"); | 952 Comment("KeyedStoreGeneric_slow"); |
772 TailCallRuntime(Runtime::kSetProperty, context, receiver, name, value, | 953 TailCallRuntime(Runtime::kSetProperty, context, receiver, name, value, |
773 SmiConstant(language_mode)); | 954 SmiConstant(language_mode)); |
774 } | 955 } |
775 } | 956 } |
776 | 957 |
777 } // namespace internal | 958 } // namespace internal |
778 } // namespace v8 | 959 } // namespace v8 |
OLD | NEW |