blob: 72f1ce05ce47909d5f7055b659c86c3a29f0407f [file] [log] [blame]
Andreas Gampe3b165bc2016-08-01 22:07:04 -07001/*
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 "arch/instruction_set.h"
23#include "base/arena_allocator.h"
24#include "base/arena_object.h"
David Brazdild9c90372016-09-14 16:53:55 +010025#include "base/array_ref.h"
Andreas Gampe3b165bc2016-08-01 22:07:04 -070026#include "base/enums.h"
27#include "base/logging.h"
28#include "base/macros.h"
29#include "managed_register.h"
30#include "offsets.h"
Andreas Gampe3b165bc2016-08-01 22:07:04 -070031
32namespace art {
33
34class ArenaAllocator;
35class DebugFrameOpCodeWriterForAssembler;
36class InstructionSetFeatures;
37class MemoryRegion;
Igor Murashkinae7ff922016-10-06 14:59:19 -070038class JNIMacroLabel;
39
40enum class JNIMacroUnaryCondition {
41 kZero,
42 kNotZero
43};
Andreas Gampe3b165bc2016-08-01 22:07:04 -070044
45template <PointerSize kPointerSize>
46class JNIMacroAssembler : public DeletableArenaObject<kArenaAllocAssembler> {
47 public:
48 static std::unique_ptr<JNIMacroAssembler<kPointerSize>> Create(
49 ArenaAllocator* arena,
50 InstructionSet instruction_set,
51 const InstructionSetFeatures* instruction_set_features = nullptr);
52
53 // Finalize the code; emit slow paths, fixup branches, add literal pool, etc.
54 virtual void FinalizeCode() = 0;
55
56 // Size of generated code
57 virtual size_t CodeSize() const = 0;
58
59 // Copy instructions out of assembly buffer into the given region of memory
60 virtual void FinalizeInstructions(const MemoryRegion& region) = 0;
61
62 // Emit code that will create an activation on the stack
63 virtual void BuildFrame(size_t frame_size,
64 ManagedRegister method_reg,
65 ArrayRef<const ManagedRegister> callee_save_regs,
66 const ManagedRegisterEntrySpills& entry_spills) = 0;
67
68 // Emit code that will remove an activation from the stack
Roland Levillain0d127e12017-07-05 17:01:11 +010069 //
70 // Argument `may_suspend` must be `true` if the compiled method may be
71 // suspended during its execution (otherwise `false`, if it is impossible
72 // to suspend during its execution).
73 virtual void RemoveFrame(size_t frame_size,
74 ArrayRef<const ManagedRegister> callee_save_regs,
75 bool may_suspend) = 0;
Andreas Gampe3b165bc2016-08-01 22:07:04 -070076
77 virtual void IncreaseFrameSize(size_t adjust) = 0;
78 virtual void DecreaseFrameSize(size_t adjust) = 0;
79
80 // Store routines
81 virtual void Store(FrameOffset offs, ManagedRegister src, size_t size) = 0;
82 virtual void StoreRef(FrameOffset dest, ManagedRegister src) = 0;
83 virtual void StoreRawPtr(FrameOffset dest, ManagedRegister src) = 0;
84
85 virtual void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister scratch) = 0;
86
87 virtual void StoreStackOffsetToThread(ThreadOffset<kPointerSize> thr_offs,
88 FrameOffset fr_offs,
89 ManagedRegister scratch) = 0;
90
91 virtual void StoreStackPointerToThread(ThreadOffset<kPointerSize> thr_offs) = 0;
92
93 virtual void StoreSpanning(FrameOffset dest,
94 ManagedRegister src,
95 FrameOffset in_off,
96 ManagedRegister scratch) = 0;
97
98 // Load routines
99 virtual void Load(ManagedRegister dest, FrameOffset src, size_t size) = 0;
100
101 virtual void LoadFromThread(ManagedRegister dest,
102 ThreadOffset<kPointerSize> src,
103 size_t size) = 0;
104
105 virtual void LoadRef(ManagedRegister dest, FrameOffset src) = 0;
106 // If unpoison_reference is true and kPoisonReference is true, then we negate the read reference.
107 virtual void LoadRef(ManagedRegister dest,
108 ManagedRegister base,
109 MemberOffset offs,
110 bool unpoison_reference) = 0;
111
112 virtual void LoadRawPtr(ManagedRegister dest, ManagedRegister base, Offset offs) = 0;
113
114 virtual void LoadRawPtrFromThread(ManagedRegister dest, ThreadOffset<kPointerSize> offs) = 0;
115
116 // Copying routines
117 virtual void Move(ManagedRegister dest, ManagedRegister src, size_t size) = 0;
118
119 virtual void CopyRawPtrFromThread(FrameOffset fr_offs,
120 ThreadOffset<kPointerSize> thr_offs,
121 ManagedRegister scratch) = 0;
122
123 virtual void CopyRawPtrToThread(ThreadOffset<kPointerSize> thr_offs,
124 FrameOffset fr_offs,
125 ManagedRegister scratch) = 0;
126
127 virtual void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister scratch) = 0;
128
129 virtual void Copy(FrameOffset dest, FrameOffset src, ManagedRegister scratch, size_t size) = 0;
130
131 virtual void Copy(FrameOffset dest,
132 ManagedRegister src_base,
133 Offset src_offset,
134 ManagedRegister scratch,
135 size_t size) = 0;
136
137 virtual void Copy(ManagedRegister dest_base,
138 Offset dest_offset,
139 FrameOffset src,
140 ManagedRegister scratch,
141 size_t size) = 0;
142
143 virtual void Copy(FrameOffset dest,
144 FrameOffset src_base,
145 Offset src_offset,
146 ManagedRegister scratch,
147 size_t size) = 0;
148
149 virtual void Copy(ManagedRegister dest,
150 Offset dest_offset,
151 ManagedRegister src,
152 Offset src_offset,
153 ManagedRegister scratch,
154 size_t size) = 0;
155
156 virtual void Copy(FrameOffset dest,
157 Offset dest_offset,
158 FrameOffset src,
159 Offset src_offset,
160 ManagedRegister scratch,
161 size_t size) = 0;
162
163 virtual void MemoryBarrier(ManagedRegister scratch) = 0;
164
165 // Sign extension
166 virtual void SignExtend(ManagedRegister mreg, size_t size) = 0;
167
168 // Zero extension
169 virtual void ZeroExtend(ManagedRegister mreg, size_t size) = 0;
170
171 // Exploit fast access in managed code to Thread::Current()
172 virtual void GetCurrentThread(ManagedRegister tr) = 0;
173 virtual void GetCurrentThread(FrameOffset dest_offset, ManagedRegister scratch) = 0;
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 virtual void CreateHandleScopeEntry(ManagedRegister out_reg,
180 FrameOffset handlescope_offset,
181 ManagedRegister in_reg,
182 bool null_allowed) = 0;
183
184 // Set up out_off to hold a Object** into the handle scope, or to be null if the
185 // value is null and null_allowed.
186 virtual void CreateHandleScopeEntry(FrameOffset out_off,
187 FrameOffset handlescope_offset,
188 ManagedRegister scratch,
189 bool null_allowed) = 0;
190
191 // src holds a handle scope entry (Object**) load this into dst
192 virtual void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) = 0;
193
194 // Heap::VerifyObject on src. In some cases (such as a reference to this) we
195 // know that src may not be null.
196 virtual void VerifyObject(ManagedRegister src, bool could_be_null) = 0;
197 virtual void VerifyObject(FrameOffset src, bool could_be_null) = 0;
198
199 // Call to address held at [base+offset]
200 virtual void Call(ManagedRegister base, Offset offset, ManagedRegister scratch) = 0;
201 virtual void Call(FrameOffset base, Offset offset, ManagedRegister scratch) = 0;
202 virtual void CallFromThread(ThreadOffset<kPointerSize> offset, ManagedRegister scratch) = 0;
203
204 // Generate code to check if Thread::Current()->exception_ is non-null
205 // and branch to a ExceptionSlowPath if it is.
206 virtual void ExceptionPoll(ManagedRegister scratch, size_t stack_adjust) = 0;
207
Igor Murashkinae7ff922016-10-06 14:59:19 -0700208 // Create a new label that can be used with Jump/Bind calls.
209 virtual std::unique_ptr<JNIMacroLabel> CreateLabel() = 0;
210 // Emit an unconditional jump to the label.
211 virtual void Jump(JNIMacroLabel* label) = 0;
212 // Emit a conditional jump to the label by applying a unary condition test to the register.
213 virtual void Jump(JNIMacroLabel* label, JNIMacroUnaryCondition cond, ManagedRegister test) = 0;
214 // Code at this offset will serve as the target for the Jump call.
215 virtual void Bind(JNIMacroLabel* label) = 0;
216
Andreas Gampe3b165bc2016-08-01 22:07:04 -0700217 virtual ~JNIMacroAssembler() {}
218
219 /**
220 * @brief Buffer of DWARF's Call Frame Information opcodes.
221 * @details It is used by debuggers and other tools to unwind the call stack.
222 */
223 virtual DebugFrameOpCodeWriterForAssembler& cfi() = 0;
224
Roland Levillain2b03a1f2017-06-06 16:09:59 +0100225 void SetEmitRunTimeChecksInDebugMode(bool value) {
226 emit_run_time_checks_in_debug_mode_ = value;
227 }
228
Andreas Gampe3b165bc2016-08-01 22:07:04 -0700229 protected:
Roland Levillain2b03a1f2017-06-06 16:09:59 +0100230 JNIMacroAssembler() {}
231
232 // Should run-time checks be emitted in debug mode?
233 bool emit_run_time_checks_in_debug_mode_ = false;
Andreas Gampe3b165bc2016-08-01 22:07:04 -0700234};
235
Igor Murashkinae7ff922016-10-06 14:59:19 -0700236// A "Label" class used with the JNIMacroAssembler
237// allowing one to use branches (jumping from one place to another).
238//
239// This is just an interface, so every platform must provide
240// its own implementation of it.
241//
242// It is only safe to use a label created
243// via JNIMacroAssembler::CreateLabel with that same macro assembler.
244class JNIMacroLabel {
245 public:
246 virtual ~JNIMacroLabel() = 0;
247
248 const InstructionSet isa_;
249 protected:
250 explicit JNIMacroLabel(InstructionSet isa) : isa_(isa) {}
251};
252
253inline JNIMacroLabel::~JNIMacroLabel() {
254 // Compulsory definition for a pure virtual destructor
255 // to avoid linking errors.
256}
257
Andreas Gampe3b165bc2016-08-01 22:07:04 -0700258template <typename T, PointerSize kPointerSize>
259class JNIMacroAssemblerFwd : public JNIMacroAssembler<kPointerSize> {
260 public:
261 void FinalizeCode() OVERRIDE {
262 asm_.FinalizeCode();
263 }
264
265 size_t CodeSize() const OVERRIDE {
266 return asm_.CodeSize();
267 }
268
269 void FinalizeInstructions(const MemoryRegion& region) OVERRIDE {
270 asm_.FinalizeInstructions(region);
271 }
272
273 DebugFrameOpCodeWriterForAssembler& cfi() OVERRIDE {
274 return asm_.cfi();
275 }
276
277 protected:
278 explicit JNIMacroAssemblerFwd(ArenaAllocator* arena) : asm_(arena) {}
279
280 T asm_;
281};
282
Igor Murashkinae7ff922016-10-06 14:59:19 -0700283template <typename Self, typename PlatformLabel, InstructionSet kIsa>
284class JNIMacroLabelCommon : public JNIMacroLabel {
285 public:
286 static Self* Cast(JNIMacroLabel* label) {
287 CHECK(label != nullptr);
288 CHECK_EQ(kIsa, label->isa_);
289
290 return reinterpret_cast<Self*>(label);
291 }
292
293 protected:
294 PlatformLabel* AsPlatformLabel() {
295 return &label_;
296 }
297
298 JNIMacroLabelCommon() : JNIMacroLabel(kIsa) {
299 }
300
301 virtual ~JNIMacroLabelCommon() OVERRIDE {}
302
303 private:
304 PlatformLabel label_;
305};
306
Andreas Gampe3b165bc2016-08-01 22:07:04 -0700307} // namespace art
308
309#endif // ART_COMPILER_UTILS_JNI_MACRO_ASSEMBLER_H_