blob: 385d1340fc843810add004501848aa0cffccbb5e [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"
Ian Rogers659efe72013-08-07 22:54:13 -070020#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 Allison50abf0a2014-06-23 13:19:59 -070033 std::unique_ptr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kThumb2)));
Ian Rogers659efe72013-08-07 22:54:13 -070034
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;
Elliott Hughes956af0f2014-12-11 14:34:28 -080043 case kQuickAbi: // R9 holds Thread*.
Ian Rogers659efe72013-08-07 22:54:13 -070044 __ LoadFromOffset(kLoadWord, PC, R9, offset.Int32Value());
45 }
46 __ bkpt(0);
47
48 size_t cs = assembler->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -070049 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Ian Rogers659efe72013-08-07 22:54:13 -070050 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
51 assembler->FinalizeInstructions(code);
52
53 return entry_stub.release();
54}
55} // namespace arm
56
Stuart Monteithb95a5342014-03-12 13:32:32 +000057namespace arm64 {
58static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
Ian Rogersdd7624d2014-03-14 17:43:00 -070059 ThreadOffset<8> offset) {
Ian Rogers700a4022014-05-19 16:49:03 -070060 std::unique_ptr<Arm64Assembler> assembler(static_cast<Arm64Assembler*>(Assembler::Create(kArm64)));
Stuart Monteithb95a5342014-03-12 13:32:32 +000061
62 switch (abi) {
63 case kInterpreterAbi: // Thread* is first argument (X0) in interpreter ABI.
Alexandre Rames37c92df2014-10-17 14:35:27 +010064 __ JumpTo(Arm64ManagedRegister::FromXRegister(X0), Offset(offset.Int32Value()),
65 Arm64ManagedRegister::FromXRegister(IP1));
Stuart Monteithb95a5342014-03-12 13:32:32 +000066
67 break;
68 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (X0).
Alexandre Rames37c92df2014-10-17 14:35:27 +010069 __ LoadRawPtr(Arm64ManagedRegister::FromXRegister(IP1),
70 Arm64ManagedRegister::FromXRegister(X0),
Stuart Monteithb95a5342014-03-12 13:32:32 +000071 Offset(JNIEnvExt::SelfOffset().Int32Value()));
72
Alexandre Rames37c92df2014-10-17 14:35:27 +010073 __ JumpTo(Arm64ManagedRegister::FromXRegister(IP1), Offset(offset.Int32Value()),
74 Arm64ManagedRegister::FromXRegister(IP0));
Stuart Monteithb95a5342014-03-12 13:32:32 +000075
76 break;
Elliott Hughes956af0f2014-12-11 14:34:28 -080077 case kQuickAbi: // X18 holds Thread*.
Alexandre Rames37c92df2014-10-17 14:35:27 +010078 __ JumpTo(Arm64ManagedRegister::FromXRegister(TR), Offset(offset.Int32Value()),
79 Arm64ManagedRegister::FromXRegister(IP0));
Stuart Monteithb95a5342014-03-12 13:32:32 +000080
81 break;
82 }
83
Serban Constantinescu32f5b4d2014-11-25 20:05:46 +000084 assembler->EmitSlowPaths();
Stuart Monteithb95a5342014-03-12 13:32:32 +000085 size_t cs = assembler->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -070086 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Stuart Monteithb95a5342014-03-12 13:32:32 +000087 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
88 assembler->FinalizeInstructions(code);
89
90 return entry_stub.release();
91}
92} // namespace arm64
93
Ian Rogers659efe72013-08-07 22:54:13 -070094namespace mips {
95static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
Ian Rogersdd7624d2014-03-14 17:43:00 -070096 ThreadOffset<4> offset) {
Ian Rogers700a4022014-05-19 16:49:03 -070097 std::unique_ptr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
Ian Rogers659efe72013-08-07 22:54:13 -070098
99 switch (abi) {
100 case kInterpreterAbi: // Thread* is first argument (A0) in interpreter ABI.
101 __ LoadFromOffset(kLoadWord, T9, A0, offset.Int32Value());
102 break;
103 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (A0).
104 __ LoadFromOffset(kLoadWord, T9, A0, JNIEnvExt::SelfOffset().Int32Value());
105 __ LoadFromOffset(kLoadWord, T9, T9, offset.Int32Value());
106 break;
Elliott Hughes956af0f2014-12-11 14:34:28 -0800107 case kQuickAbi: // S1 holds Thread*.
Ian Rogers659efe72013-08-07 22:54:13 -0700108 __ LoadFromOffset(kLoadWord, T9, S1, offset.Int32Value());
109 }
110 __ Jr(T9);
111 __ Nop();
112 __ Break();
113
114 size_t cs = assembler->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700115 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Ian Rogers659efe72013-08-07 22:54:13 -0700116 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
117 assembler->FinalizeInstructions(code);
118
119 return entry_stub.release();
120}
121} // namespace mips
122
123namespace x86 {
Ian Rogersdd7624d2014-03-14 17:43:00 -0700124static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<4> offset) {
Ian Rogers700a4022014-05-19 16:49:03 -0700125 std::unique_ptr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
Ian Rogers659efe72013-08-07 22:54:13 -0700126
127 // All x86 trampolines call via the Thread* held in fs.
128 __ fs()->jmp(Address::Absolute(offset));
129 __ int3();
130
131 size_t cs = assembler->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700132 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Ian Rogers659efe72013-08-07 22:54:13 -0700133 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
134 assembler->FinalizeInstructions(code);
135
136 return entry_stub.release();
137}
138} // namespace x86
139
Ian Rogersbefbd572014-03-06 01:13:39 -0800140namespace x86_64 {
Ian Rogersdd7624d2014-03-14 17:43:00 -0700141static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<8> offset) {
Ian Rogers700a4022014-05-19 16:49:03 -0700142 std::unique_ptr<x86_64::X86_64Assembler>
Ian Rogersdd7624d2014-03-14 17:43:00 -0700143 assembler(static_cast<x86_64::X86_64Assembler*>(Assembler::Create(kX86_64)));
Ian Rogersbefbd572014-03-06 01:13:39 -0800144
145 // All x86 trampolines call via the Thread* held in gs.
Ian Rogersdd7624d2014-03-14 17:43:00 -0700146 __ gs()->jmp(x86_64::Address::Absolute(offset, true));
Ian Rogersbefbd572014-03-06 01:13:39 -0800147 __ int3();
148
149 size_t cs = assembler->CodeSize();
Ian Rogers700a4022014-05-19 16:49:03 -0700150 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
Ian Rogersbefbd572014-03-06 01:13:39 -0800151 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
152 assembler->FinalizeInstructions(code);
153
154 return entry_stub.release();
155}
156} // namespace x86_64
157
Ian Rogersdd7624d2014-03-14 17:43:00 -0700158const std::vector<uint8_t>* CreateTrampoline64(InstructionSet isa, EntryPointCallingConvention abi,
159 ThreadOffset<8> offset) {
160 switch (isa) {
161 case kArm64:
162 return arm64::CreateTrampoline(abi, offset);
163 case kX86_64:
164 return x86_64::CreateTrampoline(offset);
165 default:
166 LOG(FATAL) << "Unexpected InstructionSet: " << isa;
Ian Rogersd4c4d952014-10-16 20:31:53 -0700167 UNREACHABLE();
Ian Rogersdd7624d2014-03-14 17:43:00 -0700168 }
169}
170
171const std::vector<uint8_t>* CreateTrampoline32(InstructionSet isa, EntryPointCallingConvention abi,
172 ThreadOffset<4> offset) {
Ian Rogers659efe72013-08-07 22:54:13 -0700173 switch (isa) {
174 case kArm:
175 case kThumb2:
176 return arm::CreateTrampoline(abi, offset);
177 case kMips:
178 return mips::CreateTrampoline(abi, offset);
179 case kX86:
180 return x86::CreateTrampoline(offset);
Ian Rogers659efe72013-08-07 22:54:13 -0700181 default:
Ian Rogersdd7624d2014-03-14 17:43:00 -0700182 LOG(FATAL) << "Unexpected InstructionSet: " << isa;
Ian Rogersd4c4d952014-10-16 20:31:53 -0700183 UNREACHABLE();
Ian Rogers659efe72013-08-07 22:54:13 -0700184 }
185}
186
187} // namespace art