blob: fb909a80f888cd63ce009b20c3c2fb887821bd80 [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
19#include "jni_internal.h"
20#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"
23#include "utils/x86/assembler_x86.h"
Ian Rogersdd7624d2014-03-14 17:43:00 -070024#include "utils/x86_64/assembler_x86_64.h"
Ian Rogers659efe72013-08-07 22:54:13 -070025
26#define __ assembler->
27
28namespace art {
29
30namespace arm {
31static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
Ian Rogersdd7624d2014-03-14 17:43:00 -070032 ThreadOffset<4> offset) {
Ian Rogers659efe72013-08-07 22:54:13 -070033 UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
34
35 switch (abi) {
36 case kInterpreterAbi: // Thread* is first argument (R0) in interpreter ABI.
37 __ LoadFromOffset(kLoadWord, PC, R0, offset.Int32Value());
38 break;
39 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (R0).
40 __ LoadFromOffset(kLoadWord, IP, R0, JNIEnvExt::SelfOffset().Int32Value());
41 __ LoadFromOffset(kLoadWord, PC, IP, offset.Int32Value());
42 break;
43 case kPortableAbi: // R9 holds Thread*.
44 case kQuickAbi: // Fall-through.
45 __ LoadFromOffset(kLoadWord, PC, R9, offset.Int32Value());
46 }
47 __ bkpt(0);
48
49 size_t cs = assembler->CodeSize();
50 UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
51 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
52 assembler->FinalizeInstructions(code);
53
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) {
Stuart Monteithb95a5342014-03-12 13:32:32 +000061 UniquePtr<Arm64Assembler> assembler(static_cast<Arm64Assembler*>(Assembler::Create(kArm64)));
62
63 switch (abi) {
64 case kInterpreterAbi: // Thread* is first argument (X0) in interpreter ABI.
65 // FIXME IPx used by VIXL - this is unsafe.
Andreas Gampec6ee54e2014-03-24 16:45:44 -070066 __ JumpTo(Arm64ManagedRegister::FromCoreRegister(X0), Offset(offset.Int32Value()),
Stuart Monteithb95a5342014-03-12 13:32:32 +000067 Arm64ManagedRegister::FromCoreRegister(IP1));
68
69 break;
70 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (X0).
71
72 __ LoadRawPtr(Arm64ManagedRegister::FromCoreRegister(IP1),
73 Arm64ManagedRegister::FromCoreRegister(X0),
74 Offset(JNIEnvExt::SelfOffset().Int32Value()));
75
76 // FIXME IPx used by VIXL - this is unsafe.
Andreas Gampec6ee54e2014-03-24 16:45:44 -070077 __ JumpTo(Arm64ManagedRegister::FromCoreRegister(IP1), Offset(offset.Int32Value()),
Stuart Monteithb95a5342014-03-12 13:32:32 +000078 Arm64ManagedRegister::FromCoreRegister(IP0));
79
80 break;
81 case kPortableAbi: // X18 holds Thread*.
82 case kQuickAbi: // Fall-through.
Andreas Gampec6ee54e2014-03-24 16:45:44 -070083 __ JumpTo(Arm64ManagedRegister::FromCoreRegister(TR), Offset(offset.Int32Value()),
Stuart Monteithb95a5342014-03-12 13:32:32 +000084 Arm64ManagedRegister::FromCoreRegister(IP0));
85
86 break;
87 }
88
89 size_t cs = assembler->CodeSize();
90 UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
91 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
92 assembler->FinalizeInstructions(code);
93
94 return entry_stub.release();
95}
96} // namespace arm64
97
Ian Rogers659efe72013-08-07 22:54:13 -070098namespace mips {
99static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700100 ThreadOffset<4> offset) {
Ian Rogers659efe72013-08-07 22:54:13 -0700101 UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
102
103 switch (abi) {
104 case kInterpreterAbi: // Thread* is first argument (A0) in interpreter ABI.
105 __ LoadFromOffset(kLoadWord, T9, A0, offset.Int32Value());
106 break;
107 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (A0).
108 __ LoadFromOffset(kLoadWord, T9, A0, JNIEnvExt::SelfOffset().Int32Value());
109 __ LoadFromOffset(kLoadWord, T9, T9, offset.Int32Value());
110 break;
111 case kPortableAbi: // S1 holds Thread*.
112 case kQuickAbi: // Fall-through.
113 __ LoadFromOffset(kLoadWord, T9, S1, offset.Int32Value());
114 }
115 __ Jr(T9);
116 __ Nop();
117 __ Break();
118
119 size_t cs = assembler->CodeSize();
120 UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
121 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
122 assembler->FinalizeInstructions(code);
123
124 return entry_stub.release();
125}
126} // namespace mips
127
128namespace x86 {
Ian Rogersdd7624d2014-03-14 17:43:00 -0700129static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<4> offset) {
Ian Rogers659efe72013-08-07 22:54:13 -0700130 UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
131
132 // All x86 trampolines call via the Thread* held in fs.
133 __ fs()->jmp(Address::Absolute(offset));
134 __ int3();
135
136 size_t cs = assembler->CodeSize();
137 UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
138 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
139 assembler->FinalizeInstructions(code);
140
141 return entry_stub.release();
142}
143} // namespace x86
144
Ian Rogersbefbd572014-03-06 01:13:39 -0800145namespace x86_64 {
Ian Rogersdd7624d2014-03-14 17:43:00 -0700146static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<8> offset) {
147 UniquePtr<x86_64::X86_64Assembler>
148 assembler(static_cast<x86_64::X86_64Assembler*>(Assembler::Create(kX86_64)));
Ian Rogersbefbd572014-03-06 01:13:39 -0800149
150 // All x86 trampolines call via the Thread* held in gs.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700151 __ gs()->jmp(x86_64::Address::Absolute(offset, true));
Ian Rogersbefbd572014-03-06 01:13:39 -0800152 __ int3();
153
154 size_t cs = assembler->CodeSize();
155 UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
156 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
157 assembler->FinalizeInstructions(code);
158
159 return entry_stub.release();
160}
161} // namespace x86_64
162
Ian Rogersdd7624d2014-03-14 17:43:00 -0700163const std::vector<uint8_t>* CreateTrampoline64(InstructionSet isa, EntryPointCallingConvention abi,
164 ThreadOffset<8> offset) {
165 switch (isa) {
166 case kArm64:
167 return arm64::CreateTrampoline(abi, offset);
168 case kX86_64:
169 return x86_64::CreateTrampoline(offset);
170 default:
171 LOG(FATAL) << "Unexpected InstructionSet: " << isa;
172 return nullptr;
173 }
174}
175
176const std::vector<uint8_t>* CreateTrampoline32(InstructionSet isa, EntryPointCallingConvention abi,
177 ThreadOffset<4> offset) {
Ian Rogers659efe72013-08-07 22:54:13 -0700178 switch (isa) {
179 case kArm:
180 case kThumb2:
181 return arm::CreateTrampoline(abi, offset);
182 case kMips:
183 return mips::CreateTrampoline(abi, offset);
184 case kX86:
185 return x86::CreateTrampoline(offset);
Ian Rogers659efe72013-08-07 22:54:13 -0700186 default:
Ian Rogersdd7624d2014-03-14 17:43:00 -0700187 LOG(FATAL) << "Unexpected InstructionSet: " << isa;
188 return nullptr;
Ian Rogers659efe72013-08-07 22:54:13 -0700189 }
190}
191
192} // namespace art