1 /* 2 * Copyright (C) 2011 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_JNI_MACRO_ASSEMBLER_H_ 18 #define ART_COMPILER_UTILS_JNI_MACRO_ASSEMBLER_H_ 19 20 #include <vector> 21 22 #include <android-base/logging.h> 23 24 #include "arch/instruction_set.h" 25 #include "base/arena_allocator.h" 26 #include "base/arena_object.h" 27 #include "base/array_ref.h" 28 #include "base/macros.h" 29 #include "base/pointer_size.h" 30 #include "managed_register.h" 31 #include "offsets.h" 32 33 namespace art HIDDEN { 34 35 class ArenaAllocator; 36 class DebugFrameOpCodeWriterForAssembler; 37 class InstructionSetFeatures; 38 class MemoryRegion; 39 class JNIMacroLabel; 40 41 enum class JNIMacroUnaryCondition { 42 kZero, 43 kNotZero 44 }; 45 46 class ArgumentLocation { 47 public: ArgumentLocation(ManagedRegister reg,size_t size)48 ArgumentLocation(ManagedRegister reg, size_t size) 49 : reg_(reg), frame_offset_(0u), size_(size) { 50 DCHECK(reg.IsRegister()); 51 } 52 ArgumentLocation(FrameOffset frame_offset,size_t size)53 ArgumentLocation(FrameOffset frame_offset, size_t size) 54 : reg_(ManagedRegister::NoRegister()), frame_offset_(frame_offset), size_(size) {} 55 IsRegister()56 bool IsRegister() const { 57 return reg_.IsRegister(); 58 } 59 GetRegister()60 ManagedRegister GetRegister() const { 61 DCHECK(IsRegister()); 62 return reg_; 63 } 64 GetFrameOffset()65 FrameOffset GetFrameOffset() const { 66 DCHECK(!IsRegister()); 67 return frame_offset_; 68 } 69 GetSize()70 size_t GetSize() const { 71 return size_; 72 } 73 74 private: 75 ManagedRegister reg_; 76 FrameOffset frame_offset_; 77 size_t size_; 78 }; 79 80 template <PointerSize kPointerSize> 81 class JNIMacroAssembler : public DeletableArenaObject<kArenaAllocAssembler> { 82 public: 83 static std::unique_ptr<JNIMacroAssembler<kPointerSize>> Create( 84 ArenaAllocator* allocator, 85 InstructionSet instruction_set, 86 const InstructionSetFeatures* instruction_set_features = nullptr); 87 88 // Finalize the code; emit slow paths, fixup branches, add literal pool, etc. 89 virtual void FinalizeCode() = 0; 90 91 // Size of generated code 92 virtual size_t CodeSize() const = 0; 93 94 // Copy instructions out of assembly buffer into the given region of memory 95 virtual void CopyInstructions(const MemoryRegion& region) = 0; 96 97 // Emit code that will create an activation on the stack 98 virtual void BuildFrame(size_t frame_size, 99 ManagedRegister method_reg, 100 ArrayRef<const ManagedRegister> callee_save_regs) = 0; 101 102 // Emit code that will remove an activation from the stack 103 // 104 // Argument `may_suspend` must be `true` if the compiled method may be 105 // suspended during its execution (otherwise `false`, if it is impossible 106 // to suspend during its execution). 107 virtual void RemoveFrame(size_t frame_size, 108 ArrayRef<const ManagedRegister> callee_save_regs, 109 bool may_suspend) = 0; 110 111 virtual void IncreaseFrameSize(size_t adjust) = 0; 112 virtual void DecreaseFrameSize(size_t adjust) = 0; 113 114 // Return the same core register but with correct size if the architecture-specific 115 // ManagedRegister has different representation for different sizes. 116 virtual ManagedRegister CoreRegisterWithSize(ManagedRegister src, size_t size) = 0; 117 118 // Store routines 119 virtual void Store(FrameOffset offs, ManagedRegister src, size_t size) = 0; 120 virtual void Store(ManagedRegister base, MemberOffset offs, ManagedRegister src, size_t size) = 0; 121 virtual void StoreRawPtr(FrameOffset dest, ManagedRegister src) = 0; 122 123 // Stores stack pointer by tagging it if required so we can walk the stack. In debuggable runtimes 124 // we use tag to tell if we are using JITed code or AOT code. In non-debuggable runtimes we never 125 // use JITed code when AOT code is present. So checking for AOT code is sufficient to detect which 126 // code is being executed. We avoid tagging in non-debuggable runtimes to reduce instructions. 127 virtual void StoreStackPointerToThread(ThreadOffset<kPointerSize> thr_offs, bool tag_sp) = 0; 128 129 // Load routines 130 virtual void Load(ManagedRegister dest, FrameOffset src, size_t size) = 0; 131 virtual void Load(ManagedRegister dest, ManagedRegister base, MemberOffset offs, size_t size) = 0; 132 virtual void LoadRawPtrFromThread(ManagedRegister dest, ThreadOffset<kPointerSize> offs) = 0; 133 134 // Load reference from a `GcRoot<>`. The default is to load as `jint`. Some architectures 135 // (say, RISC-V) override this to provide a different sign- or zero-extension. 136 virtual void LoadGcRootWithoutReadBarrier(ManagedRegister dest, 137 ManagedRegister base, 138 MemberOffset offs); 139 140 // Load reference from a `StackReference<>`. The default is to load as `jint`. Some architectures 141 // (say, RISC-V) override this to provide a different sign- or zero-extension. 142 virtual void LoadStackReference(ManagedRegister dest, FrameOffset offs); 143 144 // Copying routines 145 146 // Move arguments from `srcs` locations to `dests` locations. 147 // 148 // References shall be spilled to `refs` frame offsets (kInvalidReferenceOffset indicates 149 // a non-reference type) if they are in registers and corresponding `dests` shall be 150 // filled with `jobject` replacements. If the first argument is a reference, it is 151 // assumed to be `this` and cannot be null, all other reference arguments can be null. 152 virtual void MoveArguments(ArrayRef<ArgumentLocation> dests, 153 ArrayRef<ArgumentLocation> srcs, 154 ArrayRef<FrameOffset> refs) = 0; 155 156 virtual void Move(ManagedRegister dest, ManagedRegister src, size_t size) = 0; 157 158 virtual void Move(ManagedRegister dst, size_t value) = 0; 159 160 // Sign extension 161 virtual void SignExtend(ManagedRegister mreg, size_t size) = 0; 162 163 // Zero extension 164 virtual void ZeroExtend(ManagedRegister mreg, size_t size) = 0; 165 166 // Exploit fast access in managed code to Thread::Current() 167 virtual void GetCurrentThread(ManagedRegister dest) = 0; 168 virtual void GetCurrentThread(FrameOffset dest_offset) = 0; 169 170 // Manipulating local reference table states. 171 // 172 // These have a default implementation but they can be overridden to use register pair 173 // load/store instructions on architectures that support them (arm, arm64). 174 virtual void LoadLocalReferenceTableStates(ManagedRegister jni_env_reg, 175 ManagedRegister previous_state_reg, 176 ManagedRegister current_state_reg); 177 virtual void StoreLocalReferenceTableStates(ManagedRegister jni_env_reg, 178 ManagedRegister previous_state_reg, 179 ManagedRegister current_state_reg); 180 181 // Decode JNI transition or local `jobject`. For (weak) global `jobject`, jump to slow path. 182 virtual void DecodeJNITransitionOrLocalJObject(ManagedRegister reg, 183 JNIMacroLabel* slow_path, 184 JNIMacroLabel* resume) = 0; 185 186 // Heap::VerifyObject on src. In some cases (such as a reference to this) we 187 // know that src may not be null. 188 virtual void VerifyObject(ManagedRegister src, bool could_be_null) = 0; 189 virtual void VerifyObject(FrameOffset src, bool could_be_null) = 0; 190 191 // Jump to address held at [base+offset] (used for tail calls). 192 virtual void Jump(ManagedRegister base, Offset offset) = 0; 193 194 // Call to address held at [base+offset] 195 virtual void Call(ManagedRegister base, Offset offset) = 0; 196 virtual void CallFromThread(ThreadOffset<kPointerSize> offset) = 0; 197 198 // Generate fast-path for transition to Native. Go to `label` if any thread flag is set. 199 // The implementation can use `scratch_regs` which should be callee save core registers 200 // (already saved before this call) and must preserve all argument registers. 201 virtual void TryToTransitionFromRunnableToNative( 202 JNIMacroLabel* label, ArrayRef<const ManagedRegister> scratch_regs) = 0; 203 204 // Generate fast-path for transition to Runnable. Go to `label` if any thread flag is set. 205 // The implementation can use `scratch_regs` which should be core argument registers 206 // not used as return registers and it must preserve the `return_reg` if any. 207 virtual void TryToTransitionFromNativeToRunnable(JNIMacroLabel* label, 208 ArrayRef<const ManagedRegister> scratch_regs, 209 ManagedRegister return_reg) = 0; 210 211 // Generate suspend check and branch to `label` if there is a pending suspend request. 212 virtual void SuspendCheck(JNIMacroLabel* label) = 0; 213 214 // Generate code to check if Thread::Current()->exception_ is non-null 215 // and branch to the `label` if it is. 216 virtual void ExceptionPoll(JNIMacroLabel* label) = 0; 217 // Deliver pending exception. 218 virtual void DeliverPendingException() = 0; 219 220 // Create a new label that can be used with Jump/Bind calls. 221 virtual std::unique_ptr<JNIMacroLabel> CreateLabel() = 0; 222 // Emit an unconditional jump to the label. 223 virtual void Jump(JNIMacroLabel* label) = 0; 224 // Emit a conditional jump to the label by applying a unary condition test to the GC marking flag. 225 virtual void TestGcMarking(JNIMacroLabel* label, JNIMacroUnaryCondition cond) = 0; 226 // Emit a conditional jump to the label by applying a unary condition test to object's mark bit. 227 virtual void TestMarkBit(ManagedRegister ref, 228 JNIMacroLabel* label, 229 JNIMacroUnaryCondition cond) = 0; 230 // Emit a conditional jump to label if the loaded value from specified locations is not zero. 231 virtual void TestByteAndJumpIfNotZero(uintptr_t address, JNIMacroLabel* label) = 0; 232 // Code at this offset will serve as the target for the Jump call. 233 virtual void Bind(JNIMacroLabel* label) = 0; 234 ~JNIMacroAssembler()235 virtual ~JNIMacroAssembler() {} 236 237 /** 238 * @brief Buffer of DWARF's Call Frame Information opcodes. 239 * @details It is used by debuggers and other tools to unwind the call stack. 240 */ 241 virtual DebugFrameOpCodeWriterForAssembler& cfi() = 0; 242 SetEmitRunTimeChecksInDebugMode(bool value)243 void SetEmitRunTimeChecksInDebugMode(bool value) { 244 emit_run_time_checks_in_debug_mode_ = value; 245 } 246 247 static constexpr FrameOffset kInvalidReferenceOffset = FrameOffset(0); 248 249 protected: JNIMacroAssembler()250 JNIMacroAssembler() {} 251 252 // Should run-time checks be emitted in debug mode? 253 bool emit_run_time_checks_in_debug_mode_ = false; 254 }; 255 256 // A "Label" class used with the JNIMacroAssembler 257 // allowing one to use branches (jumping from one place to another). 258 // 259 // This is just an interface, so every platform must provide 260 // its own implementation of it. 261 // 262 // It is only safe to use a label created 263 // via JNIMacroAssembler::CreateLabel with that same macro assembler. 264 class JNIMacroLabel : public DeletableArenaObject<kArenaAllocAssembler> { 265 public: 266 virtual ~JNIMacroLabel() = 0; 267 268 const InstructionSet isa_; 269 protected: JNIMacroLabel(InstructionSet isa)270 explicit JNIMacroLabel(InstructionSet isa) : isa_(isa) {} 271 }; 272 ~JNIMacroLabel()273 inline JNIMacroLabel::~JNIMacroLabel() { 274 // Compulsory definition for a pure virtual destructor 275 // to avoid linking errors. 276 } 277 278 template <typename T, PointerSize kPointerSize> 279 class JNIMacroAssemblerFwd : public JNIMacroAssembler<kPointerSize> { 280 public: FinalizeCode()281 void FinalizeCode() override { 282 asm_.FinalizeCode(); 283 } 284 CodeSize()285 size_t CodeSize() const override { 286 return asm_.CodeSize(); 287 } 288 CopyInstructions(const MemoryRegion & region)289 void CopyInstructions(const MemoryRegion& region) override { 290 asm_.CopyInstructions(region); 291 } 292 cfi()293 DebugFrameOpCodeWriterForAssembler& cfi() override { 294 return asm_.cfi(); 295 } 296 297 protected: JNIMacroAssemblerFwd(ArenaAllocator * allocator)298 explicit JNIMacroAssemblerFwd(ArenaAllocator* allocator) : asm_(allocator) {} 299 300 T asm_; 301 }; 302 303 template <typename Self, typename PlatformLabel, InstructionSet kIsa> 304 class JNIMacroLabelCommon : public JNIMacroLabel { 305 public: Cast(JNIMacroLabel * label)306 static Self* Cast(JNIMacroLabel* label) { 307 CHECK(label != nullptr); 308 CHECK_EQ(kIsa, label->isa_); 309 310 return reinterpret_cast<Self*>(label); 311 } 312 313 protected: AsPlatformLabel()314 PlatformLabel* AsPlatformLabel() { 315 return &label_; 316 } 317 JNIMacroLabelCommon()318 JNIMacroLabelCommon() : JNIMacroLabel(kIsa) { 319 } 320 ~JNIMacroLabelCommon()321 ~JNIMacroLabelCommon() override {} 322 323 private: 324 PlatformLabel label_; 325 }; 326 327 } // namespace art 328 329 #endif // ART_COMPILER_UTILS_JNI_MACRO_ASSEMBLER_H_ 330