blob: 912f1c0746f2f8ed47937f335d4640f2a24c01a6 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "stubs/stubs.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "jni_internal.h"
#include "utils/arm/assembler_arm.h"
#include "utils/mips/assembler_mips.h"
#include "utils/x86/assembler_x86.h"
#include "sirt_ref.h"
#include "stack_indirect_reference_table.h"
#define __ assembler->
namespace art {
namespace arm {
const std::vector<uint8_t>* CreateQuickResolutionTrampoline() {
UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
// | Out args |
// | Method* | <- SP on entry
// | LR | return address into caller
// | ... | callee saves
// | R3 | possible argument
// | R2 | possible argument
// | R1 | possible argument
// | R0 | junk on call to QuickResolutionTrampolineFromCode, holds result Method*
// | Method* | Callee save Method* set up by QuickResoltuionTrampolineFromCode
// Save callee saves and ready frame for exception delivery
RegList save = (1 << R1) | (1 << R2) | (1 << R3) | (1 << R5) | (1 << R6) | (1 << R7) | (1 << R8) |
(1 << R10) | (1 << R11) | (1 << LR);
// TODO: enable when GetCalleeSaveMethod is available at stub generation time
// DCHECK_EQ(save, Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs)->GetCoreSpillMask());
__ PushList(save);
__ LoadFromOffset(kLoadWord, R12, TR, QUICK_ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode));
__ mov(R3, ShifterOperand(TR)); // Pass Thread::Current() in R3
__ IncreaseFrameSize(8); // 2 words of space for alignment
__ mov(R2, ShifterOperand(SP)); // Pass SP
// Call to resolution trampoline (method_idx, receiver, sp, Thread*)
__ blx(R12);
__ mov(R12, ShifterOperand(R0)); // Save code address returned into R12
// Restore registers which may have been modified by GC, "R0" will hold the Method*
__ DecreaseFrameSize(4);
__ PopList((1 << R0) | save);
__ bx(R12); // Leaf call to method's code
__ bkpt(0);
assembler->EmitSlowPaths();
size_t cs = assembler->CodeSize();
UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
assembler->FinalizeInstructions(code);
return resolution_trampoline.release();
}
const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() {
UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
__ LoadFromOffset(kLoadWord, PC, R0, QUICK_ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry));
__ bkpt(0);
size_t cs = assembler->CodeSize();
UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
assembler->FinalizeInstructions(code);
return entry_stub.release();
}
const std::vector<uint8_t>* CreateInterpreterToQuickEntry() {
UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
__ LoadFromOffset(kLoadWord, PC, R0, QUICK_ENTRYPOINT_OFFSET(pInterpreterToQuickEntry));
__ bkpt(0);
size_t cs = assembler->CodeSize();
UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
assembler->FinalizeInstructions(code);
return entry_stub.release();
}
} // namespace arm
namespace mips {
const std::vector<uint8_t>* CreateQuickResolutionTrampoline() {
UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
// | Out args |
// | Method* | <- SP on entry
// | RA | return address into caller
// | ... | callee saves
// | A3 | possible argument
// | A2 | possible argument
// | A1 | possible argument
// | A0/Method* | Callee save Method* set up by UnresolvedDirectMethodTrampolineFromCode
// Save callee saves and ready frame for exception delivery
__ AddConstant(SP, SP, -64);
__ StoreToOffset(kStoreWord, RA, SP, 60);
__ StoreToOffset(kStoreWord, FP, SP, 56);
__ StoreToOffset(kStoreWord, GP, SP, 52);
__ StoreToOffset(kStoreWord, S7, SP, 48);
__ StoreToOffset(kStoreWord, S6, SP, 44);
__ StoreToOffset(kStoreWord, S5, SP, 40);
__ StoreToOffset(kStoreWord, S4, SP, 36);
__ StoreToOffset(kStoreWord, S3, SP, 32);
__ StoreToOffset(kStoreWord, S2, SP, 28);
__ StoreToOffset(kStoreWord, A3, SP, 12);
__ StoreToOffset(kStoreWord, A2, SP, 8);
__ StoreToOffset(kStoreWord, A1, SP, 4);
__ LoadFromOffset(kLoadWord, T9, S1, QUICK_ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode));
__ Move(A3, S1); // Pass Thread::Current() in A3
__ Move(A2, SP); // Pass SP for Method** callee_addr
__ Jalr(T9); // Call to resolution trampoline (method_idx, receiver, sp, Thread*)
// Restore registers which may have been modified by GC
__ LoadFromOffset(kLoadWord, A0, SP, 0);
__ LoadFromOffset(kLoadWord, A1, SP, 4);
__ LoadFromOffset(kLoadWord, A2, SP, 8);
__ LoadFromOffset(kLoadWord, A3, SP, 12);
__ LoadFromOffset(kLoadWord, S2, SP, 28);
__ LoadFromOffset(kLoadWord, S3, SP, 32);
__ LoadFromOffset(kLoadWord, S4, SP, 36);
__ LoadFromOffset(kLoadWord, S5, SP, 40);
__ LoadFromOffset(kLoadWord, S6, SP, 44);
__ LoadFromOffset(kLoadWord, S7, SP, 48);
__ LoadFromOffset(kLoadWord, GP, SP, 52);
__ LoadFromOffset(kLoadWord, FP, SP, 56);
__ LoadFromOffset(kLoadWord, RA, SP, 60);
__ AddConstant(SP, SP, 64);
__ Move(T9, V0); // Put method's code in T9
__ Jr(T9); // Leaf call to method's code
__ Break();
assembler->EmitSlowPaths();
size_t cs = assembler->CodeSize();
UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
assembler->FinalizeInstructions(code);
return resolution_trampoline.release();
}
const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() {
UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
__ LoadFromOffset(kLoadWord, T9, A0, QUICK_ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry));
__ Jr(T9);
__ Break();
size_t cs = assembler->CodeSize();
UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
assembler->FinalizeInstructions(code);
return entry_stub.release();
}
const std::vector<uint8_t>* CreateInterpreterToQuickEntry() {
UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
__ LoadFromOffset(kLoadWord, T9, A0, QUICK_ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry));
__ Jr(T9);
__ Break();
size_t cs = assembler->CodeSize();
UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
assembler->FinalizeInstructions(code);
return entry_stub.release();
}
} // namespace mips
namespace x86 {
const std::vector<uint8_t>* CreateQuickResolutionTrampoline() {
UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
// Set up the callee save frame to conform with Runtime::CreateCalleeSaveMethod(kRefsAndArgs)
// return address
__ pushl(EDI);
__ pushl(ESI);
__ pushl(EBP);
__ pushl(EBX);
__ pushl(EDX);
__ pushl(ECX);
__ pushl(EAX); // <-- callee save Method* to go here
__ movl(EDX, ESP); // save ESP
__ fs()->pushl(Address::Absolute(Thread::SelfOffset())); // pass Thread*
__ pushl(EDX); // pass ESP for Method*
__ pushl(ECX); // pass receiver
__ pushl(EAX); // pass Method*
// Call to resolve method.
__ Call(ThreadOffset(QUICK_ENTRYPOINT_OFFSET(pQuickResolutionTrampolineFromCode)),
X86ManagedRegister::FromCpuRegister(ECX));
__ movl(EDI, EAX); // save code pointer in EDI
__ addl(ESP, Immediate(16)); // Pop arguments
__ popl(EAX); // Restore args.
__ popl(ECX);
__ popl(EDX);
__ popl(EBX);
__ popl(EBP); // Restore callee saves.
__ popl(ESI);
// Swap EDI callee save with code pointer
__ xchgl(EDI, Address(ESP, 0));
// Tail call to intended method.
__ ret();
assembler->EmitSlowPaths();
size_t cs = assembler->CodeSize();
UniquePtr<std::vector<uint8_t> > resolution_trampoline(new std::vector<uint8_t>(cs));
MemoryRegion code(&(*resolution_trampoline)[0], resolution_trampoline->size());
assembler->FinalizeInstructions(code);
return resolution_trampoline.release();
}
const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() {
UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
__ fs()->jmp(Address::Absolute(ThreadOffset(QUICK_ENTRYPOINT_OFFSET(pInterpreterToInterpreterEntry))));
size_t cs = assembler->CodeSize();
UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
assembler->FinalizeInstructions(code);
return entry_stub.release();
}
const std::vector<uint8_t>* CreateInterpreterToQuickEntry() {
UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
__ fs()->jmp(Address::Absolute(ThreadOffset(QUICK_ENTRYPOINT_OFFSET(pInterpreterToQuickEntry))));
size_t cs = assembler->CodeSize();
UniquePtr<std::vector<uint8_t> > entry_stub(new std::vector<uint8_t>(cs));
MemoryRegion code(&(*entry_stub)[0], entry_stub->size());
assembler->FinalizeInstructions(code);
return entry_stub.release();
}
} // namespace x86
} // namespace art