1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#ifndef ART_COMPILER_UTILS_ARM64_ASSEMBLER_ARM64_H_ 18#define ART_COMPILER_UTILS_ARM64_ASSEMBLER_ARM64_H_ 19 20#include <stdint.h> 21#include <memory> 22#include <vector> 23 24#include "base/arena_containers.h" 25#include "base/logging.h" 26#include "constants_arm64.h" 27#include "utils/arm64/managed_register_arm64.h" 28#include "utils/assembler.h" 29#include "offsets.h" 30 31// TODO: make vixl clean wrt -Wshadow. 32#pragma GCC diagnostic push 33#pragma GCC diagnostic ignored "-Wunknown-pragmas" 34#pragma GCC diagnostic ignored "-Wshadow" 35#pragma GCC diagnostic ignored "-Wmissing-noreturn" 36#include "vixl/a64/macro-assembler-a64.h" 37#include "vixl/a64/disasm-a64.h" 38#pragma GCC diagnostic pop 39 40namespace art { 41namespace arm64 { 42 43#define MEM_OP(...) vixl::MemOperand(__VA_ARGS__) 44 45enum LoadOperandType { 46 kLoadSignedByte, 47 kLoadUnsignedByte, 48 kLoadSignedHalfword, 49 kLoadUnsignedHalfword, 50 kLoadWord, 51 kLoadCoreWord, 52 kLoadSWord, 53 kLoadDWord 54}; 55 56enum StoreOperandType { 57 kStoreByte, 58 kStoreHalfword, 59 kStoreWord, 60 kStoreCoreWord, 61 kStoreSWord, 62 kStoreDWord 63}; 64 65class Arm64Exception { 66 private: 67 Arm64Exception(Arm64ManagedRegister scratch, size_t stack_adjust) 68 : scratch_(scratch), stack_adjust_(stack_adjust) { 69 } 70 71 vixl::Label* Entry() { return &exception_entry_; } 72 73 // Register used for passing Thread::Current()->exception_ . 74 const Arm64ManagedRegister scratch_; 75 76 // Stack adjust for ExceptionPool. 77 const size_t stack_adjust_; 78 79 vixl::Label exception_entry_; 80 81 friend class Arm64Assembler; 82 DISALLOW_COPY_AND_ASSIGN(Arm64Exception); 83}; 84 85class Arm64Assembler FINAL : public Assembler { 86 public: 87 // We indicate the size of the initial code generation buffer to the VIXL 88 // assembler. From there we it will automatically manage the buffer. 89 explicit Arm64Assembler(ArenaAllocator* arena) 90 : Assembler(arena), 91 exception_blocks_(arena->Adapter(kArenaAllocAssembler)), 92 vixl_masm_(new vixl::MacroAssembler(kArm64BaseBufferSize)) {} 93 94 virtual ~Arm64Assembler() { 95 delete vixl_masm_; 96 } 97 98 // Finalize the code. 99 void FinalizeCode() OVERRIDE; 100 101 // Size of generated code. 102 size_t CodeSize() const OVERRIDE; 103 const uint8_t* CodeBufferBaseAddress() const OVERRIDE; 104 105 // Copy instructions out of assembly buffer into the given region of memory. 106 void FinalizeInstructions(const MemoryRegion& region); 107 108 void SpillRegisters(vixl::CPURegList registers, int offset); 109 void UnspillRegisters(vixl::CPURegList registers, int offset); 110 111 // Emit code that will create an activation on the stack. 112 void BuildFrame(size_t frame_size, ManagedRegister method_reg, 113 const std::vector<ManagedRegister>& callee_save_regs, 114 const ManagedRegisterEntrySpills& entry_spills) OVERRIDE; 115 116 // Emit code that will remove an activation from the stack. 117 void RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs) 118 OVERRIDE; 119 120 void IncreaseFrameSize(size_t adjust) OVERRIDE; 121 void DecreaseFrameSize(size_t adjust) OVERRIDE; 122 123 // Store routines. 124 void Store(FrameOffset offs, ManagedRegister src, size_t size) OVERRIDE; 125 void StoreRef(FrameOffset dest, ManagedRegister src) OVERRIDE; 126 void StoreRawPtr(FrameOffset dest, ManagedRegister src) OVERRIDE; 127 void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister scratch) OVERRIDE; 128 void StoreImmediateToThread64(ThreadOffset<8> dest, uint32_t imm, ManagedRegister scratch) 129 OVERRIDE; 130 void StoreStackOffsetToThread64(ThreadOffset<8> thr_offs, FrameOffset fr_offs, 131 ManagedRegister scratch) OVERRIDE; 132 void StoreStackPointerToThread64(ThreadOffset<8> thr_offs) OVERRIDE; 133 void StoreSpanning(FrameOffset dest, ManagedRegister src, FrameOffset in_off, 134 ManagedRegister scratch) OVERRIDE; 135 136 // Load routines. 137 void Load(ManagedRegister dest, FrameOffset src, size_t size) OVERRIDE; 138 void LoadFromThread64(ManagedRegister dest, ThreadOffset<8> src, size_t size) OVERRIDE; 139 void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE; 140 void LoadRef(ManagedRegister dest, ManagedRegister base, MemberOffset offs, 141 bool unpoison_reference) OVERRIDE; 142 void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) OVERRIDE; 143 void LoadRawPtrFromThread64(ManagedRegister dest, ThreadOffset<8> offs) OVERRIDE; 144 145 // Copying routines. 146 void Move(ManagedRegister dest, ManagedRegister src, size_t size) OVERRIDE; 147 void CopyRawPtrFromThread64(FrameOffset fr_offs, ThreadOffset<8> thr_offs, 148 ManagedRegister scratch) OVERRIDE; 149 void CopyRawPtrToThread64(ThreadOffset<8> thr_offs, FrameOffset fr_offs, ManagedRegister scratch) 150 OVERRIDE; 151 void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch) OVERRIDE; 152 void Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch, size_t size) OVERRIDE; 153 void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, ManagedRegister scratch, 154 size_t size) OVERRIDE; 155 void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, ManagedRegister scratch, 156 size_t size) OVERRIDE; 157 void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, ManagedRegister scratch, 158 size_t size) OVERRIDE; 159 void Copy(ManagedRegister dest, Offset dest_offset, ManagedRegister src, Offset src_offset, 160 ManagedRegister scratch, size_t size) OVERRIDE; 161 void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset, 162 ManagedRegister scratch, size_t size) OVERRIDE; 163 void MemoryBarrier(ManagedRegister scratch) OVERRIDE; 164 165 // Sign extension. 166 void SignExtend(ManagedRegister mreg, size_t size) OVERRIDE; 167 168 // Zero extension. 169 void ZeroExtend(ManagedRegister mreg, size_t size) OVERRIDE; 170 171 // Exploit fast access in managed code to Thread::Current(). 172 void GetCurrentThread(ManagedRegister tr) OVERRIDE; 173 void GetCurrentThread(FrameOffset dest_offset, ManagedRegister scratch) OVERRIDE; 174 175 // Set up out_reg to hold a Object** into the handle scope, or to be null if the 176 // value is null and null_allowed. in_reg holds a possibly stale reference 177 // that can be used to avoid loading the handle scope entry to see if the value is 178 // null. 179 void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset, 180 ManagedRegister in_reg, bool null_allowed) OVERRIDE; 181 182 // Set up out_off to hold a Object** into the handle scope, or to be null if the 183 // value is null and null_allowed. 184 void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset, 185 ManagedRegister scratch, bool null_allowed) OVERRIDE; 186 187 // src holds a handle scope entry (Object**) load this into dst. 188 void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE; 189 190 // Heap::VerifyObject on src. In some cases (such as a reference to this) we 191 // know that src may not be null. 192 void VerifyObject(ManagedRegister src, bool could_be_null) OVERRIDE; 193 void VerifyObject(FrameOffset src, bool could_be_null) OVERRIDE; 194 195 // Call to address held at [base+offset]. 196 void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) OVERRIDE; 197 void Call(FrameOffset base, Offset offset, ManagedRegister scratch) OVERRIDE; 198 void CallFromThread64(ThreadOffset<8> offset, ManagedRegister scratch) OVERRIDE; 199 200 // Jump to address (not setting link register) 201 void JumpTo(ManagedRegister m_base, Offset offs, ManagedRegister m_scratch); 202 203 // Generate code to check if Thread::Current()->exception_ is non-null 204 // and branch to a ExceptionSlowPath if it is. 205 void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) OVERRIDE; 206 207 // 208 // Heap poisoning. 209 // 210 211 // Poison a heap reference contained in `reg`. 212 void PoisonHeapReference(vixl::Register reg); 213 // Unpoison a heap reference contained in `reg`. 214 void UnpoisonHeapReference(vixl::Register reg); 215 // Unpoison a heap reference contained in `reg` if heap poisoning is enabled. 216 void MaybeUnpoisonHeapReference(vixl::Register reg); 217 218 void Bind(Label* label ATTRIBUTE_UNUSED) OVERRIDE { 219 UNIMPLEMENTED(FATAL) << "Do not use Bind for ARM64"; 220 } 221 void Jump(Label* label ATTRIBUTE_UNUSED) OVERRIDE { 222 UNIMPLEMENTED(FATAL) << "Do not use Jump for ARM64"; 223 } 224 225 private: 226 static vixl::Register reg_x(int code) { 227 CHECK(code < kNumberOfXRegisters) << code; 228 if (code == SP) { 229 return vixl::sp; 230 } else if (code == XZR) { 231 return vixl::xzr; 232 } 233 return vixl::Register::XRegFromCode(code); 234 } 235 236 static vixl::Register reg_w(int code) { 237 CHECK(code < kNumberOfWRegisters) << code; 238 if (code == WSP) { 239 return vixl::wsp; 240 } else if (code == WZR) { 241 return vixl::wzr; 242 } 243 return vixl::Register::WRegFromCode(code); 244 } 245 246 static vixl::FPRegister reg_d(int code) { 247 return vixl::FPRegister::DRegFromCode(code); 248 } 249 250 static vixl::FPRegister reg_s(int code) { 251 return vixl::FPRegister::SRegFromCode(code); 252 } 253 254 // Emits Exception block. 255 void EmitExceptionPoll(Arm64Exception *exception); 256 257 void StoreWToOffset(StoreOperandType type, WRegister source, 258 XRegister base, int32_t offset); 259 void StoreToOffset(XRegister source, XRegister base, int32_t offset); 260 void StoreSToOffset(SRegister source, XRegister base, int32_t offset); 261 void StoreDToOffset(DRegister source, XRegister base, int32_t offset); 262 263 void LoadImmediate(XRegister dest, int32_t value, vixl::Condition cond = vixl::al); 264 void Load(Arm64ManagedRegister dst, XRegister src, int32_t src_offset, size_t size); 265 void LoadWFromOffset(LoadOperandType type, WRegister dest, 266 XRegister base, int32_t offset); 267 void LoadFromOffset(XRegister dest, XRegister base, int32_t offset); 268 void LoadSFromOffset(SRegister dest, XRegister base, int32_t offset); 269 void LoadDFromOffset(DRegister dest, XRegister base, int32_t offset); 270 void AddConstant(XRegister rd, int32_t value, vixl::Condition cond = vixl::al); 271 void AddConstant(XRegister rd, XRegister rn, int32_t value, vixl::Condition cond = vixl::al); 272 273 // List of exception blocks to generate at the end of the code cache. 274 ArenaVector<std::unique_ptr<Arm64Exception>> exception_blocks_; 275 276 public: 277 // Vixl assembler. 278 vixl::MacroAssembler* const vixl_masm_; 279 280 // Used for testing. 281 friend class Arm64ManagedRegister_VixlRegisters_Test; 282}; 283 284} // namespace arm64 285} // namespace art 286 287#endif // ART_COMPILER_UTILS_ARM64_ASSEMBLER_ARM64_H_ 288