| 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" // NOLINT | 5 #include "vm/globals.h" // NOLINT |
| 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 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 continue; | 297 continue; |
| 298 } | 298 } |
| 299 | 299 |
| 300 // 6. Otherwise, the value can't be encoded. | 300 // 6. Otherwise, the value can't be encoded. |
| 301 return false; | 301 return false; |
| 302 } | 302 } |
| 303 } | 303 } |
| 304 | 304 |
| 305 | 305 |
| 306 void Assembler::LoadPoolPointer(Register pp) { | 306 void Assembler::LoadPoolPointer(Register pp) { |
| 307 const intptr_t object_pool_pc_dist = | 307 CheckCodePointer(); |
| 308 Instructions::HeaderSize() - Instructions::object_pool_offset() + | 308 ldr(pp, FieldAddress(CODE_REG, Code::object_pool_offset())); |
| 309 CodeSize(); | |
| 310 // PP <- Read(PC - object_pool_pc_dist). | |
| 311 ldr(pp, Address::PC(-object_pool_pc_dist)); | |
| 312 | 309 |
| 313 // When in the PP register, the pool pointer is untagged. When we | 310 // When in the PP register, the pool pointer is untagged. When we |
| 314 // push it on the stack with TagAndPushPP it is tagged again. PopAndUntagPP | 311 // push it on the stack with TagAndPushPP it is tagged again. PopAndUntagPP |
| 315 // then untags when restoring from the stack. This will make loading from the | 312 // then untags when restoring from the stack. This will make loading from the |
| 316 // object pool only one instruction for the first 4096 entries. Otherwise, | 313 // object pool only one instruction for the first 4096 entries. Otherwise, |
| 317 // because the offset wouldn't be aligned, it would be only one instruction | 314 // because the offset wouldn't be aligned, it would be only one instruction |
| 318 // for the first 64 entries. | 315 // for the first 64 entries. |
| 319 sub(pp, pp, Operand(kHeapObjectTag)); | 316 sub(pp, pp, Operand(kHeapObjectTag)); |
| 320 set_constant_pool_allowed(pp == PP); | 317 set_constant_pool_allowed(pp == PP); |
| 321 } | 318 } |
| 322 | 319 |
| 323 | 320 |
| 324 void Assembler::LoadWordFromPoolOffset(Register dst, uint32_t offset) { | 321 void Assembler::LoadWordFromPoolOffset(Register dst, |
| 325 ASSERT(constant_pool_allowed()); | 322 uint32_t offset, |
| 326 ASSERT(dst != PP); | 323 Register pp) { |
| 324 ASSERT((pp != PP) || constant_pool_allowed()); |
| 325 ASSERT(dst != pp); |
| 327 Operand op; | 326 Operand op; |
| 328 const uint32_t upper20 = offset & 0xfffff000; | 327 const uint32_t upper20 = offset & 0xfffff000; |
| 329 if (Address::CanHoldOffset(offset)) { | 328 if (Address::CanHoldOffset(offset)) { |
| 330 ldr(dst, Address(PP, offset)); | 329 ldr(dst, Address(pp, offset)); |
| 331 } else if (Operand::CanHold(upper20, kXRegSizeInBits, &op) == | 330 } else if (Operand::CanHold(upper20, kXRegSizeInBits, &op) == |
| 332 Operand::Immediate) { | 331 Operand::Immediate) { |
| 333 const uint32_t lower12 = offset & 0x00000fff; | 332 const uint32_t lower12 = offset & 0x00000fff; |
| 334 ASSERT(Address::CanHoldOffset(lower12)); | 333 ASSERT(Address::CanHoldOffset(lower12)); |
| 335 add(dst, PP, op); | 334 add(dst, pp, op); |
| 336 ldr(dst, Address(dst, lower12)); | 335 ldr(dst, Address(dst, lower12)); |
| 337 } else { | 336 } else { |
| 338 const uint16_t offset_low = Utils::Low16Bits(offset); | 337 const uint16_t offset_low = Utils::Low16Bits(offset); |
| 339 const uint16_t offset_high = Utils::High16Bits(offset); | 338 const uint16_t offset_high = Utils::High16Bits(offset); |
| 340 movz(dst, Immediate(offset_low), 0); | 339 movz(dst, Immediate(offset_low), 0); |
| 341 if (offset_high != 0) { | 340 if (offset_high != 0) { |
| 342 movk(dst, Immediate(offset_high), 1); | 341 movk(dst, Immediate(offset_high), 1); |
| 343 } | 342 } |
| 344 ldr(dst, Address(PP, dst)); | 343 ldr(dst, Address(pp, dst)); |
| 345 } | 344 } |
| 346 } | 345 } |
| 347 | 346 |
| 348 | 347 |
| 349 void Assembler::LoadWordFromPoolOffsetFixed(Register dst, uint32_t offset) { | 348 void Assembler::LoadWordFromPoolOffsetFixed(Register dst, uint32_t offset) { |
| 350 ASSERT(constant_pool_allowed()); | 349 ASSERT(constant_pool_allowed()); |
| 351 ASSERT(dst != PP); | 350 ASSERT(dst != PP); |
| 352 Operand op; | 351 Operand op; |
| 353 const uint32_t upper20 = offset & 0xfffff000; | 352 const uint32_t upper20 = offset & 0xfffff000; |
| 354 const uint32_t lower12 = offset & 0x00000fff; | 353 const uint32_t lower12 = offset & 0x00000fff; |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 588 | 587 |
| 589 void Assembler::LoadDImmediate(VRegister vd, double immd) { | 588 void Assembler::LoadDImmediate(VRegister vd, double immd) { |
| 590 if (!fmovdi(vd, immd)) { | 589 if (!fmovdi(vd, immd)) { |
| 591 int64_t imm = bit_cast<int64_t, double>(immd); | 590 int64_t imm = bit_cast<int64_t, double>(immd); |
| 592 LoadImmediate(TMP, imm); | 591 LoadImmediate(TMP, imm); |
| 593 fmovdr(vd, TMP); | 592 fmovdr(vd, TMP); |
| 594 } | 593 } |
| 595 } | 594 } |
| 596 | 595 |
| 597 | 596 |
| 598 void Assembler::Branch(const ExternalLabel* label) { | 597 void Assembler::Branch(const StubEntry& stub_entry, |
| 599 LoadExternalLabel(TMP, label); | 598 Register pp, |
| 600 br(TMP); | 599 Patchability patchable) { |
| 601 } | 600 const Code& target = Code::Handle(stub_entry.code()); |
| 602 | 601 const int32_t offset = ObjectPool::element_offset( |
| 603 | 602 object_pool_wrapper_.FindObject(target, patchable)); |
| 604 void Assembler::Branch(const StubEntry& stub_entry) { | 603 LoadWordFromPoolOffset(CODE_REG, offset, pp); |
| 605 const ExternalLabel label(stub_entry.EntryPoint()); | 604 ldr(TMP, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 606 Branch(&label); | |
| 607 } | |
| 608 | |
| 609 | |
| 610 void Assembler::BranchPatchable(const ExternalLabel* label) { | |
| 611 // TODO(zra): Use LoadExternalLabelFixed if possible. | |
| 612 LoadImmediateFixed(TMP, label->address()); | |
| 613 br(TMP); | 605 br(TMP); |
| 614 } | 606 } |
| 615 | 607 |
| 616 void Assembler::BranchPatchable(const StubEntry& stub_entry) { | 608 void Assembler::BranchPatchable(const StubEntry& stub_entry) { |
| 617 BranchPatchable(&stub_entry.label()); | 609 Branch(stub_entry, PP, kPatchable); |
| 618 } | 610 } |
| 619 | 611 |
| 620 | 612 |
| 621 void Assembler::BranchLink(const ExternalLabel* label) { | 613 void Assembler::BranchLink(const StubEntry& stub_entry, |
| 622 LoadExternalLabel(TMP, label); | 614 Patchability patchable) { |
| 623 blr(TMP); | 615 const Code& target = Code::Handle(stub_entry.code()); |
| 624 } | 616 const int32_t offset = ObjectPool::element_offset( |
| 625 | 617 object_pool_wrapper_.FindObject(target, patchable)); |
| 626 | 618 LoadWordFromPoolOffset(CODE_REG, offset); |
| 627 void Assembler::BranchLink(const StubEntry& stub_entry) { | 619 ldr(TMP, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 628 BranchLink(&stub_entry.label()); | |
| 629 } | |
| 630 | |
| 631 | |
| 632 void Assembler::BranchLinkPatchable(const ExternalLabel* label) { | |
| 633 LoadExternalLabelFixed(TMP, label, kPatchable); | |
| 634 blr(TMP); | 620 blr(TMP); |
| 635 } | 621 } |
| 636 | 622 |
| 637 | 623 |
| 638 void Assembler::BranchLinkPatchable(const StubEntry& stub_entry) { | 624 void Assembler::BranchLinkPatchable(const StubEntry& stub_entry) { |
| 639 BranchLinkPatchable(&stub_entry.label()); | 625 BranchLink(stub_entry, kPatchable); |
| 640 } | 626 } |
| 641 | 627 |
| 642 | 628 |
| 643 void Assembler::AddImmediate(Register dest, Register rn, int64_t imm) { | 629 void Assembler::AddImmediate(Register dest, Register rn, int64_t imm) { |
| 644 Operand op; | 630 Operand op; |
| 645 if (imm == 0) { | 631 if (imm == 0) { |
| 646 if (dest != rn) { | 632 if (dest != rn) { |
| 647 mov(dest, rn); | 633 mov(dest, rn); |
| 648 } | 634 } |
| 649 return; | 635 return; |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 919 } | 905 } |
| 920 // A store buffer update is required. | 906 // A store buffer update is required. |
| 921 if (value != R0) { | 907 if (value != R0) { |
| 922 // Preserve R0. | 908 // Preserve R0. |
| 923 Push(R0); | 909 Push(R0); |
| 924 } | 910 } |
| 925 Push(LR); | 911 Push(LR); |
| 926 if (object != R0) { | 912 if (object != R0) { |
| 927 mov(R0, object); | 913 mov(R0, object); |
| 928 } | 914 } |
| 915 ldr(CODE_REG, Address(THR, Thread::update_store_buffer_code_offset())); |
| 929 ldr(TMP, Address(THR, Thread::update_store_buffer_entry_point_offset())); | 916 ldr(TMP, Address(THR, Thread::update_store_buffer_entry_point_offset())); |
| 930 blr(TMP); | 917 blr(TMP); |
| 931 Pop(LR); | 918 Pop(LR); |
| 932 if (value != R0) { | 919 if (value != R0) { |
| 933 // Restore R0. | 920 // Restore R0. |
| 934 Pop(R0); | 921 Pop(R0); |
| 935 } | 922 } |
| 936 Bind(&done); | 923 Bind(&done); |
| 937 } | 924 } |
| 938 | 925 |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1095 // the C++ world. | 1082 // the C++ world. |
| 1096 if (frame_space != 0) { | 1083 if (frame_space != 0) { |
| 1097 AddImmediate(SP, SP, -frame_space); | 1084 AddImmediate(SP, SP, -frame_space); |
| 1098 } | 1085 } |
| 1099 if (OS::ActivationFrameAlignment() > 1) { | 1086 if (OS::ActivationFrameAlignment() > 1) { |
| 1100 andi(SP, SP, Immediate(~(OS::ActivationFrameAlignment() - 1))); | 1087 andi(SP, SP, Immediate(~(OS::ActivationFrameAlignment() - 1))); |
| 1101 } | 1088 } |
| 1102 } | 1089 } |
| 1103 | 1090 |
| 1104 | 1091 |
| 1092 void Assembler::RestoreCodePointer() { |
| 1093 ldr(CODE_REG, Address(FP, kPcMarkerSlotFromFp * kWordSize)); |
| 1094 CheckCodePointer(); |
| 1095 } |
| 1096 |
| 1097 |
| 1098 void Assembler::CheckCodePointer() { |
| 1099 #ifdef DEBUG |
| 1100 Label cid_ok, instructions_ok; |
| 1101 Push(R0); |
| 1102 CompareClassId(CODE_REG, kCodeCid); |
| 1103 b(&cid_ok, EQ); |
| 1104 brk(0); |
| 1105 Bind(&cid_ok); |
| 1106 |
| 1107 const intptr_t entry_offset = |
| 1108 CodeSize() + Instructions::HeaderSize() - kHeapObjectTag; |
| 1109 adr(R0, Immediate(-entry_offset)); |
| 1110 ldr(TMP, FieldAddress(CODE_REG, Code::saved_instructions_offset())); |
| 1111 cmp(R0, Operand(TMP)); |
| 1112 b(&instructions_ok, EQ); |
| 1113 brk(1); |
| 1114 Bind(&instructions_ok); |
| 1115 Pop(R0); |
| 1116 #endif |
| 1117 } |
| 1118 |
| 1119 |
| 1105 void Assembler::EnterFrame(intptr_t frame_size) { | 1120 void Assembler::EnterFrame(intptr_t frame_size) { |
| 1106 PushPair(LR, FP); | 1121 PushPair(LR, FP); |
| 1107 mov(FP, SP); | 1122 mov(FP, SP); |
| 1108 | 1123 |
| 1109 if (frame_size > 0) { | 1124 if (frame_size > 0) { |
| 1110 sub(SP, SP, Operand(frame_size)); | 1125 sub(SP, SP, Operand(frame_size)); |
| 1111 } | 1126 } |
| 1112 } | 1127 } |
| 1113 | 1128 |
| 1114 | 1129 |
| 1115 void Assembler::LeaveFrame() { | 1130 void Assembler::LeaveFrame() { |
| 1116 mov(SP, FP); | 1131 mov(SP, FP); |
| 1117 PopPair(LR, FP); | 1132 PopPair(LR, FP); |
| 1118 } | 1133 } |
| 1119 | 1134 |
| 1120 | 1135 |
| 1121 void Assembler::EnterDartFrame(intptr_t frame_size, Register new_pp) { | 1136 void Assembler::EnterDartFrame(intptr_t frame_size, Register new_pp) { |
| 1122 ASSERT(!constant_pool_allowed()); | 1137 ASSERT(!constant_pool_allowed()); |
| 1123 // Setup the frame. | 1138 // Setup the frame. |
| 1124 adr(TMP, Immediate(-CodeSize())); // TMP gets PC marker. | |
| 1125 EnterFrame(0); | 1139 EnterFrame(0); |
| 1126 TagAndPushPPAndPcMarker(TMP); // Save PP and PC marker. | 1140 TagAndPushPPAndPcMarker(); // Save PP and PC marker. |
| 1127 | 1141 |
| 1128 // Load the pool pointer. | 1142 // Load the pool pointer. |
| 1129 if (new_pp == kNoRegister) { | 1143 if (new_pp == kNoRegister) { |
| 1130 LoadPoolPointer(); | 1144 LoadPoolPointer(); |
| 1131 } else { | 1145 } else { |
| 1132 mov(PP, new_pp); | 1146 mov(PP, new_pp); |
| 1133 set_constant_pool_allowed(true); | 1147 set_constant_pool_allowed(true); |
| 1134 } | 1148 } |
| 1135 | 1149 |
| 1136 // Reserve space. | 1150 // Reserve space. |
| 1137 if (frame_size > 0) { | 1151 if (frame_size > 0) { |
| 1138 AddImmediate(SP, SP, -frame_size); | 1152 AddImmediate(SP, SP, -frame_size); |
| 1139 } | 1153 } |
| 1140 } | 1154 } |
| 1141 | 1155 |
| 1142 | 1156 |
| 1143 // On entry to a function compiled for OSR, the caller's frame pointer, the | 1157 // On entry to a function compiled for OSR, the caller's frame pointer, the |
| 1144 // stack locals, and any copied parameters are already in place. The frame | 1158 // stack locals, and any copied parameters are already in place. The frame |
| 1145 // pointer is already set up. The PC marker is not correct for the | 1159 // pointer is already set up. The PC marker is not correct for the |
| 1146 // optimized function and there may be extra space for spill slots to | 1160 // optimized function and there may be extra space for spill slots to |
| 1147 // allocate. We must also set up the pool pointer for the function. | 1161 // allocate. We must also set up the pool pointer for the function. |
| 1148 void Assembler::EnterOsrFrame(intptr_t extra_size, Register new_pp) { | 1162 void Assembler::EnterOsrFrame(intptr_t extra_size, Register new_pp) { |
| 1149 ASSERT(!constant_pool_allowed()); | 1163 ASSERT(!constant_pool_allowed()); |
| 1150 Comment("EnterOsrFrame"); | 1164 Comment("EnterOsrFrame"); |
| 1151 adr(TMP, Immediate(-CodeSize())); | 1165 RestoreCodePointer(); |
| 1152 | 1166 LoadPoolPointer(); |
| 1153 StoreToOffset(TMP, FP, kPcMarkerSlotFromFp * kWordSize); | |
| 1154 | |
| 1155 // Setup pool pointer for this dart function. | |
| 1156 if (new_pp == kNoRegister) { | |
| 1157 LoadPoolPointer(); | |
| 1158 } else { | |
| 1159 mov(PP, new_pp); | |
| 1160 set_constant_pool_allowed(true); | |
| 1161 } | |
| 1162 | 1167 |
| 1163 if (extra_size > 0) { | 1168 if (extra_size > 0) { |
| 1164 AddImmediate(SP, SP, -extra_size); | 1169 AddImmediate(SP, SP, -extra_size); |
| 1165 } | 1170 } |
| 1166 } | 1171 } |
| 1167 | 1172 |
| 1168 | 1173 |
| 1169 void Assembler::LeaveDartFrame() { | 1174 void Assembler::LeaveDartFrame(RestorePP restore_pp) { |
| 1170 set_constant_pool_allowed(false); | 1175 if (restore_pp == kRestoreCallerPP) { |
| 1171 // Restore and untag PP. | 1176 set_constant_pool_allowed(false); |
| 1172 LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize); | 1177 // Restore and untag PP. |
| 1173 sub(PP, PP, Operand(kHeapObjectTag)); | 1178 LoadFromOffset(PP, FP, kSavedCallerPpSlotFromFp * kWordSize); |
| 1179 sub(PP, PP, Operand(kHeapObjectTag)); |
| 1180 } |
| 1174 LeaveFrame(); | 1181 LeaveFrame(); |
| 1175 } | 1182 } |
| 1176 | 1183 |
| 1177 | 1184 |
| 1178 void Assembler::EnterCallRuntimeFrame(intptr_t frame_size) { | 1185 void Assembler::EnterCallRuntimeFrame(intptr_t frame_size) { |
| 1179 EnterStubFrame(); | 1186 EnterStubFrame(); |
| 1180 | 1187 |
| 1181 // Store fpu registers with the lowest register number at the lowest | 1188 // Store fpu registers with the lowest register number at the lowest |
| 1182 // address. | 1189 // address. |
| 1183 for (int i = kNumberOfVRegisters - 1; i >= 0; i--) { | 1190 for (int i = kNumberOfVRegisters - 1; i >= 0; i--) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1229 } | 1236 } |
| 1230 | 1237 |
| 1231 | 1238 |
| 1232 void Assembler::CallRuntime(const RuntimeEntry& entry, | 1239 void Assembler::CallRuntime(const RuntimeEntry& entry, |
| 1233 intptr_t argument_count) { | 1240 intptr_t argument_count) { |
| 1234 entry.Call(this, argument_count); | 1241 entry.Call(this, argument_count); |
| 1235 } | 1242 } |
| 1236 | 1243 |
| 1237 | 1244 |
| 1238 void Assembler::EnterStubFrame() { | 1245 void Assembler::EnterStubFrame() { |
| 1239 set_constant_pool_allowed(false); | 1246 EnterDartFrame(0); |
| 1240 EnterFrame(0); | |
| 1241 // Save caller's pool pointer. Push 0 in the saved PC area for stub frames. | |
| 1242 TagAndPushPPAndPcMarker(ZR); | |
| 1243 LoadPoolPointer(); | |
| 1244 } | 1247 } |
| 1245 | 1248 |
| 1246 | 1249 |
| 1247 void Assembler::LeaveStubFrame() { | 1250 void Assembler::LeaveStubFrame() { |
| 1248 LeaveDartFrame(); | 1251 LeaveDartFrame(); |
| 1249 } | 1252 } |
| 1250 | 1253 |
| 1251 | 1254 |
| 1252 void Assembler::UpdateAllocationStats(intptr_t cid, | 1255 void Assembler::UpdateAllocationStats(intptr_t cid, |
| 1253 Heap::Space space, | 1256 Heap::Space space, |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1478 add(base, array, Operand(index, LSL, shift)); | 1481 add(base, array, Operand(index, LSL, shift)); |
| 1479 } | 1482 } |
| 1480 const OperandSize size = Address::OperandSizeFor(cid); | 1483 const OperandSize size = Address::OperandSizeFor(cid); |
| 1481 ASSERT(Address::CanHoldOffset(offset, Address::Offset, size)); | 1484 ASSERT(Address::CanHoldOffset(offset, Address::Offset, size)); |
| 1482 return Address(base, offset, Address::Offset, size); | 1485 return Address(base, offset, Address::Offset, size); |
| 1483 } | 1486 } |
| 1484 | 1487 |
| 1485 } // namespace dart | 1488 } // namespace dart |
| 1486 | 1489 |
| 1487 #endif // defined TARGET_ARCH_ARM64 | 1490 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |