| 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 |