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 |