blob: ac84d6ae408d39ed1435c1eaae73e3d49a22d171 [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) {
Dave Allison65fcc2c2014-04-28 13:45:27 -070033 // NOTE: the assembler used here is ARM, not Thumb. This is because the address
34 // returned by this function is a pointer and for thumb we would have to set the
35 // bottom bit. It doesn't matter since the instructions generated are the same
36 // size anyway.
Ian Rogers700a4022014-05-19 16:49:03 -070037 std::unique_ptr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
Ian Rogers659efe72013-08-07 22:54:13 -070038
39 switch (abi) {
40 case kInterpreterAbi: // Thread* is first argument (R0) in interpreter ABI.
41 __ LoadFromOffset(kLoadWord, PC, R0, offset.Int32Value());
42 break;
43 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (R0).
44 __ LoadFromOffset(kLoadWord, IP, R0, JNIEnvExt::SelfOffset().Int32Value());
45 __ LoadFromOffset(kLoadWord, PC, IP, offset.Int32Value());
46 break;
47 case kPortableAbi: // R9 holds Thread*.
48 case kQuickAbi: // Fall-through.
49 __ LoadFromOffset(kLoadWord, PC, R9, offset.Int32Value());
50 }
51 __ bkpt(0);
52
53 size_t cs = assembler->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -070054 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Ian Rogers659efe72013-08-07 22:54:13 -070055 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
56 assembler->FinalizeInstructions(code);
57
58 return entry_stub.release();
59}
60} // namespace arm
61
Stuart Monteithb95a5342014-03-12 13:32:32 +000062namespace arm64 {
63static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
Ian Rogersdd7624d2014-03-14 17:43:00 -070064 ThreadOffset<8> offset) {
Ian Rogers700a4022014-05-19 16:49:03 -070065 std::unique_ptr<Arm64Assembler> assembler(static_cast<Arm64Assembler*>(Assembler::Create(kArm64)));
Stuart Monteithb95a5342014-03-12 13:32:32 +000066
67 switch (abi) {
68 case kInterpreterAbi: // Thread* is first argument (X0) in interpreter ABI.
Andreas Gampec6ee54e2014-03-24 16:45:44 -070069 __ JumpTo(Arm64ManagedRegister::FromCoreRegister(X0), Offset(offset.Int32Value()),
Stuart Monteithb95a5342014-03-12 13:32:32 +000070 Arm64ManagedRegister::FromCoreRegister(IP1));
71
72 break;
73 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (X0).
Stuart Monteithb95a5342014-03-12 13:32:32 +000074 __ LoadRawPtr(Arm64ManagedRegister::FromCoreRegister(IP1),
75 Arm64ManagedRegister::FromCoreRegister(X0),
76 Offset(JNIEnvExt::SelfOffset().Int32Value()));
77
Andreas Gampec6ee54e2014-03-24 16:45:44 -070078 __ JumpTo(Arm64ManagedRegister::FromCoreRegister(IP1), Offset(offset.Int32Value()),
Stuart Monteithb95a5342014-03-12 13:32:32 +000079 Arm64ManagedRegister::FromCoreRegister(IP0));
80
81 break;
82 case kPortableAbi: // X18 holds Thread*.
83 case kQuickAbi: // Fall-through.
Andreas Gampec6ee54e2014-03-24 16:45:44 -070084 __ JumpTo(Arm64ManagedRegister::FromCoreRegister(TR), Offset(offset.Int32Value()),
Stuart Monteithb95a5342014-03-12 13:32:32 +000085 Arm64ManagedRegister::FromCoreRegister(IP0));
86
87 break;
88 }
89
90 size_t cs = assembler->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -070091 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Stuart Monteithb95a5342014-03-12 13:32:32 +000092 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
93 assembler->FinalizeInstructions(code);
94
95 return entry_stub.release();
96}
97} // namespace arm64
98
Ian Rogers659efe72013-08-07 22:54:13 -070099namespace mips {
100static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
Ian Rogersdd7624d2014-03-14 17:43:00 -0700101 ThreadOffset<4> offset) {
Ian Rogers700a4022014-05-19 16:49:03 -0700102 std::unique_ptr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
Ian Rogers659efe72013-08-07 22:54:13 -0700103
104 switch (abi) {
105 case kInterpreterAbi: // Thread* is first argument (A0) in interpreter ABI.
106 __ LoadFromOffset(kLoadWord, T9, A0, offset.Int32Value());
107 break;
108 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (A0).
109 __ LoadFromOffset(kLoadWord, T9, A0, JNIEnvExt::SelfOffset().Int32Value());
110 __ LoadFromOffset(kLoadWord, T9, T9, offset.Int32Value());
111 break;
112 case kPortableAbi: // S1 holds Thread*.
113 case kQuickAbi: // Fall-through.
114 __ LoadFromOffset(kLoadWord, T9, S1, offset.Int32Value());
115 }
116 __ Jr(T9);
117 __ Nop();
118 __ Break();
119
120 size_t cs = assembler->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700121 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Ian Rogers659efe72013-08-07 22:54:13 -0700122 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
123 assembler->FinalizeInstructions(code);
124
125 return entry_stub.release();
126}
127} // namespace mips
128
129namespace x86 {
Ian Rogersdd7624d2014-03-14 17:43:00 -0700130static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<4> offset) {
Ian Rogers700a4022014-05-19 16:49:03 -0700131 std::unique_ptr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
Ian Rogers659efe72013-08-07 22:54:13 -0700132
133 // All x86 trampolines call via the Thread* held in fs.
134 __ fs()->jmp(Address::Absolute(offset));
135 __ int3();
136
137 size_t cs = assembler->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700138 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Ian Rogers659efe72013-08-07 22:54:13 -0700139 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
140 assembler->FinalizeInstructions(code);
141
142 return entry_stub.release();
143}
144} // namespace x86
145
Ian Rogersbefbd572014-03-06 01:13:39 -0800146namespace x86_64 {
Ian Rogersdd7624d2014-03-14 17:43:00 -0700147static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<8> offset) {
Ian Rogers700a4022014-05-19 16:49:03 -0700148 std::unique_ptr<x86_64::X86_64Assembler>
Ian Rogersdd7624d2014-03-14 17:43:00 -0700149 assembler(static_cast<x86_64::X86_64Assembler*>(Assembler::Create(kX86_64)));
Ian Rogersbefbd572014-03-06 01:13:39 -0800150
151 // All x86 trampolines call via the Thread* held in gs.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700152 __ gs()->jmp(x86_64::Address::Absolute(offset, true));
Ian Rogersbefbd572014-03-06 01:13:39 -0800153 __ int3();
154
155 size_t cs = assembler->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700156 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Ian Rogersbefbd572014-03-06 01:13:39 -0800157 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
158 assembler->FinalizeInstructions(code);
159
160 return entry_stub.release();
161}
162} // namespace x86_64
163
Ian Rogersdd7624d2014-03-14 17:43:00 -0700164const std::vector<uint8_t>* CreateTrampoline64(InstructionSet isa, EntryPointCallingConvention abi,
165 ThreadOffset<8> offset) {
166 switch (isa) {
167 case kArm64:
168 return arm64::CreateTrampoline(abi, offset);
169 case kX86_64:
170 return x86_64::CreateTrampoline(offset);
171 default:
172 LOG(FATAL) << "Unexpected InstructionSet: " << isa;
173 return nullptr;
174 }
175}
176
177const std::vector<uint8_t>* CreateTrampoline32(InstructionSet isa, EntryPointCallingConvention abi,
178 ThreadOffset<4> offset) {
Ian Rogers659efe72013-08-07 22:54:13 -0700179 switch (isa) {
180 case kArm:
181 case kThumb2:
182 return arm::CreateTrampoline(abi, offset);
183 case kMips:
184 return mips::CreateTrampoline(abi, offset);
185 case kX86:
186 return x86::CreateTrampoline(offset);
Ian Rogers659efe72013-08-07 22:54:13 -0700187 default:
Ian Rogersdd7624d2014-03-14 17:43:00 -0700188 LOG(FATAL) << "Unexpected InstructionSet: " << isa;
189 return nullptr;
Ian Rogers659efe72013-08-07 22:54:13 -0700190 }
191}
192
193} // namespace art