summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jeff Hao <jeffhao@google.com> 2013-06-03 14:49:28 -0700
committer Jeff Hao <jeffhao@google.com> 2013-06-07 14:43:24 -0700
commit0aba0ba155bef7346bde19e53581200b89ae8a7a (patch)
tree6590f8a50bde7c30b57f1bb0ae67c6d88cea8116
parent515661b14b60ab9684efa1ab1d5124934406094e (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
-rw-r--r--build/Android.common.mk2
-rw-r--r--src/class_linker.cc43
-rw-r--r--src/class_linker.h11
-rw-r--r--src/compiler/driver/compiler_driver.cc61
-rw-r--r--src/compiler/driver/compiler_driver.h10
-rw-r--r--src/compiler/stubs/portable/stubs.cc136
-rw-r--r--src/compiler/stubs/quick/stubs.cc262
-rw-r--r--src/compiler/stubs/stubs.h59
-rw-r--r--src/dex2oat.cc5
-rw-r--r--src/image_test.cc3
-rw-r--r--src/image_writer.cc29
-rw-r--r--src/image_writer.h12
-rw-r--r--src/instrumentation.cc4
-rw-r--r--src/interpreter/interpreter.cc8
-rw-r--r--src/interpreter/interpreter.h6
-rw-r--r--src/mirror/abstract_method-inl.h3
-rw-r--r--src/oat.cc102
-rw-r--r--src/oat.h18
-rw-r--r--src/oat/runtime/arm/oat_support_entrypoints_arm.cc20
-rw-r--r--src/oat/runtime/arm/runtime_support_arm.S42
-rw-r--r--src/oat/runtime/mips/oat_support_entrypoints_mips.cc20
-rw-r--r--src/oat/runtime/mips/runtime_support_mips.S65
-rw-r--r--src/oat/runtime/oat_support_entrypoints.h15
-rw-r--r--src/oat/runtime/support_interpreter.cc5
-rw-r--r--src/oat/runtime/support_stubs.cc4
-rw-r--r--src/oat/runtime/x86/oat_support_entrypoints_x86.cc20
-rw-r--r--src/oat/runtime/x86/runtime_support_x86.S50
-rw-r--r--src/oat_test.cc16
-rw-r--r--src/oat_writer.cc192
-rw-r--r--src/oat_writer.h37
-rw-r--r--src/oatdump.cc2
-rw-r--r--src/runtime.cc4
-rw-r--r--src/runtime_support.h18
-rw-r--r--src/thread.cc2
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),
diff --git a/src/oat.h b/src/oat.h
index cf988918f0..c67a1a6630 100644
--- a/src/oat.h
+++ b/src/oat.h
@@ -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),