1/* 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 "base/arena_allocator.h" 20#include "jni_env_ext.h" 21 22#ifdef ART_ENABLE_CODEGEN_arm 23#include "utils/arm/assembler_arm_vixl.h" 24#endif 25 26#ifdef ART_ENABLE_CODEGEN_arm64 27#include "utils/arm64/assembler_arm64.h" 28#endif 29 30#ifdef ART_ENABLE_CODEGEN_mips 31#include "utils/mips/assembler_mips.h" 32#endif 33 34#ifdef ART_ENABLE_CODEGEN_mips64 35#include "utils/mips64/assembler_mips64.h" 36#endif 37 38#ifdef ART_ENABLE_CODEGEN_x86 39#include "utils/x86/assembler_x86.h" 40#endif 41 42#ifdef ART_ENABLE_CODEGEN_x86_64 43#include "utils/x86_64/assembler_x86_64.h" 44#endif 45 46#define __ assembler. 47 48namespace art { 49 50#ifdef ART_ENABLE_CODEGEN_arm 51namespace arm { 52 53#ifdef ___ 54#error "ARM Assembler macro already defined." 55#else 56#define ___ assembler.GetVIXLAssembler()-> 57#endif 58 59static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline( 60 ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset32 offset) { 61 using vixl::aarch32::MemOperand; 62 using vixl::aarch32::pc; 63 using vixl::aarch32::r0; 64 ArmVIXLAssembler assembler(arena); 65 66 switch (abi) { 67 case kInterpreterAbi: // Thread* is first argument (R0) in interpreter ABI. 68 ___ Ldr(pc, MemOperand(r0, offset.Int32Value())); 69 break; 70 case kJniAbi: { // Load via Thread* held in JNIEnv* in first argument (R0). 71 vixl::aarch32::UseScratchRegisterScope temps(assembler.GetVIXLAssembler()); 72 const vixl::aarch32::Register temp_reg = temps.Acquire(); 73 74 // VIXL will use the destination as a scratch register if 75 // the offset is not encodable as an immediate operand. 76 ___ Ldr(temp_reg, MemOperand(r0, JNIEnvExt::SelfOffset(4).Int32Value())); 77 ___ Ldr(pc, MemOperand(temp_reg, offset.Int32Value())); 78 break; 79 } 80 case kQuickAbi: // TR holds Thread*. 81 ___ Ldr(pc, MemOperand(tr, offset.Int32Value())); 82 } 83 84 __ FinalizeCode(); 85 size_t cs = __ CodeSize(); 86 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs)); 87 MemoryRegion code(entry_stub->data(), entry_stub->size()); 88 __ FinalizeInstructions(code); 89 90 return std::move(entry_stub); 91} 92 93#undef ___ 94 95} // namespace arm 96#endif // ART_ENABLE_CODEGEN_arm 97 98#ifdef ART_ENABLE_CODEGEN_arm64 99namespace arm64 { 100static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline( 101 ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset64 offset) { 102 Arm64Assembler assembler(arena); 103 104 switch (abi) { 105 case kInterpreterAbi: // Thread* is first argument (X0) in interpreter ABI. 106 __ JumpTo(Arm64ManagedRegister::FromXRegister(X0), Offset(offset.Int32Value()), 107 Arm64ManagedRegister::FromXRegister(IP1)); 108 109 break; 110 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (X0). 111 __ LoadRawPtr(Arm64ManagedRegister::FromXRegister(IP1), 112 Arm64ManagedRegister::FromXRegister(X0), 113 Offset(JNIEnvExt::SelfOffset(8).Int32Value())); 114 115 __ JumpTo(Arm64ManagedRegister::FromXRegister(IP1), Offset(offset.Int32Value()), 116 Arm64ManagedRegister::FromXRegister(IP0)); 117 118 break; 119 case kQuickAbi: // X18 holds Thread*. 120 __ JumpTo(Arm64ManagedRegister::FromXRegister(TR), Offset(offset.Int32Value()), 121 Arm64ManagedRegister::FromXRegister(IP0)); 122 123 break; 124 } 125 126 __ FinalizeCode(); 127 size_t cs = __ CodeSize(); 128 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs)); 129 MemoryRegion code(entry_stub->data(), entry_stub->size()); 130 __ FinalizeInstructions(code); 131 132 return std::move(entry_stub); 133} 134} // namespace arm64 135#endif // ART_ENABLE_CODEGEN_arm64 136 137#ifdef ART_ENABLE_CODEGEN_mips 138namespace mips { 139static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline( 140 ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset32 offset) { 141 MipsAssembler assembler(arena); 142 143 switch (abi) { 144 case kInterpreterAbi: // Thread* is first argument (A0) in interpreter ABI. 145 __ LoadFromOffset(kLoadWord, T9, A0, offset.Int32Value()); 146 break; 147 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (A0). 148 __ LoadFromOffset(kLoadWord, T9, A0, JNIEnvExt::SelfOffset(4).Int32Value()); 149 __ LoadFromOffset(kLoadWord, T9, T9, offset.Int32Value()); 150 break; 151 case kQuickAbi: // S1 holds Thread*. 152 __ LoadFromOffset(kLoadWord, T9, S1, offset.Int32Value()); 153 } 154 __ Jr(T9); 155 __ NopIfNoReordering(); 156 __ Break(); 157 158 __ FinalizeCode(); 159 size_t cs = __ CodeSize(); 160 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs)); 161 MemoryRegion code(entry_stub->data(), entry_stub->size()); 162 __ FinalizeInstructions(code); 163 164 return std::move(entry_stub); 165} 166} // namespace mips 167#endif // ART_ENABLE_CODEGEN_mips 168 169#ifdef ART_ENABLE_CODEGEN_mips64 170namespace mips64 { 171static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline( 172 ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset64 offset) { 173 Mips64Assembler assembler(arena); 174 175 switch (abi) { 176 case kInterpreterAbi: // Thread* is first argument (A0) in interpreter ABI. 177 __ LoadFromOffset(kLoadDoubleword, T9, A0, offset.Int32Value()); 178 break; 179 case kJniAbi: // Load via Thread* held in JNIEnv* in first argument (A0). 180 __ LoadFromOffset(kLoadDoubleword, T9, A0, JNIEnvExt::SelfOffset(8).Int32Value()); 181 __ LoadFromOffset(kLoadDoubleword, T9, T9, offset.Int32Value()); 182 break; 183 case kQuickAbi: // Fall-through. 184 __ LoadFromOffset(kLoadDoubleword, T9, S1, offset.Int32Value()); 185 } 186 __ Jr(T9); 187 __ Nop(); 188 __ Break(); 189 190 __ FinalizeCode(); 191 size_t cs = __ CodeSize(); 192 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs)); 193 MemoryRegion code(entry_stub->data(), entry_stub->size()); 194 __ FinalizeInstructions(code); 195 196 return std::move(entry_stub); 197} 198} // namespace mips64 199#endif // ART_ENABLE_CODEGEN_mips 200 201#ifdef ART_ENABLE_CODEGEN_x86 202namespace x86 { 203static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(ArenaAllocator* arena, 204 ThreadOffset32 offset) { 205 X86Assembler assembler(arena); 206 207 // All x86 trampolines call via the Thread* held in fs. 208 __ fs()->jmp(Address::Absolute(offset)); 209 __ int3(); 210 211 __ FinalizeCode(); 212 size_t cs = __ CodeSize(); 213 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs)); 214 MemoryRegion code(entry_stub->data(), entry_stub->size()); 215 __ FinalizeInstructions(code); 216 217 return std::move(entry_stub); 218} 219} // namespace x86 220#endif // ART_ENABLE_CODEGEN_x86 221 222#ifdef ART_ENABLE_CODEGEN_x86_64 223namespace x86_64 { 224static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(ArenaAllocator* arena, 225 ThreadOffset64 offset) { 226 x86_64::X86_64Assembler assembler(arena); 227 228 // All x86 trampolines call via the Thread* held in gs. 229 __ gs()->jmp(x86_64::Address::Absolute(offset, true)); 230 __ int3(); 231 232 __ FinalizeCode(); 233 size_t cs = __ CodeSize(); 234 std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs)); 235 MemoryRegion code(entry_stub->data(), entry_stub->size()); 236 __ FinalizeInstructions(code); 237 238 return std::move(entry_stub); 239} 240} // namespace x86_64 241#endif // ART_ENABLE_CODEGEN_x86_64 242 243std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline64(InstructionSet isa, 244 EntryPointCallingConvention abi, 245 ThreadOffset64 offset) { 246 ArenaPool pool; 247 ArenaAllocator arena(&pool); 248 switch (isa) { 249#ifdef ART_ENABLE_CODEGEN_arm64 250 case kArm64: 251 return arm64::CreateTrampoline(&arena, abi, offset); 252#endif 253#ifdef ART_ENABLE_CODEGEN_mips64 254 case kMips64: 255 return mips64::CreateTrampoline(&arena, abi, offset); 256#endif 257#ifdef ART_ENABLE_CODEGEN_x86_64 258 case kX86_64: 259 return x86_64::CreateTrampoline(&arena, offset); 260#endif 261 default: 262 UNUSED(abi); 263 UNUSED(offset); 264 LOG(FATAL) << "Unexpected InstructionSet: " << isa; 265 UNREACHABLE(); 266 } 267} 268 269std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline32(InstructionSet isa, 270 EntryPointCallingConvention abi, 271 ThreadOffset32 offset) { 272 ArenaPool pool; 273 ArenaAllocator arena(&pool); 274 switch (isa) { 275#ifdef ART_ENABLE_CODEGEN_arm 276 case kArm: 277 case kThumb2: 278 return arm::CreateTrampoline(&arena, abi, offset); 279#endif 280#ifdef ART_ENABLE_CODEGEN_mips 281 case kMips: 282 return mips::CreateTrampoline(&arena, abi, offset); 283#endif 284#ifdef ART_ENABLE_CODEGEN_x86 285 case kX86: 286 UNUSED(abi); 287 return x86::CreateTrampoline(&arena, offset); 288#endif 289 default: 290 LOG(FATAL) << "Unexpected InstructionSet: " << isa; 291 UNREACHABLE(); 292 } 293} 294 295} // namespace art 296