summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2011-10-04 19:13:33 -0700
committerIan Rogers <irogers@google.com>2011-10-05 22:40:00 -0700
commitad25ac568407ceb14334e8551dd1c4dd0fd6993c (patch)
treef1e2edb4b87d0b5ce35f94069db2f6cdb77db210
parent8c2f6414e1cff9a024a14369352f7ce112528b9e (diff)
downloadart-ad25ac568407ceb14334e8551dd1c4dd0fd6993c.zip
art-ad25ac568407ceb14334e8551dd1c4dd0fd6993c.tar.gz
art-ad25ac568407ceb14334e8551dd1c4dd0fd6993c.tar.bz2
Static and direct resolution stub.
Ensure that invoke static and direct go through a stub that causes resolution and initialization. Change-Id: I872900560322817d8f4378b04ac410d9ea0b3b17
-rw-r--r--src/asm_support.h6
-rw-r--r--src/class_linker.cc8
-rw-r--r--src/class_linker.h3
-rw-r--r--src/common_test.h4
-rw-r--r--src/compiler.cc58
-rw-r--r--src/compiler.h4
-rw-r--r--src/dex2oat.cc6
-rw-r--r--src/dex_cache.h12
-rw-r--r--src/heap.cc2
-rw-r--r--src/image.h2
-rw-r--r--src/image_writer.cc58
-rw-r--r--src/indirect_reference_table.h8
-rw-r--r--src/oatdump.cc2
-rw-r--r--src/runtime.cc20
-rw-r--r--src/runtime.h6
-rw-r--r--src/runtime_support.cc79
-rw-r--r--src/runtime_support.h1
-rw-r--r--src/space.cc5
-rw-r--r--src/stub_arm.cc40
-rw-r--r--src/stub_x86.cc16
-rw-r--r--src/thread.cc1
-rw-r--r--src/thread.h1
22 files changed, 303 insertions, 39 deletions
diff --git a/src/asm_support.h b/src/asm_support.h
index 1ef10b8..fb2f7cc 100644
--- a/src/asm_support.h
+++ b/src/asm_support.h
@@ -9,13 +9,13 @@
#define rLR r14
#define SUSPEND_CHECK_INTERVAL (1000)
// Offset of field Thread::top_of_managed_stack_ verified in InitCpu
-#define THREAD_TOP_OF_MANAGED_STACK_OFFSET 276
+#define THREAD_TOP_OF_MANAGED_STACK_OFFSET 280
// Offset of field Thread::top_of_managed_stack_pc_ verified in InitCpu
-#define THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET 280
+#define THREAD_TOP_OF_MANAGED_STACK_PC_OFFSET 284
#elif defined(__i386__)
// Offset of field Thread::self_ verified in InitCpu
-#define THREAD_SELF_OFFSET 372
+#define THREAD_SELF_OFFSET 376
#endif
#endif // ART_SRC_ASM_SUPPORT_H_
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 2c69651..ff3c6be 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -2401,6 +2401,14 @@ Field* ClassLinker::ResolveField(const DexFile& dex_file,
return resolved;
}
+const char* ClassLinker::MethodShorty(uint32_t method_idx, Method* referrer) {
+ Class* declaring_class = referrer->GetDeclaringClass();
+ DexCache* dex_cache = declaring_class->GetDexCache();
+ const DexFile& dex_file = FindDexFile(dex_cache);
+ const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx);
+ return dex_file.GetShorty(method_id.proto_idx_);
+}
+
void ClassLinker::DumpAllClasses(int flags) const {
// TODO: at the time this was written, it wasn't safe to call PrettyField with the ClassLinker
// lock held, because it might need to resolve a field's type, which would try to take the lock.
diff --git a/src/class_linker.h b/src/class_linker.h
index 7f08a9b..75eefc9 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -155,6 +155,9 @@ class ClassLinker {
const ClassLoader* class_loader,
bool is_static);
+ // Get shorty from method index without resolution. Used to do handlerization.
+ const char* MethodShorty(uint32_t method_idx, Method* referrer);
+
// Returns true on success, false if there's an exception pending.
// can_run_clinit=false allows the compiler to attempt to init a class,
// given the restriction that no <clinit> execution is possible.
diff --git a/src/common_test.h b/src/common_test.h
index b321071..68e3019 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -130,12 +130,16 @@ class CommonTest : public testing::Test {
#if defined(__i386__)
runtime_->SetJniStubArray(JniCompiler::CreateJniStub(kX86));
runtime_->SetAbstractMethodErrorStubArray(Compiler::CreateAbstractMethodErrorStub(kX86));
+ runtime_->SetResolutionStubArray(Compiler::CreateResolutionStub(kX86, false), false);
+ runtime_->SetResolutionStubArray(Compiler::CreateResolutionStub(kX86, true), true);
runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(kX86));
compiler_.reset(new Compiler(kX86));
#elif defined(__arm__)
runtime_->SetJniStubArray(JniCompiler::CreateJniStub(kThumb2));
runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(kThumb2));
runtime_->SetAbstractMethodErrorStubArray(Compiler::CreateAbstractMethodErrorStub(kThumb2));
+ runtime_->SetResolutionStubArray(Compiler::CreateResolutionStub(kThumb2, false), false);
+ runtime_->SetResolutionStubArray(Compiler::CreateResolutionStub(kThumb2, true), true);
compiler_.reset(new Compiler(kThumb2));
#endif
diff --git a/src/compiler.cc b/src/compiler.cc
index af5cdd6..c6705a6 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -18,23 +18,13 @@ namespace art {
namespace arm {
ByteArray* CreateAbstractMethodErrorStub();
+ void ArmCreateInvokeStub(Method* method);
+ ByteArray* ArmCreateResolutionTrampoline(bool is_static);
}
-
namespace x86 {
ByteArray* CreateAbstractMethodErrorStub();
-}
-
-ByteArray* Compiler::CreateAbstractMethodErrorStub(InstructionSet instruction_set) {
- switch (instruction_set) {
- case kArm:
- case kThumb2:
- return arm::CreateAbstractMethodErrorStub();
- case kX86:
- return x86::CreateAbstractMethodErrorStub();
- default:
- LOG(FATAL) << "Unknown InstructionSet " << (int) instruction_set;
- return NULL;
- }
+ void X86CreateInvokeStub(Method* method);
+ ByteArray* X86CreateResolutionTrampoline(bool is_static);
}
Compiler::Compiler(InstructionSet insns) : instruction_set_(insns), jni_compiler_(insns),
@@ -42,6 +32,26 @@ Compiler::Compiler(InstructionSet insns) : instruction_set_(insns), jni_compiler
CHECK(!Runtime::Current()->IsStarted());
}
+ByteArray* Compiler::CreateResolutionStub(InstructionSet instruction_set, bool is_static) {
+ if (instruction_set == kX86) {
+ return x86::X86CreateResolutionTrampoline(is_static);
+ } else {
+ CHECK(instruction_set == kArm || instruction_set == kThumb2);
+ // Generates resolution stub using ARM instruction set
+ return arm::ArmCreateResolutionTrampoline(is_static);
+ }
+}
+
+ByteArray* Compiler::CreateAbstractMethodErrorStub(InstructionSet instruction_set) {
+ if (instruction_set == kX86) {
+ return x86::CreateAbstractMethodErrorStub();
+ } else {
+ CHECK(instruction_set == kArm || instruction_set == kThumb2);
+ // Generates resolution stub using ARM instruction set
+ return arm::CreateAbstractMethodErrorStub();
+ }
+}
+
void Compiler::CompileAll(const ClassLoader* class_loader) {
DCHECK(!Runtime::Current()->IsStarted());
Resolve(class_loader);
@@ -265,13 +275,6 @@ void Compiler::CompileClass(Class* klass) {
}
}
-namespace arm {
- void ArmCreateInvokeStub(Method* method);
-}
-namespace x86 {
- void X86CreateInvokeStub(Method* method);
-}
-
void Compiler::CompileMethod(Method* method) {
if (method->IsNative()) {
jni_compiler_.Compile(method);
@@ -313,13 +316,20 @@ void Compiler::SetCodeAndDirectMethods(const ClassLoader* class_loader) {
}
void Compiler::SetCodeAndDirectMethodsDexFile(const DexFile& dex_file) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Runtime* runtime = Runtime::Current();
+ ClassLinker* class_linker = runtime->GetClassLinker();
DexCache* dex_cache = class_linker->FindDexCache(dex_file);
CodeAndDirectMethods* code_and_direct_methods = dex_cache->GetCodeAndDirectMethods();
for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) {
Method* method = dex_cache->GetResolvedMethod(i);
- if (method == NULL) {
- code_and_direct_methods->SetResolvedDirectMethodTrampoline(i);
+ if ((method == NULL) || (method->IsStatic() && !method->GetDeclaringClass()->IsInitialized())) {
+ ByteArray* res_trampoline = runtime->GetResolutionStubArray(method->IsStatic());
+ if (instruction_set_ == kX86) {
+ code_and_direct_methods->SetResolvedDirectMethodTrampoline(i, res_trampoline, kX86);
+ } else {
+ CHECK(instruction_set_ == kArm || instruction_set_ == kThumb2);
+ code_and_direct_methods->SetResolvedDirectMethodTrampoline(i, res_trampoline, kArm);
+ }
} else if (method->IsDirect()) {
code_and_direct_methods->SetResolvedDirectMethod(i, method);
} else {
diff --git a/src/compiler.h b/src/compiler.h
index f9a5c29..3b316eb 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -31,9 +31,11 @@ class Compiler {
}
// Stub to throw AbstractMethodError
- // TODO: remove from Compiler
static ByteArray* CreateAbstractMethodErrorStub(InstructionSet instruction_set);
+ // Generate the trampoline that's invoked by unresolved direct methods
+ static ByteArray* CreateResolutionStub(InstructionSet instruction_set, bool is_static);
+
private:
// Attempt to resolve all type, methods, fields, and strings
// referenced from code in the dex file following PathClassLoader
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index d34a681..1ad71a6 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -200,6 +200,12 @@ int dex2oat(int argc, char** argv) {
if (!runtime->HasAbstractMethodErrorStubArray()) {
runtime->SetAbstractMethodErrorStubArray(Compiler::CreateAbstractMethodErrorStub(kThumb2));
}
+ if (!runtime->HasResolutionStubArray(false)) {
+ runtime->SetResolutionStubArray(Compiler::CreateResolutionStub(kThumb2,false), false);
+ }
+ if (!runtime->HasResolutionStubArray(true)) {
+ runtime->SetResolutionStubArray(Compiler::CreateResolutionStub(kThumb2,true), true);
+ }
if (!runtime->HasCalleeSaveMethod()) {
runtime->SetCalleeSaveMethod(runtime->CreateCalleeSaveMethod(kThumb2));
}
diff --git a/src/dex_cache.h b/src/dex_cache.h
index a75d6f4..7ca6825 100644
--- a/src/dex_cache.h
+++ b/src/dex_cache.h
@@ -26,9 +26,15 @@ class MANAGED CodeAndDirectMethods : public IntArray {
return reinterpret_cast<Method*>(Get(MethodIndex(method_idx)));
}
- void SetResolvedDirectMethodTrampoline(uint32_t method_idx) {
- UNIMPLEMENTED(WARNING) << "need to install a trampoline to resolve the method_idx at runtime";
- Set(CodeIndex(method_idx), 0xffffffff);
+ void SetResolvedDirectMethodTrampoline(uint32_t method_idx, ByteArray* code_array,
+ InstructionSet instruction_set) {
+ DCHECK(code_array != NULL);
+ int32_t code = reinterpret_cast<int32_t>(code_array->GetData());
+ if (instruction_set == kThumb2) {
+ // Set the low-order bit so a BLX will switch to Thumb mode
+ code = code | 0x1;
+ }
+ Set(CodeIndex(method_idx), code);
Set(MethodIndex(method_idx), method_idx);
}
diff --git a/src/heap.cc b/src/heap.cc
index 17b3f58..98552a7 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -207,7 +207,7 @@ void Heap::VerifyObjectLocked(const Object* obj) {
LOG(FATAL) << "Class of object is dead: " << c << " in object: " << obj;
}
// Check obj.getClass().getClass() == obj.getClass().getClass().getClass()
- // NB we don't use the accessors here as they have internal sanity checks
+ // Note: we don't use the accessors here as they have internal sanity checks
// that we don't want to run
raw_addr = reinterpret_cast<const byte*>(c) +
Object::ClassOffset().Int32Value();
diff --git a/src/image.h b/src/image.h
index a15ead7..a5cdeb7 100644
--- a/src/image.h
+++ b/src/image.h
@@ -68,6 +68,8 @@ class PACKED ImageHeader {
enum ImageRoot {
kJniStubArray,
kAbstractMethodErrorStubArray,
+ kInstanceResolutionStubArray,
+ kStaticResolutionStubArray,
kCalleeSaveMethod,
kOatLocation,
kDexCaches,
diff --git a/src/image_writer.cc b/src/image_writer.cc
index f223136..c020a79 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -137,12 +137,12 @@ ObjectArray<Object>* ImageWriter::CreateImageRoots() const {
// build an Object[] of the roots needed to restore the runtime
ObjectArray<Object>* image_roots = ObjectArray<Object>::Alloc(object_array_class,
ImageHeader::kImageRootsMax);
- image_roots->Set(ImageHeader::kJniStubArray,
- runtime->GetJniStubArray());
+ image_roots->Set(ImageHeader::kJniStubArray, runtime->GetJniStubArray());
image_roots->Set(ImageHeader::kAbstractMethodErrorStubArray,
runtime->GetAbstractMethodErrorStubArray());
- image_roots->Set(ImageHeader::kCalleeSaveMethod,
- runtime->GetCalleeSaveMethod());
+ image_roots->Set(ImageHeader::kInstanceResolutionStubArray, runtime->GetResolutionStubArray(false));
+ image_roots->Set(ImageHeader::kStaticResolutionStubArray, runtime->GetResolutionStubArray(true));
+ image_roots->Set(ImageHeader::kCalleeSaveMethod, runtime->GetCalleeSaveMethod());
image_roots->Set(ImageHeader::kOatLocation,
String::AllocFromModifiedUtf8(oat_file_->GetLocation().c_str()));
image_roots->Set(ImageHeader::kDexCaches,
@@ -351,14 +351,58 @@ void ImageWriter::FixupDexCache(const DexCache* orig, DexCache* copy) {
CHECK(orig != NULL);
CHECK(copy != NULL);
+ // The original array value
CodeAndDirectMethods* orig_cadms = orig->GetCodeAndDirectMethods();
+ // The compacted object in local memory but not at the correct image address
CodeAndDirectMethods* copy_cadms = down_cast<CodeAndDirectMethods*>(GetLocalAddress(orig_cadms));
+ // The lazy resolution stub
+ ByteArray* orig_res_stub_array[2];
+ orig_res_stub_array[0] = Runtime::Current()->GetResolutionStubArray(false);
+ orig_res_stub_array[1] = Runtime::Current()->GetResolutionStubArray(true);
+ DCHECK(orig_res_stub_array[0] != NULL);
+ DCHECK(orig_res_stub_array[1] != NULL);
+ uint32_t orig_res_stub_array_data[2];
+ orig_res_stub_array_data[0] = reinterpret_cast<uint32_t>(orig_res_stub_array[0]->GetData());
+ orig_res_stub_array_data[1] = reinterpret_cast<uint32_t>(orig_res_stub_array[1]->GetData());
+
for (size_t i = 0; i < orig->NumResolvedMethods(); i++) {
Method* orig_method = orig->GetResolvedMethod(i);
+ if (orig_method != NULL && !InSourceSpace(orig_method)) {
+ continue;
+ }
// if it was resolved in the original, resolve it in the copy
- if (orig_method != NULL
- && InSourceSpace(orig_method)
- && orig_method == orig_cadms->GetResolvedMethod(i)) {
+ if (orig_method == NULL || (orig_method->IsStatic() &&
+ !orig_method->GetDeclaringClass()->IsInitialized())) {
+ // Do we need to relocate this for this space?
+ if (InSourceSpace(orig_res_stub_array[0])) {
+ bool is_static; // is this static? hard to tell for null methods
+ uint32_t orig_res_stub_code = orig_cadms->Get(CodeAndDirectMethods::CodeIndex(i));
+ if (orig_res_stub_code == 0) {
+ continue; // NULL maps the same in the image and the original
+ }
+ if (orig_res_stub_code - orig_res_stub_array_data[0] < 1) {
+ DCHECK(orig_method == NULL || !orig_method->IsStatic());
+ is_static = false;
+ } else {
+ DCHECK(orig_method == NULL || orig_method->IsStatic());
+ is_static = true;
+ }
+ // Compute the delta from the start of the resolution stub to its starting code.
+ // For ARM and X86 this is 0, for Thumb2 it is 1.
+ static size_t res_stub_delta = 0xFFFF;
+ if (res_stub_delta == 0xFFFF) {
+ res_stub_delta = orig_res_stub_code - orig_res_stub_array_data[is_static ? 1 : 0];
+ DCHECK(res_stub_delta == 0 || res_stub_delta == 1);
+ }
+ // Compute address in image of resolution stub and the code address
+ ByteArray* image_res_stub_array =
+ down_cast<ByteArray*>(GetImageAddress(orig_res_stub_array[is_static ? 1 : 0]));
+ int32_t image_res_stub_code =
+ reinterpret_cast<int32_t>(image_res_stub_array->GetData()) + res_stub_delta;
+ // Put the image code address in the array
+ copy_cadms->Set(CodeAndDirectMethods::CodeIndex(i), image_res_stub_code);
+ }
+ } else if (orig_method->IsDirect()) {
Method* copy_method = down_cast<Method*>(GetLocalAddress(orig_method));
copy_cadms->Set(CodeAndDirectMethods::CodeIndex(i),
reinterpret_cast<int32_t>(copy_method->code_));
diff --git a/src/indirect_reference_table.h b/src/indirect_reference_table.h
index 5595ae7..5dca3d3 100644
--- a/src/indirect_reference_table.h
+++ b/src/indirect_reference_table.h
@@ -310,6 +310,14 @@ class IndirectReferenceTable {
void VisitRoots(Heap::RootVisitor* visitor, void* arg);
+ uint32_t GetSegmentState() const {
+ return segment_state_.all;
+ }
+
+ void SetSegmentState(uint32_t new_state) {
+ segment_state_.all = new_state;
+ }
+
static Offset SegmentStateOffset() {
return Offset(OFFSETOF_MEMBER(IndirectReferenceTable, segment_state_));
}
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 3856f34..529f8e2 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -48,6 +48,8 @@ static void usage() {
const char* image_roots_descriptions_[] = {
"kJniStubArray",
"kAbstractMethodErrorStubArray",
+ "kInstanceResolutionStubArray",
+ "kStaticResolutionStubArray",
"kCalleeSaveMethod",
"kOatLocation",
"kDexCaches",
diff --git a/src/runtime.cc b/src/runtime.cc
index a874464..231c010 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -42,6 +42,8 @@ Runtime::Runtime()
exit_(NULL),
abort_(NULL),
stats_enabled_(false) {
+ resolution_stub_array_[0] = NULL;
+ resolution_stub_array_[1] = NULL;
}
Runtime::~Runtime() {
@@ -550,6 +552,8 @@ void Runtime::VisitRoots(Heap::RootVisitor* visitor, void* arg) const {
thread_list_->VisitRoots(visitor, arg);
visitor(jni_stub_array_, arg);
visitor(abstract_method_error_stub_array_, arg);
+ visitor(resolution_stub_array_[0], arg);
+ visitor(resolution_stub_array_[1], arg);
visitor(callee_save_method_, arg);
//(*visitor)(&gDvm.outOfMemoryObj, 0, ROOT_VM_INTERNAL, arg);
@@ -588,6 +592,22 @@ void Runtime::SetAbstractMethodErrorStubArray(ByteArray* abstract_method_error_s
abstract_method_error_stub_array_ = abstract_method_error_stub_array;
}
+bool Runtime::HasResolutionStubArray(bool is_static) const {
+ return resolution_stub_array_[is_static ? 1 : 0] != NULL;
+}
+
+ByteArray* Runtime::GetResolutionStubArray(bool is_static) const {
+ CHECK(HasResolutionStubArray(is_static));
+ return resolution_stub_array_[is_static ? 1 : 0];
+}
+
+void Runtime::SetResolutionStubArray(ByteArray* resolution_stub_array, bool is_static) {
+ CHECK(resolution_stub_array != NULL);
+ CHECK(!HasResolutionStubArray(is_static) ||
+ resolution_stub_array_[is_static ? 1 : 0] == resolution_stub_array);
+ resolution_stub_array_[is_static ? 1 : 0] = resolution_stub_array;
+}
+
Method* Runtime::CreateCalleeSaveMethod(InstructionSet insns) {
Class* method_class = Method::GetMethodClass();
Method* method = down_cast<Method*>(method_class->AllocObject());
diff --git a/src/runtime.h b/src/runtime.h
index 8252a60..f99d994 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -156,6 +156,10 @@ class Runtime {
ByteArray* GetAbstractMethodErrorStubArray() const;
void SetAbstractMethodErrorStubArray(ByteArray* abstract_method_error_stub_array);
+ bool HasResolutionStubArray(bool is_static) const;
+ ByteArray* GetResolutionStubArray(bool is_static) const;
+ void SetResolutionStubArray(ByteArray* resolution_stub_array, bool is_static);
+
// Returns a special method that describes all callee saves being spilled to the stack.
Method* CreateCalleeSaveMethod(InstructionSet insns);
bool HasCalleeSaveMethod() const;
@@ -221,6 +225,8 @@ class Runtime {
ByteArray* abstract_method_error_stub_array_;
+ ByteArray* resolution_stub_array_[2];
+
Method* callee_save_method_;
bool started_;
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 039a749..2bcd7d9 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -309,6 +309,85 @@ extern "C" void artThrowNegArraySizeFromCode(int32_t size, Thread* thread, Metho
thread->DeliverException();
}
+void* UnresolvedDirectMethodTrampolineFromCode(int32_t method_idx, void* sp, Thread* thread,
+ bool is_static) {
+ // TODO: this code is specific to ARM
+ // On entry the stack pointed by sp is:
+ // | argN | |
+ // | ... | |
+ // | arg4 | |
+ // | arg3 spill | | Caller's frame
+ // | arg2 spill | |
+ // | arg1 spill | |
+ // | Method* | ---
+ // | LR |
+ // | R3 | arg3
+ // | R2 | arg2
+ // | R1 | arg1
+ // | R0 | <- sp
+ uintptr_t* regs = reinterpret_cast<uintptr_t*>(sp);
+ Method** caller_sp = reinterpret_cast<Method**>(&regs[5]);
+ // Record the last top of the managed stack
+ thread->SetTopOfStack(caller_sp, regs[4]);
+ ClassLinker* linker = Runtime::Current()->GetClassLinker();
+ // Start new JNI local reference state
+ JNIEnvExt* env = thread->GetJniEnv();
+ uint32_t saved_local_ref_cookie = env->local_ref_cookie;
+ env->local_ref_cookie = env->locals.GetSegmentState();
+ // Discover shorty (avoid GCs)
+ const char* shorty = linker->MethodShorty(method_idx, *caller_sp);
+ size_t shorty_len = strlen(shorty);
+ size_t args_in_regs = shorty_len < 3 ? shorty_len : 3;
+ // Handlerize references in registers
+ int cur_arg = 1; // skip method_idx in R0, first arg is in R1
+ if (!is_static) {
+ Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
+ cur_arg++;
+ AddLocalReference<jobject>(env, obj);
+ }
+ for(size_t i = 0; i < args_in_regs; i++) {
+ char c = shorty[i + 1]; // offset to skip return value
+ if (c == 'L') {
+ Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
+ AddLocalReference<jobject>(env, obj);
+ }
+ cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
+ }
+ // Handlerize references in out going arguments
+ for(size_t i = 3; i < shorty_len; i++) {
+ char c = shorty[i + 1]; // offset to skip return value
+ if (c == 'L') {
+ Object* obj = reinterpret_cast<Object*>(regs[i + 3]); // skip R0, LR and Method* of caller
+ AddLocalReference<jobject>(env, obj);
+ }
+ cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
+ }
+ // Resolve method filling in dex cache
+ Method* called = linker->ResolveMethod(method_idx, *caller_sp, true);
+ if (!thread->IsExceptionPending()) {
+ // We got this far, ensure that the declaring class is initialized
+ linker->EnsureInitialized(called->GetDeclaringClass(), true);
+ }
+ // Restore JNI env state
+ env->locals.SetSegmentState(env->local_ref_cookie);
+ env->local_ref_cookie = saved_local_ref_cookie;
+
+ void* code;
+ if (thread->IsExceptionPending()) {
+ // Something went wrong, go into deliver exception with the pending exception in r0
+ code = reinterpret_cast<void*>(art_deliver_exception_from_code);
+ regs[0] = reinterpret_cast<uintptr_t>(thread->GetException());
+ thread->ClearException();
+ } else {
+ // Expect class to at least be initializing
+ CHECK(called->GetDeclaringClass()->IsInitializing());
+ // Set up entry into main method
+ regs[0] = reinterpret_cast<uintptr_t>(called);
+ code = const_cast<void*>(called->GetCode());
+ }
+ return code;
+}
+
// TODO: placeholder. Helper function to type
Class* InitializeTypeFromCode(uint32_t type_idx, Method* method) {
/*
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 740047d..78a5813 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -14,6 +14,7 @@ extern void DebugMe(Method* method, uint32_t info);
extern Object* DecodeJObjectInThread(Thread* thread, jobject obj);
extern void* FindNativeMethod(Thread* thread);
extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp);
+void* UnresolvedDirectMethodTrampolineFromCode(int32_t, void*, Thread*, bool);
extern Class* InitializeTypeFromCode(uint32_t type_idx, Method* method);
extern void ResolveMethodFromCode(Method* method, uint32_t method_idx);
extern void LockObjectFromCode(Thread* thread, Object* obj);
diff --git a/src/space.cc b/src/space.cc
index 911e49d..1852b0d 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -134,6 +134,11 @@ bool Space::InitFromImage(const std::string& image_file_name) {
Object* ame_stub_array = image_header.GetImageRoot(ImageHeader::kAbstractMethodErrorStubArray);
Runtime::Current()->SetAbstractMethodErrorStubArray(down_cast<ByteArray*>(ame_stub_array));
+ Object* resolution_stub_array = image_header.GetImageRoot(ImageHeader::kInstanceResolutionStubArray);
+ Runtime::Current()->SetResolutionStubArray(down_cast<ByteArray*>(resolution_stub_array), false);
+ resolution_stub_array = image_header.GetImageRoot(ImageHeader::kStaticResolutionStubArray);
+ Runtime::Current()->SetResolutionStubArray(down_cast<ByteArray*>(resolution_stub_array), true);
+
Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
Runtime::Current()->SetCalleeSaveMethod(down_cast<Method*>(callee_save_method));
diff --git a/src/stub_arm.cc b/src/stub_arm.cc
index 75d60f5..772950c 100644
--- a/src/stub_arm.cc
+++ b/src/stub_arm.cc
@@ -9,6 +9,46 @@
namespace art {
namespace arm {
+ByteArray* ArmCreateResolutionTrampoline(bool is_static) {
+ UniquePtr<ArmAssembler> assembler( static_cast<ArmAssembler*>(Assembler::Create(kArm)) );
+ RegList save = (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3) | (1 << LR);
+
+ // | Out args |
+ // | Method* | <- SP on entry
+ // | LR | return address into caller
+ // | R3 | possible argument
+ // | R2 | possible argument
+ // | R1 | possible argument
+ // | R0 | method index (loaded from code and method array - will be converted to Method*)
+ __ PushList(save);
+ __ mov(R1, ShifterOperand(SP)); // Pass address of saved R0... in R1
+ __ LoadFromOffset(kLoadWord, R12, TR,
+ OFFSETOF_MEMBER(Thread, pUnresolvedDirectMethodTrampolineFromCode));
+ __ mov(R2, ShifterOperand(TR)); // Pass Thread::Current() in R2
+ __ LoadImmediate(R3, is_static ? 1 : 0);
+ __ IncreaseFrameSize(12); // 3 words of space for alignment
+ // Call to unresolved direct method trampoline (method_idx, sp, Thread*, is_static)
+ __ blx(R12);
+ // Save code address returned into R12
+ __ mov(R12, ShifterOperand(R0));
+ // Restore registers which may have been modified by GC and R0 which will now hold the method*
+ __ DecreaseFrameSize(12);
+ __ PopList(save);
+ // Leaf call to method's code
+ __ mov(PC, ShifterOperand(R12));
+
+ __ bkpt(0);
+
+ assembler->EmitSlowPaths();
+ size_t cs = assembler->CodeSize();
+ ByteArray* resolution_trampoline = ByteArray::Alloc(cs);
+ CHECK(resolution_trampoline != NULL);
+ MemoryRegion code(resolution_trampoline->GetData(), resolution_trampoline->GetLength());
+ assembler->FinalizeInstructions(code);
+
+ return resolution_trampoline;
+}
+
typedef void (*ThrowAme)(Method*, Thread*);
ByteArray* CreateAbstractMethodErrorStub() {
diff --git a/src/stub_x86.cc b/src/stub_x86.cc
index 13f9c07..e4a56a7 100644
--- a/src/stub_x86.cc
+++ b/src/stub_x86.cc
@@ -9,6 +9,22 @@
namespace art {
namespace x86 {
+ByteArray* X86CreateResolutionTrampoline(bool) {
+ UniquePtr<X86Assembler> assembler( static_cast<X86Assembler*>(Assembler::Create(kX86)) );
+
+ // TODO: unimplemented
+ __ int3();
+
+ assembler->EmitSlowPaths();
+ size_t cs = assembler->CodeSize();
+ ByteArray* resolution_trampoline = ByteArray::Alloc(cs);
+ CHECK(resolution_trampoline != NULL);
+ MemoryRegion code(resolution_trampoline->GetData(), resolution_trampoline->GetLength());
+ assembler->FinalizeInstructions(code);
+
+ return resolution_trampoline;
+}
+
typedef void (*ThrowAme)(Method*, Thread*);
ByteArray* CreateAbstractMethodErrorStub() {
diff --git a/src/thread.cc b/src/thread.cc
index 90c172e..e4281a0 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -125,6 +125,7 @@ void Thread::InitFunctionPointers() {
#endif
pDeliverException = art_deliver_exception_from_code;
pThrowAbstractMethodErrorFromCode = ThrowAbstractMethodErrorFromCode;
+ pUnresolvedDirectMethodTrampolineFromCode = UnresolvedDirectMethodTrampolineFromCode;
pF2l = F2L;
pD2l = D2L;
pMemcpy = memcpy;
diff --git a/src/thread.h b/src/thread.h
index 4b42a00..d1da623 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -116,6 +116,7 @@ class PACKED Thread {
int (*pIdiv)(int, int);
long long (*pLmul)(long long, long long);
long long (*pLdivmod)(long long, long long);
+ void* (*pUnresolvedDirectMethodTrampolineFromCode)(int32_t, void*, Thread*, bool);
void* (*pAllocObjectFromCode)(uint32_t, void*);
void* (*pAllocArrayFromCode)(uint32_t, void*, int32_t);
void* (*pCheckAndAllocArrayFromCode)(uint32_t, void*, int32_t);