| 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" |
| 11 #include "vm/runtime_entry.h" | 11 #include "vm/runtime_entry.h" |
| 12 #include "vm/simulator.h" | 12 #include "vm/simulator.h" |
| 13 #include "vm/stack_frame.h" | 13 #include "vm/stack_frame.h" |
| 14 #include "vm/stub_code.h" | 14 #include "vm/stub_code.h" |
| 15 | 15 |
| 16 // An extra check since we are assuming the existence of /proc/cpuinfo below. | 16 // An extra check since we are assuming the existence of /proc/cpuinfo below. |
| 17 #if !defined(USING_SIMULATOR) && !defined(__linux__) && !defined(ANDROID) | 17 #if !defined(USING_SIMULATOR) && !defined(__linux__) && !defined(ANDROID) |
| 18 #error ARM64 cross-compile only supported on Linux | 18 #error ARM64 cross-compile only supported on Linux |
| 19 #endif | 19 #endif |
| 20 | 20 |
| 21 namespace dart { | 21 namespace dart { |
| 22 | 22 |
| 23 DEFINE_FLAG(bool, use_far_branches, false, "Always use far branches"); |
| 23 DEFINE_FLAG(bool, print_stop_message, false, "Print stop message."); | 24 DEFINE_FLAG(bool, print_stop_message, false, "Print stop message."); |
| 24 DECLARE_FLAG(bool, inline_alloc); | 25 DECLARE_FLAG(bool, inline_alloc); |
| 25 | 26 |
| 26 | 27 |
| 27 Assembler::Assembler(bool use_far_branches) | 28 Assembler::Assembler(bool use_far_branches) |
| 28 : buffer_(), | 29 : buffer_(), |
| 29 object_pool_(GrowableObjectArray::Handle()), | 30 object_pool_(GrowableObjectArray::Handle()), |
| 30 patchable_pool_entries_(), | 31 patchable_pool_entries_(), |
| 31 prologue_offset_(-1), | 32 prologue_offset_(-1), |
| 32 use_far_branches_(use_far_branches), | 33 use_far_branches_(use_far_branches), |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", | 117 "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", |
| 117 }; | 118 }; |
| 118 | 119 |
| 119 | 120 |
| 120 const char* Assembler::FpuRegisterName(FpuRegister reg) { | 121 const char* Assembler::FpuRegisterName(FpuRegister reg) { |
| 121 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); | 122 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); |
| 122 return fpu_reg_names[reg]; | 123 return fpu_reg_names[reg]; |
| 123 } | 124 } |
| 124 | 125 |
| 125 | 126 |
| 126 // TODO(zra): Support for far branches. Requires loading large immediates. | |
| 127 void Assembler::Bind(Label* label) { | 127 void Assembler::Bind(Label* label) { |
| 128 ASSERT(!label->IsBound()); | 128 ASSERT(!label->IsBound()); |
| 129 intptr_t bound_pc = buffer_.Size(); | 129 const intptr_t bound_pc = buffer_.Size(); |
| 130 | 130 |
| 131 while (label->IsLinked()) { | 131 while (label->IsLinked()) { |
| 132 const int64_t position = label->Position(); | 132 const int64_t position = label->Position(); |
| 133 const int64_t dest = bound_pc - position; | 133 const int64_t dest = bound_pc - position; |
| 134 const int32_t next = buffer_.Load<int32_t>(position); | 134 if (use_far_branches() && !CanEncodeImm19BranchOffset(dest)) { |
| 135 const int32_t encoded = EncodeImm19BranchOffset(dest, next); | 135 // Far branches are enabled, and we can't encode the branch offset in |
| 136 buffer_.Store<int32_t>(position, encoded); | 136 // 19 bits. |
| 137 label->position_ = DecodeImm19BranchOffset(next); | 137 |
| 138 // Grab the guarding branch instruction. |
| 139 const int32_t guard_branch = |
| 140 buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize); |
| 141 |
| 142 // Grab the far branch instruction. |
| 143 const int32_t far_branch = |
| 144 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); |
| 145 |
| 146 const Condition c = DecodeImm19BranchCondition(guard_branch); |
| 147 |
| 148 // Grab the link to the next branch. |
| 149 const int32_t next = DecodeImm26BranchOffset(far_branch); |
| 150 |
| 151 // dest is the offset is from the guarding branch instruction. |
| 152 // Correct it to be from the following instruction. |
| 153 const int64_t offset = dest - Instr::kInstrSize; |
| 154 |
| 155 // Encode the branch. |
| 156 const int32_t encoded_branch = |
| 157 EncodeImm26BranchOffset(offset, far_branch); |
| 158 |
| 159 // If the guard branch is conditioned on NV, replace it with a nop. |
| 160 if (c == NV) { |
| 161 buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize, |
| 162 Instr::kNopInstruction); |
| 163 } |
| 164 |
| 165 // Write the far branch into the buffer and link to the next branch. |
| 166 buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, encoded_branch); |
| 167 label->position_ = next; |
| 168 } else if (use_far_branches() && CanEncodeImm19BranchOffset(dest)) { |
| 169 // We assembled a far branch, but we don't need it. Replace it with a near |
| 170 // branch. |
| 171 |
| 172 // Grab the guarding branch instruction. |
| 173 const int32_t guard_branch = |
| 174 buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize); |
| 175 |
| 176 // Grab the far branch instruction. |
| 177 const int32_t far_branch = |
| 178 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); |
| 179 |
| 180 // Grab the link to the next branch. |
| 181 const int32_t next = DecodeImm26BranchOffset(far_branch); |
| 182 |
| 183 // Re-target the guarding branch and flip the conditional sense. |
| 184 int32_t encoded_guard_branch = |
| 185 EncodeImm19BranchOffset(dest, guard_branch); |
| 186 const Condition c = DecodeImm19BranchCondition(encoded_guard_branch); |
| 187 encoded_guard_branch = EncodeImm19BranchCondition( |
| 188 InvertCondition(c), encoded_guard_branch); |
| 189 |
| 190 // Write back the re-encoded instructions. The far branch becomes a nop. |
| 191 buffer_.Store<int32_t>( |
| 192 position + 0 * Instr::kInstrSize, encoded_guard_branch); |
| 193 buffer_.Store<int32_t>( |
| 194 position + 1 * Instr::kInstrSize, Instr::kNopInstruction); |
| 195 label->position_ = next; |
| 196 } else { |
| 197 const int32_t next = buffer_.Load<int32_t>(position); |
| 198 const int32_t encoded = EncodeImm19BranchOffset(dest, next); |
| 199 buffer_.Store<int32_t>(position, encoded); |
| 200 label->position_ = DecodeImm19BranchOffset(next); |
| 201 } |
| 138 } | 202 } |
| 139 label->BindTo(bound_pc); | 203 label->BindTo(bound_pc); |
| 140 } | 204 } |
| 141 | 205 |
| 142 | 206 |
| 143 void Assembler::Stop(const char* message) { | 207 void Assembler::Stop(const char* message) { |
| 144 if (FLAG_print_stop_message) { | 208 if (FLAG_print_stop_message) { |
| 145 UNIMPLEMENTED(); | 209 UNIMPLEMENTED(); |
| 146 } | 210 } |
| 147 Label stop; | 211 Label stop; |
| (...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 419 // TODO(zra): Evaluate putting all VM heap objects into the pool. | 483 // TODO(zra): Evaluate putting all VM heap objects into the pool. |
| 420 (!object.InVMHeap() || (object.raw() == Object::null()) || | 484 (!object.InVMHeap() || (object.raw() == Object::null()) || |
| 421 (object.raw() == Bool::True().raw()) || | 485 (object.raw() == Bool::True().raw()) || |
| 422 (object.raw() == Bool::False().raw())); | 486 (object.raw() == Bool::False().raw())); |
| 423 } | 487 } |
| 424 | 488 |
| 425 | 489 |
| 426 bool Assembler::CanLoadImmediateFromPool(int64_t imm, Register pp) { | 490 bool Assembler::CanLoadImmediateFromPool(int64_t imm, Register pp) { |
| 427 return !Utils::IsInt(32, imm) && | 491 return !Utils::IsInt(32, imm) && |
| 428 (pp != kNoPP) && | 492 (pp != kNoPP) && |
| 493 // We *could* put constants in the pool in a VM isolate, but it is |
| 494 // simpler to maintain the invariant that the object pool is not used |
| 495 // in the VM isolate. |
| 429 (Isolate::Current() != Dart::vm_isolate()); | 496 (Isolate::Current() != Dart::vm_isolate()); |
| 430 } | 497 } |
| 431 | 498 |
| 432 | 499 |
| 433 void Assembler::LoadExternalLabel(Register dst, | 500 void Assembler::LoadExternalLabel(Register dst, |
| 434 const ExternalLabel* label, | 501 const ExternalLabel* label, |
| 435 Patchability patchable, | 502 Patchability patchable, |
| 436 Register pp) { | 503 Register pp) { |
| 437 const int32_t offset = | 504 const int64_t target = static_cast<int64_t>(label->address()); |
| 438 Array::element_offset(FindExternalLabel(label, patchable)); | 505 if (CanLoadImmediateFromPool(target, pp)) { |
| 439 LoadWordFromPoolOffset(dst, pp, offset); | 506 const int32_t offset = |
| 507 Array::element_offset(FindExternalLabel(label, patchable)); |
| 508 LoadWordFromPoolOffset(dst, pp, offset); |
| 509 } else { |
| 510 LoadImmediate(dst, target, kNoPP); |
| 511 } |
| 440 } | 512 } |
| 441 | 513 |
| 442 | 514 |
| 443 void Assembler::LoadExternalLabelFixed(Register dst, | 515 void Assembler::LoadExternalLabelFixed(Register dst, |
| 444 const ExternalLabel* label, | 516 const ExternalLabel* label, |
| 445 Patchability patchable, | 517 Patchability patchable, |
| 446 Register pp) { | 518 Register pp) { |
| 447 const int32_t offset = | 519 const int32_t offset = |
| 448 Array::element_offset(FindExternalLabel(label, patchable)); | 520 Array::element_offset(FindExternalLabel(label, patchable)); |
| 449 LoadWordFromPoolOffsetFixed(dst, pp, offset); | 521 LoadWordFromPoolOffsetFixed(dst, pp, offset); |
| (...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 938 Register object, intptr_t class_id, Register pp) { | 1010 Register object, intptr_t class_id, Register pp) { |
| 939 LoadClassId(TMP, object, pp); | 1011 LoadClassId(TMP, object, pp); |
| 940 CompareImmediate(TMP, class_id, pp); | 1012 CompareImmediate(TMP, class_id, pp); |
| 941 } | 1013 } |
| 942 | 1014 |
| 943 | 1015 |
| 944 // Frame entry and exit. | 1016 // Frame entry and exit. |
| 945 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { | 1017 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { |
| 946 // Reserve space for arguments and align frame before entering | 1018 // Reserve space for arguments and align frame before entering |
| 947 // the C++ world. | 1019 // the C++ world. |
| 948 AddImmediate(SP, SP, -frame_space, kNoPP); | 1020 if (frame_space != 0) { |
| 1021 AddImmediate(SP, SP, -frame_space, kNoPP); |
| 1022 } |
| 949 if (OS::ActivationFrameAlignment() > 1) { | 1023 if (OS::ActivationFrameAlignment() > 1) { |
| 950 mov(TMP, SP); // SP can't be register operand of andi. | 1024 mov(TMP, SP); // SP can't be register operand of andi. |
| 951 andi(TMP, TMP, ~(OS::ActivationFrameAlignment() - 1)); | 1025 andi(TMP, TMP, ~(OS::ActivationFrameAlignment() - 1)); |
| 952 mov(SP, TMP); | 1026 mov(SP, TMP); |
| 953 } | 1027 } |
| 954 } | 1028 } |
| 955 | 1029 |
| 956 | 1030 |
| 957 void Assembler::EnterFrame(intptr_t frame_size) { | 1031 void Assembler::EnterFrame(intptr_t frame_size) { |
| 958 Push(LR); | 1032 Push(LR); |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1250 LoadImmediate(TMP, tags, pp); | 1324 LoadImmediate(TMP, tags, pp); |
| 1251 StoreFieldToOffset(TMP, instance_reg, Object::tags_offset(), pp); | 1325 StoreFieldToOffset(TMP, instance_reg, Object::tags_offset(), pp); |
| 1252 } else { | 1326 } else { |
| 1253 b(failure); | 1327 b(failure); |
| 1254 } | 1328 } |
| 1255 } | 1329 } |
| 1256 | 1330 |
| 1257 } // namespace dart | 1331 } // namespace dart |
| 1258 | 1332 |
| 1259 #endif // defined TARGET_ARCH_ARM64 | 1333 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |