blob: 3e13e4439746754bf7756a964dc592336a933697 [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"
21#include "utils/mips/assembler_mips.h"
22#include "utils/x86/assembler_x86.h"
23
24#define __ assembler->
25
26namespace art {
27
28namespace arm {
29static 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
56namespace mips {
57static 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
86namespace x86 {
87static 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
Ian Rogersbefbd572014-03-06 01:13:39 -0800103namespace x86_64 {
104static const std::vector<uint8_t>* CreateTrampoline(ThreadOffset offset) {
105 UniquePtr<x86::X86Assembler> assembler(static_cast<x86::X86Assembler*>(Assembler::Create(kX86_64)));
106
107 // All x86 trampolines call via the Thread* held in gs.
108 __ gs()->jmp(x86::Address::Absolute(offset, true));
109 __ int3();
110
111 size_t cs = assembler->CodeSize();
112 UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
113 MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
114 assembler->FinalizeInstructions(code);
115
116 return entry_stub.release();
117}
118} // namespace x86_64
119
Ian Rogers659efe72013-08-07 22:54:13 -0700120const std::vector<uint8_t>* CreateTrampoline(InstructionSet isa, EntryPointCallingConvention abi,
121 ThreadOffset offset) {
122 switch (isa) {
123 case kArm:
124 case kThumb2:
125 return arm::CreateTrampoline(abi, offset);
126 case kMips:
127 return mips::CreateTrampoline(abi, offset);
128 case kX86:
129 return x86::CreateTrampoline(offset);
Ian Rogersbefbd572014-03-06 01:13:39 -0800130 case kX86_64:
131 return x86_64::CreateTrampoline(offset);
Ian Rogers659efe72013-08-07 22:54:13 -0700132 default:
133 LOG(FATAL) << "Unknown InstructionSet: " << isa;
134 return NULL;
135 }
136}
137
138} // namespace art