diff options
author | Jeff Hao <jeffhao@google.com> | 2013-10-23 16:24:40 -0700 |
---|---|---|
committer | Jeff Hao <jeffhao@google.com> | 2013-10-29 12:01:28 -0700 |
commit | 88474b416eb257078e590bf9bc7957cee604a186 (patch) | |
tree | 7c59aa370bec9b0f2d37cb7a96d3b2effb3d92ce /runtime | |
parent | 9780099e445884d8bc9444c8c1261b02d80a26c7 (diff) | |
download | art-88474b416eb257078e590bf9bc7957cee604a186.zip art-88474b416eb257078e590bf9bc7957cee604a186.tar.gz art-88474b416eb257078e590bf9bc7957cee604a186.tar.bz2 |
Implement Interface Method Tables (IMT).
Change-Id: Idf7fe85e1293453a8ad862ff2380dcd5db4e3a39
Diffstat (limited to 'runtime')
28 files changed, 307 insertions, 29 deletions
diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc index 352982f..3dac636 100644 --- a/runtime/arch/arm/entrypoints_init_arm.cc +++ b/runtime/arch/arm/entrypoints_init_arm.cc @@ -121,10 +121,10 @@ 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" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*); extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*); extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*); 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*); extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*); @@ -253,10 +253,10 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, qpoints->pMemcpy = memcpy; // Invocation + qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; - qpoints->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check; qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check; diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S index 736ce2f..808ff5b 100644 --- a/runtime/arch/arm/quick_entrypoints_arm.S +++ b/runtime/arch/arm/quick_entrypoints_arm.S @@ -1040,6 +1040,18 @@ ENTRY art_quick_proxy_invoke_handler DELIVER_PENDING_EXCEPTION END art_quick_proxy_invoke_handler + /* + * Called to resolve an imt conflict. r12 is a hidden argument that holds the target method's + * dex method index. + */ +ENTRY art_quick_imt_conflict_trampoline + ldr r0, [sp, #0] @ load caller Method* + ldr r0, [r0, #METHOD_DEX_CACHE_METHODS_OFFSET] @ load dex_cache_resolved_methods + add r0, #OBJECT_ARRAY_DATA_OFFSET @ get starting address of data + ldr r0, [r0, r12, lsl 2] @ load the target method + b art_quick_invoke_interface_trampoline +END art_quick_imt_conflict_trampoline + .extern artQuickResolutionTrampoline ENTRY art_quick_resolution_trampoline SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc index cc975d75..331a461 100644 --- a/runtime/arch/mips/entrypoints_init_mips.cc +++ b/runtime/arch/mips/entrypoints_init_mips.cc @@ -122,10 +122,10 @@ 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" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*); extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*); extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*); 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*); extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*); @@ -253,10 +253,10 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, qpoints->pMemcpy = memcpy; // Invocation + qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; - qpoints->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check; qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check; diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S index 031d13a..451b1bb 100644 --- a/runtime/arch/mips/quick_entrypoints_mips.S +++ b/runtime/arch/mips/quick_entrypoints_mips.S @@ -1060,6 +1060,21 @@ ENTRY art_quick_proxy_invoke_handler DELIVER_PENDING_EXCEPTION END art_quick_proxy_invoke_handler + /* + * Called to resolve an imt conflict. t0 is a hidden argument that holds the target method's + * dex method index. + */ +ENTRY art_quick_imt_conflict_trampoline + GENERATE_GLOBAL_POINTER + lw $a0, 0($sp) # load caller Method* + lw $a0, METHOD_DEX_CACHE_METHODS_OFFSET($a0) # load dex_cache_resolved_methods + sll $t0, 2 # convert target method offset to bytes + add $a0, $t0 # get address of target method + lw $a0, OBJECT_ARRAY_DATA_OFFSET($a0) # load the target method + la $t9, art_quick_invoke_interface_trampoline + jr $t9 +END art_quick_imt_conflict_trampoline + .extern artQuickResolutionTrampoline ENTRY art_quick_resolution_trampoline GENERATE_GLOBAL_POINTER diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc index 89dd1b8..99b0dd5 100644 --- a/runtime/arch/x86/entrypoints_init_x86.cc +++ b/runtime/arch/x86/entrypoints_init_x86.cc @@ -104,10 +104,10 @@ 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" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*); extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*); extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*); 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*); extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*); @@ -235,10 +235,10 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, qpoints->pMemcpy = art_quick_memcpy; // Invocation + qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; - qpoints->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check; qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check; diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S index 805f6f4..6a6891b 100644 --- a/runtime/arch/x86/quick_entrypoints_x86.S +++ b/runtime/arch/x86/quick_entrypoints_x86.S @@ -997,6 +997,20 @@ DEFINE_FUNCTION art_quick_proxy_invoke_handler RETURN_OR_DELIVER_PENDING_EXCEPTION // return or deliver exception END_FUNCTION art_quick_proxy_invoke_handler + /* + * Called to resolve an imt conflict. xmm0 is a hidden argument that holds the target method's + * dex method index. + */ +DEFINE_FUNCTION art_quick_imt_conflict_trampoline + PUSH ecx + movl 8(%esp), %eax // load caller Method* + movl METHOD_DEX_CACHE_METHODS_OFFSET(%eax), %eax // load dex_cache_resolved_methods + movd %xmm0, %ecx // get target method index stored in xmm0 + movl OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4), %eax // load the target method + POP ecx + jmp art_quick_invoke_interface_trampoline +END_FUNCTION art_quick_imt_conflict_trampoline + DEFINE_FUNCTION art_quick_resolution_trampoline SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME PUSH esp // pass SP diff --git a/runtime/asm_support.h b/runtime/asm_support.h index a6700bc..e9bbf91 100644 --- a/runtime/asm_support.h +++ b/runtime/asm_support.h @@ -38,7 +38,8 @@ #define STRING_OFFSET_OFFSET 20 #define STRING_DATA_OFFSET 12 -// Offset of field Method::entry_point_from_compiled_code_ +// Offsets within java.lang.Method. +#define METHOD_DEX_CACHE_METHODS_OFFSET 16 #define METHOD_CODE_OFFSET 40 #endif // ART_RUNTIME_ASM_SUPPORT_H_ diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 03f2c9d..2fc564f 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -196,7 +196,9 @@ ClassLinker::ClassLinker(InternTable* intern_table) class_table_dirty_(false), intern_table_(intern_table), portable_resolution_trampoline_(NULL), - quick_resolution_trampoline_(NULL) { + quick_resolution_trampoline_(NULL), + portable_imt_conflict_trampoline_(NULL), + quick_imt_conflict_trampoline_(NULL) { CHECK_EQ(arraysize(class_roots_descriptors_), size_t(kClassRootsMax)); } @@ -336,6 +338,12 @@ void ClassLinker::InitFromCompiler(const std::vector<const DexFile*>& boot_class InitializePrimitiveClass(char_class.get(), Primitive::kPrimChar); SetClassRoot(kPrimitiveChar, char_class.get()); // needs descriptor + // Create runtime resolution and imt conflict methods. Also setup the default imt. + Runtime* runtime = Runtime::Current(); + runtime->SetResolutionMethod(runtime->CreateResolutionMethod()); + runtime->SetImtConflictMethod(runtime->CreateImtConflictMethod()); + runtime->SetDefaultImt(runtime->CreateDefaultImt(this)); + // Object, String and DexCache need to be rerun through FindSystemClass to finish init java_lang_Object->SetStatus(mirror::Class::kStatusNotReady, self); mirror::Class* Object_class = FindSystemClass("Ljava/lang/Object;"); @@ -1045,6 +1053,8 @@ void ClassLinker::InitFromImage() { CHECK(oat_file.GetOatHeader().GetImageFileLocation().empty()); portable_resolution_trampoline_ = oat_file.GetOatHeader().GetPortableResolutionTrampoline(); quick_resolution_trampoline_ = oat_file.GetOatHeader().GetQuickResolutionTrampoline(); + portable_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetPortableImtConflictTrampoline(); + quick_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetQuickImtConflictTrampoline(); mirror::Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches); mirror::ObjectArray<mirror::DexCache>* dex_caches = dex_caches_object->AsObjectArray<mirror::DexCache>(); @@ -3518,6 +3528,8 @@ bool ClassLinker::LinkVirtualMethods(SirtRef<mirror::Class>& klass) { bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, mirror::ObjectArray<mirror::Class>* interfaces) { + // Set the imt table to be all conflicts by default. + klass->SetImTable(Runtime::Current()->GetDefaultImt()); size_t super_ifcount; if (klass->HasSuperClass()) { super_ifcount = klass->GetSuperClass()->GetIfTableCount(); @@ -3625,6 +3637,13 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, if (klass->IsInterface()) { return true; } + // Allocate imtable + bool imtable_changed = false; + SirtRef<mirror::ObjectArray<mirror::ArtMethod> > imtable(self, AllocArtMethodArray(self, kImtSize)); + if (UNLIKELY(imtable.get() == NULL)) { + CHECK(self->IsExceptionPending()); // OOME. + return false; + } std::vector<mirror::ArtMethod*> miranda_list; MethodHelper vtable_mh(NULL, this); MethodHelper interface_mh(NULL, this); @@ -3664,6 +3683,14 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, return false; } method_array->Set(j, vtable_method); + // Place method in imt if entry is empty, place conflict otherwise. + uint32_t imt_index = interface_method->GetDexMethodIndex() % kImtSize; + if (imtable->Get(imt_index) == NULL) { + imtable->Set(imt_index, vtable_method); + imtable_changed = true; + } else { + imtable->Set(imt_index, Runtime::Current()->GetImtConflictMethod()); + } break; } } @@ -3695,6 +3722,16 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass, } } } + if (imtable_changed) { + // Fill in empty entries in interface method table with conflict. + mirror::ArtMethod* imt_conflict_method = Runtime::Current()->GetImtConflictMethod(); + for (size_t i = 0; i < kImtSize; i++) { + if (imtable->Get(i) == NULL) { + imtable->Set(i, imt_conflict_method); + } + } + klass->SetImTable(imtable.get()); + } if (!miranda_list.empty()) { int old_method_count = klass->NumVirtualMethods(); int new_method_count = old_method_count + miranda_list.size(); diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 0bc1b5f..473370d 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -51,6 +51,11 @@ typedef bool (ClassVisitor)(mirror::Class* c, void* arg); class ClassLinker { public: + // Interface method table size. Increasing this value reduces the chance of two interface methods + // colliding in the interface method table but increases the size of classes that implement + // (non-marker) interfaces. + static constexpr size_t kImtSize = 64; + // Creates the class linker by bootstrapping from dex files. static ClassLinker* CreateFromCompiler(const std::vector<const DexFile*>& boot_class_path, InternTable* intern_table) @@ -340,6 +345,18 @@ class ClassLinker { return quick_resolution_trampoline_; } + const void* GetPortableImtConflictTrampoline() const { + return portable_imt_conflict_trampoline_; + } + + const void* GetQuickImtConflictTrampoline() const { + return quick_imt_conflict_trampoline_; + } + + InternTable* GetInternTable() const { + return intern_table_; + } + // Attempts to insert a class into a class table. Returns NULL if // the class was inserted, otherwise returns an existing class with // the same descriptor and ClassLoader. @@ -608,6 +625,8 @@ class ClassLinker { const void* portable_resolution_trampoline_; const void* quick_resolution_trampoline_; + const void* portable_imt_conflict_trampoline_; + const void* quick_imt_conflict_trampoline_; friend class ImageWriter; // for GetClassRoots FRIEND_TEST(ClassLinkerTest, ClassRootDescriptors); diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 029b73e..a52b680 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -497,6 +497,7 @@ struct ClassOffsets : public CheckOffsets<mirror::Class> { offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, direct_methods_), "directMethods")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, ifields_), "iFields")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, iftable_), "ifTable")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, imtable_), "imTable")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, name_), "name")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, sfields_), "sFields")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, super_class_), "superClass")); @@ -582,11 +583,11 @@ struct StringClassOffsets : public CheckOffsets<mirror::StringClass> { offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, ASCII_), "ASCII")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, CASE_INSENSITIVE_ORDER_), "CASE_INSENSITIVE_ORDER")); - // alphabetical 64-bit - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, serialVersionUID_), "serialVersionUID")); - // alphabetical 32-bit offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, REPLACEMENT_CHAR_), "REPLACEMENT_CHAR")); + + // alphabetical 64-bit + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, serialVersionUID_), "serialVersionUID")); }; }; diff --git a/runtime/common_test.h b/runtime/common_test.h index 899eab1..673a03b 100644 --- a/runtime/common_test.h +++ b/runtime/common_test.h @@ -329,9 +329,6 @@ class CommonTest : public testing::Test { CompilerBackend compiler_backend = kQuick; #endif - if (!runtime_->HasResolutionMethod()) { - runtime_->SetResolutionMethod(runtime_->CreateResolutionMethod()); - } for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) { Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i); if (!runtime_->HasCalleeSaveMethod(type)) { diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index 2008604..7ce50c5 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -372,14 +372,21 @@ static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx, mirror: return vtable->GetWithoutChecks(vtable_index); } case kInterface: { - mirror::ArtMethod* interface_method = - this_object->GetClass()->FindVirtualMethodForInterface(resolved_method); - if (UNLIKELY(interface_method == nullptr)) { - ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method, this_object, - referrer); - return nullptr; // Failure. + uint32_t imt_index = resolved_method->GetDexMethodIndex() % ClassLinker::kImtSize; + mirror::ObjectArray<mirror::ArtMethod>* imt_table = this_object->GetClass()->GetImTable(); + mirror::ArtMethod* imt_method = imt_table->Get(imt_index); + if (!imt_method->IsImtConflictMethod()) { + return imt_method; } else { - return interface_method; + mirror::ArtMethod* interface_method = + this_object->GetClass()->FindVirtualMethodForInterface(resolved_method); + if (UNLIKELY(interface_method == nullptr)) { + ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method, this_object, + referrer); + return nullptr; // Failure. + } else { + return interface_method; + } } } default: @@ -665,6 +672,23 @@ static inline const void* GetResolutionTrampoline(ClassLinker* class_linker) { #endif } +static inline const void* GetPortableImtConflictTrampoline(ClassLinker* class_linker) { + return class_linker->GetPortableImtConflictTrampoline(); +} + +static inline const void* GetQuickImtConflictTrampoline(ClassLinker* class_linker) { + return class_linker->GetQuickImtConflictTrampoline(); +} + +// Return address of imt conflict trampoline stub for defined compiler. +static inline const void* GetImtConflictTrampoline(ClassLinker* class_linker) { +#if defined(ART_USE_PORTABLE_COMPILER) + return GetPortableImtConflictTrampoline(class_linker); +#else + return GetQuickImtConflictTrampoline(class_linker); +#endif +} + extern "C" void art_portable_proxy_invoke_handler(); static inline const void* GetPortableProxyInvokeHandler() { return reinterpret_cast<void*>(art_portable_proxy_invoke_handler); diff --git a/runtime/entrypoints/portable/portable_entrypoints.h b/runtime/entrypoints/portable/portable_entrypoints.h index d456447..dbea707 100644 --- a/runtime/entrypoints/portable/portable_entrypoints.h +++ b/runtime/entrypoints/portable/portable_entrypoints.h @@ -35,6 +35,7 @@ class Thread; // compiler ABI. struct PACKED(4) PortableEntryPoints { // Invocation + void (*pPortableImtConflictTrampoline)(mirror::ArtMethod*); void (*pPortableResolutionTrampoline)(mirror::ArtMethod*); void (*pPortableToInterpreterBridge)(mirror::ArtMethod*); }; diff --git a/runtime/entrypoints/quick/quick_entrypoints.h b/runtime/entrypoints/quick/quick_entrypoints.h index c8a85a0..1ba2066 100644 --- a/runtime/entrypoints/quick/quick_entrypoints.h +++ b/runtime/entrypoints/quick/quick_entrypoints.h @@ -118,10 +118,10 @@ struct PACKED(4) QuickEntryPoints { void* (*pMemcpy)(void*, const void*, size_t); // Invocation + void (*pQuickImtConflictTrampoline)(mirror::ArtMethod*); void (*pQuickResolutionTrampoline)(mirror::ArtMethod*); void (*pQuickToInterpreterBridge)(mirror::ArtMethod*); void (*pInvokeDirectTrampolineWithAccessCheck)(uint32_t, void*); - void (*pInvokeInterfaceTrampoline)(uint32_t, void*); void (*pInvokeInterfaceTrampolineWithAccessCheck)(uint32_t, void*); void (*pInvokeStaticTrampolineWithAccessCheck)(uint32_t, void*); void (*pInvokeSuperTrampolineWithAccessCheck)(uint32_t, void*); diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index fa28642..e12ee06 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -241,6 +241,10 @@ ImageSpace* ImageSpace::Init(const char* image_file_name, bool validate_oat_file Runtime* runtime = Runtime::Current(); mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod); runtime->SetResolutionMethod(down_cast<mirror::ArtMethod*>(resolution_method)); + mirror::Object* imt_conflict_method = image_header.GetImageRoot(ImageHeader::kImtConflictMethod); + runtime->SetImtConflictMethod(down_cast<mirror::ArtMethod*>(imt_conflict_method)); + mirror::Object* default_imt = image_header.GetImageRoot(ImageHeader::kDefaultImt); + runtime->SetDefaultImt(down_cast<mirror::ObjectArray<mirror::ArtMethod>*>(default_imt)); mirror::Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod); runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kSaveAll); diff --git a/runtime/image.h b/runtime/image.h index 2cb468f..246f106 100644 --- a/runtime/image.h +++ b/runtime/image.h @@ -90,6 +90,8 @@ class PACKED(4) ImageHeader { enum ImageRoot { kResolutionMethod, + kImtConflictMethod, + kDefaultImt, kCalleeSaveMethod, kRefsOnlySaveMethod, kRefsAndArgsSaveMethod, diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h index ccf3e59..c9bf160 100644 --- a/runtime/mirror/art_method-inl.h +++ b/runtime/mirror/art_method-inl.h @@ -202,6 +202,13 @@ inline bool ArtMethod::IsResolutionMethod() const { DCHECK(!result || IsRuntimeMethod()); return result; } + +inline bool ArtMethod::IsImtConflictMethod() const { + bool result = this == Runtime::Current()->GetImtConflictMethod(); + // Check that if we do think it is phony it looks like the imt conflict method. + DCHECK(!result || IsRuntimeMethod()); + return result; +} } // namespace mirror } // namespace art diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h index 0520893..f396fbe 100644 --- a/runtime/mirror/art_method.h +++ b/runtime/mirror/art_method.h @@ -357,6 +357,8 @@ class MANAGED ArtMethod : public Object { bool IsResolutionMethod() const; + bool IsImtConflictMethod() const; + uintptr_t NativePcOffset(const uintptr_t pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Converts a native PC to a dex PC. diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index cd5e865..7f3a302 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -139,6 +139,14 @@ inline void Class::SetVTable(ObjectArray<ArtMethod>* new_vtable) SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), new_vtable, false); } +inline ObjectArray<ArtMethod>* Class::GetImTable() const { + return GetFieldObject<ObjectArray<ArtMethod>*>(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), false); +} + +inline void Class::SetImTable(ObjectArray<ArtMethod>* new_imtable) { + SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), new_imtable, false); +} + inline bool Class::Implements(const Class* klass) const { DCHECK(klass != NULL); DCHECK(klass->IsInterface()) << PrettyClass(this); diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index d15f337..ed1aad3 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -555,6 +555,15 @@ class MANAGED Class : public StaticStorageBase { return OFFSET_OF_OBJECT_MEMBER(Class, vtable_); } + ObjectArray<ArtMethod>* GetImTable() const; + + void SetImTable(ObjectArray<ArtMethod>* new_imtable) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + static MemberOffset ImTableOffset() { + return OFFSET_OF_OBJECT_MEMBER(Class, imtable_); + } + // Given a method implemented by this class but potentially from a super class, return the // specific implementation method for this class. ArtMethod* FindVirtualMethodForVirtual(ArtMethod* method) const @@ -830,6 +839,9 @@ class MANAGED Class : public StaticStorageBase { // methods for the methods in the interface. IfTable* iftable_; + // Interface method table (imt), for quick "invoke-interface". + ObjectArray<ArtMethod>* imtable_; + // descriptor for the class such as "java.lang.Class" or "[C". Lazily initialized by ComputeName String* name_; @@ -912,6 +924,7 @@ std::ostream& operator<<(std::ostream& os, const Class::Status& rhs); class MANAGED ClassClass : public Class { private: + int32_t pad_; int64_t serialVersionUID_; friend struct art::ClassClassOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(ClassClass); diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc index 6c6d488..d0d1ee4 100644 --- a/runtime/mirror/object_test.cc +++ b/runtime/mirror/object_test.cc @@ -84,6 +84,7 @@ TEST_F(ObjectTest, AsmConstants) { EXPECT_EQ(STRING_OFFSET_OFFSET, String::OffsetOffset().Int32Value()); EXPECT_EQ(STRING_DATA_OFFSET, Array::DataOffset(sizeof(uint16_t)).Int32Value()); + EXPECT_EQ(METHOD_DEX_CACHE_METHODS_OFFSET, ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()); EXPECT_EQ(METHOD_CODE_OFFSET, ArtMethod::EntryPointFromCompiledCodeOffset().Int32Value()); } diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h index 1879f04..01d8f31 100644 --- a/runtime/mirror/string.h +++ b/runtime/mirror/string.h @@ -156,8 +156,8 @@ class MANAGED StringClass : public Class { private: CharArray* ASCII_; Object* CASE_INSENSITIVE_ORDER_; - int64_t serialVersionUID_; uint32_t REPLACEMENT_CHAR_; + int64_t serialVersionUID_; friend struct art::StringClassOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(StringClass); }; diff --git a/runtime/oat.cc b/runtime/oat.cc index 6fe5d10..defda6b 100644 --- a/runtime/oat.cc +++ b/runtime/oat.cc @@ -22,7 +22,7 @@ namespace art { const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' }; -const uint8_t OatHeader::kOatVersion[] = { '0', '0', '8', '\0' }; +const uint8_t OatHeader::kOatVersion[] = { '0', '0', '9', '\0' }; OatHeader::OatHeader() { memset(this, 0, sizeof(*this)); @@ -60,8 +60,10 @@ OatHeader::OatHeader(InstructionSet instruction_set, interpreter_to_interpreter_bridge_offset_ = 0; interpreter_to_compiled_code_bridge_offset_ = 0; jni_dlsym_lookup_offset_ = 0; + portable_imt_conflict_trampoline_offset_ = 0; portable_resolution_trampoline_offset_ = 0; portable_to_interpreter_bridge_offset_ = 0; + quick_imt_conflict_trampoline_offset_ = 0; quick_resolution_trampoline_offset_ = 0; quick_to_interpreter_bridge_offset_ = 0; } @@ -171,18 +173,37 @@ void OatHeader::SetJniDlsymLookupOffset(uint32_t offset) { UpdateChecksum(&jni_dlsym_lookup_offset_, sizeof(offset)); } +const void* OatHeader::GetPortableImtConflictTrampoline() const { + return reinterpret_cast<const uint8_t*>(this) + GetPortableImtConflictTrampolineOffset(); +} + +uint32_t OatHeader::GetPortableImtConflictTrampolineOffset() const { + DCHECK(IsValid()); + CHECK_GE(portable_imt_conflict_trampoline_offset_, jni_dlsym_lookup_offset_); + return portable_imt_conflict_trampoline_offset_; +} + +void OatHeader::SetPortableImtConflictTrampolineOffset(uint32_t offset) { + CHECK(offset == 0 || offset >= jni_dlsym_lookup_offset_); + DCHECK(IsValid()); + DCHECK_EQ(portable_imt_conflict_trampoline_offset_, 0U) << offset; + + portable_imt_conflict_trampoline_offset_ = offset; + UpdateChecksum(&portable_imt_conflict_trampoline_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_, jni_dlsym_lookup_offset_); + CHECK_GE(portable_resolution_trampoline_offset_, portable_imt_conflict_trampoline_offset_); return portable_resolution_trampoline_offset_; } void OatHeader::SetPortableResolutionTrampolineOffset(uint32_t offset) { - CHECK(offset == 0 || offset >= jni_dlsym_lookup_offset_); + CHECK(offset == 0 || offset >= portable_imt_conflict_trampoline_offset_); DCHECK(IsValid()); DCHECK_EQ(portable_resolution_trampoline_offset_, 0U) << offset; @@ -209,18 +230,37 @@ void OatHeader::SetPortableToInterpreterBridgeOffset(uint32_t offset) { UpdateChecksum(&portable_to_interpreter_bridge_offset_, sizeof(offset)); } +const void* OatHeader::GetQuickImtConflictTrampoline() const { + return reinterpret_cast<const uint8_t*>(this) + GetQuickImtConflictTrampolineOffset(); +} + +uint32_t OatHeader::GetQuickImtConflictTrampolineOffset() const { + DCHECK(IsValid()); + CHECK_GE(quick_imt_conflict_trampoline_offset_, portable_to_interpreter_bridge_offset_); + return quick_imt_conflict_trampoline_offset_; +} + +void OatHeader::SetQuickImtConflictTrampolineOffset(uint32_t offset) { + CHECK(offset == 0 || offset >= portable_to_interpreter_bridge_offset_); + DCHECK(IsValid()); + DCHECK_EQ(quick_imt_conflict_trampoline_offset_, 0U) << offset; + + quick_imt_conflict_trampoline_offset_ = offset; + UpdateChecksum(&quick_imt_conflict_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_to_interpreter_bridge_offset_); + CHECK_GE(quick_resolution_trampoline_offset_, quick_imt_conflict_trampoline_offset_); return quick_resolution_trampoline_offset_; } void OatHeader::SetQuickResolutionTrampolineOffset(uint32_t offset) { - CHECK(offset == 0 || offset >= portable_to_interpreter_bridge_offset_); + CHECK(offset == 0 || offset >= quick_imt_conflict_trampoline_offset_); DCHECK(IsValid()); DCHECK_EQ(quick_resolution_trampoline_offset_, 0U) << offset; diff --git a/runtime/oat.h b/runtime/oat.h index a9dc540..c864c2c 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -62,6 +62,9 @@ class PACKED(4) OatHeader { const void* GetPortableResolutionTrampoline() const; uint32_t GetPortableResolutionTrampolineOffset() const; void SetPortableResolutionTrampolineOffset(uint32_t offset); + const void* GetPortableImtConflictTrampoline() const; + uint32_t GetPortableImtConflictTrampolineOffset() const; + void SetPortableImtConflictTrampolineOffset(uint32_t offset); const void* GetPortableToInterpreterBridge() const; uint32_t GetPortableToInterpreterBridgeOffset() const; void SetPortableToInterpreterBridgeOffset(uint32_t offset); @@ -69,6 +72,9 @@ class PACKED(4) OatHeader { const void* GetQuickResolutionTrampoline() const; uint32_t GetQuickResolutionTrampolineOffset() const; void SetQuickResolutionTrampolineOffset(uint32_t offset); + const void* GetQuickImtConflictTrampoline() const; + uint32_t GetQuickImtConflictTrampolineOffset() const; + void SetQuickImtConflictTrampolineOffset(uint32_t offset); const void* GetQuickToInterpreterBridge() const; uint32_t GetQuickToInterpreterBridgeOffset() const; void SetQuickToInterpreterBridgeOffset(uint32_t offset); @@ -91,8 +97,10 @@ class PACKED(4) OatHeader { uint32_t interpreter_to_interpreter_bridge_offset_; uint32_t interpreter_to_compiled_code_bridge_offset_; uint32_t jni_dlsym_lookup_offset_; + uint32_t portable_imt_conflict_trampoline_offset_; uint32_t portable_resolution_trampoline_offset_; uint32_t portable_to_interpreter_bridge_offset_; + uint32_t quick_imt_conflict_trampoline_offset_; uint32_t quick_resolution_trampoline_offset_; uint32_t quick_to_interpreter_bridge_offset_; diff --git a/runtime/object_utils.h b/runtime/object_utils.h index 3ca3c0b..bf25b81 100644 --- a/runtime/object_utils.h +++ b/runtime/object_utils.h @@ -458,6 +458,8 @@ class MethodHelper { Runtime* runtime = Runtime::Current(); if (method_ == runtime->GetResolutionMethod()) { return "<runtime internal resolution method>"; + } else if (method_ == runtime->GetImtConflictMethod()) { + return "<runtime internal imt conflict method>"; } else if (method_ == runtime->GetCalleeSaveMethod(Runtime::kSaveAll)) { return "<runtime internal callee-save all registers method>"; } else if (method_ == runtime->GetCalleeSaveMethod(Runtime::kRefsOnly)) { diff --git a/runtime/runtime.cc b/runtime/runtime.cc index f46b794..34cf45b 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -84,6 +84,8 @@ Runtime::Runtime() java_vm_(NULL), pre_allocated_OutOfMemoryError_(NULL), resolution_method_(NULL), + imt_conflict_method_(NULL), + default_imt_(NULL), threads_being_born_(0), shutdown_cond_(new ConditionVariable("Runtime shutdown", *Locks::runtime_shutdown_lock_)), shutting_down_(false), @@ -1175,6 +1177,10 @@ void Runtime::VisitNonThreadRoots(RootVisitor* visitor, void* arg) { } resolution_method_ = reinterpret_cast<mirror::ArtMethod*>(visitor(resolution_method_, arg)); DCHECK(resolution_method_ != nullptr); + imt_conflict_method_ = reinterpret_cast<mirror::ArtMethod*>(visitor(imt_conflict_method_, arg)); + DCHECK(imt_conflict_method_ != nullptr); + default_imt_ = reinterpret_cast<mirror::ObjectArray<mirror::ArtMethod>*>(visitor(default_imt_, arg)); + DCHECK(default_imt_ != nullptr); for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) { callee_save_methods_[i] = reinterpret_cast<mirror::ArtMethod*>( visitor(callee_save_methods_[i], arg)); @@ -1192,6 +1198,31 @@ void Runtime::VisitRoots(RootVisitor* visitor, void* arg, bool only_dirty, bool VisitNonConcurrentRoots(visitor, arg); } +mirror::ObjectArray<mirror::ArtMethod>* Runtime::CreateDefaultImt(ClassLinker* cl) { + Thread* self = Thread::Current(); + SirtRef<mirror::ObjectArray<mirror::ArtMethod> > imtable(self, cl->AllocArtMethodArray(self, 64)); + mirror::ArtMethod* imt_conflict_method = Runtime::Current()->GetImtConflictMethod(); + for (size_t i = 0; i < 64; i++) { + imtable->Set(i, imt_conflict_method); + } + return imtable.get(); +} + +mirror::ArtMethod* Runtime::CreateImtConflictMethod() { + mirror::Class* method_class = mirror::ArtMethod::GetJavaLangReflectArtMethod(); + Thread* self = Thread::Current(); + SirtRef<mirror::ArtMethod> + method(self, down_cast<mirror::ArtMethod*>(method_class->AllocObject(self))); + method->SetDeclaringClass(method_class); + // TODO: use a special method for imt conflict method saves + method->SetDexMethodIndex(DexFile::kDexNoIndex); + // When compiling, the code pointer will get set later when the image is loaded. + Runtime* r = Runtime::Current(); + ClassLinker* cl = r->GetClassLinker(); + method->SetEntryPointFromCompiledCode(r->IsCompiler() ? NULL : GetImtConflictTrampoline(cl)); + return method.get(); +} + mirror::ArtMethod* Runtime::CreateResolutionMethod() { mirror::Class* method_class = mirror::ArtMethod::GetJavaLangReflectArtMethod(); Thread* self = Thread::Current(); diff --git a/runtime/runtime.h b/runtime/runtime.h index b6429b6..51d9074 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -45,6 +45,7 @@ namespace gc { namespace mirror { class ArtMethod; class ClassLoader; + template<class T> class ObjectArray; template<class T> class PrimitiveArray; typedef PrimitiveArray<int8_t> ByteArray; class String; @@ -349,6 +350,39 @@ class Runtime { mirror::ArtMethod* CreateResolutionMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Returns a special method that calls into a trampoline for runtime imt conflicts + mirror::ArtMethod* GetImtConflictMethod() const { + CHECK(HasImtConflictMethod()); + return imt_conflict_method_; + } + + bool HasImtConflictMethod() const { + return imt_conflict_method_ != NULL; + } + + void SetImtConflictMethod(mirror::ArtMethod* method) { + imt_conflict_method_ = method; + } + + mirror::ArtMethod* CreateImtConflictMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + // Returns an imt with every entry set to conflict, used as default imt for all classes. + mirror::ObjectArray<mirror::ArtMethod>* GetDefaultImt() const { + CHECK(HasDefaultImt()); + return default_imt_; + } + + bool HasDefaultImt() const { + return default_imt_ != NULL; + } + + void SetDefaultImt(mirror::ObjectArray<mirror::ArtMethod>* imt) { + default_imt_ = imt; + } + + mirror::ObjectArray<mirror::ArtMethod>* CreateDefaultImt(ClassLinker* cl) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Returns a special method that describes all callee saves being spilled to the stack. enum CalleeSaveType { kSaveAll, @@ -485,6 +519,10 @@ class Runtime { mirror::ArtMethod* resolution_method_; + mirror::ArtMethod* imt_conflict_method_; + + mirror::ObjectArray<mirror::ArtMethod>* default_imt_; + // A non-zero value indicates that a thread has been created but not yet initialized. Guarded by // the shutdown lock so that threads aren't born while we're shutting down. size_t threads_being_born_ GUARDED_BY(Locks::runtime_shutdown_lock_); diff --git a/runtime/thread.cc b/runtime/thread.cc index 3063658..9751076 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1555,6 +1555,7 @@ static const EntryPointInfo gThreadEntryPointInfo[] = { INTERPRETER_ENTRY_POINT_INFO(pInterpreterToInterpreterBridge), INTERPRETER_ENTRY_POINT_INFO(pInterpreterToCompiledCodeBridge), JNI_ENTRY_POINT_INFO(pDlsymLookup), + PORTABLE_ENTRY_POINT_INFO(pPortableImtConflictTrampoline), PORTABLE_ENTRY_POINT_INFO(pPortableResolutionTrampoline), PORTABLE_ENTRY_POINT_INFO(pPortableToInterpreterBridge), QUICK_ENTRY_POINT_INFO(pAllocArray), @@ -1617,10 +1618,10 @@ static const EntryPointInfo gThreadEntryPointInfo[] = { QUICK_ENTRY_POINT_INFO(pMemcmp16), QUICK_ENTRY_POINT_INFO(pStringCompareTo), QUICK_ENTRY_POINT_INFO(pMemcpy), + QUICK_ENTRY_POINT_INFO(pQuickImtConflictTrampoline), QUICK_ENTRY_POINT_INFO(pQuickResolutionTrampoline), QUICK_ENTRY_POINT_INFO(pQuickToInterpreterBridge), QUICK_ENTRY_POINT_INFO(pInvokeDirectTrampolineWithAccessCheck), - QUICK_ENTRY_POINT_INFO(pInvokeInterfaceTrampoline), QUICK_ENTRY_POINT_INFO(pInvokeInterfaceTrampolineWithAccessCheck), QUICK_ENTRY_POINT_INFO(pInvokeStaticTrampolineWithAccessCheck), QUICK_ENTRY_POINT_INFO(pInvokeSuperTrampolineWithAccessCheck), |