| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
| 10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
| (...skipping 654 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 665 cmn(rn, op); | 665 cmn(rn, op); |
| 666 } else { | 666 } else { |
| 667 ASSERT(rn != TMP2); | 667 ASSERT(rn != TMP2); |
| 668 LoadImmediate(TMP2, imm, pp); | 668 LoadImmediate(TMP2, imm, pp); |
| 669 cmp(rn, Operand(TMP2)); | 669 cmp(rn, Operand(TMP2)); |
| 670 } | 670 } |
| 671 } | 671 } |
| 672 | 672 |
| 673 | 673 |
| 674 void Assembler::LoadFromOffset( | 674 void Assembler::LoadFromOffset( |
| 675 Register dest, Register base, int32_t offset, OperandSize sz) { | 675 Register dest, Register base, int32_t offset, Register pp, OperandSize sz) { |
| 676 if (Address::CanHoldOffset(offset, Address::Offset, sz)) { | 676 if (Address::CanHoldOffset(offset, Address::Offset, sz)) { |
| 677 ldr(dest, Address(base, offset, Address::Offset, sz), sz); | 677 ldr(dest, Address(base, offset, Address::Offset, sz), sz); |
| 678 } else { | 678 } else { |
| 679 ASSERT(base != TMP2); | 679 ASSERT(base != TMP2); |
| 680 // Since offset is 32-bits, it won't be loaded from the pool. | 680 AddImmediate(TMP2, base, offset, pp); |
| 681 AddImmediate(TMP2, base, offset, kNoPP); | |
| 682 ldr(dest, Address(TMP2), sz); | 681 ldr(dest, Address(TMP2), sz); |
| 683 } | 682 } |
| 684 } | 683 } |
| 685 | 684 |
| 686 | 685 |
| 687 void Assembler::LoadDFromOffset(VRegister dest, Register base, int32_t offset) { | 686 void Assembler::LoadDFromOffset( |
| 687 VRegister dest, Register base, int32_t offset, Register pp) { |
| 688 if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) { | 688 if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) { |
| 689 fldrd(dest, Address(base, offset, Address::Offset, kDWord)); | 689 fldrd(dest, Address(base, offset, Address::Offset, kDWord)); |
| 690 } else { | 690 } else { |
| 691 ASSERT(base != TMP2); | 691 ASSERT(base != TMP2); |
| 692 // Since offset is 32-bits, it won't be loaded from the pool. | 692 AddImmediate(TMP2, base, offset, pp); |
| 693 AddImmediate(TMP2, base, offset, kNoPP); | |
| 694 fldrd(dest, Address(TMP2)); | 693 fldrd(dest, Address(TMP2)); |
| 695 } | 694 } |
| 696 } | 695 } |
| 697 | 696 |
| 698 | 697 |
| 698 void Assembler::LoadQFromOffset( |
| 699 VRegister dest, Register base, int32_t offset, Register pp) { |
| 700 if (Address::CanHoldOffset(offset, Address::Offset, kQWord)) { |
| 701 fldrq(dest, Address(base, offset, Address::Offset, kQWord)); |
| 702 } else { |
| 703 ASSERT(base != TMP2); |
| 704 AddImmediate(TMP2, base, offset, pp); |
| 705 fldrq(dest, Address(TMP2)); |
| 706 } |
| 707 } |
| 708 |
| 709 |
| 699 void Assembler::StoreToOffset( | 710 void Assembler::StoreToOffset( |
| 700 Register src, Register base, int32_t offset, OperandSize sz) { | 711 Register src, Register base, int32_t offset, Register pp, OperandSize sz) { |
| 701 ASSERT(base != TMP2); | 712 ASSERT(base != TMP2); |
| 702 if (Address::CanHoldOffset(offset, Address::Offset, sz)) { | 713 if (Address::CanHoldOffset(offset, Address::Offset, sz)) { |
| 703 str(src, Address(base, offset, Address::Offset, sz), sz); | 714 str(src, Address(base, offset, Address::Offset, sz), sz); |
| 704 } else { | 715 } else { |
| 705 ASSERT(src != TMP2); | 716 ASSERT(src != TMP2); |
| 706 // Since offset is 32-bits, it won't be loaded from the pool. | 717 AddImmediate(TMP2, base, offset, pp); |
| 707 AddImmediate(TMP2, base, offset, kNoPP); | |
| 708 str(src, Address(TMP2), sz); | 718 str(src, Address(TMP2), sz); |
| 709 } | 719 } |
| 710 } | 720 } |
| 711 | 721 |
| 712 | 722 |
| 713 void Assembler::StoreDToOffset(VRegister src, Register base, int32_t offset) { | 723 void Assembler::StoreDToOffset( |
| 724 VRegister src, Register base, int32_t offset, Register pp) { |
| 714 if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) { | 725 if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) { |
| 715 fstrd(src, Address(base, offset, Address::Offset, kDWord)); | 726 fstrd(src, Address(base, offset, Address::Offset, kDWord)); |
| 716 } else { | 727 } else { |
| 717 ASSERT(base != TMP2); | 728 ASSERT(base != TMP2); |
| 718 // Since offset is 32-bits, it won't be loaded from the pool. | 729 AddImmediate(TMP2, base, offset, pp); |
| 719 AddImmediate(TMP2, base, offset, kNoPP); | |
| 720 fstrd(src, Address(TMP2)); | 730 fstrd(src, Address(TMP2)); |
| 721 } | 731 } |
| 722 } | 732 } |
| 723 | 733 |
| 724 | 734 |
| 735 void Assembler::StoreQToOffset( |
| 736 VRegister src, Register base, int32_t offset, Register pp) { |
| 737 if (Address::CanHoldOffset(offset, Address::Offset, kQWord)) { |
| 738 fstrq(src, Address(base, offset, Address::Offset, kQWord)); |
| 739 } else { |
| 740 ASSERT(base != TMP2); |
| 741 AddImmediate(TMP2, base, offset, pp); |
| 742 fstrq(src, Address(TMP2)); |
| 743 } |
| 744 } |
| 745 |
| 746 |
| 725 // Store into object. | 747 // Store into object. |
| 726 // Preserves object and value registers. | 748 // Preserves object and value registers. |
| 727 void Assembler::StoreIntoObjectFilterNoSmi(Register object, | 749 void Assembler::StoreIntoObjectFilterNoSmi(Register object, |
| 728 Register value, | 750 Register value, |
| 729 Label* no_update) { | 751 Label* no_update) { |
| 730 COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) && | 752 COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) && |
| 731 (kOldObjectAlignmentOffset == 0), young_alignment); | 753 (kOldObjectAlignmentOffset == 0), young_alignment); |
| 732 | 754 |
| 733 // Write-barrier triggers if the value is in the new space (has bit set) and | 755 // Write-barrier triggers if the value is in the new space (has bit set) and |
| 734 // the object is in the old space (has bit cleared). | 756 // the object is in the old space (has bit cleared). |
| (...skipping 12 matching lines...) Expand all Loading... |
| 747 // For the value we are only interested in the new/old bit and the tag bit. | 769 // For the value we are only interested in the new/old bit and the tag bit. |
| 748 // And the new bit with the tag bit. The resulting bit will be 0 for a Smi. | 770 // And the new bit with the tag bit. The resulting bit will be 0 for a Smi. |
| 749 and_(TMP, value, Operand(value, LSL, kObjectAlignmentLog2 - 1)); | 771 and_(TMP, value, Operand(value, LSL, kObjectAlignmentLog2 - 1)); |
| 750 // And the result with the negated space bit of the object. | 772 // And the result with the negated space bit of the object. |
| 751 bic(TMP, TMP, Operand(object)); | 773 bic(TMP, TMP, Operand(object)); |
| 752 tsti(TMP, kNewObjectAlignmentOffset); | 774 tsti(TMP, kNewObjectAlignmentOffset); |
| 753 b(no_update, EQ); | 775 b(no_update, EQ); |
| 754 } | 776 } |
| 755 | 777 |
| 756 | 778 |
| 779 void Assembler::StoreIntoObjectOffset(Register object, |
| 780 int32_t offset, |
| 781 Register value, |
| 782 Register pp, |
| 783 bool can_value_be_smi) { |
| 784 if (Address::CanHoldOffset(offset - kHeapObjectTag)) { |
| 785 StoreIntoObject( |
| 786 object, FieldAddress(object, offset), value, can_value_be_smi); |
| 787 } else { |
| 788 AddImmediate(TMP, object, offset - kHeapObjectTag, pp); |
| 789 StoreIntoObject(object, Address(TMP), value, can_value_be_smi); |
| 790 } |
| 791 } |
| 792 |
| 793 |
| 757 void Assembler::StoreIntoObject(Register object, | 794 void Assembler::StoreIntoObject(Register object, |
| 758 const Address& dest, | 795 const Address& dest, |
| 759 Register value, | 796 Register value, |
| 760 bool can_value_be_smi) { | 797 bool can_value_be_smi) { |
| 761 ASSERT(object != value); | 798 ASSERT(object != value); |
| 762 str(value, dest); | 799 str(value, dest); |
| 763 Label done; | 800 Label done; |
| 764 if (can_value_be_smi) { | 801 if (can_value_be_smi) { |
| 765 StoreIntoObjectFilter(object, value, &done); | 802 StoreIntoObjectFilter(object, value, &done); |
| 766 } else { | 803 } else { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 792 #if defined(DEBUG) | 829 #if defined(DEBUG) |
| 793 Label done; | 830 Label done; |
| 794 StoreIntoObjectFilter(object, value, &done); | 831 StoreIntoObjectFilter(object, value, &done); |
| 795 Stop("Store buffer update is required"); | 832 Stop("Store buffer update is required"); |
| 796 Bind(&done); | 833 Bind(&done); |
| 797 #endif // defined(DEBUG) | 834 #endif // defined(DEBUG) |
| 798 // No store buffer update. | 835 // No store buffer update. |
| 799 } | 836 } |
| 800 | 837 |
| 801 | 838 |
| 839 void Assembler::StoreIntoObjectOffsetNoBarrier(Register object, |
| 840 int32_t offset, |
| 841 Register value, |
| 842 Register pp) { |
| 843 if (Address::CanHoldOffset(offset - kHeapObjectTag)) { |
| 844 StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value); |
| 845 } else { |
| 846 AddImmediate(TMP, object, offset - kHeapObjectTag, pp); |
| 847 StoreIntoObjectNoBarrier(object, Address(TMP), value); |
| 848 } |
| 849 } |
| 850 |
| 851 |
| 802 void Assembler::StoreIntoObjectNoBarrier(Register object, | 852 void Assembler::StoreIntoObjectNoBarrier(Register object, |
| 803 const Address& dest, | 853 const Address& dest, |
| 804 const Object& value) { | 854 const Object& value) { |
| 805 ASSERT(value.IsSmi() || value.InVMHeap() || | 855 ASSERT(value.IsSmi() || value.InVMHeap() || |
| 806 (value.IsOld() && value.IsNotTemporaryScopedHandle())); | 856 (value.IsOld() && value.IsNotTemporaryScopedHandle())); |
| 807 // No store buffer update. | 857 // No store buffer update. |
| 808 LoadObject(TMP, value, PP); | 858 LoadObject(TMP2, value, PP); |
| 809 str(TMP, dest); | 859 str(TMP2, dest); |
| 810 } | 860 } |
| 811 | 861 |
| 812 | 862 |
| 813 void Assembler::LoadClassId(Register result, Register object) { | 863 void Assembler::StoreIntoObjectOffsetNoBarrier(Register object, |
| 864 int32_t offset, |
| 865 const Object& value, |
| 866 Register pp) { |
| 867 if (Address::CanHoldOffset(offset - kHeapObjectTag)) { |
| 868 StoreIntoObjectNoBarrier(object, FieldAddress(object, offset), value); |
| 869 } else { |
| 870 AddImmediate(TMP, object, offset - kHeapObjectTag, pp); |
| 871 StoreIntoObjectNoBarrier(object, Address(TMP), value); |
| 872 } |
| 873 } |
| 874 |
| 875 |
| 876 void Assembler::LoadClassId(Register result, Register object, Register pp) { |
| 814 ASSERT(RawObject::kClassIdTagPos == 16); | 877 ASSERT(RawObject::kClassIdTagPos == 16); |
| 815 ASSERT(RawObject::kClassIdTagSize == 16); | 878 ASSERT(RawObject::kClassIdTagSize == 16); |
| 816 const intptr_t class_id_offset = Object::tags_offset() + | 879 const intptr_t class_id_offset = Object::tags_offset() + |
| 817 RawObject::kClassIdTagPos / kBitsPerByte; | 880 RawObject::kClassIdTagPos / kBitsPerByte; |
| 818 LoadFromOffset(result, object, class_id_offset - kHeapObjectTag, | 881 LoadFromOffset(result, object, class_id_offset - kHeapObjectTag, pp, |
| 819 kUnsignedHalfword); | 882 kUnsignedHalfword); |
| 820 } | 883 } |
| 821 | 884 |
| 822 | 885 |
| 823 void Assembler::LoadClassById(Register result, Register class_id) { | 886 void Assembler::LoadClassById(Register result, Register class_id, Register pp) { |
| 824 ASSERT(result != class_id); | 887 ASSERT(result != class_id); |
| 825 LoadFieldFromOffset(result, CTX, Context::isolate_offset()); | 888 LoadFieldFromOffset(result, CTX, Context::isolate_offset(), pp); |
| 826 const intptr_t table_offset_in_isolate = | 889 const intptr_t table_offset_in_isolate = |
| 827 Isolate::class_table_offset() + ClassTable::table_offset(); | 890 Isolate::class_table_offset() + ClassTable::table_offset(); |
| 828 LoadFromOffset(result, result, table_offset_in_isolate); | 891 LoadFromOffset(result, result, table_offset_in_isolate, pp); |
| 829 ldr(result, Address(result, class_id, UXTX, Address::Scaled)); | 892 ldr(result, Address(result, class_id, UXTX, Address::Scaled)); |
| 830 } | 893 } |
| 831 | 894 |
| 832 | 895 |
| 833 void Assembler::LoadClass(Register result, Register object) { | 896 void Assembler::LoadClass(Register result, Register object, Register pp) { |
| 834 ASSERT(object != TMP); | 897 ASSERT(object != TMP); |
| 835 LoadClassId(TMP, object); | 898 LoadClassId(TMP, object, pp); |
| 836 LoadClassById(result, TMP); | 899 LoadClassById(result, TMP, pp); |
| 837 } | 900 } |
| 838 | 901 |
| 839 | 902 |
| 840 void Assembler::CompareClassId(Register object, | 903 void Assembler::CompareClassId( |
| 841 intptr_t class_id) { | 904 Register object, intptr_t class_id, Register pp) { |
| 842 LoadClassId(TMP, object); | 905 LoadClassId(TMP, object, pp); |
| 843 CompareImmediate(TMP, class_id, PP); | 906 CompareImmediate(TMP, class_id, pp); |
| 844 } | 907 } |
| 845 | 908 |
| 846 | 909 |
| 847 // Frame entry and exit. | 910 // Frame entry and exit. |
| 848 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { | 911 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { |
| 849 // Reserve space for arguments and align frame before entering | 912 // Reserve space for arguments and align frame before entering |
| 850 // the C++ world. | 913 // the C++ world. |
| 851 AddImmediate(SP, SP, -frame_space, kNoPP); | 914 AddImmediate(SP, SP, -frame_space, kNoPP); |
| 852 if (OS::ActivationFrameAlignment() > 1) { | 915 if (OS::ActivationFrameAlignment() > 1) { |
| 853 mov(TMP, SP); // SP can't be register operand of andi. | 916 mov(TMP, SP); // SP can't be register operand of andi. |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 915 | 978 |
| 916 // On entry to a function compiled for OSR, the caller's frame pointer, the | 979 // On entry to a function compiled for OSR, the caller's frame pointer, the |
| 917 // stack locals, and any copied parameters are already in place. The frame | 980 // stack locals, and any copied parameters are already in place. The frame |
| 918 // pointer is already set up. The PC marker is not correct for the | 981 // pointer is already set up. The PC marker is not correct for the |
| 919 // optimized function and there may be extra space for spill slots to | 982 // optimized function and there may be extra space for spill slots to |
| 920 // allocate. We must also set up the pool pointer for the function. | 983 // allocate. We must also set up the pool pointer for the function. |
| 921 void Assembler::EnterOsrFrame(intptr_t extra_size, Register new_pp) { | 984 void Assembler::EnterOsrFrame(intptr_t extra_size, Register new_pp) { |
| 922 Comment("EnterOsrFrame"); | 985 Comment("EnterOsrFrame"); |
| 923 adr(TMP, -CodeSize()); | 986 adr(TMP, -CodeSize()); |
| 924 | 987 |
| 925 StoreToOffset(TMP, FP, kPcMarkerSlotFromFp * kWordSize); | 988 StoreToOffset(TMP, FP, kPcMarkerSlotFromFp * kWordSize, kNoPP); |
| 926 | 989 |
| 927 // Setup pool pointer for this dart function. | 990 // Setup pool pointer for this dart function. |
| 928 if (new_pp == kNoPP) { | 991 if (new_pp == kNoPP) { |
| 929 LoadPoolPointer(PP); | 992 LoadPoolPointer(PP); |
| 930 } else { | 993 } else { |
| 931 mov(PP, new_pp); | 994 mov(PP, new_pp); |
| 932 } | 995 } |
| 933 | 996 |
| 934 if (extra_size > 0) { | 997 if (extra_size > 0) { |
| 935 AddImmediate(SP, SP, -extra_size, PP); | 998 AddImmediate(SP, SP, -extra_size, PP); |
| 936 } | 999 } |
| 937 } | 1000 } |
| 938 | 1001 |
| 939 | 1002 |
| 940 void Assembler::LeaveDartFrame() { | 1003 void Assembler::LeaveDartFrame() { |
| 941 // Restore and untag PP. | 1004 // Restore and untag PP. |
| 942 LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize); | 1005 LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize, kNoPP); |
| 943 sub(PP, PP, Operand(kHeapObjectTag)); | 1006 sub(PP, PP, Operand(kHeapObjectTag)); |
| 944 LeaveFrame(); | 1007 LeaveFrame(); |
| 945 } | 1008 } |
| 946 | 1009 |
| 947 | 1010 |
| 948 void Assembler::EnterCallRuntimeFrame(intptr_t frame_size) { | 1011 void Assembler::EnterCallRuntimeFrame(intptr_t frame_size) { |
| 949 EnterFrame(0); | 1012 EnterFrame(0); |
| 950 | 1013 |
| 951 // Store fpu registers with the lowest register number at the lowest | 1014 // Store fpu registers with the lowest register number at the lowest |
| 952 // address. | 1015 // address. |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1015 Push(ZR); // Push 0 in the saved PC area for stub frames. | 1078 Push(ZR); // Push 0 in the saved PC area for stub frames. |
| 1016 TagAndPushPP(); // Save caller's pool pointer | 1079 TagAndPushPP(); // Save caller's pool pointer |
| 1017 if (load_pp) { | 1080 if (load_pp) { |
| 1018 LoadPoolPointer(PP); | 1081 LoadPoolPointer(PP); |
| 1019 } | 1082 } |
| 1020 } | 1083 } |
| 1021 | 1084 |
| 1022 | 1085 |
| 1023 void Assembler::LeaveStubFrame() { | 1086 void Assembler::LeaveStubFrame() { |
| 1024 // Restore and untag PP. | 1087 // Restore and untag PP. |
| 1025 LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize); | 1088 LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize, kNoPP); |
| 1026 sub(PP, PP, Operand(kHeapObjectTag)); | 1089 sub(PP, PP, Operand(kHeapObjectTag)); |
| 1027 LeaveFrame(); | 1090 LeaveFrame(); |
| 1028 } | 1091 } |
| 1029 | 1092 |
| 1030 | 1093 |
| 1031 void Assembler::UpdateAllocationStats(intptr_t cid, | 1094 void Assembler::UpdateAllocationStats(intptr_t cid, |
| 1032 Register temp_reg, | 1095 Register temp_reg, |
| 1033 Register pp, | 1096 Register pp, |
| 1034 Heap::Space space) { | 1097 Heap::Space space) { |
| 1035 ASSERT(temp_reg != kNoRegister); | 1098 ASSERT(temp_reg != kNoRegister); |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1144 ASSERT(instance_size >= kHeapObjectTag); | 1207 ASSERT(instance_size >= kHeapObjectTag); |
| 1145 AddImmediate( | 1208 AddImmediate( |
| 1146 instance_reg, instance_reg, -instance_size + kHeapObjectTag, pp); | 1209 instance_reg, instance_reg, -instance_size + kHeapObjectTag, pp); |
| 1147 UpdateAllocationStats(cls.id(), temp_reg, pp); | 1210 UpdateAllocationStats(cls.id(), temp_reg, pp); |
| 1148 | 1211 |
| 1149 uword tags = 0; | 1212 uword tags = 0; |
| 1150 tags = RawObject::SizeTag::update(instance_size, tags); | 1213 tags = RawObject::SizeTag::update(instance_size, tags); |
| 1151 ASSERT(cls.id() != kIllegalCid); | 1214 ASSERT(cls.id() != kIllegalCid); |
| 1152 tags = RawObject::ClassIdTag::update(cls.id(), tags); | 1215 tags = RawObject::ClassIdTag::update(cls.id(), tags); |
| 1153 LoadImmediate(TMP, tags, pp); | 1216 LoadImmediate(TMP, tags, pp); |
| 1154 StoreFieldToOffset(TMP, instance_reg, Object::tags_offset()); | 1217 StoreFieldToOffset(TMP, instance_reg, Object::tags_offset(), pp); |
| 1155 } else { | 1218 } else { |
| 1156 b(failure); | 1219 b(failure); |
| 1157 } | 1220 } |
| 1158 } | 1221 } |
| 1159 | 1222 |
| 1160 } // namespace dart | 1223 } // namespace dart |
| 1161 | 1224 |
| 1162 #endif // defined TARGET_ARCH_ARM64 | 1225 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |