Home | History | Annotate | Download | only in trampolines
      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_thumb2.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 
     48 namespace art {
     49 
     50 #ifdef ART_ENABLE_CODEGEN_arm
     51 namespace arm {
     52 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
     53     ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset<4> offset) {
     54   Thumb2Assembler assembler(arena);
     55 
     56   switch (abi) {
     57     case kInterpreterAbi:  // Thread* is first argument (R0) in interpreter ABI.
     58       __ LoadFromOffset(kLoadWord, PC, R0, offset.Int32Value());
     59       break;
     60     case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (R0).
     61       __ LoadFromOffset(kLoadWord, IP, R0, JNIEnvExt::SelfOffset(4).Int32Value());
     62       __ LoadFromOffset(kLoadWord, PC, IP, offset.Int32Value());
     63       break;
     64     case kQuickAbi:  // R9 holds Thread*.
     65       __ LoadFromOffset(kLoadWord, PC, R9, offset.Int32Value());
     66   }
     67   __ bkpt(0);
     68 
     69   __ FinalizeCode();
     70   size_t cs = __ CodeSize();
     71   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
     72   MemoryRegion code(entry_stub->data(), entry_stub->size());
     73   __ FinalizeInstructions(code);
     74 
     75   return std::move(entry_stub);
     76 }
     77 }  // namespace arm
     78 #endif  // ART_ENABLE_CODEGEN_arm
     79 
     80 #ifdef ART_ENABLE_CODEGEN_arm64
     81 namespace arm64 {
     82 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
     83     ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset<8> offset) {
     84   Arm64Assembler assembler(arena);
     85 
     86   switch (abi) {
     87     case kInterpreterAbi:  // Thread* is first argument (X0) in interpreter ABI.
     88       __ JumpTo(Arm64ManagedRegister::FromXRegister(X0), Offset(offset.Int32Value()),
     89           Arm64ManagedRegister::FromXRegister(IP1));
     90 
     91       break;
     92     case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (X0).
     93       __ LoadRawPtr(Arm64ManagedRegister::FromXRegister(IP1),
     94                       Arm64ManagedRegister::FromXRegister(X0),
     95                       Offset(JNIEnvExt::SelfOffset(8).Int32Value()));
     96 
     97       __ JumpTo(Arm64ManagedRegister::FromXRegister(IP1), Offset(offset.Int32Value()),
     98                 Arm64ManagedRegister::FromXRegister(IP0));
     99 
    100       break;
    101     case kQuickAbi:  // X18 holds Thread*.
    102       __ JumpTo(Arm64ManagedRegister::FromXRegister(TR), Offset(offset.Int32Value()),
    103                 Arm64ManagedRegister::FromXRegister(IP0));
    104 
    105       break;
    106   }
    107 
    108   __ FinalizeCode();
    109   size_t cs = __ CodeSize();
    110   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
    111   MemoryRegion code(entry_stub->data(), entry_stub->size());
    112   __ FinalizeInstructions(code);
    113 
    114   return std::move(entry_stub);
    115 }
    116 }  // namespace arm64
    117 #endif  // ART_ENABLE_CODEGEN_arm64
    118 
    119 #ifdef ART_ENABLE_CODEGEN_mips
    120 namespace mips {
    121 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
    122     ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset<4> offset) {
    123   MipsAssembler assembler(arena);
    124 
    125   switch (abi) {
    126     case kInterpreterAbi:  // Thread* is first argument (A0) in interpreter ABI.
    127       __ LoadFromOffset(kLoadWord, T9, A0, offset.Int32Value());
    128       break;
    129     case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (A0).
    130       __ LoadFromOffset(kLoadWord, T9, A0, JNIEnvExt::SelfOffset(4).Int32Value());
    131       __ LoadFromOffset(kLoadWord, T9, T9, offset.Int32Value());
    132       break;
    133     case kQuickAbi:  // S1 holds Thread*.
    134       __ LoadFromOffset(kLoadWord, T9, S1, offset.Int32Value());
    135   }
    136   __ Jr(T9);
    137   __ Nop();
    138   __ Break();
    139 
    140   __ FinalizeCode();
    141   size_t cs = __ CodeSize();
    142   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
    143   MemoryRegion code(entry_stub->data(), entry_stub->size());
    144   __ FinalizeInstructions(code);
    145 
    146   return std::move(entry_stub);
    147 }
    148 }  // namespace mips
    149 #endif  // ART_ENABLE_CODEGEN_mips
    150 
    151 #ifdef ART_ENABLE_CODEGEN_mips64
    152 namespace mips64 {
    153 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(
    154     ArenaAllocator* arena, EntryPointCallingConvention abi, ThreadOffset<8> offset) {
    155   Mips64Assembler assembler(arena);
    156 
    157   switch (abi) {
    158     case kInterpreterAbi:  // Thread* is first argument (A0) in interpreter ABI.
    159       __ LoadFromOffset(kLoadDoubleword, T9, A0, offset.Int32Value());
    160       break;
    161     case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (A0).
    162       __ LoadFromOffset(kLoadDoubleword, T9, A0, JNIEnvExt::SelfOffset(8).Int32Value());
    163       __ LoadFromOffset(kLoadDoubleword, T9, T9, offset.Int32Value());
    164       break;
    165     case kQuickAbi:  // Fall-through.
    166       __ LoadFromOffset(kLoadDoubleword, T9, S1, offset.Int32Value());
    167   }
    168   __ Jr(T9);
    169   __ Nop();
    170   __ Break();
    171 
    172   __ FinalizeCode();
    173   size_t cs = __ CodeSize();
    174   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
    175   MemoryRegion code(entry_stub->data(), entry_stub->size());
    176   __ FinalizeInstructions(code);
    177 
    178   return std::move(entry_stub);
    179 }
    180 }  // namespace mips64
    181 #endif  // ART_ENABLE_CODEGEN_mips
    182 
    183 #ifdef ART_ENABLE_CODEGEN_x86
    184 namespace x86 {
    185 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(ArenaAllocator* arena,
    186                                                                     ThreadOffset<4> offset) {
    187   X86Assembler assembler(arena);
    188 
    189   // All x86 trampolines call via the Thread* held in fs.
    190   __ fs()->jmp(Address::Absolute(offset));
    191   __ int3();
    192 
    193   __ FinalizeCode();
    194   size_t cs = __ CodeSize();
    195   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
    196   MemoryRegion code(entry_stub->data(), entry_stub->size());
    197   __ FinalizeInstructions(code);
    198 
    199   return std::move(entry_stub);
    200 }
    201 }  // namespace x86
    202 #endif  // ART_ENABLE_CODEGEN_x86
    203 
    204 #ifdef ART_ENABLE_CODEGEN_x86_64
    205 namespace x86_64 {
    206 static std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline(ArenaAllocator* arena,
    207                                                                     ThreadOffset<8> offset) {
    208   x86_64::X86_64Assembler assembler(arena);
    209 
    210   // All x86 trampolines call via the Thread* held in gs.
    211   __ gs()->jmp(x86_64::Address::Absolute(offset, true));
    212   __ int3();
    213 
    214   __ FinalizeCode();
    215   size_t cs = __ CodeSize();
    216   std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
    217   MemoryRegion code(entry_stub->data(), entry_stub->size());
    218   __ FinalizeInstructions(code);
    219 
    220   return std::move(entry_stub);
    221 }
    222 }  // namespace x86_64
    223 #endif  // ART_ENABLE_CODEGEN_x86_64
    224 
    225 std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline64(InstructionSet isa,
    226                                                                EntryPointCallingConvention abi,
    227                                                                ThreadOffset<8> offset) {
    228   ArenaPool pool;
    229   ArenaAllocator arena(&pool);
    230   switch (isa) {
    231 #ifdef ART_ENABLE_CODEGEN_arm64
    232     case kArm64:
    233       return arm64::CreateTrampoline(&arena, abi, offset);
    234 #endif
    235 #ifdef ART_ENABLE_CODEGEN_mips64
    236     case kMips64:
    237       return mips64::CreateTrampoline(&arena, abi, offset);
    238 #endif
    239 #ifdef ART_ENABLE_CODEGEN_x86_64
    240     case kX86_64:
    241       return x86_64::CreateTrampoline(&arena, offset);
    242 #endif
    243     default:
    244       UNUSED(abi);
    245       UNUSED(offset);
    246       LOG(FATAL) << "Unexpected InstructionSet: " << isa;
    247       UNREACHABLE();
    248   }
    249 }
    250 
    251 std::unique_ptr<const std::vector<uint8_t>> CreateTrampoline32(InstructionSet isa,
    252                                                                EntryPointCallingConvention abi,
    253                                                                ThreadOffset<4> offset) {
    254   ArenaPool pool;
    255   ArenaAllocator arena(&pool);
    256   switch (isa) {
    257 #ifdef ART_ENABLE_CODEGEN_arm
    258     case kArm:
    259     case kThumb2:
    260       return arm::CreateTrampoline(&arena, abi, offset);
    261 #endif
    262 #ifdef ART_ENABLE_CODEGEN_mips
    263     case kMips:
    264       return mips::CreateTrampoline(&arena, abi, offset);
    265 #endif
    266 #ifdef ART_ENABLE_CODEGEN_x86
    267     case kX86:
    268       UNUSED(abi);
    269       return x86::CreateTrampoline(&arena, offset);
    270 #endif
    271     default:
    272       LOG(FATAL) << "Unexpected InstructionSet: " << isa;
    273       UNREACHABLE();
    274   }
    275 }
    276 
    277 }  // namespace art
    278