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/accessor-assembler.h" | 5 #include "src/ic/accessor-assembler.h" |
6 #include "src/ic/accessor-assembler-impl.h" | 6 #include "src/ic/accessor-assembler-impl.h" |
7 | 7 |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/code-stubs.h" | 9 #include "src/code-stubs.h" |
10 #include "src/ic/handler-configuration.h" | 10 #include "src/ic/handler-configuration.h" |
(...skipping 652 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
663 Bind(&if_double_field); | 663 Bind(&if_double_field); |
664 { | 664 { |
665 Comment("store double field"); | 665 Comment("store double field"); |
666 HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(), | 666 HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(), |
667 value, transition, miss); | 667 value, transition, miss); |
668 } | 668 } |
669 | 669 |
670 Bind(&if_heap_object_field); | 670 Bind(&if_heap_object_field); |
671 { | 671 { |
672 Comment("store heap object field"); | 672 Comment("store heap object field"); |
673 // Generate full field type check here and then store value as Tagged. | 673 HandleStoreFieldAndReturn(handler_word, holder, |
674 Node* prepared_value = | 674 Representation::HeapObject(), value, transition, |
675 PrepareValueForWrite(value, Representation::HeapObject(), miss); | 675 miss); |
676 Node* value_index_in_descriptor = | |
677 DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word); | |
678 Node* descriptors = | |
679 LoadMapDescriptors(transition ? transition : LoadMap(holder)); | |
680 Node* maybe_field_type = | |
681 LoadFixedArrayElement(descriptors, value_index_in_descriptor); | |
682 Label do_store(this); | |
683 GotoIf(TaggedIsSmi(maybe_field_type), &do_store); | |
684 // Check that value type matches the field type. | |
685 { | |
686 Node* field_type = LoadWeakCellValue(maybe_field_type, miss); | |
687 Branch(WordEqual(LoadMap(prepared_value), field_type), &do_store, miss); | |
688 } | |
689 Bind(&do_store); | |
690 HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(), | |
691 prepared_value, transition, miss); | |
692 } | 676 } |
693 | 677 |
694 Bind(&if_smi_field); | 678 Bind(&if_smi_field); |
695 { | 679 { |
696 Comment("store smi field"); | 680 Comment("store smi field"); |
697 HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(), | 681 HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(), |
698 value, transition, miss); | 682 value, transition, miss); |
699 } | 683 } |
700 } | 684 } |
701 | 685 |
702 void AccessorAssemblerImpl::HandleStoreFieldAndReturn( | 686 void AccessorAssemblerImpl::HandleStoreFieldAndReturn( |
703 Node* handler_word, Node* holder, Representation representation, | 687 Node* handler_word, Node* holder, Representation representation, |
704 Node* value, Node* transition, Label* miss) { | 688 Node* value, Node* transition, Label* miss) { |
705 bool transition_to_field = transition != nullptr; | 689 bool transition_to_field = transition != nullptr; |
706 Node* prepared_value = PrepareValueForWrite(value, representation, miss); | 690 Node* prepared_value = PrepareValueForStore( |
707 | 691 handler_word, holder, representation, transition, value, miss); |
708 if (transition_to_field) { | |
709 Label storage_extended(this); | |
710 GotoUnless(IsSetWord<StoreHandler::ExtendStorageBits>(handler_word), | |
711 &storage_extended); | |
712 Comment("[ Extend storage"); | |
713 ExtendPropertiesBackingStore(holder); | |
714 Comment("] Extend storage"); | |
715 Goto(&storage_extended); | |
716 | |
717 Bind(&storage_extended); | |
718 } | |
719 | 692 |
720 Node* offset = DecodeWord<StoreHandler::FieldOffsetBits>(handler_word); | 693 Node* offset = DecodeWord<StoreHandler::FieldOffsetBits>(handler_word); |
721 Label if_inobject(this), if_out_of_object(this); | 694 Label if_inobject(this), if_out_of_object(this); |
722 Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject, | 695 Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject, |
723 &if_out_of_object); | 696 &if_out_of_object); |
724 | 697 |
725 Bind(&if_inobject); | 698 Bind(&if_inobject); |
726 { | 699 { |
727 StoreNamedField(holder, offset, true, representation, prepared_value, | 700 StoreNamedField(holder, offset, true, representation, prepared_value, |
728 transition_to_field); | 701 transition_to_field); |
729 if (transition_to_field) { | 702 if (transition_to_field) { |
730 StoreMap(holder, transition); | 703 StoreMap(holder, transition); |
731 } | 704 } |
732 Return(value); | 705 Return(value); |
733 } | 706 } |
734 | 707 |
735 Bind(&if_out_of_object); | 708 Bind(&if_out_of_object); |
736 { | 709 { |
| 710 if (transition_to_field) { |
| 711 Label storage_extended(this); |
| 712 GotoUnless(IsSetWord<StoreHandler::ExtendStorageBits>(handler_word), |
| 713 &storage_extended); |
| 714 Comment("[ Extend storage"); |
| 715 ExtendPropertiesBackingStore(holder); |
| 716 Comment("] Extend storage"); |
| 717 Goto(&storage_extended); |
| 718 |
| 719 Bind(&storage_extended); |
| 720 } |
| 721 |
737 StoreNamedField(holder, offset, false, representation, prepared_value, | 722 StoreNamedField(holder, offset, false, representation, prepared_value, |
738 transition_to_field); | 723 transition_to_field); |
739 if (transition_to_field) { | 724 if (transition_to_field) { |
740 StoreMap(holder, transition); | 725 StoreMap(holder, transition); |
741 } | 726 } |
742 Return(value); | 727 Return(value); |
743 } | 728 } |
744 } | 729 } |
745 | 730 |
| 731 Node* AccessorAssemblerImpl::PrepareValueForStore(Node* handler_word, |
| 732 Node* holder, |
| 733 Representation representation, |
| 734 Node* transition, Node* value, |
| 735 Label* bailout) { |
| 736 if (representation.IsDouble()) { |
| 737 value = TryTaggedToFloat64(value, bailout); |
| 738 |
| 739 } else if (representation.IsHeapObject()) { |
| 740 GotoIf(TaggedIsSmi(value), bailout); |
| 741 Node* value_index_in_descriptor = |
| 742 DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word); |
| 743 Node* descriptors = |
| 744 LoadMapDescriptors(transition ? transition : LoadMap(holder)); |
| 745 Node* maybe_field_type = |
| 746 LoadFixedArrayElement(descriptors, value_index_in_descriptor); |
| 747 |
| 748 Label done(this); |
| 749 GotoIf(TaggedIsSmi(maybe_field_type), &done); |
| 750 // Check that value type matches the field type. |
| 751 { |
| 752 Node* field_type = LoadWeakCellValue(maybe_field_type, bailout); |
| 753 Branch(WordEqual(LoadMap(value), field_type), &done, bailout); |
| 754 } |
| 755 Bind(&done); |
| 756 |
| 757 } else if (representation.IsSmi()) { |
| 758 GotoUnless(TaggedIsSmi(value), bailout); |
| 759 |
| 760 } else { |
| 761 DCHECK(representation.IsTagged()); |
| 762 } |
| 763 return value; |
| 764 } |
| 765 |
| 766 void AccessorAssemblerImpl::ExtendPropertiesBackingStore(Node* object) { |
| 767 Node* properties = LoadProperties(object); |
| 768 Node* length = LoadFixedArrayBaseLength(properties); |
| 769 |
| 770 ParameterMode mode = OptimalParameterMode(); |
| 771 length = TaggedToParameter(length, mode); |
| 772 |
| 773 Node* delta = IntPtrOrSmiConstant(JSObject::kFieldsAdded, mode); |
| 774 Node* new_capacity = IntPtrOrSmiAdd(length, delta, mode); |
| 775 |
| 776 // Grow properties array. |
| 777 ElementsKind kind = FAST_ELEMENTS; |
| 778 DCHECK(kMaxNumberOfDescriptors + JSObject::kFieldsAdded < |
| 779 FixedArrayBase::GetMaxLengthForNewSpaceAllocation(kind)); |
| 780 // The size of a new properties backing store is guaranteed to be small |
| 781 // enough that the new backing store will be allocated in new space. |
| 782 CSA_ASSERT(this, |
| 783 UintPtrOrSmiLessThan( |
| 784 new_capacity, |
| 785 IntPtrOrSmiConstant( |
| 786 kMaxNumberOfDescriptors + JSObject::kFieldsAdded, mode), |
| 787 mode)); |
| 788 |
| 789 Node* new_properties = AllocateFixedArray(kind, new_capacity, mode); |
| 790 |
| 791 FillFixedArrayWithValue(kind, new_properties, length, new_capacity, |
| 792 Heap::kUndefinedValueRootIndex, mode); |
| 793 |
| 794 // |new_properties| is guaranteed to be in new space, so we can skip |
| 795 // the write barrier. |
| 796 CopyFixedArrayElements(kind, properties, new_properties, length, |
| 797 SKIP_WRITE_BARRIER, mode); |
| 798 |
| 799 StoreObjectField(object, JSObject::kPropertiesOffset, new_properties); |
| 800 } |
| 801 |
| 802 void AccessorAssemblerImpl::StoreNamedField(Node* object, Node* offset, |
| 803 bool is_inobject, |
| 804 Representation representation, |
| 805 Node* value, |
| 806 bool transition_to_field) { |
| 807 bool store_value_as_double = representation.IsDouble(); |
| 808 Node* property_storage = object; |
| 809 if (!is_inobject) { |
| 810 property_storage = LoadProperties(object); |
| 811 } |
| 812 |
| 813 if (representation.IsDouble()) { |
| 814 if (!FLAG_unbox_double_fields || !is_inobject) { |
| 815 if (transition_to_field) { |
| 816 Node* heap_number = AllocateHeapNumberWithValue(value, MUTABLE); |
| 817 // Store the new mutable heap number into the object. |
| 818 value = heap_number; |
| 819 store_value_as_double = false; |
| 820 } else { |
| 821 // Load the heap number. |
| 822 property_storage = LoadObjectField(property_storage, offset); |
| 823 // Store the double value into it. |
| 824 offset = IntPtrConstant(HeapNumber::kValueOffset); |
| 825 } |
| 826 } |
| 827 } |
| 828 |
| 829 if (store_value_as_double) { |
| 830 StoreObjectFieldNoWriteBarrier(property_storage, offset, value, |
| 831 MachineRepresentation::kFloat64); |
| 832 } else if (representation.IsSmi()) { |
| 833 StoreObjectFieldNoWriteBarrier(property_storage, offset, value); |
| 834 } else { |
| 835 StoreObjectField(property_storage, offset, value); |
| 836 } |
| 837 } |
| 838 |
746 void AccessorAssemblerImpl::EmitFastElementsBoundsCheck( | 839 void AccessorAssemblerImpl::EmitFastElementsBoundsCheck( |
747 Node* object, Node* elements, Node* intptr_index, | 840 Node* object, Node* elements, Node* intptr_index, |
748 Node* is_jsarray_condition, Label* miss) { | 841 Node* is_jsarray_condition, Label* miss) { |
749 Variable var_length(this, MachineType::PointerRepresentation()); | 842 Variable var_length(this, MachineType::PointerRepresentation()); |
750 Comment("Fast elements bounds check"); | 843 Comment("Fast elements bounds check"); |
751 Label if_array(this), length_loaded(this, &var_length); | 844 Label if_array(this), length_loaded(this, &var_length); |
752 GotoIf(is_jsarray_condition, &if_array); | 845 GotoIf(is_jsarray_condition, &if_array); |
753 { | 846 { |
754 var_length.Bind(SmiUntag(LoadFixedArrayBaseLength(elements))); | 847 var_length.Bind(SmiUntag(LoadFixedArrayBaseLength(elements))); |
755 Goto(&length_loaded); | 848 Goto(&length_loaded); |
(...skipping 1071 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1827 void AccessorAssembler::GenerateKeyedStoreICTrampolineTF( | 1920 void AccessorAssembler::GenerateKeyedStoreICTrampolineTF( |
1828 CodeAssemblerState* state, LanguageMode language_mode) { | 1921 CodeAssemblerState* state, LanguageMode language_mode) { |
1829 AccessorAssemblerImpl assembler(state); | 1922 AccessorAssemblerImpl assembler(state); |
1830 assembler.GenerateKeyedStoreICTrampolineTF(language_mode); | 1923 assembler.GenerateKeyedStoreICTrampolineTF(language_mode); |
1831 } | 1924 } |
1832 | 1925 |
1833 #undef ACCESSOR_ASSEMBLER_PUBLIC_INTERFACE | 1926 #undef ACCESSOR_ASSEMBLER_PUBLIC_INTERFACE |
1834 | 1927 |
1835 } // namespace internal | 1928 } // namespace internal |
1836 } // namespace v8 | 1929 } // namespace v8 |
OLD | NEW |