diff options
author | 2013-06-03 14:49:28 -0700 | |
---|---|---|
committer | 2013-06-07 14:43:24 -0700 | |
commit | 0aba0ba155bef7346bde19e53581200b89ae8a7a (patch) | |
tree | 6590f8a50bde7c30b57f1bb0ae67c6d88cea8116 | |
parent | 515661b14b60ab9684efa1ab1d5124934406094e (diff) |
Created compiled stubs in image.
Saves class linker from having to set code pointers when loading
from an image. Added stubs for quick and portable resolution
trampolines, and interpreter-to-interpreter and interpreter-to-quick
entry points. Also added sizing stats output for oat writer.
Change-Id: I3905fae81047742c23d1cf0ca001db798db971b1
34 files changed, 1032 insertions, 254 deletions
diff --git a/build/Android.common.mk b/build/Android.common.mk index 43f7ff5296..ba5fe9f2ed 100644 --- a/build/Android.common.mk +++ b/build/Android.common.mk @@ -172,6 +172,8 @@ LIBART_COMMON_SRC_FILES := \ src/compiled_method.cc \ src/compiler/driver/compiler_driver.cc \ src/compiler/llvm/runtime_support_llvm.cc \ + src/compiler/stubs/portable/stubs.cc \ + src/compiler/stubs/quick/stubs.cc \ src/debugger.cc \ src/dex_file.cc \ src/dex_file_verifier.cc \ diff --git a/src/class_linker.cc b/src/class_linker.cc index 9faf3de190..0fae4248e9 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -74,8 +74,9 @@ namespace art { -void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item, - ShadowFrame* shadow_frame, JValue* result); +extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, JValue* result); static void ThrowNoClassDefFoundError(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2))) @@ -201,7 +202,9 @@ ClassLinker::ClassLinker(InternTable* intern_table) array_iftable_(NULL), init_done_(false), is_dirty_(false), - intern_table_(intern_table) { + intern_table_(intern_table), + portable_resolution_trampoline_(NULL), + quick_resolution_trampoline_(NULL) { CHECK_EQ(arraysize(class_roots_descriptors_), size_t(kClassRootsMax)); } @@ -952,6 +955,8 @@ void ClassLinker::InitFromImage() { CHECK_EQ(oat_file->GetOatHeader().GetImageFileLocationOatChecksum(), 0U); CHECK_EQ(oat_file->GetOatHeader().GetImageFileLocationOatDataBegin(), 0U); CHECK(oat_file->GetOatHeader().GetImageFileLocation().empty()); + portable_resolution_trampoline_ = oat_file->GetOatHeader().GetPortableResolutionTrampoline(); + quick_resolution_trampoline_ = oat_file->GetOatHeader().GetQuickResolutionTrampoline(); mirror::Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches); mirror::ObjectArray<mirror::DexCache>* dex_caches = dex_caches_object->AsObjectArray<mirror::DexCache>(); @@ -1038,19 +1043,12 @@ void ClassLinker::InitFromImageCallback(mirror::Object* obj, void* arg) { return; } - // Check if object is a method without its code set and point it to the resolution trampoline. + // Set entry points to interpreter for methods in interpreter only mode. if (obj->IsMethod()) { mirror::AbstractMethod* method = obj->AsMethod(); - // Install entry point from interpreter. - if (!method->IsNative() && !method->IsProxyMethod() && - (method->GetEntryPointFromCompiledCode() == NULL || - Runtime::Current()->GetInstrumentation()->InterpretOnly())) { - method->SetEntryPointFromInterpreter(interpreter::EnterInterpreterFromInterpreter); - } else { - method->SetEntryPointFromInterpreter(artInterpreterToQuickEntry); - } - if (method->GetEntryPointFromCompiledCode() == NULL) { - method->SetEntryPointFromCompiledCode(GetResolutionTrampoline()); + if (Runtime::Current()->GetInstrumentation()->InterpretOnly() && !method->IsNative()) { + method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterEntry); + method->SetEntryPointFromCompiledCode(GetInterpreterEntryPoint()); } } } @@ -1612,10 +1610,11 @@ static void LinkCode(SirtRef<mirror::AbstractMethod>& method, const OatFile::Oat // Install entry point from interpreter. Runtime* runtime = Runtime::Current(); - if (!method->IsNative() && !method->IsProxyMethod() && - (method->GetEntryPointFromCompiledCode() == NULL || - runtime->GetInstrumentation()->InterpretOnly())) { - method->SetEntryPointFromInterpreter(interpreter::EnterInterpreterFromInterpreter); + bool enter_interpreter = method->GetEntryPointFromCompiledCode() == NULL || + (runtime->GetInstrumentation()->InterpretOnly() && + !method->IsNative() && !method->IsProxyMethod()); + if (enter_interpreter) { + method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterEntry); } else { method->SetEntryPointFromInterpreter(artInterpreterToQuickEntry); } @@ -1627,7 +1626,7 @@ static void LinkCode(SirtRef<mirror::AbstractMethod>& method, const OatFile::Oat if (method->IsStatic() && !method->IsConstructor()) { // For static methods excluding the class initializer, install the trampoline. - method->SetEntryPointFromCompiledCode(GetResolutionTrampoline()); + method->SetEntryPointFromCompiledCode(GetResolutionTrampoline(runtime->GetClassLinker())); } if (method->IsNative()) { @@ -1635,10 +1634,8 @@ static void LinkCode(SirtRef<mirror::AbstractMethod>& method, const OatFile::Oat method->UnregisterNative(Thread::Current()); } - if (method->GetEntryPointFromCompiledCode() == NULL || - (runtime->GetInstrumentation()->InterpretOnly() && !method->IsNative() && - !method->IsProxyMethod())) { - // No code? You must mean to go into the interpreter. + if (enter_interpreter) { + // Set entry point from compiled code if there's no code or in interpreter only mode. method->SetEntryPointFromCompiledCode(GetInterpreterEntryPoint()); } diff --git a/src/class_linker.h b/src/class_linker.h index 79fa8bafbb..eab1fcc814 100644 --- a/src/class_linker.h +++ b/src/class_linker.h @@ -334,6 +334,14 @@ class ClassLinker { is_dirty_ = true; } + const void* GetPortableResolutionTrampoline() const { + return portable_resolution_trampoline_; + } + + const void* GetQuickResolutionTrampoline() const { + return quick_resolution_trampoline_; + } + private: explicit ClassLinker(InternTable*); @@ -593,6 +601,9 @@ class ClassLinker { InternTable* intern_table_; + const void* portable_resolution_trampoline_; + const void* quick_resolution_trampoline_; + friend class CommonTest; friend class ImageWriter; // for GetClassRoots friend class ObjectTest; diff --git a/src/compiler/driver/compiler_driver.cc b/src/compiler/driver/compiler_driver.cc index 1b8f87d51f..834be64d74 100644 --- a/src/compiler/driver/compiler_driver.cc +++ b/src/compiler/driver/compiler_driver.cc @@ -24,6 +24,7 @@ #include "base/stl_util.h" #include "base/timing_logger.h" #include "class_linker.h" +#include "compiler/stubs/stubs.h" #include "dex_compilation_unit.h" #include "dex_file-inl.h" #include "jni_internal.h" @@ -448,6 +449,66 @@ CompilerTls* CompilerDriver::GetTls() { return res; } +const std::vector<uint8_t>* CompilerDriver::CreatePortableResolutionTrampoline() const { + switch (instruction_set_) { + case kArm: + case kThumb2: + return arm::CreatePortableResolutionTrampoline(); + case kMips: + return mips::CreatePortableResolutionTrampoline(); + case kX86: + return x86::CreatePortableResolutionTrampoline(); + default: + LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_; + return NULL; + } +} + +const std::vector<uint8_t>* CompilerDriver::CreateQuickResolutionTrampoline() const { + switch (instruction_set_) { + case kArm: + case kThumb2: + return arm::CreateQuickResolutionTrampoline(); + case kMips: + return mips::CreateQuickResolutionTrampoline(); + case kX86: + return x86::CreateQuickResolutionTrampoline(); + default: + LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_; + return NULL; + } +} + +const std::vector<uint8_t>* CompilerDriver::CreateInterpreterToInterpreterEntry() const { + switch (instruction_set_) { + case kArm: + case kThumb2: + return arm::CreateInterpreterToInterpreterEntry(); + case kMips: + return mips::CreateInterpreterToInterpreterEntry(); + case kX86: + return x86::CreateInterpreterToInterpreterEntry(); + default: + LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_; + return NULL; + } +} + +const std::vector<uint8_t>* CompilerDriver::CreateInterpreterToQuickEntry() const { + switch (instruction_set_) { + case kArm: + case kThumb2: + return arm::CreateInterpreterToQuickEntry(); + case kMips: + return mips::CreateInterpreterToQuickEntry(); + case kX86: + return x86::CreateInterpreterToQuickEntry(); + default: + LOG(FATAL) << "Unknown InstructionSet: " << instruction_set_; + return NULL; + } +} + void CompilerDriver::CompileAll(jobject class_loader, const std::vector<const DexFile*>& dex_files) { DCHECK(!Runtime::Current()->IsStarted()); diff --git a/src/compiler/driver/compiler_driver.h b/src/compiler/driver/compiler_driver.h index 9fd3c81c21..4f77bdb7a7 100644 --- a/src/compiler/driver/compiler_driver.h +++ b/src/compiler/driver/compiler_driver.h @@ -98,6 +98,16 @@ class CompilerDriver { CompilerTls* GetTls(); + // Generate the trampolines that are invoked by unresolved direct methods. + const std::vector<uint8_t>* CreatePortableResolutionTrampoline() const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const std::vector<uint8_t>* CreateQuickResolutionTrampoline() const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const std::vector<uint8_t>* CreateInterpreterToQuickEntry() const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // A class is uniquely located by its DexFile and the class_defs_ table index into that DexFile typedef std::pair<const DexFile*, uint32_t> ClassReference; diff --git a/src/compiler/stubs/portable/stubs.cc b/src/compiler/stubs/portable/stubs.cc new file mode 100644 index 0000000000..db551bf368 --- /dev/null +++ b/src/compiler/stubs/portable/stubs.cc @@ -0,0 +1,136 @@ +/* + * 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 "compiler/stubs/stubs.h" +#include "jni_internal.h" +#include "oat/utils/arm/assembler_arm.h" +#include "oat/utils/mips/assembler_mips.h" +#include "oat/utils/x86/assembler_x86.h" +#include "oat/runtime/oat_support_entrypoints.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 diff --git a/src/compiler/stubs/quick/stubs.cc b/src/compiler/stubs/quick/stubs.cc new file mode 100644 index 0000000000..a8e691f35b --- /dev/null +++ b/src/compiler/stubs/quick/stubs.cc @@ -0,0 +1,262 @@ +/* + * 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 "compiler/stubs/stubs.h" +#include "jni_internal.h" +#include "oat/utils/arm/assembler_arm.h" +#include "oat/utils/mips/assembler_mips.h" +#include "oat/utils/x86/assembler_x86.h" +#include "oat/runtime/oat_support_entrypoints.h" +#include "stack_indirect_reference_table.h" +#include "sirt_ref.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, 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, 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, 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, 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, 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, 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(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(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(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 diff --git a/src/compiler/stubs/stubs.h b/src/compiler/stubs/stubs.h new file mode 100644 index 0000000000..ebe761df35 --- /dev/null +++ b/src/compiler/stubs/stubs.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2012 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. + */ + +#ifndef ART_SRC_COMPILER_STUBS_STUBS_H_ +#define ART_SRC_COMPILER_STUBS_STUBS_H_ + +#include "runtime.h" + +namespace art { + +namespace arm { +const std::vector<uint8_t>* CreatePortableResolutionTrampoline() + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +const std::vector<uint8_t>* CreateQuickResolutionTrampoline() + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +const std::vector<uint8_t>* CreateInterpreterToQuickEntry() + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +} + +namespace mips { +const std::vector<uint8_t>* CreatePortableResolutionTrampoline() + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +const std::vector<uint8_t>* CreateQuickResolutionTrampoline() + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +const std::vector<uint8_t>* CreateInterpreterToQuickEntry() + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +} + +namespace x86 { +const std::vector<uint8_t>* CreatePortableResolutionTrampoline() + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +const std::vector<uint8_t>* CreateQuickResolutionTrampoline() + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +const std::vector<uint8_t>* CreateInterpreterToInterpreterEntry() + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +const std::vector<uint8_t>* CreateInterpreterToQuickEntry() + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +} + +} // namespace art + +#endif // ART_SRC_COMPILER_STUBS_STUBS_H_ diff --git a/src/dex2oat.cc b/src/dex2oat.cc index 3f13d5939f..2f3edc443b 100644 --- a/src/dex2oat.cc +++ b/src/dex2oat.cc @@ -280,9 +280,8 @@ class Dex2Oat { std::string image_file_location; uint32_t image_file_location_oat_checksum = 0; uint32_t image_file_location_oat_data_begin = 0; - Heap* heap = Runtime::Current()->GetHeap(); - if (heap->GetSpaces().size() > 1) { - ImageSpace* image_space = heap->GetImageSpace(); + if (!driver->IsImage()) { + ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace(); image_file_location_oat_checksum = image_space->GetImageHeader().GetOatChecksum(); image_file_location_oat_data_begin = reinterpret_cast<uint32_t>(image_space->GetImageHeader().GetOatDataBegin()); diff --git a/src/image_test.cc b/src/image_test.cc index 8066a90957..cd1a34fa56 100644 --- a/src/image_test.cc +++ b/src/image_test.cc @@ -48,7 +48,8 @@ TEST_F(ImageTest, WriteRead) { dex_files.push_back(java_lang_dex_file_); dex_files.push_back(conscrypt_file_); VectorOutputStream output_stream(tmp_elf.GetFilename(), oat_contents); - bool success_oat = OatWriter::Create(output_stream, dex_files, 0, 0, "", *compiler_driver_.get()); + bool success_oat = OatWriter::Create(output_stream, dex_files, 0, 0, "", + *compiler_driver_.get()); ASSERT_TRUE(success_oat); // Force all system classes into memory diff --git a/src/image_writer.cc b/src/image_writer.cc index 12b756e3e0..4eea1cab29 100644 --- a/src/image_writer.cc +++ b/src/image_writer.cc @@ -81,6 +81,10 @@ bool ImageWriter::Write(const std::string& image_filename, } oat_file_ = OatFile::OpenWritable(oat_file.get(), oat_location); class_linker->RegisterOatFile(*oat_file_); + interpreter_to_interpreter_entry_offset_ = oat_file_->GetOatHeader().GetInterpreterToInterpreterEntryOffset(); + interpreter_to_quick_entry_offset_ = oat_file_->GetOatHeader().GetInterpreterToQuickEntryOffset(); + portable_resolution_trampoline_offset_ = oat_file_->GetOatHeader().GetPortableResolutionTrampolineOffset(); + quick_resolution_trampoline_offset_ = oat_file_->GetOatHeader().GetQuickResolutionTrampolineOffset(); { Thread::Current()->TransitionFromSuspendedToRunnable(); @@ -507,17 +511,34 @@ void ImageWriter::FixupMethod(const AbstractMethod* orig, AbstractMethod* copy) if (orig->IsAbstract()) { // Code for abstract methods is set to the abstract method error stub when we load the image. copy->SetEntryPointFromCompiledCode(NULL); + copy->SetEntryPointFromInterpreter(reinterpret_cast<EntryPointFromInterpreter*> + (GetOatAddress(interpreter_to_interpreter_entry_offset_))); return; + } else { + copy->SetEntryPointFromInterpreter(reinterpret_cast<EntryPointFromInterpreter*> + (GetOatAddress(interpreter_to_quick_entry_offset_))); } if (orig == Runtime::Current()->GetResolutionMethod()) { - // The resolution method's code is set to the resolution trampoline when we load the image. - copy->SetEntryPointFromCompiledCode(NULL); +#if defined(ART_USE_PORTABLE_COMPILER) + copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_resolution_trampoline_offset_)); +#else + copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_resolution_trampoline_offset_)); +#endif return; } - // Non-abstract methods have code - copy->SetEntryPointFromCompiledCode(GetOatAddress(orig->GetOatCodeOffset())); + // Use original code if it exists. Otherwise, set the code pointer to the resolution trampoline. + const byte* code = GetOatAddress(orig->GetOatCodeOffset()); + if (code != NULL) { + copy->SetEntryPointFromCompiledCode(code); + } else { +#if defined(ART_USE_PORTABLE_COMPILER) + copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_resolution_trampoline_offset_)); +#else + copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_resolution_trampoline_offset_)); +#endif + } if (orig->IsNative()) { // The native method's pointer is set to a stub to lookup via dlsym when we load the image. diff --git a/src/image_writer.h b/src/image_writer.h index 0cccf69a16..1de31491dd 100644 --- a/src/image_writer.h +++ b/src/image_writer.h @@ -39,7 +39,9 @@ class ImageWriter { public: explicit ImageWriter(std::set<std::string>* image_classes) : oat_file_(NULL), image_end_(0), image_begin_(NULL), image_classes_(image_classes), - oat_data_begin_(NULL) {} + oat_data_begin_(NULL), interpreter_to_interpreter_entry_offset_(0), + interpreter_to_quick_entry_offset_(0), portable_resolution_trampoline_offset_(0), + quick_resolution_trampoline_offset_(0) {} ~ImageWriter() {} @@ -196,7 +198,13 @@ class ImageWriter { // Beginning target oat address for the pointers from the output image to its oat file. const byte* oat_data_begin_; - // DexCaches seen while scanning for fixing up CodeAndDirectMethods. + // Offset from oat_data_begin_ to the stubs. + uint32_t interpreter_to_interpreter_entry_offset_; + uint32_t interpreter_to_quick_entry_offset_; + uint32_t portable_resolution_trampoline_offset_; + uint32_t quick_resolution_trampoline_offset_; + + // DexCaches seen while scanning for fixing up CodeAndDirectMethods typedef std::set<mirror::DexCache*> Set; Set dex_caches_; }; diff --git a/src/instrumentation.cc b/src/instrumentation.cc index 39fd37766a..8af0885ef4 100644 --- a/src/instrumentation.cc +++ b/src/instrumentation.cc @@ -62,7 +62,7 @@ bool Instrumentation::InstallStubsForClass(mirror::Class* klass) { if (is_initialized || !method->IsStatic() || method->IsConstructor()) { new_code = class_linker->GetOatCodeFor(method); } else { - new_code = GetResolutionTrampoline(); + new_code = GetResolutionTrampoline(class_linker); } } else { // !uninstall if (!interpreter_stubs_installed_ || method->IsNative()) { @@ -380,7 +380,7 @@ const void* Instrumentation::GetQuickCodeFor(const mirror::AbstractMethod* metho if (LIKELY(!instrumentation_stubs_installed_)) { const void* code = method->GetEntryPointFromCompiledCode(); DCHECK(code != NULL); - if (LIKELY(code != GetResolutionTrampoline())) { + if (LIKELY(code != GetResolutionTrampoline(runtime->GetClassLinker()))) { return code; } } diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc index 94237a01bc..c7b9c58c74 100644 --- a/src/interpreter/interpreter.cc +++ b/src/interpreter/interpreter.cc @@ -133,7 +133,7 @@ static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh, } } else { // Not special, continue with regular interpreter execution. - EnterInterpreterFromInterpreter(self, mh, code_item, shadow_frame, result); + artInterpreterToInterpreterEntry(self, mh, code_item, shadow_frame, result); } } @@ -2816,9 +2816,9 @@ JValue EnterInterpreterFromStub(Thread* self, MethodHelper& mh, const DexFile::C return Execute(self, mh, code_item, shadow_frame, JValue()); } -void EnterInterpreterFromInterpreter(Thread* self, MethodHelper& mh, - const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame, - JValue* result) +void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, JValue* result) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) { ThrowStackOverflowError(self); diff --git a/src/interpreter/interpreter.h b/src/interpreter/interpreter.h index bae3b65c89..20166ac545 100644 --- a/src/interpreter/interpreter.h +++ b/src/interpreter/interpreter.h @@ -47,9 +47,9 @@ extern JValue EnterInterpreterFromStub(Thread* self, MethodHelper& mh, ShadowFrame& shadow_frame) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); -extern void EnterInterpreterFromInterpreter(Thread* self, MethodHelper& mh, - const DexFile::CodeItem* code_item, - ShadowFrame* shadow_frame, JValue* result) +extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, JValue* result) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); } // namespace interpreter diff --git a/src/mirror/abstract_method-inl.h b/src/mirror/abstract_method-inl.h index d4f0f2c6bc..a8238867aa 100644 --- a/src/mirror/abstract_method-inl.h +++ b/src/mirror/abstract_method-inl.h @@ -117,7 +117,8 @@ inline void AbstractMethod::AssertPcIsWithinCode(uintptr_t pc) const { if (GetEntryPointFromCompiledCode() == GetInterpreterEntryPoint()) { return; } - if (GetEntryPointFromCompiledCode() == GetResolutionTrampoline()) { + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + if (GetEntryPointFromCompiledCode() == GetResolutionTrampoline(class_linker)) { return; } DCHECK(IsWithinCode(pc)) diff --git a/src/oat.cc b/src/oat.cc index 4eb97f5e41..e606953ed5 100644 --- a/src/oat.cc +++ b/src/oat.cc @@ -22,7 +22,7 @@ namespace art { const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' }; -const uint8_t OatHeader::kOatVersion[] = { '0', '0', '5', '\0' }; +const uint8_t OatHeader::kOatVersion[] = { '0', '0', '6', '\0' }; OatHeader::OatHeader() { memset(this, 0, sizeof(*this)); @@ -57,6 +57,10 @@ OatHeader::OatHeader(InstructionSet instruction_set, UpdateChecksum(image_file_location.data(), image_file_location_size_); executable_offset_ = 0; + interpreter_to_interpreter_entry_offset_ = 0; + interpreter_to_quick_entry_offset_ = 0; + portable_resolution_trampoline_offset_ = 0; + quick_resolution_trampoline_offset_ = 0; } bool OatHeader::IsValid() const { @@ -97,6 +101,92 @@ uint32_t OatHeader::GetExecutableOffset() const { return executable_offset_; } +void OatHeader::SetExecutableOffset(uint32_t executable_offset) { + DCHECK_ALIGNED(executable_offset, kPageSize); + CHECK_GT(executable_offset, sizeof(OatHeader)); + DCHECK(IsValid()); + DCHECK_EQ(executable_offset_, 0U); + + executable_offset_ = executable_offset; + UpdateChecksum(&executable_offset_, sizeof(executable_offset)); +} + +const void* OatHeader::GetInterpreterToInterpreterEntry() const { + return reinterpret_cast<const uint8_t*>(this) + GetInterpreterToInterpreterEntryOffset(); +} + +uint32_t OatHeader::GetInterpreterToInterpreterEntryOffset() const { + DCHECK(IsValid()); + CHECK_GE(interpreter_to_interpreter_entry_offset_, executable_offset_); + return interpreter_to_interpreter_entry_offset_; +} + +void OatHeader::SetInterpreterToInterpreterEntryOffset(uint32_t offset) { + CHECK(offset == 0 || offset >= executable_offset_); + DCHECK(IsValid()); + DCHECK_EQ(interpreter_to_interpreter_entry_offset_, 0U) << offset; + + interpreter_to_interpreter_entry_offset_ = offset; + UpdateChecksum(&interpreter_to_interpreter_entry_offset_, sizeof(offset)); +} + +const void* OatHeader::GetInterpreterToQuickEntry() const { + return reinterpret_cast<const uint8_t*>(this) + GetInterpreterToQuickEntryOffset(); +} + +uint32_t OatHeader::GetInterpreterToQuickEntryOffset() const { + DCHECK(IsValid()); + CHECK_GE(interpreter_to_quick_entry_offset_, interpreter_to_interpreter_entry_offset_); + return interpreter_to_quick_entry_offset_; +} + +void OatHeader::SetInterpreterToQuickEntryOffset(uint32_t offset) { + CHECK(offset == 0 || offset >= interpreter_to_interpreter_entry_offset_); + DCHECK(IsValid()); + DCHECK_EQ(interpreter_to_quick_entry_offset_, 0U) << offset; + + interpreter_to_quick_entry_offset_ = offset; + UpdateChecksum(&interpreter_to_quick_entry_offset_, sizeof(offset)); +} + +const void* OatHeader::GetPortableResolutionTrampoline() const { + return reinterpret_cast<const uint8_t*>(this) + GetPortableResolutionTrampolineOffset(); +} + +uint32_t OatHeader::GetPortableResolutionTrampolineOffset() const { + DCHECK(IsValid()); + CHECK_GE(portable_resolution_trampoline_offset_, interpreter_to_quick_entry_offset_); + return portable_resolution_trampoline_offset_; +} + +void OatHeader::SetPortableResolutionTrampolineOffset(uint32_t offset) { + CHECK(offset == 0 || offset >= interpreter_to_quick_entry_offset_); + DCHECK(IsValid()); + DCHECK_EQ(portable_resolution_trampoline_offset_, 0U) << offset; + + portable_resolution_trampoline_offset_ = offset; + UpdateChecksum(&portable_resolution_trampoline_offset_, sizeof(offset)); +} + +const void* OatHeader::GetQuickResolutionTrampoline() const { + return reinterpret_cast<const uint8_t*>(this) + GetQuickResolutionTrampolineOffset(); +} + +uint32_t OatHeader::GetQuickResolutionTrampolineOffset() const { + DCHECK(IsValid()); + CHECK_GE(quick_resolution_trampoline_offset_, portable_resolution_trampoline_offset_); + return quick_resolution_trampoline_offset_; +} + +void OatHeader::SetQuickResolutionTrampolineOffset(uint32_t offset) { + CHECK(offset == 0 || offset >= portable_resolution_trampoline_offset_); + DCHECK(IsValid()); + DCHECK_EQ(quick_resolution_trampoline_offset_, 0U) << offset; + + quick_resolution_trampoline_offset_ = offset; + UpdateChecksum(&quick_resolution_trampoline_offset_, sizeof(offset)); +} + uint32_t OatHeader::GetImageFileLocationOatChecksum() const { CHECK(IsValid()); return image_file_location_oat_checksum_; @@ -123,16 +213,6 @@ std::string OatHeader::GetImageFileLocation() const { GetImageFileLocationSize()); } -void OatHeader::SetExecutableOffset(uint32_t executable_offset) { - DCHECK_ALIGNED(executable_offset, kPageSize); - CHECK_GT(executable_offset, sizeof(OatHeader)); - DCHECK(IsValid()); - DCHECK_EQ(executable_offset_, 0U); - - executable_offset_ = executable_offset; - UpdateChecksum(&executable_offset_, sizeof(executable_offset)); -} - OatMethodOffsets::OatMethodOffsets() : code_offset_(0), frame_size_in_bytes_(0), @@ -43,8 +43,20 @@ class PACKED(4) OatHeader { return dex_file_count_; } uint32_t GetExecutableOffset() const; - InstructionSet GetInstructionSet() const; void SetExecutableOffset(uint32_t executable_offset); + const void* GetInterpreterToInterpreterEntry() const; + uint32_t GetInterpreterToInterpreterEntryOffset() const; + void SetInterpreterToInterpreterEntryOffset(uint32_t offset); + const void* GetInterpreterToQuickEntry() const; + uint32_t GetInterpreterToQuickEntryOffset() const; + void SetInterpreterToQuickEntryOffset(uint32_t offset); + const void* GetPortableResolutionTrampoline() const; + uint32_t GetPortableResolutionTrampolineOffset() const; + void SetPortableResolutionTrampolineOffset(uint32_t offset); + const void* GetQuickResolutionTrampoline() const; + uint32_t GetQuickResolutionTrampolineOffset() const; + void SetQuickResolutionTrampolineOffset(uint32_t offset); + InstructionSet GetInstructionSet() const; uint32_t GetImageFileLocationOatChecksum() const; uint32_t GetImageFileLocationOatDataBegin() const; uint32_t GetImageFileLocationSize() const; @@ -62,6 +74,10 @@ class PACKED(4) OatHeader { InstructionSet instruction_set_; uint32_t dex_file_count_; uint32_t executable_offset_; + uint32_t interpreter_to_interpreter_entry_offset_; + uint32_t interpreter_to_quick_entry_offset_; + uint32_t portable_resolution_trampoline_offset_; + uint32_t quick_resolution_trampoline_offset_; uint32_t image_file_location_oat_checksum_; uint32_t image_file_location_oat_data_begin_; diff --git a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc index 1a5fe47e58..2e9453ce9c 100644 --- a/src/oat/runtime/arm/oat_support_entrypoints_arm.cc +++ b/src/oat/runtime/arm/oat_support_entrypoints_arm.cc @@ -91,12 +91,26 @@ extern "C" uint64_t art_quick_shl_long(uint64_t, uint32_t); extern "C" uint64_t art_quick_shr_long(uint64_t, uint32_t); extern "C" uint64_t art_quick_ushr_long(uint64_t, uint32_t); +// Interpreter entrypoints. +extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, JValue* result); +extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, JValue* result); + // Intrinsic entrypoints. extern "C" int32_t __memcmp16(void*, void*, int32_t); extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t); extern "C" int32_t art_quick_string_compareto(void*, void*); // Invoke entrypoints. +extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called, + mirror::Object* receiver, + mirror::AbstractMethod** sp, Thread* thread); +extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called, + mirror::Object* receiver, + mirror::AbstractMethod** sp, Thread* thread); extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*); extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*); @@ -187,6 +201,10 @@ void InitEntryPoints(EntryPoints* points) { points->pShrLong = art_quick_shr_long; points->pUshrLong = art_quick_ushr_long; + // Interpreter + points->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry; + points->pInterpreterToQuickEntry = artInterpreterToQuickEntry; + // Intrinsics points->pIndexOf = art_quick_indexof; points->pMemcmp16 = __memcmp16; @@ -194,6 +212,8 @@ void InitEntryPoints(EntryPoints* points) { points->pMemcpy = memcpy; // Invocation + points->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline; + points->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline; points->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; points->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; points->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; diff --git a/src/oat/runtime/arm/runtime_support_arm.S b/src/oat/runtime/arm/runtime_support_arm.S index b8d2265226..f19e8bada0 100644 --- a/src/oat/runtime/arm/runtime_support_arm.S +++ b/src/oat/runtime/arm/runtime_support_arm.S @@ -246,48 +246,6 @@ INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvok INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck - /* - * Portable resolution trampoline. - */ - .extern artPortableResolutionTrampoline -ENTRY art_portable_resolution_trampoline - push {r0, r1, r2, r3, lr} @ spill regs - .save {r0, r1, r2, r3, lr} - .pad #20 - .cfi_adjust_cfa_offset 20 - sub sp, #12 @ pad stack pointer to align frame - .pad #12 - .cfi_adjust_cfa_offset 12 - mov r3, r9 @ pass Thread::Current - mov r2, sp @ pass stack pointer - blx artPortableResolutionTrampoline @ (method, receiver, sp, Thread*) - mov r12, r0 @ save method code pointer result - add sp, #12 @ remove padding from stack pointer - .cfi_adjust_cfa_offset -12 - pop {r0, r1, r2, r3, lr} @ restore regs - .cfi_adjust_cfa_offset -20 - cmp r12, #0 @ is method code null? - bxne r12 @ if non-null, tail call to method's code - bx lr @ otherwise, return to caller to handle exception -END art_portable_resolution_trampoline - - /* - * Quick resolution trampoline. - */ - .extern artQuickResolutionTrampoline -ENTRY art_quick_resolution_trampoline - SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME @ save callee saves in case allocation triggers GC - mov r3, r9 @ pass Thread::Current - mov r2, sp @ pass stack pointer - blx artQuickResolutionTrampoline @ (called method, receiver, sp, Thread*) - mov r12, r0 @ save method code pointer result - add sp, #4 @ set up stack pointer - .cfi_adjust_cfa_offset -4 - pop {r0-r3, r5-r8, r10-r11, lr} @ 11 words, r0 will hold method* - .cfi_adjust_cfa_offset -44 - bx r12 @ leaf call to method code -END art_quick_resolution_trampoline - /* * Portable invocation stub. * On entry: diff --git a/src/oat/runtime/mips/oat_support_entrypoints_mips.cc b/src/oat/runtime/mips/oat_support_entrypoints_mips.cc index eb82c42894..8e066118cd 100644 --- a/src/oat/runtime/mips/oat_support_entrypoints_mips.cc +++ b/src/oat/runtime/mips/oat_support_entrypoints_mips.cc @@ -93,12 +93,26 @@ extern "C" uint64_t art_quick_shl_long(uint64_t, uint32_t); extern "C" uint64_t art_quick_shr_long(uint64_t, uint32_t); extern "C" uint64_t art_quick_ushr_long(uint64_t, uint32_t); +// Interpreter entrypoints. +extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, JValue* result); +extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, JValue* result); + // Intrinsic entrypoints. extern "C" int32_t __memcmp16(void*, void*, int32_t); extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t); extern "C" int32_t art_quick_string_compareto(void*, void*); // Invoke entrypoints. +extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called, + mirror::Object* receiver, + mirror::AbstractMethod** sp, Thread* thread); +extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called, + mirror::Object* receiver, + mirror::AbstractMethod** sp, Thread* thread); extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*); extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*); @@ -188,6 +202,10 @@ void InitEntryPoints(EntryPoints* points) { points->pShrLong = art_quick_shr_long; points->pUshrLong = art_quick_ushr_long; + // Interpreter + points->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry; + points->pInterpreterToQuickEntry = artInterpreterToQuickEntry; + // Intrinsics points->pIndexOf = art_quick_indexof; points->pMemcmp16 = __memcmp16; @@ -195,6 +213,8 @@ void InitEntryPoints(EntryPoints* points) { points->pMemcpy = memcpy; // Invocation + points->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline; + points->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline; points->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; points->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; points->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; diff --git a/src/oat/runtime/mips/runtime_support_mips.S b/src/oat/runtime/mips/runtime_support_mips.S index 2eeb662e35..45d583e097 100644 --- a/src/oat/runtime/mips/runtime_support_mips.S +++ b/src/oat/runtime/mips/runtime_support_mips.S @@ -413,71 +413,6 @@ INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvoke INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck /* - * Portable resolution trampoline. - */ - .extern artPortableResolutionTrampoline -ENTRY art_portable_resolution_trampoline - GENERATE_GLOBAL_POINTER - addiu $sp, $sp, -32 # leave room for $a0, $a1, $a2, $a3, and $ra - .cfi_adjust_cfa_offset 32 - sw $ra, 16($sp) - .cfi_rel_offset 31, 16 - sw $a3, 12($sp) - .cfi_rel_offset 7, 12 - sw $a2, 8($sp) - .cfi_rel_offset 6, 8 - sw $a1, 4($sp) - .cfi_rel_offset 5, 4 - sw $a0, 0($sp) - .cfi_rel_offset 4, 0 - move $a3, $s1 # pass Thread::Current() - jal artPortableResolutionTrampoline # (method, receiver, sp, Thread*) - move $a2, $sp # pass stack pointer - lw $a0, 0($sp) # restore registers from stack - lw $a1, 4($sp) - lw $a2, 8($sp) - lw $a3, 12($sp) - lw $ra, 16($sp) - beq $v0, $zero, resolve_fail - addiu $sp, $sp, 32 # restore the stack - .cfi_adjust_cfa_offset -32 - jr $t9 # leaf call to method's code - move $t9, $v0 # put method code result in $t9 -resolve_fail: - jr $ra - nop -END art_portable_resolution_trampoline - - /* - * Quick resolution trampoline. - */ - .extern artQuickResolutionTrampoline -ENTRY art_quick_resolution_trampoline - GENERATE_GLOBAL_POINTER - SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME - move $a3, $s1 # pass Thread::Current() - jal artQuickResolutionTrampoline # (method, receiver, sp, Thread*) - move $a2, $sp # pass stack pointer - move $t9, $v0 # put method code result in $t9 - lw $a0, 0($sp) # restore registers from stack - lw $a1, 4($sp) - lw $a2, 8($sp) - lw $a3, 12($sp) - lw $s2, 28($sp) - lw $s3, 32($sp) - lw $s4, 36($sp) - lw $s5, 40($sp) - lw $s6, 44($sp) - lw $s7, 48($sp) - lw $gp, 52($sp) - lw $fp, 56($sp) - lw $ra, 60($sp) - jr $t9 # leaf call to method's code - addiu $sp, $sp, 64 # restore the stack - .cfi_adjust_cfa_offset -64 -END art_quick_resolution_trampoline - - /* * Common invocation stub for portable and quick. * On entry: * a0 = method pointer diff --git a/src/oat/runtime/oat_support_entrypoints.h b/src/oat/runtime/oat_support_entrypoints.h index 75c93783b5..c1a2587c45 100644 --- a/src/oat/runtime/oat_support_entrypoints.h +++ b/src/oat/runtime/oat_support_entrypoints.h @@ -17,6 +17,7 @@ #ifndef ART_SRC_OAT_RUNTIME_OAT_SUPPORT_ENTRYPOINTS_H_ #define ART_SRC_OAT_RUNTIME_OAT_SUPPORT_ENTRYPOINTS_H_ +#include "dex_file-inl.h" #include "runtime.h" #define ENTRYPOINT_OFFSET(x) \ @@ -30,6 +31,8 @@ class Class; class Object; } // namespace mirror class DvmDex; +class MethodHelper; +class ShadowFrame; class Thread; struct PACKED(4) EntryPoints { @@ -104,6 +107,14 @@ struct PACKED(4) EntryPoints { uint64_t (*pShrLong)(uint64_t, uint32_t); uint64_t (*pUshrLong)(uint64_t, uint32_t); + // Interpreter + void (*pInterpreterToInterpreterEntry)(Thread* self, MethodHelper& mh, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, JValue* result); + void (*pInterpreterToQuickEntry)(Thread* self, MethodHelper& mh, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, JValue* result); + // Intrinsics int32_t (*pIndexOf)(void*, uint32_t, uint32_t, uint32_t); int32_t (*pMemcmp16)(void*, void*, int32_t); @@ -111,6 +122,10 @@ struct PACKED(4) EntryPoints { void* (*pMemcpy)(void*, const void*, size_t); // Invocation + const void* (*pPortableResolutionTrampolineFromCode)(mirror::AbstractMethod*, mirror::Object*, + mirror::AbstractMethod**, Thread*); + const void* (*pQuickResolutionTrampolineFromCode)(mirror::AbstractMethod*, mirror::Object*, + mirror::AbstractMethod**, Thread*); void (*pInvokeDirectTrampolineWithAccessCheck)(uint32_t, void*); void (*pInvokeInterfaceTrampoline)(uint32_t, void*); void (*pInvokeInterfaceTrampolineWithAccessCheck)(uint32_t, void*); diff --git a/src/oat/runtime/support_interpreter.cc b/src/oat/runtime/support_interpreter.cc index 7060a41a6c..55be54f2c2 100644 --- a/src/oat/runtime/support_interpreter.cc +++ b/src/oat/runtime/support_interpreter.cc @@ -110,8 +110,9 @@ extern "C" uint64_t artInterpreterEntry(mirror::AbstractMethod* method, Thread* return result.GetJ(); } -void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item, - ShadowFrame* shadow_frame, JValue* result) +extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, JValue* result) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::AbstractMethod* method = shadow_frame->GetMethod(); uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_; diff --git a/src/oat/runtime/support_stubs.cc b/src/oat/runtime/support_stubs.cc index 97d5f66079..71b67d06bb 100644 --- a/src/oat/runtime/support_stubs.cc +++ b/src/oat/runtime/support_stubs.cc @@ -144,7 +144,7 @@ extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* c // Expect class to at least be initializing. DCHECK(called->GetDeclaringClass()->IsInitializing()); // Don't want infinite recursion. - DCHECK(code != GetResolutionTrampoline()); + DCHECK(code != GetResolutionTrampoline(linker)); // Set up entry into main method *called_addr = called; } @@ -393,7 +393,7 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* call // Expect class to at least be initializing. DCHECK(called->GetDeclaringClass()->IsInitializing()); // Don't want infinite recursion. - DCHECK(code != GetResolutionTrampoline()); + DCHECK(code != GetResolutionTrampoline(linker)); // Set up entry into main method regs[0] = reinterpret_cast<uintptr_t>(called); } diff --git a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc index 357bbe0819..a90a583e9f 100644 --- a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc +++ b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc @@ -75,6 +75,14 @@ extern "C" uint64_t art_quick_lshl_from_code(uint64_t, uint32_t); extern "C" uint64_t art_quick_lshr_from_code(uint64_t, uint32_t); extern "C" uint64_t art_quick_lushr_from_code(uint64_t, uint32_t); +// Interpreter entrypoints. +extern "C" void artInterpreterToInterpreterEntry(Thread* self, MethodHelper& mh, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, JValue* result); +extern "C" void artInterpreterToQuickEntry(Thread* self, MethodHelper& mh, + const DexFile::CodeItem* code_item, + ShadowFrame* shadow_frame, JValue* result); + // Intrinsic entrypoints. extern "C" int32_t art_quick_memcmp16(void*, void*, int32_t); extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t); @@ -82,6 +90,12 @@ extern "C" int32_t art_quick_string_compareto(void*, void*); extern "C" void* art_quick_memcpy(void*, const void*, size_t); // Invoke entrypoints. +extern "C" const void* artPortableResolutionTrampoline(mirror::AbstractMethod* called, + mirror::Object* receiver, + mirror::AbstractMethod** sp, Thread* thread); +extern "C" const void* artQuickResolutionTrampoline(mirror::AbstractMethod* called, + mirror::Object* receiver, + mirror::AbstractMethod** sp, Thread* thread); extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*); extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*); @@ -171,6 +185,10 @@ void InitEntryPoints(EntryPoints* points) { points->pShrLong = art_quick_lshr_from_code; points->pUshrLong = art_quick_lushr_from_code; + // Interpreter + points->pInterpreterToInterpreterEntry = artInterpreterToInterpreterEntry; + points->pInterpreterToQuickEntry = artInterpreterToQuickEntry; + // Intrinsics points->pIndexOf = art_quick_indexof; points->pMemcmp16 = art_quick_memcmp16; @@ -178,6 +196,8 @@ void InitEntryPoints(EntryPoints* points) { points->pMemcpy = art_quick_memcpy; // Invocation + points->pPortableResolutionTrampolineFromCode = artPortableResolutionTrampoline; + points->pQuickResolutionTrampolineFromCode = artQuickResolutionTrampoline; points->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; points->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; points->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; diff --git a/src/oat/runtime/x86/runtime_support_x86.S b/src/oat/runtime/x86/runtime_support_x86.S index 734aad1e3d..ee6db0c3f8 100644 --- a/src/oat/runtime/x86/runtime_support_x86.S +++ b/src/oat/runtime/x86/runtime_support_x86.S @@ -301,56 +301,6 @@ INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvok INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck - /* - * Portable resolution trampoline. - */ -DEFINE_FUNCTION art_portable_resolution_trampoline - PUSH ebp // stash %ebp - movl %esp, %ebp // save %esp - .cfi_def_cfa_register ebp - subl LITERAL(8), %esp // align stack - movl 8(%ebp), %eax // load the called method* into %eax - leal 8(%ebp), %edx // put the called method* address in %edx - pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current() - pushl %edx // pass called method* address - pushl 12(%ebp) // pass receiver - pushl 8(%ebp) // pass method* - call SYMBOL(artPortableResolutionTrampoline) // (method, receiver, sp, Thread*) - leave // restore the stack and %ebp - .cfi_def_cfa esp, 4 - .cfi_restore ebp - cmpl LITERAL(0), %eax // check if returned method code is null - je resolve_fail // if null, jump to return to handle - jmp *%eax // otherwise, tail call to intended method -resolve_fail: - ret -END_FUNCTION art_portable_resolution_trampoline - - /* - * Quick resolution trampoline. - */ -DEFINE_FUNCTION art_quick_resolution_trampoline - SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME - movl %esp, %edx // save stack pointer - pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current() - .cfi_adjust_cfa_offset 4 - PUSH edx // pass stack pointer - PUSH ecx // pass receiver - PUSH eax // pass method* - call SYMBOL(artQuickResolutionTrampoline) // (method_idx, sp, Thread*) - movl %eax, %edi // save returned code pointer in %edi - addl LITERAL(16), %esp // pop arguments - .cfi_adjust_cfa_offset -16 - POP eax // restore registers - POP ecx - POP edx - POP ebx - POP ebp - POP esi - xchgl %edi, (%esp) // swap %edi and code pointer - ret // tail call to intended method -END_FUNCTION art_quick_resolution_trampoline - /* * Portable invocation stub. * On entry: diff --git a/src/oat_test.cc b/src/oat_test.cc index dd336d9a9b..c7c063a9d1 100644 --- a/src/oat_test.cc +++ b/src/oat_test.cc @@ -68,16 +68,16 @@ TEST_F(OatTest, WriteRead) { const bool compile = false; // DISABLED_ due to the time to compile libcore ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - jobject class_loader = NULL; - if (compile) { - // TODO: make selectable + // TODO: make selectable #if defined(ART_USE_PORTABLE_COMPILER) - CompilerBackend compiler_backend = kPortable; + CompilerBackend compiler_backend = kPortable; #else - CompilerBackend compiler_backend = kQuick; + CompilerBackend compiler_backend = kQuick; #endif - compiler_driver_.reset(new CompilerDriver(compiler_backend, kThumb2, false, 2, false, - NULL, true, true)); + compiler_driver_.reset(new CompilerDriver(compiler_backend, kThumb2, false, 2, false, + NULL, true, true)); + jobject class_loader = NULL; + if (compile) { compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath()); } @@ -143,7 +143,7 @@ TEST_F(OatTest, WriteRead) { TEST_F(OatTest, OatHeaderSizeCheck) { // If this test is failing and you have to update these constants, // it is time to update OatHeader::kOatVersion - EXPECT_EQ(36U, sizeof(OatHeader)); + EXPECT_EQ(52U, sizeof(OatHeader)); EXPECT_EQ(28U, sizeof(OatMethodOffsets)); } diff --git a/src/oat_writer.cc b/src/oat_writer.cc index 8acbfe9ca5..a4bd87d4c0 100644 --- a/src/oat_writer.cc +++ b/src/oat_writer.cc @@ -54,13 +54,35 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, uint32_t image_file_location_oat_begin, const std::string& image_file_location, const CompilerDriver* compiler) - : compiler_driver_(compiler) { - image_file_location_oat_checksum_ = image_file_location_oat_checksum; - image_file_location_oat_begin_ = image_file_location_oat_begin; - image_file_location_ = image_file_location; - dex_files_ = &dex_files; - oat_header_ = NULL; - executable_offset_padding_length_ = 0; + : compiler_driver_(compiler), + dex_files_(&dex_files), + image_file_location_oat_checksum_(image_file_location_oat_checksum), + image_file_location_oat_begin_(image_file_location_oat_begin), + image_file_location_(image_file_location), + oat_header_(NULL), + size_dex_file_alignment_(0), + size_executable_offset_alignment_(0), + size_oat_header_(0), + size_oat_header_image_file_location_(0), + size_dex_file_(0), + size_interpreter_to_interpreter_entry_(0), + size_interpreter_to_quick_entry_(0), + size_portable_resolution_trampoline_(0), + size_quick_resolution_trampoline_(0), + size_stubs_alignment_(0), + size_code_size_(0), + size_code_(0), + size_code_alignment_(0), + size_mapping_table_(0), + size_vmap_table_(0), + size_gc_map_(0), + size_oat_dex_file_location_size_(0), + size_oat_dex_file_location_data_(0), + size_oat_dex_file_location_checksum_(0), + size_oat_dex_file_offset_(0), + size_oat_dex_file_methods_offsets_(0), + size_oat_class_status_(0), + size_oat_class_method_offsets_(0) { size_t offset = InitOatHeader(); offset = InitOatDexFiles(offset); @@ -70,6 +92,7 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, offset = InitOatCodeDexFiles(offset); CHECK_EQ(dex_files_->size(), oat_dex_files_.size()); + CHECK(image_file_location.empty() == compiler->IsImage()); } OatWriter::~OatWriter() { @@ -106,7 +129,9 @@ size_t OatWriter::InitDexFiles(size_t offset) { // calculate the offsets within OatDexFiles to the DexFiles for (size_t i = 0; i != dex_files_->size(); ++i) { // dex files are required to be 4 byte aligned + size_t original_offset = offset; offset = RoundUp(offset, 4); + size_dex_file_alignment_ += offset - original_offset; // set offset in OatDexFile to DexFile oat_dex_files_[i]->dex_file_offset_ = offset; @@ -162,7 +187,33 @@ size_t OatWriter::InitOatCode(size_t offset) { // required to be on a new page boundary offset = RoundUp(offset, kPageSize); oat_header_->SetExecutableOffset(offset); - executable_offset_padding_length_ = offset - old_offset; + size_executable_offset_alignment_ = offset - old_offset; + if (compiler_driver_->IsImage()) { + InstructionSet instruction_set = compiler_driver_->GetInstructionSet(); + oat_header_->SetInterpreterToInterpreterEntryOffset(offset); + interpreter_to_interpreter_entry_.reset(compiler_driver_->CreateInterpreterToInterpreterEntry()); + offset += interpreter_to_interpreter_entry_->size(); + + offset = CompiledCode::AlignCode(offset, instruction_set); + oat_header_->SetInterpreterToQuickEntryOffset(offset); + interpreter_to_quick_entry_.reset(compiler_driver_->CreateInterpreterToQuickEntry()); + offset += interpreter_to_quick_entry_->size(); + + offset = CompiledCode::AlignCode(offset, instruction_set); + oat_header_->SetPortableResolutionTrampolineOffset(offset); + portable_resolution_trampoline_.reset(compiler_driver_->CreatePortableResolutionTrampoline()); + offset += portable_resolution_trampoline_->size(); + + offset = CompiledCode::AlignCode(offset, instruction_set); + oat_header_->SetQuickResolutionTrampolineOffset(offset); + quick_resolution_trampoline_.reset(compiler_driver_->CreateQuickResolutionTrampoline()); + offset += quick_resolution_trampoline_->size(); + } else { + oat_header_->SetInterpreterToInterpreterEntryOffset(0); + oat_header_->SetInterpreterToQuickEntryOffset(0); + oat_header_->SetPortableResolutionTrampolineOffset(0); + oat_header_->SetQuickResolutionTrampolineOffset(0); + } return offset; } @@ -389,11 +440,13 @@ bool OatWriter::Write(OutputStream& out) { PLOG(ERROR) << "Failed to write oat header to " << out.GetLocation(); return false; } + size_oat_header_ += sizeof(*oat_header_); if (!out.WriteFully(image_file_location_.data(), image_file_location_.size())) { PLOG(ERROR) << "Failed to write oat header image file location to " << out.GetLocation(); return false; } + size_oat_header_image_file_location_ += image_file_location_.size(); if (!WriteTables(out)) { LOG(ERROR) << "Failed to write oat tables to " << out.GetLocation(); @@ -412,12 +465,64 @@ bool OatWriter::Write(OutputStream& out) { return false; } + LOG(INFO) << "size_dex_file_alignment_=" << size_dex_file_alignment_; + LOG(INFO) << "size_executable_offset_alignment_=" << size_executable_offset_alignment_; + LOG(INFO) << "size_oat_header_=" << size_oat_header_; + LOG(INFO) << "size_oat_header_image_file_location_=" << size_oat_header_image_file_location_; + LOG(INFO) << "size_dex_file_=" << size_dex_file_; + LOG(INFO) << "size_interpreter_to_interpreter_entry_=" << size_interpreter_to_interpreter_entry_; + LOG(INFO) << "size_interpreter_to_quick_entry_=" << size_interpreter_to_quick_entry_; + LOG(INFO) << "size_portable_resolution_trampoline_=" << size_portable_resolution_trampoline_; + LOG(INFO) << "size_quick_resolution_trampoline_=" << size_quick_resolution_trampoline_; + LOG(INFO) << "size_stubs_alignment_=" << size_stubs_alignment_; + LOG(INFO) << "size_code_size_=" << size_code_size_; + LOG(INFO) << "size_code_=" << size_code_; + LOG(INFO) << "size_code_alignment_=" << size_code_alignment_; + LOG(INFO) << "size_mapping_table_=" << size_mapping_table_; + LOG(INFO) << "size_vmap_table_=" << size_vmap_table_; + LOG(INFO) << "size_gc_map_=" << size_gc_map_; + LOG(INFO) << "size_oat_dex_file_location_size_=" << size_oat_dex_file_location_size_; + LOG(INFO) << "size_oat_dex_file_location_data=" << size_oat_dex_file_location_data_; + LOG(INFO) << "size_oat_dex_file_location_checksum_=" << size_oat_dex_file_location_checksum_; + LOG(INFO) << "size_oat_dex_file_offset_=" << size_oat_dex_file_offset_; + LOG(INFO) << "size_oat_dex_file_methods_offsets_=" << size_oat_dex_file_methods_offsets_; + LOG(INFO) << "size_oat_class_status_=" << size_oat_class_status_; + LOG(INFO) << "size_oat_class_method_offsets=" << size_oat_class_method_offsets_; + + uint32_t size_total = + size_dex_file_alignment_ + + size_executable_offset_alignment_ + + size_oat_header_ + + size_oat_header_image_file_location_ + + size_dex_file_ + + size_interpreter_to_interpreter_entry_ + + size_interpreter_to_quick_entry_ + + size_portable_resolution_trampoline_ + + size_quick_resolution_trampoline_ + + size_stubs_alignment_ + + size_code_size_ + + size_code_ + + size_code_alignment_ + + size_mapping_table_ + + size_vmap_table_ + + size_gc_map_ + + size_oat_dex_file_location_size_ + + size_oat_dex_file_location_data_ + + size_oat_dex_file_location_checksum_ + + size_oat_dex_file_offset_ + + size_oat_dex_file_methods_offsets_ + + size_oat_class_status_ + + size_oat_class_method_offsets_; + + LOG(INFO) << "size_total=" << size_total; + DCHECK_EQ(size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent))); + return true; } bool OatWriter::WriteTables(OutputStream& out) { for (size_t i = 0; i != oat_dex_files_.size(); ++i) { - if (!oat_dex_files_[i]->Write(out)) { + if (!oat_dex_files_[i]->Write(this, out)) { PLOG(ERROR) << "Failed to write oat dex information to " << out.GetLocation(); return false; } @@ -436,9 +541,10 @@ bool OatWriter::WriteTables(OutputStream& out) { PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << out.GetLocation(); return false; } + size_dex_file_ += dex_file->GetHeader().file_size_; } for (size_t i = 0; i != oat_classes_.size(); ++i) { - if (!oat_classes_[i]->Write(out)) { + if (!oat_classes_[i]->Write(this, out)) { PLOG(ERROR) << "Failed to write oat methods information to " << out.GetLocation(); return false; } @@ -448,13 +554,59 @@ bool OatWriter::WriteTables(OutputStream& out) { size_t OatWriter::WriteCode(OutputStream& out) { uint32_t offset = oat_header_->GetExecutableOffset(); - off_t new_offset = out.Seek(executable_offset_padding_length_, kSeekCurrent); + off_t new_offset = out.Seek(size_executable_offset_alignment_, kSeekCurrent); if (static_cast<uint32_t>(new_offset) != offset) { PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset << " Expected: " << offset << " File: " << out.GetLocation(); return 0; } DCHECK_OFFSET(); + if (compiler_driver_->IsImage()) { + InstructionSet instruction_set = compiler_driver_->GetInstructionSet(); + if (!out.WriteFully(&(*interpreter_to_interpreter_entry_)[0], interpreter_to_interpreter_entry_->size())) { + PLOG(ERROR) << "Failed to write interpreter to interpreter entry to " << out.GetLocation(); + return false; + } + size_interpreter_to_interpreter_entry_ += interpreter_to_interpreter_entry_->size(); + offset += interpreter_to_interpreter_entry_->size(); + DCHECK_OFFSET(); + + uint32_t aligned_offset = CompiledCode::AlignCode(offset, instruction_set); + uint32_t alignment_padding = aligned_offset - offset; + out.Seek(alignment_padding, kSeekCurrent); + size_stubs_alignment_ += alignment_padding; + if (!out.WriteFully(&(*interpreter_to_quick_entry_)[0], interpreter_to_quick_entry_->size())) { + PLOG(ERROR) << "Failed to write interpreter to quick entry to " << out.GetLocation(); + return false; + } + size_interpreter_to_quick_entry_ += interpreter_to_quick_entry_->size(); + offset += alignment_padding + interpreter_to_quick_entry_->size(); + DCHECK_OFFSET(); + + aligned_offset = CompiledCode::AlignCode(offset, instruction_set); + alignment_padding = aligned_offset - offset; + out.Seek(alignment_padding, kSeekCurrent); + size_stubs_alignment_ += alignment_padding; + if (!out.WriteFully(&(*portable_resolution_trampoline_)[0], portable_resolution_trampoline_->size())) { + PLOG(ERROR) << "Failed to write portable resolution trampoline to " << out.GetLocation(); + return false; + } + size_portable_resolution_trampoline_ += portable_resolution_trampoline_->size(); + offset += alignment_padding + portable_resolution_trampoline_->size(); + DCHECK_OFFSET(); + + aligned_offset = CompiledCode::AlignCode(offset, instruction_set); + alignment_padding = aligned_offset - offset; + out.Seek(alignment_padding, kSeekCurrent); + size_stubs_alignment_ += alignment_padding; + if (!out.WriteFully(&(*quick_resolution_trampoline_)[0], quick_resolution_trampoline_->size())) { + PLOG(ERROR) << "Failed to write quick resolution trampoline to " << out.GetLocation(); + return false; + } + size_quick_resolution_trampoline_ += quick_resolution_trampoline_->size(); + offset += alignment_padding + quick_resolution_trampoline_->size(); + DCHECK_OFFSET(); + } return offset; } @@ -547,6 +699,7 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_c uint32_t aligned_code_delta = aligned_offset - offset; if (aligned_code_delta != 0) { off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent); + size_code_alignment_ += aligned_code_delta; if (static_cast<uint32_t>(new_offset) != aligned_offset) { PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset << " Expected: " << aligned_offset << " File: " << out.GetLocation(); @@ -572,12 +725,14 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_c ReportWriteFailure("method code size", method_idx, dex_file, out); return 0; } + size_code_size_ += sizeof(code_size); offset += sizeof(code_size); DCHECK_OFFSET(); if (!out.WriteFully(&code[0], code_size)) { ReportWriteFailure("method code", method_idx, dex_file, out); return 0; } + size_code_ += code_size; offset += code_size; } DCHECK_OFFSET(); @@ -602,6 +757,7 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_c ReportWriteFailure("mapping table", method_idx, dex_file, out); return 0; } + size_mapping_table_ += mapping_table_size; offset += mapping_table_size; } DCHECK_OFFSET(); @@ -625,6 +781,7 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_c ReportWriteFailure("vmap table", method_idx, dex_file, out); return 0; } + size_vmap_table_ += vmap_table_size; offset += vmap_table_size; } DCHECK_OFFSET(); @@ -648,6 +805,7 @@ size_t OatWriter::WriteCodeMethod(OutputStream& out, size_t offset, size_t oat_c ReportWriteFailure("GC map", method_idx, dex_file, out); return 0; } + size_gc_map_ += gc_map_size; offset += gc_map_size; } DCHECK_OFFSET(); @@ -683,29 +841,35 @@ void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const { sizeof(methods_offsets_[0]) * methods_offsets_.size()); } -bool OatWriter::OatDexFile::Write(OutputStream& out) const { +bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream& out) const { DCHECK_OFFSET_(); if (!out.WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) { PLOG(ERROR) << "Failed to write dex file location length to " << out.GetLocation(); return false; } + oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_); if (!out.WriteFully(dex_file_location_data_, dex_file_location_size_)) { PLOG(ERROR) << "Failed to write dex file location data to " << out.GetLocation(); return false; } + oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_; if (!out.WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) { PLOG(ERROR) << "Failed to write dex file location checksum to " << out.GetLocation(); return false; } + oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_); if (!out.WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) { PLOG(ERROR) << "Failed to write dex file offset to " << out.GetLocation(); return false; } + oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_); if (!out.WriteFully(&methods_offsets_[0], sizeof(methods_offsets_[0]) * methods_offsets_.size())) { PLOG(ERROR) << "Failed to write methods offsets to " << out.GetLocation(); return false; } + oat_writer->size_oat_dex_file_methods_offsets_ += + sizeof(methods_offsets_[0]) * methods_offsets_.size(); return true; } @@ -736,12 +900,13 @@ void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const { sizeof(method_offsets_[0]) * method_offsets_.size()); } -bool OatWriter::OatClass::Write(OutputStream& out) const { +bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream& out) const { DCHECK_OFFSET_(); if (!out.WriteFully(&status_, sizeof(status_))) { PLOG(ERROR) << "Failed to write class status to " << out.GetLocation(); return false; } + oat_writer->size_oat_class_status_ += sizeof(status_); DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(0)), out.Seek(0, kSeekCurrent)); if (!out.WriteFully(&method_offsets_[0], @@ -749,6 +914,7 @@ bool OatWriter::OatClass::Write(OutputStream& out) const { PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation(); return false; } + oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size(); DCHECK_EQ(static_cast<off_t>(GetOatMethodOffsetsOffsetFromOatHeader(method_offsets_.size())), out.Seek(0, kSeekCurrent)); return true; diff --git a/src/oat_writer.h b/src/oat_writer.h index e1d76f459f..b201d6b4ee 100644 --- a/src/oat_writer.h +++ b/src/oat_writer.h @@ -83,7 +83,8 @@ class OatWriter { size_t InitOatDexFiles(size_t offset); size_t InitDexFiles(size_t offset); size_t InitOatClasses(size_t offset); - size_t InitOatCode(size_t offset); + size_t InitOatCode(size_t offset) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); size_t InitOatCodeDexFiles(size_t offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); size_t InitOatCodeDexFile(size_t offset, @@ -120,7 +121,7 @@ class OatWriter { explicit OatDexFile(size_t offset, const DexFile& dex_file); size_t SizeOf() const; void UpdateChecksum(OatHeader& oat_header) const; - bool Write(OutputStream& out) const; + bool Write(OatWriter* oat_writer, OutputStream& out) const; // Offset of start of OatDexFile from beginning of OatHeader. It is // used to validate file position when writing. @@ -144,7 +145,7 @@ class OatWriter { size_t GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const; size_t SizeOf() const; void UpdateChecksum(OatHeader& oat_header) const; - bool Write(OutputStream& out) const; + bool Write(OatWriter* oat_writer, OutputStream& out) const; // Offset of start of OatClass from beginning of OatHeader. It is // used to validate file position when writing. For Portable, it @@ -175,7 +176,35 @@ class OatWriter { OatHeader* oat_header_; std::vector<OatDexFile*> oat_dex_files_; std::vector<OatClass*> oat_classes_; - uint32_t executable_offset_padding_length_; + UniquePtr<const std::vector<uint8_t> > interpreter_to_interpreter_entry_; + UniquePtr<const std::vector<uint8_t> > interpreter_to_quick_entry_; + UniquePtr<const std::vector<uint8_t> > portable_resolution_trampoline_; + UniquePtr<const std::vector<uint8_t> > quick_resolution_trampoline_; + + // output stats + uint32_t size_dex_file_alignment_; + uint32_t size_executable_offset_alignment_; + uint32_t size_oat_header_; + uint32_t size_oat_header_image_file_location_; + uint32_t size_dex_file_; + uint32_t size_interpreter_to_interpreter_entry_; + uint32_t size_interpreter_to_quick_entry_; + uint32_t size_portable_resolution_trampoline_; + uint32_t size_quick_resolution_trampoline_; + uint32_t size_stubs_alignment_; + uint32_t size_code_size_; + uint32_t size_code_; + uint32_t size_code_alignment_; + uint32_t size_mapping_table_; + uint32_t size_vmap_table_; + uint32_t size_gc_map_; + uint32_t size_oat_dex_file_location_size_; + uint32_t size_oat_dex_file_location_data_; + uint32_t size_oat_dex_file_location_checksum_; + uint32_t size_oat_dex_file_offset_; + uint32_t size_oat_dex_file_methods_offsets_; + uint32_t size_oat_class_status_; + uint32_t size_oat_class_method_offsets_; template <class T> struct MapCompare { public: diff --git a/src/oatdump.cc b/src/oatdump.cc index 7a99f8dc0e..538e1bb99a 100644 --- a/src/oatdump.cc +++ b/src/oatdump.cc @@ -880,7 +880,7 @@ class ImageDumper { const void* GetOatCodeBegin(mirror::AbstractMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const void* code = m->GetEntryPointFromCompiledCode(); - if (code == GetResolutionTrampoline()) { + if (code == GetResolutionTrampoline(Runtime::Current()->GetClassLinker())) { code = oat_dumper_->GetOatCode(m); } if (oat_dumper_->GetInstructionSet() == kThumb2) { diff --git a/src/runtime.cc b/src/runtime.cc index 45d2988e97..c21a1c4924 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -1109,7 +1109,9 @@ mirror::AbstractMethod* Runtime::CreateResolutionMethod() { // TODO: use a special method for resolution method saves method->SetDexMethodIndex(DexFile::kDexNoIndex16); // When compiling, the code pointer will get set later when the image is loaded. - method->SetEntryPointFromCompiledCode(Runtime::Current()->IsCompiler() ? NULL : GetResolutionTrampoline()); + Runtime* r = Runtime::Current(); + ClassLinker* cl = r->GetClassLinker(); + method->SetEntryPointFromCompiledCode(r->IsCompiler() ? NULL : GetResolutionTrampoline(cl)); return method.get(); } diff --git a/src/runtime_support.h b/src/runtime_support.h index 5fc8da53b6..094e23a0fd 100644 --- a/src/runtime_support.h +++ b/src/runtime_support.h @@ -34,14 +34,12 @@ extern "C" void art_interpreter_invoke_handler(); extern "C" void art_jni_dlsym_lookup_stub(); extern "C" void art_portable_abstract_method_error_stub(); extern "C" void art_portable_proxy_invoke_handler(); -extern "C" void art_portable_resolution_trampoline(); extern "C" void art_quick_abstract_method_error_stub(); extern "C" void art_quick_deoptimize(); extern "C" void art_quick_instrumentation_entry_from_code(void*); extern "C" void art_quick_instrumentation_exit_from_code(); extern "C" void art_quick_interpreter_entry(void*); extern "C" void art_quick_proxy_invoke_handler(); -extern "C" void art_quick_resolution_trampoline(); extern "C" void art_work_around_app_jni_bugs(); extern "C" double art_l2d(int64_t l); @@ -373,22 +371,20 @@ static inline void* GetInterpreterEntryPoint() { return reinterpret_cast<void*>(art_quick_interpreter_entry); } -// Return address of portable resolution trampoline stub. -static inline void* GetPortableResolutionTrampoline() { - return reinterpret_cast<void*>(art_portable_resolution_trampoline); +static inline const void* GetPortableResolutionTrampoline(ClassLinker* class_linker) { + return class_linker->GetPortableResolutionTrampoline(); } -// Return address of quick resolution trampoline stub. -static inline void* GetQuickResolutionTrampoline() { - return reinterpret_cast<void*>(art_quick_resolution_trampoline); +static inline const void* GetQuickResolutionTrampoline(ClassLinker* class_linker) { + return class_linker->GetQuickResolutionTrampoline(); } // Return address of resolution trampoline stub for defined compiler. -static inline void* GetResolutionTrampoline() { +static inline const void* GetResolutionTrampoline(ClassLinker* class_linker) { #if defined(ART_USE_PORTABLE_COMPILER) - return GetPortableResolutionTrampoline(); + return GetPortableResolutionTrampoline(class_linker); #else - return GetQuickResolutionTrampoline(); + return GetQuickResolutionTrampoline(class_linker); #endif } diff --git a/src/thread.cc b/src/thread.cc index 91f0d7bf00..9e865329f5 100644 --- a/src/thread.cc +++ b/src/thread.cc @@ -1648,6 +1648,8 @@ static const EntryPointInfo gThreadEntryPointInfo[] = { ENTRY_POINT_INFO(pMemcmp16), ENTRY_POINT_INFO(pStringCompareTo), ENTRY_POINT_INFO(pMemcpy), + ENTRY_POINT_INFO(pPortableResolutionTrampolineFromCode), + ENTRY_POINT_INFO(pQuickResolutionTrampolineFromCode), ENTRY_POINT_INFO(pInvokeDirectTrampolineWithAccessCheck), ENTRY_POINT_INFO(pInvokeInterfaceTrampoline), ENTRY_POINT_INFO(pInvokeInterfaceTrampolineWithAccessCheck), |