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 "jni_internal.h"
     20 #include "utils/arm/assembler_arm.h"
     21 #include "utils/mips/assembler_mips.h"
     22 #include "utils/x86/assembler_x86.h"
     23 
     24 #define __ assembler->
     25 
     26 namespace art {
     27 
     28 namespace arm {
     29 static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
     30                                                     ThreadOffset offset) {
     31   UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
     32 
     33   switch (abi) {
     34     case kInterpreterAbi:  // Thread* is first argument (R0) in interpreter ABI.
     35       __ LoadFromOffset(kLoadWord, PC, R0, offset.Int32Value());
     36       break;
     37     case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (R0).
     38       __ LoadFromOffset(kLoadWord, IP, R0, JNIEnvExt::SelfOffset().Int32Value());
     39       __ LoadFromOffset(kLoadWord, PC, IP, offset.Int32Value());
     40       break;
     41     case kPortableAbi:  // R9 holds Thread*.
     42     case kQuickAbi:  // Fall-through.
     43       __ LoadFromOffset(kLoadWord, PC, R9, offset.Int32Value());
     44   }
     45   __ bkpt(0);
     46 
     47   size_t cs = assembler->CodeSize();
     48   UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
     49   MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
     50   assembler->FinalizeInstructions(code);
     51 
     52   return entry_stub.release();
     53 }
     54 }  // namespace arm
     55 
     56 namespace mips {
     57 static const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
     58                                                     ThreadOffset offset) {
     59   UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
     60 
     61   switch (abi) {
     62     case kInterpreterAbi:  // Thread* is first argument (A0) in interpreter ABI.
     63       __ LoadFromOffset(kLoadWord, T9, A0, offset.Int32Value());
     64       break;
     65     case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (A0).
     66       __ LoadFromOffset(kLoadWord, T9, A0, JNIEnvExt::SelfOffset().Int32Value());
     67       __ LoadFromOffset(kLoadWord, T9, T9, offset.Int32Value());
     68       break;
     69     case kPortableAbi:  // S1 holds Thread*.
     70     case kQuickAbi:  // Fall-through.
     71       __ LoadFromOffset(kLoadWord, T9, S1, offset.Int32Value());
     72   }
     73   __ Jr(T9);
     74   __ Nop();
     75   __ Break();
     76 
     77   size_t cs = assembler->CodeSize();
     78   UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
     79   MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
     80   assembler->FinalizeInstructions(code);
     81 
     82   return entry_stub.release();
     83 }
     84 }  // namespace mips
     85 
     86 namespace x86 {
     87 static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset offset) {
     88   UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
     89 
     90   // All x86 trampolines call via the Thread* held in fs.
     91   __ fs()->jmp(Address::Absolute(offset));
     92   __ int3();
     93 
     94   size_t cs = assembler->CodeSize();
     95   UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
     96   MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
     97   assembler->FinalizeInstructions(code);
     98 
     99   return entry_stub.release();
    100 }
    101 }  // namespace x86
    102 
    103 const std::vector<uint8_t>* CreateTrampoline(InstructionSet isa, EntryPointCallingConvention abi,
    104                                              ThreadOffset offset) {
    105   switch (isa) {
    106     case kArm:
    107     case kThumb2:
    108       return arm::CreateTrampoline(abi, offset);
    109     case kMips:
    110       return mips::CreateTrampoline(abi, offset);
    111     case kX86:
    112       return x86::CreateTrampoline(offset);
    113     default:
    114       LOG(FATAL) << "Unknown InstructionSet: " << isa;
    115       return NULL;
    116   }
    117 }
    118 
    119 }  // namespace art
    120