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