1 /*
2 * Copyright (C) 2013 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 #include "trampoline_compiler.h"
18
19 #include "base/arena_allocator.h"
20 #include "jni_env_ext.h"
21
22 #ifdef ART_ENABLE_CODEGEN_arm
23 #include "utils/arm/assembler_arm_vixl.h"
24 #endif
25
26 #ifdef ART_ENABLE_CODEGEN_arm64
27 #include "utils/arm64/assembler_arm64.h"
28 #endif
29
30 #ifdef ART_ENABLE_CODEGEN_mips
31 #include "utils/mips/assembler_mips.h"
32 #endif
33
34 #ifdef ART_ENABLE_CODEGEN_mips64
35 #include "utils/mips64/assembler_mips64.h"
36 #endif
37
38 #ifdef ART_ENABLE_CODEGEN_x86
39 #include "utils/x86/assembler_x86.h"
40 #endif
41
42 #ifdef ART_ENABLE_CODEGEN_x86_64
43 #include "utils/x86_64/assembler_x86_64.h"
44 #endif
45
46 #define __ assembler.
47
48 namespace art {
49
50 #ifdef ART_ENABLE_CODEGEN_arm
51 namespace arm {
52
53 #ifdef ___
54 #error "ARM Assembler macro already defined."
55 #else
56 #define ___ assembler.GetVIXLAssembler()->
57 #endif
58
CreateTrampoline(ArenaAllocator * arena,EntryPointCallingConvention abi,ThreadOffset32 offset)59 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
60 ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset32 offset) {
61 using vixl::aarch32::MemOperand;
62 using vixl::aarch32::pc;
63 using vixl::aarch32::r0;
64 ArmVIXLAssembler assembler(arena);
65
66 switch (abi) {
67 case kInterpreterAbi: // Thread* is first argument (R0) in interpreter ABI.
68 ___ Ldr(pc, MemOperand(r0, offset.Int32Value()));
69 break;
70 case kJniAbi: { // Load via Thread* held in JNIEnv* in first argument (R0).
71 vixl::aarch32::UseScratchRegisterScope temps(assembler.GetVIXLAssembler());
72 const vixl::aarch32::Register temp_reg = temps.Acquire();
73
74 // VIXL will use the destination as a scratch register if
75 // the offset is not encodable as an immediate operand.
76 ___ Ldr(temp_reg, MemOperand(r0, JNIEnvExt::SelfOffset(4).Int32Value()));
77 ___ Ldr(pc, MemOperand(temp_reg, offset.Int32Value()));
78 break;
79 }
80 case kQuickAbi: // TR holds Thread*.
81 ___ Ldr(pc, MemOperand(tr, offset.Int32Value()));
82 }
83
84 __ FinalizeCode();
85 size_t cs = __ CodeSize();
86 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
87 MemoryRegion code(entry_stub->data(), entry_stub->size());
88 __ FinalizeInstructions(code);
89
90 return std::move(entry_stub);
91 }
92
93 #undef ___
94
95 } // namespace arm
96 #endif // ART_ENABLE_CODEGEN_arm
97
98 #ifdef ART_ENABLE_CODEGEN_arm64
99 namespace arm64 {
CreateTrampoline(ArenaAllocator * arena,EntryPointCallingConvention abi,ThreadOffset64 offset)100 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
101 ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset64 offset) {
102 Arm64Assembler assembler(arena);
103
104 switch (abi) {
105 case kInterpreterAbi: // Thread* is first argument (X0) in interpreter ABI.
106 __ JumpTo(Arm64ManagedRegister::FromXRegister(X0), Offset(offset.Int32Value()),
107 Arm64ManagedRegister::FromXRegister(IP1));
108
109 break;
110 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (X0).
111 __ LoadRawPtr(Arm64ManagedRegister::FromXRegister(IP1),
112 Arm64ManagedRegister::FromXRegister(X0),
113 Offset(JNIEnvExt::SelfOffset(8).Int32Value()));
114
115 __ JumpTo(Arm64ManagedRegister::FromXRegister(IP1), Offset(offset.Int32Value()),
116 Arm64ManagedRegister::FromXRegister(IP0));
117
118 break;
119 case kQuickAbi: // X18 holds Thread*.
120 __ JumpTo(Arm64ManagedRegister::FromXRegister(TR), Offset(offset.Int32Value()),
121 Arm64ManagedRegister::FromXRegister(IP0));
122
123 break;
124 }
125
126 __ FinalizeCode();
127 size_t cs = __ CodeSize();
128 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
129 MemoryRegion code(entry_stub->data(), entry_stub->size());
130 __ FinalizeInstructions(code);
131
132 return std::move(entry_stub);
133 }
134 } // namespace arm64
135 #endif // ART_ENABLE_CODEGEN_arm64
136
137 #ifdef ART_ENABLE_CODEGEN_mips
138 namespace mips {
CreateTrampoline(ArenaAllocator * arena,EntryPointCallingConvention abi,ThreadOffset32 offset)139 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
140 ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset32 offset) {
141 MipsAssembler assembler(arena);
142
143 switch (abi) {
144 case kInterpreterAbi: // Thread* is first argument (A0) in interpreter ABI.
145 __ LoadFromOffset(kLoadWord, T9, A0, offset.Int32Value());
146 break;
147 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (A0).
148 __ LoadFromOffset(kLoadWord, T9, A0, JNIEnvExt::SelfOffset(4).Int32Value());
149 __ LoadFromOffset(kLoadWord, T9, T9, offset.Int32Value());
150 break;
151 case kQuickAbi: // S1 holds Thread*.
152 __ LoadFromOffset(kLoadWord, T9, S1, offset.Int32Value());
153 }
154 __ Jr(T9);
155 __ NopIfNoReordering();
156 __ Break();
157
158 __ FinalizeCode();
159 size_t cs = __ CodeSize();
160 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
161 MemoryRegion code(entry_stub->data(), entry_stub->size());
162 __ FinalizeInstructions(code);
163
164 return std::move(entry_stub);
165 }
166 } // namespace mips
167 #endif // ART_ENABLE_CODEGEN_mips
168
169 #ifdef ART_ENABLE_CODEGEN_mips64
170 namespace mips64 {
CreateTrampoline(ArenaAllocator * arena,EntryPointCallingConvention abi,ThreadOffset64 offset)171 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
172 ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset64 offset) {
173 Mips64Assembler assembler(arena);
174
175 switch (abi) {
176 case kInterpreterAbi: // Thread* is first argument (A0) in interpreter ABI.
177 __ LoadFromOffset(kLoadDoubleword, T9, A0, offset.Int32Value());
178 break;
179 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (A0).
180 __ LoadFromOffset(kLoadDoubleword, T9, A0, JNIEnvExt::SelfOffset(8).Int32Value());
181 __ LoadFromOffset(kLoadDoubleword, T9, T9, offset.Int32Value());
182 break;
183 case kQuickAbi: // Fall-through.
184 __ LoadFromOffset(kLoadDoubleword, T9, S1, offset.Int32Value());
185 }
186 __ Jr(T9);
187 __ Nop();
188 __ Break();
189
190 __ FinalizeCode();
191 size_t cs = __ CodeSize();
192 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
193 MemoryRegion code(entry_stub->data(), entry_stub->size());
194 __ FinalizeInstructions(code);
195
196 return std::move(entry_stub);
197 }
198 } // namespace mips64
199 #endif // ART_ENABLE_CODEGEN_mips
200
201 #ifdef ART_ENABLE_CODEGEN_x86
202 namespace x86 {
CreateTrampoline(ArenaAllocator * arena,ThreadOffset32 offset)203 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(ArenaAllocator* arena,
204 ThreadOffset32 offset) {
205 X86Assembler assembler(arena);
206
207 // All x86 trampolines call via the Thread* held in fs.
208 __ fs()->jmp(Address::Absolute(offset));
209 __ int3();
210
211 __ FinalizeCode();
212 size_t cs = __ CodeSize();
213 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
214 MemoryRegion code(entry_stub->data(), entry_stub->size());
215 __ FinalizeInstructions(code);
216
217 return std::move(entry_stub);
218 }
219 } // namespace x86
220 #endif // ART_ENABLE_CODEGEN_x86
221
222 #ifdef ART_ENABLE_CODEGEN_x86_64
223 namespace x86_64 {
CreateTrampoline(ArenaAllocator * arena,ThreadOffset64 offset)224 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(ArenaAllocator* arena,
225 ThreadOffset64 offset) {
226 x86_64::X86_64Assembler assembler(arena);
227
228 // All x86 trampolines call via the Thread* held in gs.
229 __ gs()->jmp(x86_64::Address::Absolute(offset, true));
230 __ int3();
231
232 __ FinalizeCode();
233 size_t cs = __ CodeSize();
234 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
235 MemoryRegion code(entry_stub->data(), entry_stub->size());
236 __ FinalizeInstructions(code);
237
238 return std::move(entry_stub);
239 }
240 } // namespace x86_64
241 #endif // ART_ENABLE_CODEGEN_x86_64
242
CreateTrampoline64(InstructionSet isa,EntryPointCallingConvention abi,ThreadOffset64 offset)243 std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline64(InstructionSet isa,
244 EntryPointCallingConvention abi,
245 ThreadOffset64 offset) {
246 ArenaPool pool;
247 ArenaAllocator arena(&pool);
248 switch (isa) {
249 #ifdef ART_ENABLE_CODEGEN_arm64
250 case kArm64:
251 return arm64::CreateTrampoline(&arena, abi, offset);
252 #endif
253 #ifdef ART_ENABLE_CODEGEN_mips64
254 case kMips64:
255 return mips64::CreateTrampoline(&arena, abi, offset);
256 #endif
257 #ifdef ART_ENABLE_CODEGEN_x86_64
258 case kX86_64:
259 return x86_64::CreateTrampoline(&arena, offset);
260 #endif
261 default:
262 UNUSED(abi);
263 UNUSED(offset);
264 LOG(FATAL) << "Unexpected InstructionSet: " << isa;
265 UNREACHABLE();
266 }
267 }
268
CreateTrampoline32(InstructionSet isa,EntryPointCallingConvention abi,ThreadOffset32 offset)269 std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline32(InstructionSet isa,
270 EntryPointCallingConvention abi,
271 ThreadOffset32 offset) {
272 ArenaPool pool;
273 ArenaAllocator arena(&pool);
274 switch (isa) {
275 #ifdef ART_ENABLE_CODEGEN_arm
276 case kArm:
277 case kThumb2:
278 return arm::CreateTrampoline(&arena, abi, offset);
279 #endif
280 #ifdef ART_ENABLE_CODEGEN_mips
281 case kMips:
282 return mips::CreateTrampoline(&arena, abi, offset);
283 #endif
284 #ifdef ART_ENABLE_CODEGEN_x86
285 case kX86:
286 UNUSED(abi);
287 return x86::CreateTrampoline(&arena, offset);
288 #endif
289 default:
290 LOG(FATAL) << "Unexpected InstructionSet: " << isa;
291 UNREACHABLE();
292 }
293 }
294
295 } // namespace art
296