OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/mips/codegen-mips.h" | 5 #include "src/mips/codegen-mips.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_MIPS | 7 #if V8_TARGET_ARCH_MIPS |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 | 10 |
(...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
598 DCHECK(masm->has_frame()); | 598 DCHECK(masm->has_frame()); |
599 masm->set_has_frame(false); | 599 masm->set_has_frame(false); |
600 } | 600 } |
601 | 601 |
602 | 602 |
603 // ------------------------------------------------------------------------- | 603 // ------------------------------------------------------------------------- |
604 // Code generators | 604 // Code generators |
605 | 605 |
606 #define __ ACCESS_MASM(masm) | 606 #define __ ACCESS_MASM(masm) |
607 | 607 |
608 void ElementsTransitionGenerator::GenerateMapChangeElementsTransition( | |
609 MacroAssembler* masm, | |
610 Register receiver, | |
611 Register key, | |
612 Register value, | |
613 Register target_map, | |
614 AllocationSiteMode mode, | |
615 Label* allocation_memento_found) { | |
616 Register scratch_elements = t0; | |
617 DCHECK(!AreAliased(receiver, key, value, target_map, | |
618 scratch_elements)); | |
619 | |
620 if (mode == TRACK_ALLOCATION_SITE) { | |
621 DCHECK(allocation_memento_found != NULL); | |
622 __ JumpIfJSArrayHasAllocationMemento( | |
623 receiver, scratch_elements, allocation_memento_found); | |
624 } | |
625 | |
626 // Set transitioned map. | |
627 __ sw(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
628 __ RecordWriteField(receiver, | |
629 HeapObject::kMapOffset, | |
630 target_map, | |
631 t5, | |
632 kRAHasNotBeenSaved, | |
633 kDontSaveFPRegs, | |
634 EMIT_REMEMBERED_SET, | |
635 OMIT_SMI_CHECK); | |
636 } | |
637 | |
638 | |
639 void ElementsTransitionGenerator::GenerateSmiToDouble( | |
640 MacroAssembler* masm, | |
641 Register receiver, | |
642 Register key, | |
643 Register value, | |
644 Register target_map, | |
645 AllocationSiteMode mode, | |
646 Label* fail) { | |
647 // Register ra contains the return address. | |
648 Label loop, entry, convert_hole, gc_required, only_change_map, done; | |
649 Register elements = t0; | |
650 Register length = t1; | |
651 Register array = t2; | |
652 Register array_end = array; | |
653 | |
654 // target_map parameter can be clobbered. | |
655 Register scratch1 = target_map; | |
656 Register scratch2 = t5; | |
657 Register scratch3 = t3; | |
658 | |
659 // Verify input registers don't conflict with locals. | |
660 DCHECK(!AreAliased(receiver, key, value, target_map, | |
661 elements, length, array, scratch2)); | |
662 | |
663 Register scratch = t6; | |
664 | |
665 if (mode == TRACK_ALLOCATION_SITE) { | |
666 __ JumpIfJSArrayHasAllocationMemento(receiver, elements, fail); | |
667 } | |
668 | |
669 // Check for empty arrays, which only require a map transition and no changes | |
670 // to the backing store. | |
671 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
672 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex); | |
673 __ Branch(&only_change_map, eq, at, Operand(elements)); | |
674 | |
675 __ push(ra); | |
676 __ lw(length, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
677 // elements: source FixedArray | |
678 // length: number of elements (smi-tagged) | |
679 | |
680 // Allocate new FixedDoubleArray. | |
681 __ sll(scratch, length, 2); | |
682 __ Addu(scratch, scratch, FixedDoubleArray::kHeaderSize); | |
683 __ Allocate(scratch, array, t3, scratch2, &gc_required, DOUBLE_ALIGNMENT); | |
684 // array: destination FixedDoubleArray, tagged as heap object | |
685 | |
686 // Set destination FixedDoubleArray's length and map. | |
687 __ LoadRoot(scratch2, Heap::kFixedDoubleArrayMapRootIndex); | |
688 __ sw(length, FieldMemOperand(array, FixedDoubleArray::kLengthOffset)); | |
689 // Update receiver's map. | |
690 __ sw(scratch2, FieldMemOperand(array, HeapObject::kMapOffset)); | |
691 | |
692 __ sw(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
693 __ RecordWriteField(receiver, | |
694 HeapObject::kMapOffset, | |
695 target_map, | |
696 scratch2, | |
697 kRAHasBeenSaved, | |
698 kDontSaveFPRegs, | |
699 OMIT_REMEMBERED_SET, | |
700 OMIT_SMI_CHECK); | |
701 // Replace receiver's backing store with newly created FixedDoubleArray. | |
702 __ Addu(scratch1, array, Operand(kHeapObjectTag - kHeapObjectTag)); | |
703 __ sw(scratch1, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
704 __ RecordWriteField(receiver, | |
705 JSObject::kElementsOffset, | |
706 scratch1, | |
707 scratch2, | |
708 kRAHasBeenSaved, | |
709 kDontSaveFPRegs, | |
710 EMIT_REMEMBERED_SET, | |
711 OMIT_SMI_CHECK); | |
712 | |
713 | |
714 // Prepare for conversion loop. | |
715 __ Addu(scratch1, elements, | |
716 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | |
717 __ Addu(scratch3, array, | |
718 Operand(FixedDoubleArray::kHeaderSize - kHeapObjectTag)); | |
719 __ Lsa(array_end, scratch3, length, 2); | |
720 | |
721 // Repurpose registers no longer in use. | |
722 Register hole_lower = elements; | |
723 Register hole_upper = length; | |
724 __ li(hole_lower, Operand(kHoleNanLower32)); | |
725 __ li(hole_upper, Operand(kHoleNanUpper32)); | |
726 | |
727 // scratch1: begin of source FixedArray element fields, not tagged | |
728 // hole_lower: kHoleNanLower32 | |
729 // hole_upper: kHoleNanUpper32 | |
730 // array_end: end of destination FixedDoubleArray, not tagged | |
731 // scratch3: begin of FixedDoubleArray element fields, not tagged | |
732 | |
733 __ Branch(&entry); | |
734 | |
735 __ bind(&only_change_map); | |
736 __ sw(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
737 __ RecordWriteField(receiver, | |
738 HeapObject::kMapOffset, | |
739 target_map, | |
740 scratch2, | |
741 kRAHasBeenSaved, | |
742 kDontSaveFPRegs, | |
743 OMIT_REMEMBERED_SET, | |
744 OMIT_SMI_CHECK); | |
745 __ Branch(&done); | |
746 | |
747 // Call into runtime if GC is required. | |
748 __ bind(&gc_required); | |
749 __ lw(ra, MemOperand(sp, 0)); | |
750 __ Branch(USE_DELAY_SLOT, fail); | |
751 __ addiu(sp, sp, kPointerSize); // In delay slot. | |
752 | |
753 // Convert and copy elements. | |
754 __ bind(&loop); | |
755 __ lw(scratch2, MemOperand(scratch1)); | |
756 __ Addu(scratch1, scratch1, kIntSize); | |
757 // scratch2: current element | |
758 __ UntagAndJumpIfNotSmi(scratch2, scratch2, &convert_hole); | |
759 | |
760 // Normal smi, convert to double and store. | |
761 __ mtc1(scratch2, f0); | |
762 __ cvt_d_w(f0, f0); | |
763 __ sdc1(f0, MemOperand(scratch3)); | |
764 __ Branch(USE_DELAY_SLOT, &entry); | |
765 __ addiu(scratch3, scratch3, kDoubleSize); // In delay slot. | |
766 | |
767 // Hole found, store the-hole NaN. | |
768 __ bind(&convert_hole); | |
769 if (FLAG_debug_code) { | |
770 // Restore a "smi-untagged" heap object. | |
771 __ SmiTag(scratch2); | |
772 __ Or(scratch2, scratch2, Operand(1)); | |
773 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | |
774 __ Assert(eq, kObjectFoundInSmiOnlyArray, at, Operand(scratch2)); | |
775 } | |
776 // mantissa | |
777 __ sw(hole_lower, MemOperand(scratch3, Register::kMantissaOffset)); | |
778 // exponent | |
779 __ sw(hole_upper, MemOperand(scratch3, Register::kExponentOffset)); | |
780 __ addiu(scratch3, scratch3, kDoubleSize); | |
781 | |
782 __ bind(&entry); | |
783 __ Branch(&loop, lt, scratch3, Operand(array_end)); | |
784 | |
785 __ bind(&done); | |
786 __ pop(ra); | |
787 } | |
788 | |
789 | |
790 void ElementsTransitionGenerator::GenerateDoubleToObject( | |
791 MacroAssembler* masm, | |
792 Register receiver, | |
793 Register key, | |
794 Register value, | |
795 Register target_map, | |
796 AllocationSiteMode mode, | |
797 Label* fail) { | |
798 // Register ra contains the return address. | |
799 Label entry, loop, convert_hole, gc_required, only_change_map; | |
800 Register elements = t0; | |
801 Register array = t2; | |
802 Register length = t1; | |
803 Register scratch = t5; | |
804 | |
805 // Verify input registers don't conflict with locals. | |
806 DCHECK(!AreAliased(receiver, key, value, target_map, | |
807 elements, array, length, scratch)); | |
808 | |
809 if (mode == TRACK_ALLOCATION_SITE) { | |
810 __ JumpIfJSArrayHasAllocationMemento(receiver, elements, fail); | |
811 } | |
812 | |
813 // Check for empty arrays, which only require a map transition and no changes | |
814 // to the backing store. | |
815 __ lw(elements, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
816 __ LoadRoot(at, Heap::kEmptyFixedArrayRootIndex); | |
817 __ Branch(&only_change_map, eq, at, Operand(elements)); | |
818 | |
819 __ MultiPush( | |
820 value.bit() | key.bit() | receiver.bit() | target_map.bit() | ra.bit()); | |
821 | |
822 __ lw(length, FieldMemOperand(elements, FixedArray::kLengthOffset)); | |
823 // elements: source FixedArray | |
824 // length: number of elements (smi-tagged) | |
825 | |
826 // Allocate new FixedArray. | |
827 // Re-use value and target_map registers, as they have been saved on the | |
828 // stack. | |
829 Register array_size = value; | |
830 Register allocate_scratch = target_map; | |
831 __ sll(array_size, length, 1); | |
832 __ Addu(array_size, array_size, FixedDoubleArray::kHeaderSize); | |
833 __ Allocate(array_size, array, allocate_scratch, scratch, &gc_required, | |
834 NO_ALLOCATION_FLAGS); | |
835 // array: destination FixedArray, not tagged as heap object | |
836 // Set destination FixedDoubleArray's length and map. | |
837 __ LoadRoot(scratch, Heap::kFixedArrayMapRootIndex); | |
838 __ sw(length, FieldMemOperand(array, FixedDoubleArray::kLengthOffset)); | |
839 __ sw(scratch, FieldMemOperand(array, HeapObject::kMapOffset)); | |
840 | |
841 // Prepare for conversion loop. | |
842 Register src_elements = elements; | |
843 Register dst_elements = target_map; | |
844 Register dst_end = length; | |
845 Register heap_number_map = scratch; | |
846 __ Addu(src_elements, src_elements, Operand( | |
847 FixedDoubleArray::kHeaderSize - kHeapObjectTag | |
848 + Register::kExponentOffset)); | |
849 __ Addu(dst_elements, array, | |
850 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | |
851 __ Lsa(dst_end, dst_elements, dst_end, 1); | |
852 | |
853 // Allocating heap numbers in the loop below can fail and cause a jump to | |
854 // gc_required. We can't leave a partly initialized FixedArray behind, | |
855 // so pessimistically fill it with holes now. | |
856 Label initialization_loop, initialization_loop_entry; | |
857 __ LoadRoot(scratch, Heap::kTheHoleValueRootIndex); | |
858 __ Branch(&initialization_loop_entry); | |
859 __ bind(&initialization_loop); | |
860 __ sw(scratch, MemOperand(dst_elements)); | |
861 __ Addu(dst_elements, dst_elements, Operand(kPointerSize)); | |
862 __ bind(&initialization_loop_entry); | |
863 __ Branch(&initialization_loop, lt, dst_elements, Operand(dst_end)); | |
864 | |
865 __ Addu(dst_elements, array, | |
866 Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | |
867 __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); | |
868 // Using offsetted addresses. | |
869 // dst_elements: begin of destination FixedArray element fields, not tagged | |
870 // src_elements: begin of source FixedDoubleArray element fields, not tagged, | |
871 // points to the exponent | |
872 // dst_end: end of destination FixedArray, not tagged | |
873 // array: destination FixedArray | |
874 // heap_number_map: heap number map | |
875 __ Branch(&entry); | |
876 | |
877 // Call into runtime if GC is required. | |
878 __ bind(&gc_required); | |
879 __ MultiPop( | |
880 value.bit() | key.bit() | receiver.bit() | target_map.bit() | ra.bit()); | |
881 | |
882 __ Branch(fail); | |
883 | |
884 __ bind(&loop); | |
885 Register upper_bits = key; | |
886 __ lw(upper_bits, MemOperand(src_elements)); | |
887 __ Addu(src_elements, src_elements, kDoubleSize); | |
888 // upper_bits: current element's upper 32 bit | |
889 // src_elements: address of next element's upper 32 bit | |
890 __ Branch(&convert_hole, eq, a1, Operand(kHoleNanUpper32)); | |
891 | |
892 // Non-hole double, copy value into a heap number. | |
893 Register heap_number = receiver; | |
894 Register scratch2 = value; | |
895 Register scratch3 = t6; | |
896 __ AllocateHeapNumber(heap_number, scratch2, scratch3, heap_number_map, | |
897 &gc_required); | |
898 // heap_number: new heap number | |
899 // Load mantissa of current element, src_elements | |
900 // point to exponent of next element. | |
901 __ lw(scratch2, MemOperand(src_elements, (Register::kMantissaOffset | |
902 - Register::kExponentOffset - kDoubleSize))); | |
903 __ sw(scratch2, FieldMemOperand(heap_number, HeapNumber::kMantissaOffset)); | |
904 __ sw(upper_bits, FieldMemOperand(heap_number, HeapNumber::kExponentOffset)); | |
905 __ mov(scratch2, dst_elements); | |
906 __ sw(heap_number, MemOperand(dst_elements)); | |
907 __ Addu(dst_elements, dst_elements, kIntSize); | |
908 __ RecordWrite(array, | |
909 scratch2, | |
910 heap_number, | |
911 kRAHasBeenSaved, | |
912 kDontSaveFPRegs, | |
913 EMIT_REMEMBERED_SET, | |
914 OMIT_SMI_CHECK); | |
915 __ Branch(&entry); | |
916 | |
917 // Replace the-hole NaN with the-hole pointer. | |
918 __ bind(&convert_hole); | |
919 __ LoadRoot(scratch2, Heap::kTheHoleValueRootIndex); | |
920 __ sw(scratch2, MemOperand(dst_elements)); | |
921 __ Addu(dst_elements, dst_elements, kIntSize); | |
922 | |
923 __ bind(&entry); | |
924 __ Branch(&loop, lt, dst_elements, Operand(dst_end)); | |
925 | |
926 __ MultiPop(receiver.bit() | target_map.bit() | value.bit() | key.bit()); | |
927 // Replace receiver's backing store with newly created and filled FixedArray. | |
928 __ sw(array, FieldMemOperand(receiver, JSObject::kElementsOffset)); | |
929 __ RecordWriteField(receiver, | |
930 JSObject::kElementsOffset, | |
931 array, | |
932 scratch, | |
933 kRAHasBeenSaved, | |
934 kDontSaveFPRegs, | |
935 EMIT_REMEMBERED_SET, | |
936 OMIT_SMI_CHECK); | |
937 __ pop(ra); | |
938 | |
939 __ bind(&only_change_map); | |
940 // Update receiver's map. | |
941 __ sw(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | |
942 __ RecordWriteField(receiver, | |
943 HeapObject::kMapOffset, | |
944 target_map, | |
945 scratch, | |
946 kRAHasNotBeenSaved, | |
947 kDontSaveFPRegs, | |
948 OMIT_REMEMBERED_SET, | |
949 OMIT_SMI_CHECK); | |
950 } | |
951 | |
952 | |
953 void StringCharLoadGenerator::Generate(MacroAssembler* masm, | 608 void StringCharLoadGenerator::Generate(MacroAssembler* masm, |
954 Register string, | 609 Register string, |
955 Register index, | 610 Register index, |
956 Register result, | 611 Register result, |
957 Label* call_runtime) { | 612 Label* call_runtime) { |
958 // Fetch the instance type of the receiver into result register. | 613 // Fetch the instance type of the receiver into result register. |
959 __ lw(result, FieldMemOperand(string, HeapObject::kMapOffset)); | 614 __ lw(result, FieldMemOperand(string, HeapObject::kMapOffset)); |
960 __ lbu(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); | 615 __ lbu(result, FieldMemOperand(result, Map::kInstanceTypeOffset)); |
961 | 616 |
962 // We need special handling for indirect strings. | 617 // We need special handling for indirect strings. |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1118 } | 773 } |
1119 } | 774 } |
1120 | 775 |
1121 | 776 |
1122 #undef __ | 777 #undef __ |
1123 | 778 |
1124 } // namespace internal | 779 } // namespace internal |
1125 } // namespace v8 | 780 } // namespace v8 |
1126 | 781 |
1127 #endif // V8_TARGET_ARCH_MIPS | 782 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |