• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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