1659efe783f45f46b9940aecf07be981057102ca7Ian Rogers/*
2659efe783f45f46b9940aecf07be981057102ca7Ian Rogers * Copyright (C) 2013 The Android Open Source Project
3659efe783f45f46b9940aecf07be981057102ca7Ian Rogers *
4659efe783f45f46b9940aecf07be981057102ca7Ian Rogers * Licensed under the Apache License, Version 2.0 (the "License");
5659efe783f45f46b9940aecf07be981057102ca7Ian Rogers * you may not use this file except in compliance with the License.
6659efe783f45f46b9940aecf07be981057102ca7Ian Rogers * You may obtain a copy of the License at
7659efe783f45f46b9940aecf07be981057102ca7Ian Rogers *
8659efe783f45f46b9940aecf07be981057102ca7Ian Rogers *      http://www.apache.org/licenses/LICENSE-2.0
9659efe783f45f46b9940aecf07be981057102ca7Ian Rogers *
10659efe783f45f46b9940aecf07be981057102ca7Ian Rogers * Unless required by applicable law or agreed to in writing, software
11659efe783f45f46b9940aecf07be981057102ca7Ian Rogers * distributed under the License is distributed on an "AS IS" BASIS,
12659efe783f45f46b9940aecf07be981057102ca7Ian Rogers * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13659efe783f45f46b9940aecf07be981057102ca7Ian Rogers * See the License for the specific language governing permissions and
14659efe783f45f46b9940aecf07be981057102ca7Ian Rogers * limitations under the License.
15659efe783f45f46b9940aecf07be981057102ca7Ian Rogers */
16659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
17659efe783f45f46b9940aecf07be981057102ca7Ian Rogers#include "trampoline_compiler.h"
18659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
1968d8b42ddec39ec0174162d90d4abaa004d1983eIan Rogers#include "jni_env_ext.h"
20659efe783f45f46b9940aecf07be981057102ca7Ian Rogers#include "utils/arm/assembler_arm.h"
21b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith#include "utils/arm64/assembler_arm64.h"
22659efe783f45f46b9940aecf07be981057102ca7Ian Rogers#include "utils/mips/assembler_mips.h"
2357b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe#include "utils/mips64/assembler_mips64.h"
24659efe783f45f46b9940aecf07be981057102ca7Ian Rogers#include "utils/x86/assembler_x86.h"
25dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers#include "utils/x86_64/assembler_x86_64.h"
26659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
27659efe783f45f46b9940aecf07be981057102ca7Ian Rogers#define __ assembler->
28659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
29659efe783f45f46b9940aecf07be981057102ca7Ian Rogersnamespace art {
30659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
31659efe783f45f46b9940aecf07be981057102ca7Ian Rogersnamespace arm {
32659efe783f45f46b9940aecf07be981057102ca7Ian Rogersstatic const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
33dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers                                                    ThreadOffset<4> offset) {
3450abf0ad03c2cad0fa7969fc1b0bfadb0ca3bf3aDave Allison  std::unique_ptr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kThumb2)));
35659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
36659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  switch (abi) {
37659efe783f45f46b9940aecf07be981057102ca7Ian Rogers    case kInterpreterAbi:  // Thread* is first argument (R0) in interpreter ABI.
38659efe783f45f46b9940aecf07be981057102ca7Ian Rogers      __ LoadFromOffset(kLoadWord, PC, R0, offset.Int32Value());
39659efe783f45f46b9940aecf07be981057102ca7Ian Rogers      break;
40659efe783f45f46b9940aecf07be981057102ca7Ian Rogers    case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (R0).
41659efe783f45f46b9940aecf07be981057102ca7Ian Rogers      __ LoadFromOffset(kLoadWord, IP, R0, JNIEnvExt::SelfOffset().Int32Value());
42659efe783f45f46b9940aecf07be981057102ca7Ian Rogers      __ LoadFromOffset(kLoadWord, PC, IP, offset.Int32Value());
43659efe783f45f46b9940aecf07be981057102ca7Ian Rogers      break;
44956af0f0cb05422e38c1d22cbef309d16b8a1a12Elliott Hughes    case kQuickAbi:  // R9 holds Thread*.
45659efe783f45f46b9940aecf07be981057102ca7Ian Rogers      __ LoadFromOffset(kLoadWord, PC, R9, offset.Int32Value());
46659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  }
47659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  __ bkpt(0);
48659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
49659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  size_t cs = assembler->CodeSize();
50700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers  std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
51659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
52659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  assembler->FinalizeInstructions(code);
53659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
54659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  return entry_stub.release();
55659efe783f45f46b9940aecf07be981057102ca7Ian Rogers}
56659efe783f45f46b9940aecf07be981057102ca7Ian Rogers}  // namespace arm
57659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
58b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteithnamespace arm64 {
59b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteithstatic const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
60dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers                                                    ThreadOffset<8> offset) {
61700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers  std::unique_ptr<Arm64Assembler> assembler(static_cast<Arm64Assembler*>(Assembler::Create(kArm64)));
62b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith
63b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith  switch (abi) {
64b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith    case kInterpreterAbi:  // Thread* is first argument (X0) in interpreter ABI.
6537c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames      __ JumpTo(Arm64ManagedRegister::FromXRegister(X0), Offset(offset.Int32Value()),
6637c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames          Arm64ManagedRegister::FromXRegister(IP1));
67b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith
68b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith      break;
69b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith    case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (X0).
7037c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames      __ LoadRawPtr(Arm64ManagedRegister::FromXRegister(IP1),
7137c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames                      Arm64ManagedRegister::FromXRegister(X0),
72b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith                      Offset(JNIEnvExt::SelfOffset().Int32Value()));
73b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith
7437c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames      __ JumpTo(Arm64ManagedRegister::FromXRegister(IP1), Offset(offset.Int32Value()),
7537c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames                Arm64ManagedRegister::FromXRegister(IP0));
76b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith
77b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith      break;
78956af0f0cb05422e38c1d22cbef309d16b8a1a12Elliott Hughes    case kQuickAbi:  // X18 holds Thread*.
7937c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames      __ JumpTo(Arm64ManagedRegister::FromXRegister(TR), Offset(offset.Int32Value()),
8037c92df53979f9f6ab83155ab9521d554d717161Alexandre Rames                Arm64ManagedRegister::FromXRegister(IP0));
81b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith
82b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith      break;
83b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith  }
84b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith
8532f5b4d2c8c9b52e9522941c159577b21752d0faSerban Constantinescu  assembler->EmitSlowPaths();
86b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith  size_t cs = assembler->CodeSize();
87700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers  std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
88b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
89b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith  assembler->FinalizeInstructions(code);
90b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith
91b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith  return entry_stub.release();
92b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith}
93b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith}  // namespace arm64
94b95a5345ae4217b70ca36f0cced92f68dda7caf5Stuart Monteith
95659efe783f45f46b9940aecf07be981057102ca7Ian Rogersnamespace mips {
96659efe783f45f46b9940aecf07be981057102ca7Ian Rogersstatic const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
97dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers                                                    ThreadOffset<4> offset) {
98700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers  std::unique_ptr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
99659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
100659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  switch (abi) {
101659efe783f45f46b9940aecf07be981057102ca7Ian Rogers    case kInterpreterAbi:  // Thread* is first argument (A0) in interpreter ABI.
102659efe783f45f46b9940aecf07be981057102ca7Ian Rogers      __ LoadFromOffset(kLoadWord, T9, A0, offset.Int32Value());
103659efe783f45f46b9940aecf07be981057102ca7Ian Rogers      break;
104659efe783f45f46b9940aecf07be981057102ca7Ian Rogers    case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (A0).
105659efe783f45f46b9940aecf07be981057102ca7Ian Rogers      __ LoadFromOffset(kLoadWord, T9, A0, JNIEnvExt::SelfOffset().Int32Value());
106659efe783f45f46b9940aecf07be981057102ca7Ian Rogers      __ LoadFromOffset(kLoadWord, T9, T9, offset.Int32Value());
107659efe783f45f46b9940aecf07be981057102ca7Ian Rogers      break;
108956af0f0cb05422e38c1d22cbef309d16b8a1a12Elliott Hughes    case kQuickAbi:  // S1 holds Thread*.
109659efe783f45f46b9940aecf07be981057102ca7Ian Rogers      __ LoadFromOffset(kLoadWord, T9, S1, offset.Int32Value());
110659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  }
111659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  __ Jr(T9);
112659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  __ Nop();
113659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  __ Break();
114659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
115659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  size_t cs = assembler->CodeSize();
116700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers  std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
117659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
118659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  assembler->FinalizeInstructions(code);
119659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
120659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  return entry_stub.release();
121659efe783f45f46b9940aecf07be981057102ca7Ian Rogers}
122659efe783f45f46b9940aecf07be981057102ca7Ian Rogers}  // namespace mips
123659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
12457b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampenamespace mips64 {
12557b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampestatic const std::vector<uint8_t>* CreateTrampoline(EntryPointCallingConvention abi,
12657b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe                                                    ThreadOffset<8> offset) {
12757b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe  std::unique_ptr<Mips64Assembler> assembler(static_cast<Mips64Assembler*>(Assembler::Create(kMips64)));
12857b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe
12957b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe  switch (abi) {
13057b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe    case kInterpreterAbi:  // Thread* is first argument (A0) in interpreter ABI.
13157b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe      __ LoadFromOffset(kLoadDoubleword, T9, A0, offset.Int32Value());
13257b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe      break;
13357b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe    case kJniAbi:  // Load via Thread* held in JNIEnv* in first argument (A0).
13457b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe      __ LoadFromOffset(kLoadDoubleword, T9, A0, JNIEnvExt::SelfOffset().Int32Value());
13557b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe      __ LoadFromOffset(kLoadDoubleword, T9, T9, offset.Int32Value());
13657b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe      break;
13757b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe    case kQuickAbi:  // Fall-through.
13857b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe      __ LoadFromOffset(kLoadDoubleword, T9, S1, offset.Int32Value());
13957b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe  }
14057b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe  __ Jr(T9);
14157b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe  __ Nop();
14257b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe  __ Break();
14357b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe
14457b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe  size_t cs = assembler->CodeSize();
14557b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe  std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
14657b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
14757b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe  assembler->FinalizeInstructions(code);
14857b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe
14957b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe  return entry_stub.release();
15057b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe}
15157b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe}  // namespace mips64
15257b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe
153659efe783f45f46b9940aecf07be981057102ca7Ian Rogersnamespace x86 {
154dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogersstatic const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<4> offset) {
155700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers  std::unique_ptr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
156659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
157659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  // All x86 trampolines call via the Thread* held in fs.
158659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  __ fs()->jmp(Address::Absolute(offset));
159659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  __ int3();
160659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
161659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  size_t cs = assembler->CodeSize();
162700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers  std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
163659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
164659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  assembler->FinalizeInstructions(code);
165659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
166659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  return entry_stub.release();
167659efe783f45f46b9940aecf07be981057102ca7Ian Rogers}
168659efe783f45f46b9940aecf07be981057102ca7Ian Rogers}  // namespace x86
169659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
170befbd5731ecca08f08780ee28a913d08ffb14656Ian Rogersnamespace x86_64 {
171dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogersstatic const std::vector<uint8_t>* CreateTrampoline(ThreadOffset<8> offset) {
172700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers  std::unique_ptr<x86_64::X86_64Assembler>
173dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers      assembler(static_cast<x86_64::X86_64Assembler*>(Assembler::Create(kX86_64)));
174befbd5731ecca08f08780ee28a913d08ffb14656Ian Rogers
175befbd5731ecca08f08780ee28a913d08ffb14656Ian Rogers  // All x86 trampolines call via the Thread* held in gs.
176dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers  __ gs()->jmp(x86_64::Address::Absolute(offset, true));
177befbd5731ecca08f08780ee28a913d08ffb14656Ian Rogers  __ int3();
178befbd5731ecca08f08780ee28a913d08ffb14656Ian Rogers
179befbd5731ecca08f08780ee28a913d08ffb14656Ian Rogers  size_t cs = assembler->CodeSize();
180700a402244a1a423da4f3ba8032459f4b65fa18fIan Rogers  std::unique_ptr<std::vector<uint8_t>> entry_stub(new std::vector<uint8_t>(cs));
181befbd5731ecca08f08780ee28a913d08ffb14656Ian Rogers  MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
182befbd5731ecca08f08780ee28a913d08ffb14656Ian Rogers  assembler->FinalizeInstructions(code);
183befbd5731ecca08f08780ee28a913d08ffb14656Ian Rogers
184befbd5731ecca08f08780ee28a913d08ffb14656Ian Rogers  return entry_stub.release();
185befbd5731ecca08f08780ee28a913d08ffb14656Ian Rogers}
186befbd5731ecca08f08780ee28a913d08ffb14656Ian Rogers}  // namespace x86_64
187befbd5731ecca08f08780ee28a913d08ffb14656Ian Rogers
188dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogersconst std::vector<uint8_t>* CreateTrampoline64(InstructionSet isa, EntryPointCallingConvention abi,
189dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers                                               ThreadOffset<8> offset) {
190dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers  switch (isa) {
191dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers    case kArm64:
192dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers      return arm64::CreateTrampoline(abi, offset);
19357b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe    case kMips64:
19457b34294758e9c00993913ebe43c7ee4698a5cc6Andreas Gampe      return mips64::CreateTrampoline(abi, offset);
195dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers    case kX86_64:
196dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers      return x86_64::CreateTrampoline(offset);
197dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers    default:
198dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers      LOG(FATAL) << "Unexpected InstructionSet: " << isa;
199d4c4d953035d4418126d36517e402f411d6a87f3Ian Rogers      UNREACHABLE();
200dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers  }
201dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers}
202dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers
203dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogersconst std::vector<uint8_t>* CreateTrampoline32(InstructionSet isa, EntryPointCallingConvention abi,
204dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers                                               ThreadOffset<4> offset) {
205659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  switch (isa) {
206659efe783f45f46b9940aecf07be981057102ca7Ian Rogers    case kArm:
207659efe783f45f46b9940aecf07be981057102ca7Ian Rogers    case kThumb2:
208659efe783f45f46b9940aecf07be981057102ca7Ian Rogers      return arm::CreateTrampoline(abi, offset);
209659efe783f45f46b9940aecf07be981057102ca7Ian Rogers    case kMips:
210659efe783f45f46b9940aecf07be981057102ca7Ian Rogers      return mips::CreateTrampoline(abi, offset);
211659efe783f45f46b9940aecf07be981057102ca7Ian Rogers    case kX86:
212659efe783f45f46b9940aecf07be981057102ca7Ian Rogers      return x86::CreateTrampoline(offset);
213659efe783f45f46b9940aecf07be981057102ca7Ian Rogers    default:
214dd7624d2b9e599d57762d12031b10b89defc9807Ian Rogers      LOG(FATAL) << "Unexpected InstructionSet: " << isa;
215d4c4d953035d4418126d36517e402f411d6a87f3Ian Rogers      UNREACHABLE();
216659efe783f45f46b9940aecf07be981057102ca7Ian Rogers  }
217659efe783f45f46b9940aecf07be981057102ca7Ian Rogers}
218659efe783f45f46b9940aecf07be981057102ca7Ian Rogers
219659efe783f45f46b9940aecf07be981057102ca7Ian Rogers}  // namespace art
220