blob: cb51ed8fc83fc575b73bc2ef648988457a84314e [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
Ian Rogers68d8b422014-07-17 11:09:10 -070019#include "jni_env_ext.h"
Vladimir Markofbeb4ae2015-06-16 11:32:01 +000020#include "utils/arm/assembler_arm.h"
Stuart Monteithb95a5342014-03-12 13:32:32 +000021#include "utils/arm64/assembler_arm64.h"
Ian Rogers659efe72013-08-07 22:54:13 -070022#include "utils/mips/assembler_mips.h"
Andreas Gampe57b34292015-01-14 15:45:59 -080023#include "utils/mips64/assembler_mips64.h"
Ian Rogers659efe72013-08-07 22:54:13 -070024#include "utils/x86/assembler_x86.h"
Ian Rogersdd7624d2014-03-14 17:43:00 -070025#include "utils/x86_64/assembler_x86_64.h"
Ian Rogers659efe72013-08-07 22:54:13 -070026
Vladimir Markofbeb4ae2015-06-16 11:32:01 +000027#define __ assembler->
Ian Rogers659efe72013-08-07 22:54:13 -070028
29namespace art {
30
31namespace arm {
32static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
Ian Rogersdd7624d2014-03-14 17:43:00 -070033 ThreadOffset<4> offset) {
Vladimir Markofbeb4ae2015-06-16 11:32:01 +000034 std::unique_ptr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kThumb2)));
Ian Rogers659efe72013-08-07 22:54:13 -070035
36 switch (abi) {
37 case kInterpreterAbi: // Thread* is first argument (R0) in interpreter ABI.
38 __ LoadFromOffset(kLoadWord, PC, R0, offset.Int32Value());
39 break;
40 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (R0).
41 __ LoadFromOffset(kLoadWord, IP, R0, JNIEnvExt::SelfOffset().Int32Value());
42 __ LoadFromOffset(kLoadWord, PC, IP, offset.Int32Value());
43 break;
Elliott Hughes956af0f2014-12-11 14:34:28 -080044 case kQuickAbi: // R9 holds Thread*.
Ian Rogers659efe72013-08-07 22:54:13 -070045 __ LoadFromOffset(kLoadWord, PC, R9, offset.Int32Value());
46 }
47 __ bkpt(0);
48
Vladimir Markofbeb4ae2015-06-16 11:32:01 +000049 size_t cs = assembler->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -070050 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Ian Rogers659efe72013-08-07 22:54:13 -070051 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
Vladimir Markofbeb4ae2015-06-16 11:32:01 +000052 assembler->FinalizeInstructions(code);
Ian Rogers659efe72013-08-07 22:54:13 -070053
54 return entry_stub.release();
55}
56} // namespace arm
57
Stuart Monteithb95a5342014-03-12 13:32:32 +000058namespace arm64 {
59static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
Ian Rogersdd7624d2014-03-14 17:43:00 -070060 ThreadOffset<8> offset) {
Vladimir Markofbeb4ae2015-06-16 11:32:01 +000061 std::unique_ptr<Arm64Assembler> assembler(static_cast<Arm64Assembler*>(Assembler::Create(kArm64)));
Stuart Monteithb95a5342014-03-12 13:32:32 +000062
63 switch (abi) {
64 case kInterpreterAbi: // Thread* is first argument (X0) in interpreter ABI.
Alexandre Rames37c92df2014-10-17 14:35:27 +010065 __ JumpTo(Arm64ManagedRegister::FromXRegister(X0), Offset(offset.Int32Value()),
66 Arm64ManagedRegister::FromXRegister(IP1));
Stuart Monteithb95a5342014-03-12 13:32:32 +000067
68 break;
69 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (X0).
Alexandre Rames37c92df2014-10-17 14:35:27 +010070 __ LoadRawPtr(Arm64ManagedRegister::FromXRegister(IP1),
71 Arm64ManagedRegister::FromXRegister(X0),
Stuart Monteithb95a5342014-03-12 13:32:32 +000072 Offset(JNIEnvExt::SelfOffset().Int32Value()));
73
Alexandre Rames37c92df2014-10-17 14:35:27 +010074 __ JumpTo(Arm64ManagedRegister::FromXRegister(IP1), Offset(offset.Int32Value()),
75 Arm64ManagedRegister::FromXRegister(IP0));
Stuart Monteithb95a5342014-03-12 13:32:32 +000076
77 break;
Elliott Hughes956af0f2014-12-11 14:34:28 -080078 case kQuickAbi: // X18 holds Thread*.
Alexandre Rames37c92df2014-10-17 14:35:27 +010079 __ JumpTo(Arm64ManagedRegister::FromXRegister(TR), Offset(offset.Int32Value()),
80 Arm64ManagedRegister::FromXRegister(IP0));
Stuart Monteithb95a5342014-03-12 13:32:32 +000081
82 break;
83 }
84
Vladimir Markofbeb4ae2015-06-16 11:32:01 +000085 assembler->EmitSlowPaths();
86 size_t cs = assembler->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -070087 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Stuart Monteithb95a5342014-03-12 13:32:32 +000088 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
Vladimir Markofbeb4ae2015-06-16 11:32:01 +000089 assembler->FinalizeInstructions(code);
Stuart Monteithb95a5342014-03-12 13:32:32 +000090
91 return entry_stub.release();
92}
93} // namespace arm64
94
Ian Rogers659efe72013-08-07 22:54:13 -070095namespace mips {
96static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
Ian Rogersdd7624d2014-03-14 17:43:00 -070097 ThreadOffset<4> offset) {
Vladimir Markofbeb4ae2015-06-16 11:32:01 +000098 std::unique_ptr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
Ian Rogers659efe72013-08-07 22:54:13 -070099
100 switch (abi) {
101 case kInterpreterAbi: // Thread* is first argument (A0) in interpreter ABI.
102 __ LoadFromOffset(kLoadWord, T9, A0, offset.Int32Value());
103 break;
104 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (A0).
105 __ LoadFromOffset(kLoadWord, T9, A0, JNIEnvExt::SelfOffset().Int32Value());
106 __ LoadFromOffset(kLoadWord, T9, T9, offset.Int32Value());
107 break;
Elliott Hughes956af0f2014-12-11 14:34:28 -0800108 case kQuickAbi: // S1 holds Thread*.
Ian Rogers659efe72013-08-07 22:54:13 -0700109 __ LoadFromOffset(kLoadWord, T9, S1, offset.Int32Value());
110 }
111 __ Jr(T9);
112 __ Nop();
113 __ Break();
114
Vladimir Markofbeb4ae2015-06-16 11:32:01 +0000115 size_t cs = assembler->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700116 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Ian Rogers659efe72013-08-07 22:54:13 -0700117 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
Vladimir Markofbeb4ae2015-06-16 11:32:01 +0000118 assembler->FinalizeInstructions(code);
Ian Rogers659efe72013-08-07 22:54:13 -0700119
120 return entry_stub.release();
121}
122} // namespace mips
123
Andreas Gampe57b34292015-01-14 15:45:59 -0800124namespace mips64 {
125static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
126 ThreadOffset<8> offset) {
Vladimir Markofbeb4ae2015-06-16 11:32:01 +0000127 std::unique_ptr<Mips64Assembler> assembler(static_cast<Mips64Assembler*>(Assembler::Create(kMips64)));
Andreas Gampe57b34292015-01-14 15:45:59 -0800128
129 switch (abi) {
130 case kInterpreterAbi: // Thread* is first argument (A0) in interpreter ABI.
131 __ LoadFromOffset(kLoadDoubleword, T9, A0, offset.Int32Value());
132 break;
133 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (A0).
134 __ LoadFromOffset(kLoadDoubleword, T9, A0, JNIEnvExt::SelfOffset().Int32Value());
135 __ LoadFromOffset(kLoadDoubleword, T9, T9, offset.Int32Value());
136 break;
137 case kQuickAbi: // Fall-through.
138 __ LoadFromOffset(kLoadDoubleword, T9, S1, offset.Int32Value());
139 }
140 __ Jr(T9);
141 __ Nop();
142 __ Break();
143
Vladimir Markofbeb4ae2015-06-16 11:32:01 +0000144 size_t cs = assembler->CodeSize();
Andreas Gampe57b34292015-01-14 15:45:59 -0800145 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
146 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
Vladimir Markofbeb4ae2015-06-16 11:32:01 +0000147 assembler->FinalizeInstructions(code);
Andreas Gampe57b34292015-01-14 15:45:59 -0800148
149 return entry_stub.release();
150}
151} // namespace mips64
152
Ian Rogers659efe72013-08-07 22:54:13 -0700153namespace x86 {
Ian Rogersdd7624d2014-03-14 17:43:00 -0700154static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<4> offset) {
Vladimir Markofbeb4ae2015-06-16 11:32:01 +0000155 std::unique_ptr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
Ian Rogers659efe72013-08-07 22:54:13 -0700156
157 // All x86 trampolines call via the Thread* held in fs.
158 __ fs()->jmp(Address::Absolute(offset));
159 __ int3();
160
Vladimir Markofbeb4ae2015-06-16 11:32:01 +0000161 size_t cs = assembler->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700162 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Ian Rogers659efe72013-08-07 22:54:13 -0700163 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
Vladimir Markofbeb4ae2015-06-16 11:32:01 +0000164 assembler->FinalizeInstructions(code);
Ian Rogers659efe72013-08-07 22:54:13 -0700165
166 return entry_stub.release();
167}
168} // namespace x86
169
Ian Rogersbefbd572014-03-06 01:13:39 -0800170namespace x86_64 {
Ian Rogersdd7624d2014-03-14 17:43:00 -0700171static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<8> offset) {
Vladimir Markofbeb4ae2015-06-16 11:32:01 +0000172 std::unique_ptr<x86_64::X86_64Assembler>
173 assembler(static_cast<x86_64::X86_64Assembler*>(Assembler::Create(kX86_64)));
Ian Rogersbefbd572014-03-06 01:13:39 -0800174
175 // All x86 trampolines call via the Thread* held in gs.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700176 __ gs()->jmp(x86_64::Address::Absolute(offset, true));
Ian Rogersbefbd572014-03-06 01:13:39 -0800177 __ int3();
178
Vladimir Markofbeb4ae2015-06-16 11:32:01 +0000179 size_t cs = assembler->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700180 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Ian Rogersbefbd572014-03-06 01:13:39 -0800181 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
Vladimir Markofbeb4ae2015-06-16 11:32:01 +0000182 assembler->FinalizeInstructions(code);
Ian Rogersbefbd572014-03-06 01:13:39 -0800183
184 return entry_stub.release();
185}
186} // namespace x86_64
187
Ian Rogersdd7624d2014-03-14 17:43:00 -0700188const std::vector<uint8_t>* CreateTrampoline64(InstructionSet isa, EntryPointCallingConvention abi,
189 ThreadOffset<8> offset) {
190 switch (isa) {
191 case kArm64:
192 return arm64::CreateTrampoline(abi, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -0800193 case kMips64:
194 return mips64::CreateTrampoline(abi, offset);
Ian Rogersdd7624d2014-03-14 17:43:00 -0700195 case kX86_64:
196 return x86_64::CreateTrampoline(offset);
197 default:
198 LOG(FATAL) << "Unexpected InstructionSet: " << isa;
Ian Rogersd4c4d952014-10-16 20:31:53 -0700199 UNREACHABLE();
Ian Rogersdd7624d2014-03-14 17:43:00 -0700200 }
201}
202
203const std::vector<uint8_t>* CreateTrampoline32(InstructionSet isa, EntryPointCallingConvention abi,
204 ThreadOffset<4> offset) {
Ian Rogers659efe72013-08-07 22:54:13 -0700205 switch (isa) {
206 case kArm:
207 case kThumb2:
208 return arm::CreateTrampoline(abi, offset);
209 case kMips:
210 return mips::CreateTrampoline(abi, offset);
211 case kX86:
212 return x86::CreateTrampoline(offset);
Ian Rogers659efe72013-08-07 22:54:13 -0700213 default:
Ian Rogersdd7624d2014-03-14 17:43:00 -0700214 LOG(FATAL) << "Unexpected InstructionSet: " << isa;
Ian Rogersd4c4d952014-10-16 20:31:53 -0700215 UNREACHABLE();
Ian Rogers659efe72013-08-07 22:54:13 -0700216 }
217}
218
219} // namespace art