blob: cee68478a44f240063f2dd44ed8f0fd76ecf5ca1 [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 "stack_indirect_reference_table.h"
#include "sirt_ref.h"
#define __ assembler->
namespace art {
namespace arm {
const std::vector<uint8_t>* CreatePortableResolutionTrampoline() {
UniquePtr<ArmAssembler> assembler(static_cast<ArmAssembler*>(Assembler::Create(kArm)));
RegList save = (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3) | (1 << LR);
__ PushList(save);
__ LoadFromOffset(kLoadWord, R12, TR, ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode));
__ mov(R3, ShifterOperand(TR)); // Pass Thread::Current() in R3
__ mov(R2, ShifterOperand(SP)); // Pass sp for Method** callee_addr
__ IncreaseFrameSize(12); // 3 words of space for alignment
// Call to resolution trampoline (callee, receiver, callee_addr, Thread*)
__ blx(R12);
__ mov(R12, ShifterOperand(R0)); // Save code address returned into R12
__ DecreaseFrameSize(12);
__ PopList(save);
__ cmp(R12, ShifterOperand(0));
__ bx(R12, NE); // If R12 != 0 tail call method's code
__ bx(LR); // Return to caller to handle exception
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();
}
} // namespace arm
namespace mips {
const std::vector<uint8_t>* CreatePortableResolutionTrampoline() {
UniquePtr<MipsAssembler> assembler(static_cast<MipsAssembler*>(Assembler::Create(kMips)));
// Build frame and save argument registers and RA.
__ AddConstant(SP, SP, -32);
__ StoreToOffset(kStoreWord, RA, SP, 28);
__ StoreToOffset(kStoreWord, A3, SP, 12);
__ StoreToOffset(kStoreWord, A2, SP, 8);
__ StoreToOffset(kStoreWord, A1, SP, 4);
__ StoreToOffset(kStoreWord, A0, SP, 0);
__ LoadFromOffset(kLoadWord, T9, S1,
ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode));
__ Move(A3, S1); // Pass Thread::Current() in A3
__ Move(A2, SP); // Pass SP for Method** callee_addr
__ Jalr(T9); // Call to resolution trampoline (callee, receiver, callee_addr, Thread*)
// Restore frame, argument registers, and RA.
__ LoadFromOffset(kLoadWord, A0, SP, 0);
__ LoadFromOffset(kLoadWord, A1, SP, 4);
__ LoadFromOffset(kLoadWord, A2, SP, 8);
__ LoadFromOffset(kLoadWord, A3, SP, 12);
__ LoadFromOffset(kLoadWord, RA, SP, 28);
__ AddConstant(SP, SP, 32);
Label resolve_fail;
__ EmitBranch(V0, ZERO, &resolve_fail, true);
__ Jr(V0); // If V0 != 0 tail call method's code
__ Bind(&resolve_fail, false);
__ Jr(RA); // Return to caller to handle exception
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();
}
} // namespace mips
namespace x86 {
const std::vector<uint8_t>* CreatePortableResolutionTrampoline() {
UniquePtr<X86Assembler> assembler(static_cast<X86Assembler*>(Assembler::Create(kX86)));
__ pushl(EBP);
__ movl(EBP, ESP); // save ESP
__ subl(ESP, Immediate(8)); // Align stack
__ movl(EAX, Address(EBP, 8)); // Method* called
__ leal(EDX, Address(EBP, 8)); // Method** called_addr
__ fs()->pushl(Address::Absolute(Thread::SelfOffset())); // pass thread
__ pushl(EDX); // pass called_addr
__ pushl(ECX); // pass receiver
__ pushl(EAX); // pass called
// Call to resolve method.
__ Call(ThreadOffset(ENTRYPOINT_OFFSET(pPortableResolutionTrampolineFromCode)),
X86ManagedRegister::FromCpuRegister(ECX));
__ leave();
Label resolve_fail; // forward declaration
__ cmpl(EAX, Immediate(0));
__ j(kEqual, &resolve_fail);
__ jmp(EAX);
// Tail call to intended method.
__ Bind(&resolve_fail);
__ 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();
}
} // namespace x86
} // namespace art