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_thumb2.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 {
CreateTrampoline(ArenaAllocator * arena,EntryPointCallingConvention abi,ThreadOffset<4> offset)52 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
53     ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset<4> offset) {
54   Thumb2Assembler assembler(arena);
55 
56   switch (abi) {
57     case kInterpreterAbi:  // Thread* is first argument (R0) in interpreter ABI.
58       __ LoadFromOffset(kLoadWord, PC, R0, offset.Int32Value());
59       break;
60     case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (R0).
61       __ LoadFromOffset(kLoadWord, IP, R0, JNIEnvExt::SelfOffset(4).Int32Value());
62       __ LoadFromOffset(kLoadWord, PC, IP, offset.Int32Value());
63       break;
64     case kQuickAbi:  // R9 holds Thread*.
65       __ LoadFromOffset(kLoadWord, PC, R9, offset.Int32Value());
66   }
67   __ bkpt(0);
68 
69   __ FinalizeCode();
70   size_t cs = __ CodeSize();
71   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
72   MemoryRegion code(entry_stub->data(), entry_stub->size());
73   __ FinalizeInstructions(code);
74 
75   return std::move(entry_stub);
76 }
77 }  // namespace arm
78 #endif  // ART_ENABLE_CODEGEN_arm
79 
80 #ifdef ART_ENABLE_CODEGEN_arm64
81 namespace arm64 {
CreateTrampoline(ArenaAllocator * arena,EntryPointCallingConvention abi,ThreadOffset<8> offset)82 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
83     ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset<8> offset) {
84   Arm64Assembler assembler(arena);
85 
86   switch (abi) {
87     case kInterpreterAbi:  // Thread* is first argument (X0) in interpreter ABI.
88       __ JumpTo(Arm64ManagedRegister::FromXRegister(X0), Offset(offset.Int32Value()),
89           Arm64ManagedRegister::FromXRegister(IP1));
90 
91       break;
92     case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (X0).
93       __ LoadRawPtr(Arm64ManagedRegister::FromXRegister(IP1),
94                       Arm64ManagedRegister::FromXRegister(X0),
95                       Offset(JNIEnvExt::SelfOffset(8).Int32Value()));
96 
97       __ JumpTo(Arm64ManagedRegister::FromXRegister(IP1), Offset(offset.Int32Value()),
98                 Arm64ManagedRegister::FromXRegister(IP0));
99 
100       break;
101     case kQuickAbi:  // X18 holds Thread*.
102       __ JumpTo(Arm64ManagedRegister::FromXRegister(TR), Offset(offset.Int32Value()),
103                 Arm64ManagedRegister::FromXRegister(IP0));
104 
105       break;
106   }
107 
108   __ FinalizeCode();
109   size_t cs = __ CodeSize();
110   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
111   MemoryRegion code(entry_stub->data(), entry_stub->size());
112   __ FinalizeInstructions(code);
113 
114   return std::move(entry_stub);
115 }
116 }  // namespace arm64
117 #endif  // ART_ENABLE_CODEGEN_arm64
118 
119 #ifdef ART_ENABLE_CODEGEN_mips
120 namespace mips {
CreateTrampoline(ArenaAllocator * arena,EntryPointCallingConvention abi,ThreadOffset<4> offset)121 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
122     ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset<4> offset) {
123   MipsAssembler assembler(arena);
124 
125   switch (abi) {
126     case kInterpreterAbi:  // Thread* is first argument (A0) in interpreter ABI.
127       __ LoadFromOffset(kLoadWord, T9, A0, offset.Int32Value());
128       break;
129     case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (A0).
130       __ LoadFromOffset(kLoadWord, T9, A0, JNIEnvExt::SelfOffset(4).Int32Value());
131       __ LoadFromOffset(kLoadWord, T9, T9, offset.Int32Value());
132       break;
133     case kQuickAbi:  // S1 holds Thread*.
134       __ LoadFromOffset(kLoadWord, T9, S1, offset.Int32Value());
135   }
136   __ Jr(T9);
137   __ Nop();
138   __ Break();
139 
140   __ FinalizeCode();
141   size_t cs = __ CodeSize();
142   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
143   MemoryRegion code(entry_stub->data(), entry_stub->size());
144   __ FinalizeInstructions(code);
145 
146   return std::move(entry_stub);
147 }
148 }  // namespace mips
149 #endif  // ART_ENABLE_CODEGEN_mips
150 
151 #ifdef ART_ENABLE_CODEGEN_mips64
152 namespace mips64 {
CreateTrampoline(ArenaAllocator * arena,EntryPointCallingConvention abi,ThreadOffset<8> offset)153 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
154     ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset<8> offset) {
155   Mips64Assembler assembler(arena);
156 
157   switch (abi) {
158     case kInterpreterAbi:  // Thread* is first argument (A0) in interpreter ABI.
159       __ LoadFromOffset(kLoadDoubleword, T9, A0, offset.Int32Value());
160       break;
161     case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (A0).
162       __ LoadFromOffset(kLoadDoubleword, T9, A0, JNIEnvExt::SelfOffset(8).Int32Value());
163       __ LoadFromOffset(kLoadDoubleword, T9, T9, offset.Int32Value());
164       break;
165     case kQuickAbi:  // Fall-through.
166       __ LoadFromOffset(kLoadDoubleword, T9, S1, offset.Int32Value());
167   }
168   __ Jr(T9);
169   __ Nop();
170   __ Break();
171 
172   __ FinalizeCode();
173   size_t cs = __ CodeSize();
174   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
175   MemoryRegion code(entry_stub->data(), entry_stub->size());
176   __ FinalizeInstructions(code);
177 
178   return std::move(entry_stub);
179 }
180 }  // namespace mips64
181 #endif  // ART_ENABLE_CODEGEN_mips
182 
183 #ifdef ART_ENABLE_CODEGEN_x86
184 namespace x86 {
CreateTrampoline(ArenaAllocator * arena,ThreadOffset<4> offset)185 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(ArenaAllocator* arena,
186                                                                     ThreadOffset<4> offset) {
187   X86Assembler assembler(arena);
188 
189   // All x86 trampolines call via the Thread* held in fs.
190   __ fs()->jmp(Address::Absolute(offset));
191   __ int3();
192 
193   __ FinalizeCode();
194   size_t cs = __ CodeSize();
195   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
196   MemoryRegion code(entry_stub->data(), entry_stub->size());
197   __ FinalizeInstructions(code);
198 
199   return std::move(entry_stub);
200 }
201 }  // namespace x86
202 #endif  // ART_ENABLE_CODEGEN_x86
203 
204 #ifdef ART_ENABLE_CODEGEN_x86_64
205 namespace x86_64 {
CreateTrampoline(ArenaAllocator * arena,ThreadOffset<8> offset)206 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(ArenaAllocator* arena,
207                                                                     ThreadOffset<8> offset) {
208   x86_64::X86_64Assembler assembler(arena);
209 
210   // All x86 trampolines call via the Thread* held in gs.
211   __ gs()->jmp(x86_64::Address::Absolute(offset, true));
212   __ int3();
213 
214   __ FinalizeCode();
215   size_t cs = __ CodeSize();
216   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
217   MemoryRegion code(entry_stub->data(), entry_stub->size());
218   __ FinalizeInstructions(code);
219 
220   return std::move(entry_stub);
221 }
222 }  // namespace x86_64
223 #endif  // ART_ENABLE_CODEGEN_x86_64
224 
CreateTrampoline64(InstructionSet isa,EntryPointCallingConvention abi,ThreadOffset<8> offset)225 std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline64(InstructionSet isa,
226                                                                EntryPointCallingConvention abi,
227                                                                ThreadOffset<8> offset) {
228   ArenaPool pool;
229   ArenaAllocator arena(&pool);
230   switch (isa) {
231 #ifdef ART_ENABLE_CODEGEN_arm64
232     case kArm64:
233       return arm64::CreateTrampoline(&arena, abi, offset);
234 #endif
235 #ifdef ART_ENABLE_CODEGEN_mips64
236     case kMips64:
237       return mips64::CreateTrampoline(&arena, abi, offset);
238 #endif
239 #ifdef ART_ENABLE_CODEGEN_x86_64
240     case kX86_64:
241       return x86_64::CreateTrampoline(&arena, offset);
242 #endif
243     default:
244       UNUSED(abi);
245       UNUSED(offset);
246       LOG(FATAL) << "Unexpected InstructionSet: " << isa;
247       UNREACHABLE();
248   }
249 }
250 
CreateTrampoline32(InstructionSet isa,EntryPointCallingConvention abi,ThreadOffset<4> offset)251 std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline32(InstructionSet isa,
252                                                                EntryPointCallingConvention abi,
253                                                                ThreadOffset<4> offset) {
254   ArenaPool pool;
255   ArenaAllocator arena(&pool);
256   switch (isa) {
257 #ifdef ART_ENABLE_CODEGEN_arm
258     case kArm:
259     case kThumb2:
260       return arm::CreateTrampoline(&arena, abi, offset);
261 #endif
262 #ifdef ART_ENABLE_CODEGEN_mips
263     case kMips:
264       return mips::CreateTrampoline(&arena, abi, offset);
265 #endif
266 #ifdef ART_ENABLE_CODEGEN_x86
267     case kX86:
268       UNUSED(abi);
269       return x86::CreateTrampoline(&arena, offset);
270 #endif
271     default:
272       LOG(FATAL) << "Unexpected InstructionSet: " << isa;
273       UNREACHABLE();
274   }
275 }
276 
277 }  // namespace art
278