| 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 guard 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 // offset is from the branch instruction. |
| 152 const int64_t offset = dest - Instr::kInstrSize; |
| 153 |
| 154 // Encode the branch. |
| 155 const int32_t encoded_branch = |
| 156 EncodeImm26BranchOffset(offset, far_branch); |
| 157 |
| 158 // Replace NV conditioned branches with nops. |
| 159 if (c == NV) { |
| 160 buffer_.Store<int32_t>(position + 0 * Instr::kInstrSize, |
| 161 Instr::kNopInstruction); |
| 162 } |
| 163 |
| 164 // Write the far branch into the buffer, and link to the next branch. |
| 165 buffer_.Store<int32_t>(position + 1 * Instr::kInstrSize, encoded_branch); |
| 166 label->position_ = next; |
| 167 } else if (use_far_branches() && CanEncodeImm19BranchOffset(dest)) { |
| 168 // We assembled a far branch, but we don't need it. Replace with a near |
| 169 // branch. |
| 170 |
| 171 // Grab the guarding branch instruction. |
| 172 const int32_t guard_branch = |
| 173 buffer_.Load<int32_t>(position + 0 * Instr::kInstrSize); |
| 174 |
| 175 // Grab the far branch instruction. |
| 176 const int32_t far_branch = |
| 177 buffer_.Load<int32_t>(position + 1 * Instr::kInstrSize); |
| 178 |
| 179 // Grab the link to the next branch. |
| 180 const int32_t next = DecodeImm26BranchOffset(far_branch); |
| 181 |
| 182 // Re-target the near branch and flip the conditional sense. |
| 183 int32_t encoded_guard_branch = |
| 184 EncodeImm19BranchOffset(dest, guard_branch); |
| 185 Condition c = DecodeImm19BranchCondition(encoded_guard_branch); |
| 186 encoded_guard_branch = EncodeImm19BranchCondition( |
| 187 InvertCondition(c), encoded_guard_branch); |
| 188 |
| 189 // Write back re-encoded instructions. Far branch becomes nop. |
| 190 buffer_.Store<int32_t>( |
| 191 position + 0 * Instr::kInstrSize, encoded_guard_branch); |
| 192 buffer_.Store<int32_t>( |
| 193 position + 1 * Instr::kInstrSize, Instr::kNopInstruction); |
| 194 label->position_ = next; |
| 195 } else { |
| 196 const int32_t next = buffer_.Load<int32_t>(position); |
| 197 const int32_t encoded = EncodeImm19BranchOffset(dest, next); |
| 198 buffer_.Store<int32_t>(position, encoded); |
| 199 label->position_ = DecodeImm19BranchOffset(next); |
| 200 } |
| 138 } | 201 } |
| 139 label->BindTo(bound_pc); | 202 label->BindTo(bound_pc); |
| 140 } | 203 } |
| 141 | 204 |
| 142 | 205 |
| 143 void Assembler::Stop(const char* message) { | 206 void Assembler::Stop(const char* message) { |
| 144 if (FLAG_print_stop_message) { | 207 if (FLAG_print_stop_message) { |
| 145 UNIMPLEMENTED(); | 208 UNIMPLEMENTED(); |
| 146 } | 209 } |
| 147 Label stop; | 210 Label stop; |
| (...skipping 790 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 938 Register object, intptr_t class_id, Register pp) { | 1001 Register object, intptr_t class_id, Register pp) { |
| 939 LoadClassId(TMP, object, pp); | 1002 LoadClassId(TMP, object, pp); |
| 940 CompareImmediate(TMP, class_id, pp); | 1003 CompareImmediate(TMP, class_id, pp); |
| 941 } | 1004 } |
| 942 | 1005 |
| 943 | 1006 |
| 944 // Frame entry and exit. | 1007 // Frame entry and exit. |
| 945 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { | 1008 void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) { |
| 946 // Reserve space for arguments and align frame before entering | 1009 // Reserve space for arguments and align frame before entering |
| 947 // the C++ world. | 1010 // the C++ world. |
| 948 AddImmediate(SP, SP, -frame_space, kNoPP); | 1011 if (frame_space != 0) { |
| 1012 AddImmediate(SP, SP, -frame_space, kNoPP); |
| 1013 } |
| 949 if (OS::ActivationFrameAlignment() > 1) { | 1014 if (OS::ActivationFrameAlignment() > 1) { |
| 950 mov(TMP, SP); // SP can't be register operand of andi. | 1015 mov(TMP, SP); // SP can't be register operand of andi. |
| 951 andi(TMP, TMP, ~(OS::ActivationFrameAlignment() - 1)); | 1016 andi(TMP, TMP, ~(OS::ActivationFrameAlignment() - 1)); |
| 952 mov(SP, TMP); | 1017 mov(SP, TMP); |
| 953 } | 1018 } |
| 954 } | 1019 } |
| 955 | 1020 |
| 956 | 1021 |
| 957 void Assembler::EnterFrame(intptr_t frame_size) { | 1022 void Assembler::EnterFrame(intptr_t frame_size) { |
| 958 Push(LR); | 1023 Push(LR); |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1250 LoadImmediate(TMP, tags, pp); | 1315 LoadImmediate(TMP, tags, pp); |
| 1251 StoreFieldToOffset(TMP, instance_reg, Object::tags_offset(), pp); | 1316 StoreFieldToOffset(TMP, instance_reg, Object::tags_offset(), pp); |
| 1252 } else { | 1317 } else { |
| 1253 b(failure); | 1318 b(failure); |
| 1254 } | 1319 } |
| 1255 } | 1320 } |
| 1256 | 1321 |
| 1257 } // namespace dart | 1322 } // namespace dart |
| 1258 | 1323 |
| 1259 #endif // defined TARGET_ARCH_ARM64 | 1324 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |