blob: facc6304e514b093f02627313f78f86835fcdd87 [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 Markocf93a5c2015-06-16 11:33:24 +000020#include "utils/arm/assembler_thumb2.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 Markocf93a5c2015-06-16 11:33:24 +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 Markocf93a5c2015-06-16 11:33:24 +000034 Thumb2Assembler assembler;
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 Markocf93a5c2015-06-16 11:33:24 +000049 __ FinalizeCode();
50 size_t cs = __ CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -070051 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Ian Rogers659efe72013-08-07 22:54:13 -070052 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
Vladimir Markocf93a5c2015-06-16 11:33:24 +000053 __ FinalizeInstructions(code);
Ian Rogers659efe72013-08-07 22:54:13 -070054
55 return entry_stub.release();
56}
57} // namespace arm
58
Stuart Monteithb95a5342014-03-12 13:32:32 +000059namespace arm64 {
60static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
Ian Rogersdd7624d2014-03-14 17:43:00 -070061 ThreadOffset<8> offset) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +000062 Arm64Assembler assembler;
Stuart Monteithb95a5342014-03-12 13:32:32 +000063
64 switch (abi) {
65 case kInterpreterAbi: // Thread* is first argument (X0) in interpreter ABI.
Alexandre Rames37c92df2014-10-17 14:35:27 +010066 __ JumpTo(Arm64ManagedRegister::FromXRegister(X0), Offset(offset.Int32Value()),
67 Arm64ManagedRegister::FromXRegister(IP1));
Stuart Monteithb95a5342014-03-12 13:32:32 +000068
69 break;
70 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (X0).
Alexandre Rames37c92df2014-10-17 14:35:27 +010071 __ LoadRawPtr(Arm64ManagedRegister::FromXRegister(IP1),
72 Arm64ManagedRegister::FromXRegister(X0),
Stuart Monteithb95a5342014-03-12 13:32:32 +000073 Offset(JNIEnvExt::SelfOffset().Int32Value()));
74
Alexandre Rames37c92df2014-10-17 14:35:27 +010075 __ JumpTo(Arm64ManagedRegister::FromXRegister(IP1), Offset(offset.Int32Value()),
76 Arm64ManagedRegister::FromXRegister(IP0));
Stuart Monteithb95a5342014-03-12 13:32:32 +000077
78 break;
Elliott Hughes956af0f2014-12-11 14:34:28 -080079 case kQuickAbi: // X18 holds Thread*.
Alexandre Rames37c92df2014-10-17 14:35:27 +010080 __ JumpTo(Arm64ManagedRegister::FromXRegister(TR), Offset(offset.Int32Value()),
81 Arm64ManagedRegister::FromXRegister(IP0));
Stuart Monteithb95a5342014-03-12 13:32:32 +000082
83 break;
84 }
85
Vladimir Markocf93a5c2015-06-16 11:33:24 +000086 __ FinalizeCode();
87 size_t cs = __ CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -070088 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Stuart Monteithb95a5342014-03-12 13:32:32 +000089 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
Vladimir Markocf93a5c2015-06-16 11:33:24 +000090 __ FinalizeInstructions(code);
Stuart Monteithb95a5342014-03-12 13:32:32 +000091
92 return entry_stub.release();
93}
94} // namespace arm64
95
Ian Rogers659efe72013-08-07 22:54:13 -070096namespace mips {
97static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
Ian Rogersdd7624d2014-03-14 17:43:00 -070098 ThreadOffset<4> offset) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +000099 MipsAssembler assembler;
Ian Rogers659efe72013-08-07 22:54:13 -0700100
101 switch (abi) {
102 case kInterpreterAbi: // Thread* is first argument (A0) in interpreter ABI.
103 __ LoadFromOffset(kLoadWord, T9, A0, offset.Int32Value());
104 break;
105 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (A0).
106 __ LoadFromOffset(kLoadWord, T9, A0, JNIEnvExt::SelfOffset().Int32Value());
107 __ LoadFromOffset(kLoadWord, T9, T9, offset.Int32Value());
108 break;
Elliott Hughes956af0f2014-12-11 14:34:28 -0800109 case kQuickAbi: // S1 holds Thread*.
Ian Rogers659efe72013-08-07 22:54:13 -0700110 __ LoadFromOffset(kLoadWord, T9, S1, offset.Int32Value());
111 }
112 __ Jr(T9);
113 __ Nop();
114 __ Break();
115
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000116 __ FinalizeCode();
117 size_t cs = __ CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700118 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Ian Rogers659efe72013-08-07 22:54:13 -0700119 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000120 __ FinalizeInstructions(code);
Ian Rogers659efe72013-08-07 22:54:13 -0700121
122 return entry_stub.release();
123}
124} // namespace mips
125
Andreas Gampe57b34292015-01-14 15:45:59 -0800126namespace mips64 {
127static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
128 ThreadOffset<8> offset) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000129 Mips64Assembler assembler;
Andreas Gampe57b34292015-01-14 15:45:59 -0800130
131 switch (abi) {
132 case kInterpreterAbi: // Thread* is first argument (A0) in interpreter ABI.
133 __ LoadFromOffset(kLoadDoubleword, T9, A0, offset.Int32Value());
134 break;
135 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (A0).
136 __ LoadFromOffset(kLoadDoubleword, T9, A0, JNIEnvExt::SelfOffset().Int32Value());
137 __ LoadFromOffset(kLoadDoubleword, T9, T9, offset.Int32Value());
138 break;
139 case kQuickAbi: // Fall-through.
140 __ LoadFromOffset(kLoadDoubleword, T9, S1, offset.Int32Value());
141 }
142 __ Jr(T9);
143 __ Nop();
144 __ Break();
145
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000146 __ FinalizeCode();
147 size_t cs = __ CodeSize();
Andreas Gampe57b34292015-01-14 15:45:59 -0800148 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
149 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000150 __ FinalizeInstructions(code);
Andreas Gampe57b34292015-01-14 15:45:59 -0800151
152 return entry_stub.release();
153}
154} // namespace mips64
155
Ian Rogers659efe72013-08-07 22:54:13 -0700156namespace x86 {
Ian Rogersdd7624d2014-03-14 17:43:00 -0700157static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<4> offset) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000158 X86Assembler assembler;
Ian Rogers659efe72013-08-07 22:54:13 -0700159
160 // All x86 trampolines call via the Thread* held in fs.
161 __ fs()->jmp(Address::Absolute(offset));
162 __ int3();
163
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000164 __ FinalizeCode();
165 size_t cs = __ CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700166 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Ian Rogers659efe72013-08-07 22:54:13 -0700167 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000168 __ FinalizeInstructions(code);
Ian Rogers659efe72013-08-07 22:54:13 -0700169
170 return entry_stub.release();
171}
172} // namespace x86
173
Ian Rogersbefbd572014-03-06 01:13:39 -0800174namespace x86_64 {
Ian Rogersdd7624d2014-03-14 17:43:00 -0700175static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<8> offset) {
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000176 x86_64::X86_64Assembler assembler;
Ian Rogersbefbd572014-03-06 01:13:39 -0800177
178 // All x86 trampolines call via the Thread* held in gs.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700179 __ gs()->jmp(x86_64::Address::Absolute(offset, true));
Ian Rogersbefbd572014-03-06 01:13:39 -0800180 __ int3();
181
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000182 __ FinalizeCode();
183 size_t cs = __ CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700184 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Ian Rogersbefbd572014-03-06 01:13:39 -0800185 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000186 __ FinalizeInstructions(code);
Ian Rogersbefbd572014-03-06 01:13:39 -0800187
188 return entry_stub.release();
189}
190} // namespace x86_64
191
Ian Rogersdd7624d2014-03-14 17:43:00 -0700192const std::vector<uint8_t>* CreateTrampoline64(InstructionSet isa, EntryPointCallingConvention abi,
193 ThreadOffset<8> offset) {
194 switch (isa) {
195 case kArm64:
196 return arm64::CreateTrampoline(abi, offset);
Andreas Gampe57b34292015-01-14 15:45:59 -0800197 case kMips64:
198 return mips64::CreateTrampoline(abi, offset);
Ian Rogersdd7624d2014-03-14 17:43:00 -0700199 case kX86_64:
200 return x86_64::CreateTrampoline(offset);
201 default:
202 LOG(FATAL) << "Unexpected InstructionSet: " << isa;
Ian Rogersd4c4d952014-10-16 20:31:53 -0700203 UNREACHABLE();
Ian Rogersdd7624d2014-03-14 17:43:00 -0700204 }
205}
206
207const std::vector<uint8_t>* CreateTrampoline32(InstructionSet isa, EntryPointCallingConvention abi,
208 ThreadOffset<4> offset) {
Ian Rogers659efe72013-08-07 22:54:13 -0700209 switch (isa) {
210 case kArm:
211 case kThumb2:
212 return arm::CreateTrampoline(abi, offset);
213 case kMips:
214 return mips::CreateTrampoline(abi, offset);
215 case kX86:
216 return x86::CreateTrampoline(offset);
Ian Rogers659efe72013-08-07 22:54:13 -0700217 default:
Ian Rogersdd7624d2014-03-14 17:43:00 -0700218 LOG(FATAL) << "Unexpected InstructionSet: " << isa;
Ian Rogersd4c4d952014-10-16 20:31:53 -0700219 UNREACHABLE();
Ian Rogers659efe72013-08-07 22:54:13 -0700220 }
221}
222
223} // namespace art