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
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 9faf3de..0fae424 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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 79fa8ba..eab1fcc 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -334,6 +334,14 @@
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 @@
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 1b8f87d..834be64 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 @@
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 9fd3c81..4f77bdb 100644
--- a/src/compiler/driver/compiler_driver.h
+++ b/src/compiler/driver/compiler_driver.h
@@ -98,6 +98,16 @@
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 0000000..db551bf
--- /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 0000000..a8e691f
--- /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 0000000..ebe761d
--- /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 3f13d59..2f3edc4 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -280,9 +280,8 @@
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 8066a90..cd1a34f 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -48,7 +48,8 @@
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 12b756e..4eea1ca 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -81,6 +81,10 @@
}
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 @@
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 0cccf69..1de3149 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -39,7 +39,9 @@
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 @@
// 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 39fd377..8af0885 100644
--- a/src/instrumentation.cc
+++ b/src/instrumentation.cc
@@ -62,7 +62,7 @@
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 @@
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 94237a0..c7b9c58 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -133,7 +133,7 @@
}
} 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 @@
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 bae3b65..20166ac 100644
--- a/src/interpreter/interpreter.h
+++ b/src/interpreter/interpreter.h
@@ -47,9 +47,9 @@
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 d4f0f2c..a823886 100644
--- a/src/mirror/abstract_method-inl.h
+++ b/src/mirror/abstract_method-inl.h
@@ -117,7 +117,8 @@
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 4eb97f5..e606953 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 @@
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 @@
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 @@
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),
diff --git a/src/oat.h b/src/oat.h
index cf98891..c67a1a6 100644
--- a/src/oat.h
+++ b/src/oat.h
@@ -43,8 +43,20 @@
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 @@
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 1a5fe47..2e9453c 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_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 @@
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 @@
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 b8d2265..f19e8ba 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_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 eb82c42..8e06611 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_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 @@
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 @@
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 2eeb662..45d583e 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_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 75c9378..c1a2587 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 Object;
} // namespace mirror
class DvmDex;
+class MethodHelper;
+class ShadowFrame;
class Thread;
struct PACKED(4) EntryPoints {
@@ -104,6 +107,14 @@
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 @@
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 7060a41..55be54f 100644
--- a/src/oat/runtime/support_interpreter.cc
+++ b/src/oat/runtime/support_interpreter.cc
@@ -110,8 +110,9 @@
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 97d5f66..71b67d0 100644
--- a/src/oat/runtime/support_stubs.cc
+++ b/src/oat/runtime/support_stubs.cc
@@ -144,7 +144,7 @@
// 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 @@
// 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 357bbe0..a90a583 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_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" 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 @@
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 @@
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 734aad1..ee6db0c 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_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 dd336d9..c7c063a 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -68,16 +68,16 @@
const bool compile = false; // DISABLED_ due to the time to compile libcore
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ // TODO: make selectable
+#if defined(ART_USE_PORTABLE_COMPILER)
+ CompilerBackend compiler_backend = kPortable;
+#else
+ CompilerBackend compiler_backend = kQuick;
+#endif
+ compiler_driver_.reset(new CompilerDriver(compiler_backend, kThumb2, false, 2, false,
+ NULL, true, true));
jobject class_loader = NULL;
if (compile) {
- // TODO: make selectable
-#if defined(ART_USE_PORTABLE_COMPILER)
- CompilerBackend compiler_backend = kPortable;
-#else
- CompilerBackend compiler_backend = kQuick;
-#endif
- compiler_driver_.reset(new CompilerDriver(compiler_backend, kThumb2, false, 2, false,
- NULL, true, true));
compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath());
}
@@ -143,7 +143,7 @@
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 8acbfe9..a4bd87d 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -54,13 +54,35 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 e1d76f4..b201d6b 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -83,7 +83,8 @@
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 @@
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 @@
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 @@
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 7a99f8d..538e1bb 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -880,7 +880,7 @@
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 45d2988..c21a1c4 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -1109,7 +1109,9 @@
// 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 5fc8da5..094e23a 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -34,14 +34,12 @@
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 @@
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 91f0d7b..9e86532 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1648,6 +1648,8 @@
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),