| 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 585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 596 if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) { | 596 if (Operand::IsImmLogical(imm, kXRegSizeInBits, &imm_op)) { |
| 597 tsti(rn, imm); | 597 tsti(rn, imm); |
| 598 } else { | 598 } else { |
| 599 LoadImmediate(TMP, imm, pp); | 599 LoadImmediate(TMP, imm, pp); |
| 600 tst(rn, Operand(TMP)); | 600 tst(rn, Operand(TMP)); |
| 601 } | 601 } |
| 602 } | 602 } |
| 603 | 603 |
| 604 | 604 |
| 605 void Assembler::CompareImmediate(Register rn, int64_t imm, Register pp) { | 605 void Assembler::CompareImmediate(Register rn, int64_t imm, Register pp) { |
| 606 ASSERT(rn != TMP2); | |
| 607 Operand op; | 606 Operand op; |
| 608 if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) { | 607 if (Operand::CanHold(imm, kXRegSizeInBits, &op) == Operand::Immediate) { |
| 609 cmp(rn, op); | 608 cmp(rn, op); |
| 610 } else if (Operand::CanHold(-imm, kXRegSizeInBits, &op) == | 609 } else if (Operand::CanHold(-imm, kXRegSizeInBits, &op) == |
| 611 Operand::Immediate) { | 610 Operand::Immediate) { |
| 612 cmn(rn, op); | 611 cmn(rn, op); |
| 613 } else { | 612 } else { |
| 613 ASSERT(rn != TMP2); |
| 614 LoadImmediate(TMP2, imm, pp); | 614 LoadImmediate(TMP2, imm, pp); |
| 615 cmp(rn, Operand(TMP2)); | 615 cmp(rn, Operand(TMP2)); |
| 616 } | 616 } |
| 617 } | 617 } |
| 618 | 618 |
| 619 | 619 |
| 620 void Assembler::LoadFromOffset( | 620 void Assembler::LoadFromOffset( |
| 621 Register dest, Register base, int32_t offset, OperandSize sz) { | 621 Register dest, Register base, int32_t offset, OperandSize sz) { |
| 622 ASSERT(base != TMP2); | |
| 623 if (Address::CanHoldOffset(offset, Address::Offset, sz)) { | 622 if (Address::CanHoldOffset(offset, Address::Offset, sz)) { |
| 624 ldr(dest, Address(base, offset, Address::Offset, sz), sz); | 623 ldr(dest, Address(base, offset, Address::Offset, sz), sz); |
| 625 } else { | 624 } else { |
| 625 ASSERT(base != TMP2); |
| 626 // Since offset is 32-bits, it won't be loaded from the pool. | 626 // Since offset is 32-bits, it won't be loaded from the pool. |
| 627 AddImmediate(TMP2, base, offset, kNoPP); | 627 AddImmediate(TMP2, base, offset, kNoPP); |
| 628 ldr(dest, Address(TMP2), sz); | 628 ldr(dest, Address(TMP2), sz); |
| 629 } | 629 } |
| 630 } | 630 } |
| 631 | 631 |
| 632 | 632 |
| 633 void Assembler::LoadDFromOffset(VRegister dest, Register base, int32_t offset) { |
| 634 if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) { |
| 635 fldrd(dest, Address(base, offset, Address::Offset, kDWord)); |
| 636 } else { |
| 637 ASSERT(base != TMP2); |
| 638 // Since offset is 32-bits, it won't be loaded from the pool. |
| 639 AddImmediate(TMP2, base, offset, kNoPP); |
| 640 fldrd(dest, Address(TMP2)); |
| 641 } |
| 642 } |
| 643 |
| 644 |
| 633 void Assembler::StoreToOffset( | 645 void Assembler::StoreToOffset( |
| 634 Register src, Register base, int32_t offset, OperandSize sz) { | 646 Register src, Register base, int32_t offset, OperandSize sz) { |
| 635 ASSERT(src != TMP2); | |
| 636 ASSERT(base != TMP2); | 647 ASSERT(base != TMP2); |
| 637 if (Address::CanHoldOffset(offset, Address::Offset, sz)) { | 648 if (Address::CanHoldOffset(offset, Address::Offset, sz)) { |
| 638 str(src, Address(base, offset, Address::Offset, sz), sz); | 649 str(src, Address(base, offset, Address::Offset, sz), sz); |
| 639 } else { | 650 } else { |
| 651 ASSERT(src != TMP2); |
| 640 // Since offset is 32-bits, it won't be loaded from the pool. | 652 // Since offset is 32-bits, it won't be loaded from the pool. |
| 641 AddImmediate(TMP2, base, offset, kNoPP); | 653 AddImmediate(TMP2, base, offset, kNoPP); |
| 642 str(src, Address(TMP2), sz); | 654 str(src, Address(TMP2), sz); |
| 643 } | 655 } |
| 644 } | 656 } |
| 645 | 657 |
| 646 | 658 |
| 659 void Assembler::StoreDToOffset(VRegister src, Register base, int32_t offset) { |
| 660 if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) { |
| 661 fstrd(src, Address(base, offset, Address::Offset, kDWord)); |
| 662 } else { |
| 663 ASSERT(base != TMP2); |
| 664 // Since offset is 32-bits, it won't be loaded from the pool. |
| 665 AddImmediate(TMP2, base, offset, kNoPP); |
| 666 fstrd(src, Address(TMP2)); |
| 667 } |
| 668 } |
| 669 |
| 670 |
| 647 // Store into object. | 671 // Store into object. |
| 648 // Preserves object and value registers. | 672 // Preserves object and value registers. |
| 649 void Assembler::StoreIntoObjectFilterNoSmi(Register object, | 673 void Assembler::StoreIntoObjectFilterNoSmi(Register object, |
| 650 Register value, | 674 Register value, |
| 651 Label* no_update) { | 675 Label* no_update) { |
| 652 COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) && | 676 COMPILE_ASSERT((kNewObjectAlignmentOffset == kWordSize) && |
| 653 (kOldObjectAlignmentOffset == 0), young_alignment); | 677 (kOldObjectAlignmentOffset == 0), young_alignment); |
| 654 | 678 |
| 655 // Write-barrier triggers if the value is in the new space (has bit set) and | 679 // Write-barrier triggers if the value is in the new space (has bit set) and |
| 656 // the object is in the old space (has bit cleared). | 680 // the object is in the old space (has bit cleared). |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 866 // Restore and untag PP. | 890 // Restore and untag PP. |
| 867 LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize); | 891 LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize); |
| 868 sub(PP, PP, Operand(kHeapObjectTag)); | 892 sub(PP, PP, Operand(kHeapObjectTag)); |
| 869 LeaveFrame(); | 893 LeaveFrame(); |
| 870 } | 894 } |
| 871 | 895 |
| 872 | 896 |
| 873 void Assembler::EnterCallRuntimeFrame(intptr_t frame_size) { | 897 void Assembler::EnterCallRuntimeFrame(intptr_t frame_size) { |
| 874 EnterFrame(0); | 898 EnterFrame(0); |
| 875 | 899 |
| 876 // TODO(zra): also save volatile FPU registers. | 900 // Store fpu registers with the lowest register number at the lowest |
| 901 // address. |
| 902 for (int i = kNumberOfVRegisters - 1; i >= 0; i--) { |
| 903 if ((i >= kAbiFirstPreservedFpuReg) && (i <= kAbiLastPreservedFpuReg)) { |
| 904 // TODO(zra): When SIMD is added, we must also preserve the top |
| 905 // 64-bits of the callee-saved registers. |
| 906 continue; |
| 907 } |
| 908 // TODO(zra): Save the whole V register. |
| 909 VRegister reg = static_cast<VRegister>(i); |
| 910 PushDouble(reg); |
| 911 } |
| 877 | 912 |
| 878 for (int i = kDartFirstVolatileCpuReg; i <= kDartLastVolatileCpuReg; i++) { | 913 for (int i = kDartFirstVolatileCpuReg; i <= kDartLastVolatileCpuReg; i++) { |
| 879 const Register reg = static_cast<Register>(i); | 914 const Register reg = static_cast<Register>(i); |
| 880 if ((reg != R16) && (reg != R17)) { | 915 if ((reg != TMP) && (reg != TMP2)) { |
| 881 Push(reg); | 916 Push(reg); |
| 882 } | 917 } |
| 883 } | 918 } |
| 884 | 919 |
| 885 ReserveAlignedFrameSpace(frame_size); | 920 ReserveAlignedFrameSpace(frame_size); |
| 886 } | 921 } |
| 887 | 922 |
| 888 | 923 |
| 889 void Assembler::LeaveCallRuntimeFrame() { | 924 void Assembler::LeaveCallRuntimeFrame() { |
| 890 // SP might have been modified to reserve space for arguments | 925 // SP might have been modified to reserve space for arguments |
| 891 // and ensure proper alignment of the stack frame. | 926 // and ensure proper alignment of the stack frame. |
| 892 // We need to restore it before restoring registers. | 927 // We need to restore it before restoring registers. |
| 893 // TODO(zra): Also include FPU regs in this count once they are added. | 928 // TODO(zra): Also include FPU regs in this count once they are added. |
| 894 const intptr_t kPushedRegistersSize = | 929 const intptr_t kPushedRegistersSize = |
| 895 kDartVolatileCpuRegCount * kWordSize; | 930 kDartVolatileCpuRegCount * kWordSize + |
| 931 kDartVolatileFpuRegCount * kWordSize; |
| 896 AddImmediate(SP, FP, -kPushedRegistersSize, PP); | 932 AddImmediate(SP, FP, -kPushedRegistersSize, PP); |
| 897 for (int i = kDartLastVolatileCpuReg; i >= kDartFirstVolatileCpuReg; i--) { | 933 for (int i = kDartLastVolatileCpuReg; i >= kDartFirstVolatileCpuReg; i--) { |
| 898 const Register reg = static_cast<Register>(i); | 934 const Register reg = static_cast<Register>(i); |
| 899 if ((reg != R16) && (reg != R17)) { | 935 if ((reg != TMP) && (reg != TMP2)) { |
| 900 Pop(reg); | 936 Pop(reg); |
| 901 } | 937 } |
| 902 } | 938 } |
| 903 | 939 |
| 940 for (int i = 0; i < kNumberOfVRegisters; i++) { |
| 941 if ((i >= kAbiFirstPreservedFpuReg) && (i <= kAbiLastPreservedFpuReg)) { |
| 942 // TODO(zra): When SIMD is added, we must also restore the top |
| 943 // 64-bits of the callee-saved registers. |
| 944 continue; |
| 945 } |
| 946 // TODO(zra): Restore the whole V register. |
| 947 VRegister reg = static_cast<VRegister>(i); |
| 948 PopDouble(reg); |
| 949 } |
| 950 |
| 904 Pop(FP); | 951 Pop(FP); |
| 905 Pop(LR); | 952 Pop(LR); |
| 906 } | 953 } |
| 907 | 954 |
| 908 | 955 |
| 909 void Assembler::CallRuntime(const RuntimeEntry& entry, | 956 void Assembler::CallRuntime(const RuntimeEntry& entry, |
| 910 intptr_t argument_count) { | 957 intptr_t argument_count) { |
| 911 entry.Call(this, argument_count); | 958 entry.Call(this, argument_count); |
| 912 } | 959 } |
| 913 | 960 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1010 AddImmediate(temp_reg, temp_reg, class_offset, pp); | 1057 AddImmediate(temp_reg, temp_reg, class_offset, pp); |
| 1011 ldr(TMP, Address(temp_reg, count_field_offset)); | 1058 ldr(TMP, Address(temp_reg, count_field_offset)); |
| 1012 AddImmediate(TMP, TMP, 1, pp); | 1059 AddImmediate(TMP, TMP, 1, pp); |
| 1013 str(TMP, Address(temp_reg, count_field_offset)); | 1060 str(TMP, Address(temp_reg, count_field_offset)); |
| 1014 ldr(TMP, Address(temp_reg, size_field_offset)); | 1061 ldr(TMP, Address(temp_reg, size_field_offset)); |
| 1015 add(TMP, TMP, Operand(size_reg)); | 1062 add(TMP, TMP, Operand(size_reg)); |
| 1016 str(TMP, Address(temp_reg, size_field_offset)); | 1063 str(TMP, Address(temp_reg, size_field_offset)); |
| 1017 } | 1064 } |
| 1018 } | 1065 } |
| 1019 | 1066 |
| 1067 |
| 1068 void Assembler::TryAllocate(const Class& cls, |
| 1069 Label* failure, |
| 1070 Register instance_reg, |
| 1071 Register temp_reg, |
| 1072 Register pp) { |
| 1073 ASSERT(failure != NULL); |
| 1074 if (FLAG_inline_alloc) { |
| 1075 Heap* heap = Isolate::Current()->heap(); |
| 1076 const intptr_t instance_size = cls.instance_size(); |
| 1077 LoadImmediate(instance_reg, heap->TopAddress(), pp); |
| 1078 ldr(instance_reg, Address(instance_reg)); |
| 1079 AddImmediate(instance_reg, instance_reg, instance_size, pp); |
| 1080 |
| 1081 // instance_reg: potential next object start. |
| 1082 LoadImmediate(TMP, heap->EndAddress(), pp); |
| 1083 ldr(TMP, Address(TMP)); |
| 1084 CompareRegisters(TMP, instance_reg); |
| 1085 // fail if heap end unsigned less than or equal to instance_reg. |
| 1086 b(failure, LS); |
| 1087 |
| 1088 // Successfully allocated the object, now update top to point to |
| 1089 // next object start and store the class in the class field of object. |
| 1090 LoadImmediate(TMP, heap->TopAddress(), pp); |
| 1091 str(instance_reg, Address(TMP)); |
| 1092 |
| 1093 ASSERT(instance_size >= kHeapObjectTag); |
| 1094 AddImmediate( |
| 1095 instance_reg, instance_reg, -instance_size + kHeapObjectTag, pp); |
| 1096 UpdateAllocationStats(cls.id(), temp_reg, pp); |
| 1097 |
| 1098 uword tags = 0; |
| 1099 tags = RawObject::SizeTag::update(instance_size, tags); |
| 1100 ASSERT(cls.id() != kIllegalCid); |
| 1101 tags = RawObject::ClassIdTag::update(cls.id(), tags); |
| 1102 LoadImmediate(TMP, tags, pp); |
| 1103 StoreFieldToOffset(TMP, instance_reg, Object::tags_offset()); |
| 1104 } else { |
| 1105 b(failure); |
| 1106 } |
| 1107 } |
| 1108 |
| 1020 } // namespace dart | 1109 } // namespace dart |
| 1021 | 1110 |
| 1022 #endif // defined TARGET_ARCH_ARM64 | 1111 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |