blob: 70f290d60e25a8cf5a7ab554506781b9ad11f16c [file] [log] [blame]
Ian Rogers659efe72013-08-07 22:54:13 -07001/*
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
Vladimir Marko93205e32016-04-13 11:59:46 +010019#include "base/arena_allocator.h"
Ian Rogers68d8b422014-07-17 11:09:10 -070020#include "jni_env_ext.h"
Alex Light50fa9932015-08-10 15:30:07 -070021
22#ifdef ART_ENABLE_CODEGEN_arm
Anton Kirilovba8023b2016-08-09 14:13:59 +010023#include "utils/arm/assembler_arm_vixl.h"
Alex Light50fa9932015-08-10 15:30:07 -070024#endif
25
26#ifdef ART_ENABLE_CODEGEN_arm64
Stuart Monteithb95a5342014-03-12 13:32:32 +000027#include "utils/arm64/assembler_arm64.h"
Alex Light50fa9932015-08-10 15:30:07 -070028#endif
29
30#ifdef ART_ENABLE_CODEGEN_mips
Ian Rogers659efe72013-08-07 22:54:13 -070031#include "utils/mips/assembler_mips.h"
Alex Light50fa9932015-08-10 15:30:07 -070032#endif
33
34#ifdef ART_ENABLE_CODEGEN_mips64
Andreas Gampe57b34292015-01-14 15:45:59 -080035#include "utils/mips64/assembler_mips64.h"
Alex Light50fa9932015-08-10 15:30:07 -070036#endif
37
38#ifdef ART_ENABLE_CODEGEN_x86
Ian Rogers659efe72013-08-07 22:54:13 -070039#include "utils/x86/assembler_x86.h"
Alex Light50fa9932015-08-10 15:30:07 -070040#endif
41
42#ifdef ART_ENABLE_CODEGEN_x86_64
Ian Rogersdd7624d2014-03-14 17:43:00 -070043#include "utils/x86_64/assembler_x86_64.h"
Alex Light50fa9932015-08-10 15:30:07 -070044#endif
Ian Rogers659efe72013-08-07 22:54:13 -070045
Vladimir Markocf93a5c2015-06-16 11:33:24 +000046#define __ assembler.
Ian Rogers659efe72013-08-07 22:54:13 -070047
48namespace art {
49
Alex Light50fa9932015-08-10 15:30:07 -070050#ifdef ART_ENABLE_CODEGEN_arm
Ian Rogers659efe72013-08-07 22:54:13 -070051namespace arm {
Anton Kirilovba8023b2016-08-09 14:13:59 +010052
53#ifdef ___
54#error "ARM Assembler macro already defined."
55#else
56#define ___ assembler.GetVIXLAssembler()->
57#endif
58
Vladimir Marko93205e32016-04-13 11:59:46 +010059static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
Andreas Gampe542451c2016-07-26 09:02:02 -070060 ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset32 offset) {
Anton Kirilovba8023b2016-08-09 14:13:59 +010061 using vixl::aarch32::MemOperand;
62 using vixl::aarch32::pc;
63 using vixl::aarch32::r0;
64 ArmVIXLAssembler assembler(arena);
Ian Rogers659efe72013-08-07 22:54:13 -070065
66 switch (abi) {
67 case kInterpreterAbi: // Thread* is first argument (R0) in interpreter ABI.
Anton Kirilovba8023b2016-08-09 14:13:59 +010068 ___ Ldr(pc, MemOperand(r0, offset.Int32Value()));
Ian Rogers659efe72013-08-07 22:54:13 -070069 break;
Anton Kirilovba8023b2016-08-09 14:13:59 +010070 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()));
Ian Rogers659efe72013-08-07 22:54:13 -070078 break;
Anton Kirilovba8023b2016-08-09 14:13:59 +010079 }
80 case kQuickAbi: // TR holds Thread*.
81 ___ Ldr(pc, MemOperand(tr, offset.Int32Value()));
Ian Rogers659efe72013-08-07 22:54:13 -070082 }
Ian Rogers659efe72013-08-07 22:54:13 -070083
Vladimir Markocf93a5c2015-06-16 11:33:24 +000084 __ FinalizeCode();
85 size_t cs = __ CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -070086 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Vladimir Marko93205e32016-04-13 11:59:46 +010087 MemoryRegion code(entry_stub->data(), entry_stub->size());
Vladimir Markocf93a5c2015-06-16 11:33:24 +000088 __ FinalizeInstructions(code);
Ian Rogers659efe72013-08-07 22:54:13 -070089
Vladimir Marko93205e32016-04-13 11:59:46 +010090 return std::move(entry_stub);
Ian Rogers659efe72013-08-07 22:54:13 -070091}
Anton Kirilovba8023b2016-08-09 14:13:59 +010092
93#undef ___
94
Ian Rogers659efe72013-08-07 22:54:13 -070095} // namespace arm
Alex Light50fa9932015-08-10 15:30:07 -070096#endif // ART_ENABLE_CODEGEN_arm
Ian Rogers659efe72013-08-07 22:54:13 -070097
Alex Light50fa9932015-08-10 15:30:07 -070098#ifdef ART_ENABLE_CODEGEN_arm64
Stuart Monteithb95a5342014-03-12 13:32:32 +000099namespace arm64 {
Vladimir Marko93205e32016-04-13 11:59:46 +0100100static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
Andreas Gampe542451c2016-07-26 09:02:02 -0700101 ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset64 offset) {
Vladimir Marko93205e32016-04-13 11:59:46 +0100102 Arm64Assembler assembler(arena);
Stuart Monteithb95a5342014-03-12 13:32:32 +0000103
104 switch (abi) {
105 case kInterpreterAbi: // Thread* is first argument (X0) in interpreter ABI.
Alexandre Rames37c92df2014-10-17 14:35:27 +0100106 __ JumpTo(Arm64ManagedRegister::FromXRegister(X0), Offset(offset.Int32Value()),
107 Arm64ManagedRegister::FromXRegister(IP1));
Stuart Monteithb95a5342014-03-12 13:32:32 +0000108
109 break;
110 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (X0).
Alexandre Rames37c92df2014-10-17 14:35:27 +0100111 __ LoadRawPtr(Arm64ManagedRegister::FromXRegister(IP1),
112 Arm64ManagedRegister::FromXRegister(X0),
Andreas Gampe4d98c842015-12-09 15:14:04 -0800113 Offset(JNIEnvExt::SelfOffset(8).Int32Value()));
Stuart Monteithb95a5342014-03-12 13:32:32 +0000114
Alexandre Rames37c92df2014-10-17 14:35:27 +0100115 __ JumpTo(Arm64ManagedRegister::FromXRegister(IP1), Offset(offset.Int32Value()),
116 Arm64ManagedRegister::FromXRegister(IP0));
Stuart Monteithb95a5342014-03-12 13:32:32 +0000117
118 break;
Elliott Hughes956af0f2014-12-11 14:34:28 -0800119 case kQuickAbi: // X18 holds Thread*.
Alexandre Rames37c92df2014-10-17 14:35:27 +0100120 __ JumpTo(Arm64ManagedRegister::FromXRegister(TR), Offset(offset.Int32Value()),
121 Arm64ManagedRegister::FromXRegister(IP0));
Stuart Monteithb95a5342014-03-12 13:32:32 +0000122
123 break;
124 }
125
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000126 __ FinalizeCode();
127 size_t cs = __ CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700128 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Vladimir Marko93205e32016-04-13 11:59:46 +0100129 MemoryRegion code(entry_stub->data(), entry_stub->size());
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000130 __ FinalizeInstructions(code);
Stuart Monteithb95a5342014-03-12 13:32:32 +0000131
Vladimir Marko93205e32016-04-13 11:59:46 +0100132 return std::move(entry_stub);
Stuart Monteithb95a5342014-03-12 13:32:32 +0000133}
134} // namespace arm64
Alex Light50fa9932015-08-10 15:30:07 -0700135#endif // ART_ENABLE_CODEGEN_arm64
Stuart Monteithb95a5342014-03-12 13:32:32 +0000136
Alex Light50fa9932015-08-10 15:30:07 -0700137#ifdef ART_ENABLE_CODEGEN_mips
Ian Rogers659efe72013-08-07 22:54:13 -0700138namespace mips {
Vladimir Marko93205e32016-04-13 11:59:46 +0100139static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
Andreas Gampe542451c2016-07-26 09:02:02 -0700140 ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset32 offset) {
Vladimir Marko93205e32016-04-13 11:59:46 +0100141 MipsAssembler assembler(arena);
Ian Rogers659efe72013-08-07 22:54:13 -0700142
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).
Andreas Gampe4d98c842015-12-09 15:14:04 -0800148 __ LoadFromOffset(kLoadWord, T9, A0, JNIEnvExt::SelfOffset(4).Int32Value());
Ian Rogers659efe72013-08-07 22:54:13 -0700149 __ LoadFromOffset(kLoadWord, T9, T9, offset.Int32Value());
150 break;
Elliott Hughes956af0f2014-12-11 14:34:28 -0800151 case kQuickAbi: // S1 holds Thread*.
Ian Rogers659efe72013-08-07 22:54:13 -0700152 __ LoadFromOffset(kLoadWord, T9, S1, offset.Int32Value());
153 }
154 __ Jr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700155 __ NopIfNoReordering();
Ian Rogers659efe72013-08-07 22:54:13 -0700156 __ Break();
157
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000158 __ FinalizeCode();
159 size_t cs = __ CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700160 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Vladimir Marko93205e32016-04-13 11:59:46 +0100161 MemoryRegion code(entry_stub->data(), entry_stub->size());
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000162 __ FinalizeInstructions(code);
Ian Rogers659efe72013-08-07 22:54:13 -0700163
Vladimir Marko93205e32016-04-13 11:59:46 +0100164 return std::move(entry_stub);
Ian Rogers659efe72013-08-07 22:54:13 -0700165}
166} // namespace mips
Alex Light50fa9932015-08-10 15:30:07 -0700167#endif // ART_ENABLE_CODEGEN_mips
Ian Rogers659efe72013-08-07 22:54:13 -0700168
Alex Light50fa9932015-08-10 15:30:07 -0700169#ifdef ART_ENABLE_CODEGEN_mips64
Andreas Gampe57b34292015-01-14 15:45:59 -0800170namespace mips64 {
Vladimir Marko93205e32016-04-13 11:59:46 +0100171static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
Andreas Gampe542451c2016-07-26 09:02:02 -0700172 ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset64 offset) {
Vladimir Marko93205e32016-04-13 11:59:46 +0100173 Mips64Assembler assembler(arena);
Andreas Gampe57b34292015-01-14 15:45:59 -0800174
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).
Andreas Gampe4d98c842015-12-09 15:14:04 -0800180 __ LoadFromOffset(kLoadDoubleword, T9, A0, JNIEnvExt::SelfOffset(8).Int32Value());
Andreas Gampe57b34292015-01-14 15:45:59 -0800181 __ 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
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000190 __ FinalizeCode();
191 size_t cs = __ CodeSize();
Andreas Gampe57b34292015-01-14 15:45:59 -0800192 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Vladimir Marko93205e32016-04-13 11:59:46 +0100193 MemoryRegion code(entry_stub->data(), entry_stub->size());
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000194 __ FinalizeInstructions(code);
Andreas Gampe57b34292015-01-14 15:45:59 -0800195
Vladimir Marko93205e32016-04-13 11:59:46 +0100196 return std::move(entry_stub);
Andreas Gampe57b34292015-01-14 15:45:59 -0800197}
198} // namespace mips64
Alex Light50fa9932015-08-10 15:30:07 -0700199#endif // ART_ENABLE_CODEGEN_mips
Andreas Gampe57b34292015-01-14 15:45:59 -0800200
Alex Light50fa9932015-08-10 15:30:07 -0700201#ifdef ART_ENABLE_CODEGEN_x86
Ian Rogers659efe72013-08-07 22:54:13 -0700202namespace x86 {
Vladimir Marko93205e32016-04-13 11:59:46 +0100203static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(ArenaAllocator* arena,
Andreas Gampe542451c2016-07-26 09:02:02 -0700204 ThreadOffset32 offset) {
Vladimir Marko93205e32016-04-13 11:59:46 +0100205 X86Assembler assembler(arena);
Ian Rogers659efe72013-08-07 22:54:13 -0700206
207 // All x86 trampolines call via the Thread* held in fs.
208 __ fs()->jmp(Address::Absolute(offset));
209 __ int3();
210
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000211 __ FinalizeCode();
212 size_t cs = __ CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700213 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Vladimir Marko93205e32016-04-13 11:59:46 +0100214 MemoryRegion code(entry_stub->data(), entry_stub->size());
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000215 __ FinalizeInstructions(code);
Ian Rogers659efe72013-08-07 22:54:13 -0700216
Vladimir Marko93205e32016-04-13 11:59:46 +0100217 return std::move(entry_stub);
Ian Rogers659efe72013-08-07 22:54:13 -0700218}
219} // namespace x86
Alex Light50fa9932015-08-10 15:30:07 -0700220#endif // ART_ENABLE_CODEGEN_x86
Ian Rogers659efe72013-08-07 22:54:13 -0700221
Alex Light50fa9932015-08-10 15:30:07 -0700222#ifdef ART_ENABLE_CODEGEN_x86_64
Ian Rogersbefbd572014-03-06 01:13:39 -0800223namespace x86_64 {
Vladimir Marko93205e32016-04-13 11:59:46 +0100224static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(ArenaAllocator* arena,
Andreas Gampe542451c2016-07-26 09:02:02 -0700225 ThreadOffset64 offset) {
Vladimir Marko93205e32016-04-13 11:59:46 +0100226 x86_64::X86_64Assembler assembler(arena);
Ian Rogersbefbd572014-03-06 01:13:39 -0800227
228 // All x86 trampolines call via the Thread* held in gs.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700229 __ gs()->jmp(x86_64::Address::Absolute(offset, true));
Ian Rogersbefbd572014-03-06 01:13:39 -0800230 __ int3();
231
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000232 __ FinalizeCode();
233 size_t cs = __ CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700234 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Vladimir Marko93205e32016-04-13 11:59:46 +0100235 MemoryRegion code(entry_stub->data(), entry_stub->size());
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000236 __ FinalizeInstructions(code);
Ian Rogersbefbd572014-03-06 01:13:39 -0800237
Vladimir Marko93205e32016-04-13 11:59:46 +0100238 return std::move(entry_stub);
Ian Rogersbefbd572014-03-06 01:13:39 -0800239}
240} // namespace x86_64
Alex Light50fa9932015-08-10 15:30:07 -0700241#endif // ART_ENABLE_CODEGEN_x86_64
Ian Rogersbefbd572014-03-06 01:13:39 -0800242
Vladimir Marko93205e32016-04-13 11:59:46 +0100243std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline64(InstructionSet isa,
244 EntryPointCallingConvention abi,
Andreas Gampe542451c2016-07-26 09:02:02 -0700245 ThreadOffset64 offset) {
Vladimir Marko93205e32016-04-13 11:59:46 +0100246 ArenaPool pool;
247 ArenaAllocator arena(&pool);
Ian Rogersdd7624d2014-03-14 17:43:00 -0700248 switch (isa) {
Alex Light50fa9932015-08-10 15:30:07 -0700249#ifdef ART_ENABLE_CODEGEN_arm64
Ian Rogersdd7624d2014-03-14 17:43:00 -0700250 case kArm64:
Vladimir Marko93205e32016-04-13 11:59:46 +0100251 return arm64::CreateTrampoline(&arena, abi, offset);
Alex Light50fa9932015-08-10 15:30:07 -0700252#endif
253#ifdef ART_ENABLE_CODEGEN_mips64
Andreas Gampe57b34292015-01-14 15:45:59 -0800254 case kMips64:
Vladimir Marko93205e32016-04-13 11:59:46 +0100255 return mips64::CreateTrampoline(&arena, abi, offset);
Alex Light50fa9932015-08-10 15:30:07 -0700256#endif
257#ifdef ART_ENABLE_CODEGEN_x86_64
Ian Rogersdd7624d2014-03-14 17:43:00 -0700258 case kX86_64:
Vladimir Marko93205e32016-04-13 11:59:46 +0100259 return x86_64::CreateTrampoline(&arena, offset);
Alex Light50fa9932015-08-10 15:30:07 -0700260#endif
Ian Rogersdd7624d2014-03-14 17:43:00 -0700261 default:
Alex Light50fa9932015-08-10 15:30:07 -0700262 UNUSED(abi);
263 UNUSED(offset);
Ian Rogersdd7624d2014-03-14 17:43:00 -0700264 LOG(FATAL) << "Unexpected InstructionSet: " << isa;
Ian Rogersd4c4d952014-10-16 20:31:53 -0700265 UNREACHABLE();
Ian Rogersdd7624d2014-03-14 17:43:00 -0700266 }
267}
268
Vladimir Marko93205e32016-04-13 11:59:46 +0100269std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline32(InstructionSet isa,
270 EntryPointCallingConvention abi,
Andreas Gampe542451c2016-07-26 09:02:02 -0700271 ThreadOffset32 offset) {
Vladimir Marko93205e32016-04-13 11:59:46 +0100272 ArenaPool pool;
273 ArenaAllocator arena(&pool);
Ian Rogers659efe72013-08-07 22:54:13 -0700274 switch (isa) {
Alex Light50fa9932015-08-10 15:30:07 -0700275#ifdef ART_ENABLE_CODEGEN_arm
Ian Rogers659efe72013-08-07 22:54:13 -0700276 case kArm:
277 case kThumb2:
Vladimir Marko93205e32016-04-13 11:59:46 +0100278 return arm::CreateTrampoline(&arena, abi, offset);
Alex Light50fa9932015-08-10 15:30:07 -0700279#endif
280#ifdef ART_ENABLE_CODEGEN_mips
Ian Rogers659efe72013-08-07 22:54:13 -0700281 case kMips:
Vladimir Marko93205e32016-04-13 11:59:46 +0100282 return mips::CreateTrampoline(&arena, abi, offset);
Alex Light50fa9932015-08-10 15:30:07 -0700283#endif
284#ifdef ART_ENABLE_CODEGEN_x86
Ian Rogers659efe72013-08-07 22:54:13 -0700285 case kX86:
Alex Light50fa9932015-08-10 15:30:07 -0700286 UNUSED(abi);
Vladimir Marko93205e32016-04-13 11:59:46 +0100287 return x86::CreateTrampoline(&arena, offset);
Alex Light50fa9932015-08-10 15:30:07 -0700288#endif
Ian Rogers659efe72013-08-07 22:54:13 -0700289 default:
Ian Rogersdd7624d2014-03-14 17:43:00 -0700290 LOG(FATAL) << "Unexpected InstructionSet: " << isa;
Ian Rogersd4c4d952014-10-16 20:31:53 -0700291 UNREACHABLE();
Ian Rogers659efe72013-08-07 22:54:13 -0700292 }
293}
294
295} // namespace art