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