diff options
author | Ian Rogers <irogers@google.com> | 2011-10-04 19:13:33 -0700 |
---|---|---|
committer | Ian Rogers <irogers@google.com> | 2011-10-05 22:40:00 -0700 |
commit | ad25ac568407ceb14334e8551dd1c4dd0fd6993c (patch) | |
tree | f1e2edb4b87d0b5ce35f94069db2f6cdb77db210 | |
parent | 8c2f6414e1cff9a024a14369352f7ce112528b9e (diff) | |
download | art-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.h | 6 | ||||
-rw-r--r-- | src/class_linker.cc | 8 | ||||
-rw-r--r-- | src/class_linker.h | 3 | ||||
-rw-r--r-- | src/common_test.h | 4 | ||||
-rw-r--r-- | src/compiler.cc | 58 | ||||
-rw-r--r-- | src/compiler.h | 4 | ||||
-rw-r--r-- | src/dex2oat.cc | 6 | ||||
-rw-r--r-- | src/dex_cache.h | 12 | ||||
-rw-r--r-- | src/heap.cc | 2 | ||||
-rw-r--r-- | src/image.h | 2 | ||||
-rw-r--r-- | src/image_writer.cc | 58 | ||||
-rw-r--r-- | src/indirect_reference_table.h | 8 | ||||
-rw-r--r-- | src/oatdump.cc | 2 | ||||
-rw-r--r-- | src/runtime.cc | 20 | ||||
-rw-r--r-- | src/runtime.h | 6 | ||||
-rw-r--r-- | src/runtime_support.cc | 79 | ||||
-rw-r--r-- | src/runtime_support.h | 1 | ||||
-rw-r--r-- | src/space.cc | 5 | ||||
-rw-r--r-- | src/stub_arm.cc | 40 | ||||
-rw-r--r-- | src/stub_x86.cc | 16 | ||||
-rw-r--r-- | src/thread.cc | 1 | ||||
-rw-r--r-- | src/thread.h | 1 |
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**>(®s[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); |