diff options
author | 2016-01-14 18:43:36 +0000 | |
---|---|---|
committer | 2016-01-14 18:43:36 +0000 | |
commit | 7b4199a5fa9f151fbf3af2a34f26d04215a1016c (patch) | |
tree | 111493b5fee26087dcc8abc1a1f56a140d549c8d /runtime/class_linker.cc | |
parent | 15db4dcfcc17dfe6c41d3c7b26355ccfa2504f4e (diff) | |
parent | 705ad49f353d3f90d8b63625aca2c2035bacdbef (diff) |
Merge "Support directly invoking interface default methods"
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r-- | runtime/class_linker.cc | 458 |
1 files changed, 259 insertions, 199 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 41842e88f3..3d0629554b 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -46,6 +46,7 @@ #include "dex_file-inl.h" #include "entrypoints/entrypoint_utils.h" #include "entrypoints/runtime_asm_entrypoints.h" +#include "experimental_flags.h" #include "gc_root-inl.h" #include "gc/accounting/card_table-inl.h" #include "gc/accounting/heap_bitmap.h" @@ -4825,7 +4826,6 @@ bool ClassLinker::LinkVirtualMethods( return false; } bool has_defaults = false; - // TODO May need to replace this with real VTable for invoke_super // Assign each method an IMT index and set the default flag. for (size_t i = 0; i < num_virtual_methods; ++i) { ArtMethod* m = klass->GetVirtualMethodDuringLinking(i, image_pointer_size_); @@ -5463,6 +5463,53 @@ static void SanityCheckVTable(Handle<mirror::Class> klass, uint32_t pointer_size } } +static void FillImtFromSuperClass(Handle<mirror::Class> klass, + Handle<mirror::IfTable> iftable, + ArtMethod* unimplemented_method, + ArtMethod* imt_conflict_method, + ArtMethod** out_imt, + size_t pointer_size) SHARED_REQUIRES(Locks::mutator_lock_) { + DCHECK(klass->HasSuperClass()); + mirror::Class* super_class = klass->GetSuperClass(); + if (super_class->ShouldHaveEmbeddedImtAndVTable()) { + for (size_t i = 0; i < mirror::Class::kImtSize; ++i) { + out_imt[i] = super_class->GetEmbeddedImTableEntry(i, pointer_size); + } + } else { + // No imt in the super class, need to reconstruct from the iftable. + mirror::IfTable* if_table = super_class->GetIfTable(); + const size_t length = super_class->GetIfTableCount(); + for (size_t i = 0; i < length; ++i) { + mirror::Class* interface = iftable->GetInterface(i); + const size_t num_virtuals = interface->NumDeclaredVirtualMethods(); + const size_t method_array_count = if_table->GetMethodArrayCount(i); + DCHECK_EQ(num_virtuals, method_array_count); + if (method_array_count == 0) { + continue; + } + auto* method_array = if_table->GetMethodArray(i); + for (size_t j = 0; j < num_virtuals; ++j) { + auto method = method_array->GetElementPtrSize<ArtMethod*>(j, pointer_size); + DCHECK(method != nullptr) << PrettyClass(super_class); + // Miranda methods cannot be used to implement an interface method and defaults should be + // skipped in case we override it. + if (method->IsDefault() || method->IsMiranda()) { + continue; + } + ArtMethod* interface_method = interface->GetVirtualMethod(j, pointer_size); + uint32_t imt_index = interface_method->GetDexMethodIndex() % mirror::Class::kImtSize; + auto** imt_ref = &out_imt[imt_index]; + if (*imt_ref == unimplemented_method) { + *imt_ref = method; + } else if (*imt_ref != imt_conflict_method) { + *imt_ref = imt_conflict_method; + } + } + } + } +} + +// TODO This method needs to be split up into several smaller methods. bool ClassLinker::LinkInterfaceMethods( Thread* self, Handle<mirror::Class> klass, @@ -5470,7 +5517,19 @@ bool ClassLinker::LinkInterfaceMethods( ArtMethod** out_imt) { StackHandleScope<3> hs(self); Runtime* const runtime = Runtime::Current(); + + const bool is_interface = klass->IsInterface(); + // TODO It might in the future prove useful to make interfaces have full iftables, allowing a + // faster invoke-super implementation in the interpreter/across dex-files. + // We will just skip doing any of this on non-debug builds for speed. + if (is_interface && + !kIsDebugBuild && + !runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods)) { + return true; + } + const bool has_superclass = klass->HasSuperClass(); + const bool fill_tables = !is_interface; const size_t super_ifcount = has_superclass ? klass->GetSuperClass()->GetIfTableCount() : 0U; const size_t method_alignment = ArtMethod::Alignment(image_pointer_size_); const size_t method_size = ArtMethod::Size(image_pointer_size_); @@ -5478,10 +5537,6 @@ bool ClassLinker::LinkInterfaceMethods( MutableHandle<mirror::IfTable> iftable(hs.NewHandle(klass->GetIfTable())); - // If we're an interface, we don't need the vtable pointers, so we're done. - if (klass->IsInterface()) { - return true; - } // These are allocated on the heap to begin, we then transfer to linear alloc when we re-create // the virtual methods array. // Need to use low 4GB arenas for compiler or else the pointers wont fit in 32 bit method array @@ -5498,71 +5553,42 @@ bool ClassLinker::LinkInterfaceMethods( ArtMethod* const unimplemented_method = runtime->GetImtUnimplementedMethod(); ArtMethod* const imt_conflict_method = runtime->GetImtConflictMethod(); // Copy the IMT from the super class if possible. - bool extend_super_iftable = false; - if (has_superclass) { - mirror::Class* super_class = klass->GetSuperClass(); - extend_super_iftable = true; - if (super_class->ShouldHaveEmbeddedImtAndVTable()) { - for (size_t i = 0; i < mirror::Class::kImtSize; ++i) { - out_imt[i] = super_class->GetEmbeddedImTableEntry(i, image_pointer_size_); - } - } else { - // No imt in the super class, need to reconstruct from the iftable. - mirror::IfTable* if_table = super_class->GetIfTable(); - const size_t length = super_class->GetIfTableCount(); - for (size_t i = 0; i < length; ++i) { - mirror::Class* interface = iftable->GetInterface(i); - const size_t num_virtuals = interface->NumVirtualMethods(); - const size_t method_array_count = if_table->GetMethodArrayCount(i); - DCHECK_EQ(num_virtuals, method_array_count); - if (method_array_count == 0) { - continue; - } - auto* method_array = if_table->GetMethodArray(i); - for (size_t j = 0; j < num_virtuals; ++j) { - auto method = method_array->GetElementPtrSize<ArtMethod*>(j, image_pointer_size_); - DCHECK(method != nullptr) << PrettyClass(super_class); - // Miranda methods cannot be used to implement an interface method and defaults should be - // skipped in case we override it. - if (method->IsDefault() || method->IsMiranda()) { - continue; - } - ArtMethod* interface_method = interface->GetVirtualMethod(j, image_pointer_size_); - uint32_t imt_index = interface_method->GetDexMethodIndex() % mirror::Class::kImtSize; - auto** imt_ref = &out_imt[imt_index]; - if (*imt_ref == unimplemented_method) { - *imt_ref = method; - } else if (*imt_ref != imt_conflict_method) { - *imt_ref = imt_conflict_method; - } - } - } - } + const bool extend_super_iftable = has_superclass; + if (has_superclass && fill_tables) { + FillImtFromSuperClass(klass, + iftable, + unimplemented_method, + imt_conflict_method, + out_imt, + image_pointer_size_); } + // Allocate method arrays before since we don't want miss visiting miranda method roots due to // thread suspension. - for (size_t i = 0; i < ifcount; ++i) { - size_t num_methods = iftable->GetInterface(i)->NumVirtualMethods(); - if (num_methods > 0) { - const bool is_super = i < super_ifcount; - // This is an interface implemented by a super-class. Therefore we can just copy the method - // array from the superclass. - const bool super_interface = is_super && extend_super_iftable; - mirror::PointerArray* method_array; - if (super_interface) { - mirror::IfTable* if_table = klass->GetSuperClass()->GetIfTable(); - DCHECK(if_table != nullptr); - DCHECK(if_table->GetMethodArray(i) != nullptr); - // If we are working on a super interface, try extending the existing method array. - method_array = down_cast<mirror::PointerArray*>(if_table->GetMethodArray(i)->Clone(self)); - } else { - method_array = AllocPointerArray(self, num_methods); - } - if (UNLIKELY(method_array == nullptr)) { - self->AssertPendingOOMException(); - return false; + if (fill_tables) { + for (size_t i = 0; i < ifcount; ++i) { + size_t num_methods = iftable->GetInterface(i)->NumDeclaredVirtualMethods(); + if (num_methods > 0) { + const bool is_super = i < super_ifcount; + // This is an interface implemented by a super-class. Therefore we can just copy the method + // array from the superclass. + const bool super_interface = is_super && extend_super_iftable; + mirror::PointerArray* method_array; + if (super_interface) { + mirror::IfTable* if_table = klass->GetSuperClass()->GetIfTable(); + DCHECK(if_table != nullptr); + DCHECK(if_table->GetMethodArray(i) != nullptr); + // If we are working on a super interface, try extending the existing method array. + method_array = down_cast<mirror::PointerArray*>(if_table->GetMethodArray(i)->Clone(self)); + } else { + method_array = AllocPointerArray(self, num_methods); + } + if (UNLIKELY(method_array == nullptr)) { + self->AssertPendingOOMException(); + return false; + } + iftable->SetMethodArray(i, method_array); } - iftable->SetMethodArray(i, method_array); } } @@ -5578,12 +5604,16 @@ bool ClassLinker::LinkInterfaceMethods( DCHECK_GE(i, 0u); DCHECK_LT(i, ifcount); - size_t num_methods = iftable->GetInterface(i)->NumVirtualMethods(); + size_t num_methods = iftable->GetInterface(i)->NumDeclaredVirtualMethods(); if (num_methods > 0) { StackHandleScope<2> hs2(self); const bool is_super = i < super_ifcount; const bool super_interface = is_super && extend_super_iftable; - auto method_array(hs2.NewHandle(iftable->GetMethodArray(i))); + // We don't actually create or fill these tables for interfaces, we just copy some methods for + // conflict methods. Just set this as nullptr in those cases. + Handle<mirror::PointerArray> method_array(fill_tables + ? hs2.NewHandle(iftable->GetMethodArray(i)) + : hs2.NewHandle<mirror::PointerArray>(nullptr)); ArraySlice<ArtMethod> input_virtual_methods; ScopedNullHandle<mirror::PointerArray> null_handle; @@ -5596,7 +5626,7 @@ bool ClassLinker::LinkInterfaceMethods( // at the super-classes iftable methods (copied into method_array previously) when we are // looking for the implementation of a super-interface method but that is rather dirty. bool using_virtuals; - if (super_interface) { + if (super_interface || is_interface) { // If we are overwriting a super class interface, try to only virtual methods instead of the // whole vtable. using_virtuals = true; @@ -5606,6 +5636,7 @@ bool ClassLinker::LinkInterfaceMethods( // For a new interface, however, we need the whole vtable in case a new // interface method is implemented in the whole superclass. using_virtuals = false; + DCHECK(vtable.Get() != nullptr); input_vtable_array = vtable; input_array_length = input_vtable_array->GetLength(); } @@ -5655,13 +5686,15 @@ bool ClassLinker::LinkInterfaceMethods( break; } else { found_impl = true; - method_array->SetElementPtrSize(j, vtable_method, image_pointer_size_); - // Place method in imt if entry is empty, place conflict otherwise. - SetIMTRef(unimplemented_method, - imt_conflict_method, - image_pointer_size_, - vtable_method, - /*out*/imt_ptr); + if (LIKELY(fill_tables)) { + method_array->SetElementPtrSize(j, vtable_method, image_pointer_size_); + // Place method in imt if entry is empty, place conflict otherwise. + SetIMTRef(unimplemented_method, + imt_conflict_method, + image_pointer_size_, + vtable_method, + /*out*/imt_ptr); + } break; } } @@ -5688,7 +5721,7 @@ bool ClassLinker::LinkInterfaceMethods( method_array->GetElementPtrSize<ArtMethod*>(j, image_pointer_size_); DCHECK(supers_method != nullptr); DCHECK(interface_name_comparator.HasSameNameAndSignature(supers_method)); - if (!supers_method->IsOverridableByDefaultMethod()) { + if (LIKELY(!supers_method->IsOverridableByDefaultMethod())) { // The method is not overridable by a default method (i.e. it is directly implemented // in some class). Therefore move onto the next interface method. continue; @@ -5710,11 +5743,13 @@ bool ClassLinker::LinkInterfaceMethods( } else { // See if we already have a conflict method for this method. ArtMethod* preexisting_conflict = FindSameNameAndSignature(interface_name_comparator, - default_conflict_methods); + default_conflict_methods); if (LIKELY(preexisting_conflict != nullptr)) { // We already have another conflict we can reuse. default_conflict_method = preexisting_conflict; } else { + // Note that we do this even if we are an interface since we need to create this and + // cannot reuse another classes. // Create a new conflict method for this to use. default_conflict_method = reinterpret_cast<ArtMethod*>(allocator.Alloc(method_size)); @@ -5724,7 +5759,7 @@ bool ClassLinker::LinkInterfaceMethods( } current_method = default_conflict_method; break; - } + } // case kDefaultConflict case DefaultMethodSearchResult::kDefaultFound: { DCHECK(current_method != nullptr); // Found a default method. @@ -5733,8 +5768,12 @@ bool ClassLinker::LinkInterfaceMethods( // We found a default method but it was the same one we already have from our // superclass. Don't bother adding it to our vtable again. current_method = vtable_impl; - } else { + } else if (LIKELY(fill_tables)) { + // Interfaces don't need to copy default methods since they don't have vtables. // Only record this default method if it is new to save space. + // TODO It might be worthwhile to copy default methods on interfaces anyway since it + // would make lookup for interface super much faster. (We would only need to scan + // the iftable to find if there is a NSME or AME.) ArtMethod* old = FindSameNameAndSignature(interface_name_comparator, default_methods); if (old == nullptr) { // We found a default method implementation and there were no conflicts. @@ -5745,7 +5784,7 @@ bool ClassLinker::LinkInterfaceMethods( } } break; - } + } // case kDefaultFound case DefaultMethodSearchResult::kAbstractFound: { DCHECK(current_method == nullptr); // Abstract method masks all defaults. @@ -5757,38 +5796,46 @@ bool ClassLinker::LinkInterfaceMethods( current_method = vtable_impl; } break; - } + } // case kAbstractFound } - if (current_method != nullptr) { - // We found a default method implementation. Record it in the iftable and IMT. - method_array->SetElementPtrSize(j, current_method, image_pointer_size_); - SetIMTRef(unimplemented_method, - imt_conflict_method, - image_pointer_size_, - current_method, - /*out*/imt_ptr); - } else if (!super_interface) { - // We could not find an implementation for this method and since it is a brand new - // interface we searched the entire vtable (and all default methods) for an implementation - // but couldn't find one. We therefore need to make a miranda method. - // - // Find out if there is already a miranda method we can use. - ArtMethod* miranda_method = FindSameNameAndSignature(interface_name_comparator, - miranda_methods); - if (miranda_method == nullptr) { - DCHECK(interface_method->IsAbstract()) << PrettyMethod(interface_method); - miranda_method = reinterpret_cast<ArtMethod*>(allocator.Alloc(method_size)); - CHECK(miranda_method != nullptr); - // Point the interface table at a phantom slot. - new(miranda_method) ArtMethod(interface_method, image_pointer_size_); - miranda_methods.push_back(miranda_method); + if (LIKELY(fill_tables)) { + if (current_method != nullptr) { + // We found a default method implementation. Record it in the iftable and IMT. + method_array->SetElementPtrSize(j, current_method, image_pointer_size_); + SetIMTRef(unimplemented_method, + imt_conflict_method, + image_pointer_size_, + current_method, + /*out*/imt_ptr); + } else if (!super_interface) { + // We could not find an implementation for this method and since it is a brand new + // interface we searched the entire vtable (and all default methods) for an + // implementation but couldn't find one. We therefore need to make a miranda method. + // + // Find out if there is already a miranda method we can use. + ArtMethod* miranda_method = FindSameNameAndSignature(interface_name_comparator, + miranda_methods); + if (miranda_method == nullptr) { + DCHECK(interface_method->IsAbstract()) << PrettyMethod(interface_method); + miranda_method = reinterpret_cast<ArtMethod*>(allocator.Alloc(method_size)); + CHECK(miranda_method != nullptr); + // Point the interface table at a phantom slot. + new(miranda_method) ArtMethod(interface_method, image_pointer_size_); + miranda_methods.push_back(miranda_method); + } + method_array->SetElementPtrSize(j, miranda_method, image_pointer_size_); } - method_array->SetElementPtrSize(j, miranda_method, image_pointer_size_); } - } - } - } - if (!miranda_methods.empty() || !default_methods.empty() || !default_conflict_methods.empty()) { + } // For each method in interface end. + } // if (num_methods > 0) + } // For each interface. + const bool has_new_virtuals = !(miranda_methods.empty() && + default_methods.empty() && + default_conflict_methods.empty()); + // TODO don't extend virtuals of interface unless necessary (when is it?). + if (has_new_virtuals) { + DCHECK(!is_interface || (default_methods.empty() && miranda_methods.empty())) + << "Interfaces should only have default-conflict methods appended to them."; VLOG(class_linker) << PrettyClass(klass.Get()) << ": miranda_methods=" << miranda_methods.size() << " default_methods=" << default_methods.size() << " default_conflict_methods=" << default_conflict_methods.size(); @@ -5885,101 +5932,102 @@ bool ClassLinker::LinkInterfaceMethods( // suspension assert. self->EndAssertNoThreadSuspension(old_cause); - const size_t old_vtable_count = vtable->GetLength(); - const size_t new_vtable_count = old_vtable_count + - miranda_methods.size() + - default_methods.size() + - default_conflict_methods.size(); - miranda_methods.clear(); - vtable.Assign(down_cast<mirror::PointerArray*>(vtable->CopyOf(self, new_vtable_count))); - if (UNLIKELY(vtable.Get() == nullptr)) { - self->AssertPendingOOMException(); - return false; - } - out = methods->begin(method_size, method_alignment) + old_method_count; - size_t vtable_pos = old_vtable_count; - for (size_t i = old_method_count; i < new_method_count; ++i) { - // Leave the declaring class alone as type indices are relative to it - out->SetMethodIndex(0xFFFF & vtable_pos); - vtable->SetElementPtrSize(vtable_pos, &*out, image_pointer_size_); - ++out; - ++vtable_pos; - } - CHECK_EQ(vtable_pos, new_vtable_count); - // Update old vtable methods. We use the default_translations map to figure out what each vtable - // entry should be updated to, if they need to be at all. - for (size_t i = 0; i < old_vtable_count; ++i) { - ArtMethod* translated_method = vtable->GetElementPtrSize<ArtMethod*>(i, image_pointer_size_); - // Try and find what we need to change this method to. - auto translation_it = default_translations.find(i); - bool found_translation = false; - if (translation_it != default_translations.end()) { - if (translation_it->second.IsInConflict()) { - // Find which conflict method we are to use for this method. - MethodNameAndSignatureComparator old_method_comparator( - translated_method->GetInterfaceMethodIfProxy(image_pointer_size_)); - ArtMethod* new_conflict_method = FindSameNameAndSignature(old_method_comparator, - default_conflict_methods); - CHECK(new_conflict_method != nullptr) << "Expected a conflict method!"; - translated_method = new_conflict_method; - } else if (translation_it->second.IsAbstract()) { - // Find which miranda method we are to use for this method. - MethodNameAndSignatureComparator old_method_comparator( - translated_method->GetInterfaceMethodIfProxy(image_pointer_size_)); - ArtMethod* miranda_method = FindSameNameAndSignature(old_method_comparator, - miranda_methods); - DCHECK(miranda_method != nullptr); - translated_method = miranda_method; + if (fill_tables) { + // Update the vtable to the new method structures. We can skip this for interfaces since they + // do not have vtables. + const size_t old_vtable_count = vtable->GetLength(); + const size_t new_vtable_count = old_vtable_count + + miranda_methods.size() + + default_methods.size() + + default_conflict_methods.size(); + vtable.Assign(down_cast<mirror::PointerArray*>(vtable->CopyOf(self, new_vtable_count))); + if (UNLIKELY(vtable.Get() == nullptr)) { + self->AssertPendingOOMException(); + return false; + } + out = methods->begin(method_size, method_alignment) + old_method_count; + size_t vtable_pos = old_vtable_count; + // Update all the newly copied method's indexes so they denote their placement in the vtable. + for (size_t i = old_method_count; i < new_method_count; ++i) { + // Leave the declaring class alone the method's dex_code_item_offset_ and dex_method_index_ + // fields are references into the dex file the method was defined in. Since the ArtMethod + // does not store that information it uses declaring_class_->dex_cache_. + out->SetMethodIndex(0xFFFF & vtable_pos); + vtable->SetElementPtrSize(vtable_pos, &*out, image_pointer_size_); + ++out; + ++vtable_pos; + } + CHECK_EQ(vtable_pos, new_vtable_count); + // Update old vtable methods. We use the default_translations map to figure out what each + // vtable entry should be updated to, if they need to be at all. + for (size_t i = 0; i < old_vtable_count; ++i) { + ArtMethod* translated_method = vtable->GetElementPtrSize<ArtMethod*>( + i, image_pointer_size_); + // Try and find what we need to change this method to. + auto translation_it = default_translations.find(i); + bool found_translation = false; + if (translation_it != default_translations.end()) { + if (translation_it->second.IsInConflict()) { + // Find which conflict method we are to use for this method. + MethodNameAndSignatureComparator old_method_comparator( + translated_method->GetInterfaceMethodIfProxy(image_pointer_size_)); + ArtMethod* new_conflict_method = FindSameNameAndSignature(old_method_comparator, + default_conflict_methods); + CHECK(new_conflict_method != nullptr) << "Expected a conflict method!"; + translated_method = new_conflict_method; + } else if (translation_it->second.IsAbstract()) { + // Find which miranda method we are to use for this method. + MethodNameAndSignatureComparator old_method_comparator( + translated_method->GetInterfaceMethodIfProxy(image_pointer_size_)); + ArtMethod* miranda_method = FindSameNameAndSignature(old_method_comparator, + miranda_methods); + DCHECK(miranda_method != nullptr); + translated_method = miranda_method; + } else { + // Normal default method (changed from an older default or abstract interface method). + DCHECK(translation_it->second.IsTranslation()); + translated_method = translation_it->second.GetTranslation(); + } + found_translation = true; + } + DCHECK(translated_method != nullptr); + auto it = move_table.find(translated_method); + if (it != move_table.end()) { + auto* new_method = it->second; + DCHECK(new_method != nullptr); + vtable->SetElementPtrSize(i, new_method, image_pointer_size_); } else { - // Normal default method (changed from an older default or abstract interface method). - DCHECK(translation_it->second.IsTranslation()); - translated_method = translation_it->second.GetTranslation(); + // If it was not going to be updated we wouldn't have put it into the default_translations + // map. + CHECK(!found_translation) << "We were asked to update this vtable entry. Must not fail."; } - found_translation = true; } - DCHECK(translated_method != nullptr); - auto it = move_table.find(translated_method); - if (it != move_table.end()) { - auto* new_method = it->second; - DCHECK(new_method != nullptr); - vtable->SetElementPtrSize(i, new_method, image_pointer_size_); - } else { - // If it was not going to be updated we wouldn't have put it into the default_translations - // map. - CHECK(!found_translation) << "We were asked to update this vtable entry. Must not fail."; - } - } - - if (kIsDebugBuild) { - for (size_t i = 0; i < new_vtable_count; ++i) { - CHECK(move_table.find(vtable->GetElementPtrSize<ArtMethod*>(i, image_pointer_size_)) == - move_table.end()); + klass->SetVTable(vtable.Get()); + + // Go fix up all the stale iftable pointers. + for (size_t i = 0; i < ifcount; ++i) { + for (size_t j = 0, count = iftable->GetMethodArrayCount(i); j < count; ++j) { + auto* method_array = iftable->GetMethodArray(i); + auto* m = method_array->GetElementPtrSize<ArtMethod*>(j, image_pointer_size_); + DCHECK(m != nullptr) << PrettyClass(klass.Get()); + auto it = move_table.find(m); + if (it != move_table.end()) { + auto* new_m = it->second; + DCHECK(new_m != nullptr) << PrettyClass(klass.Get()); + method_array->SetElementPtrSize(j, new_m, image_pointer_size_); + } + } } - } - klass->SetVTable(vtable.Get()); - // Go fix up all the stale (old miranda or default method) pointers. - // First do it on the iftable. - for (size_t i = 0; i < ifcount; ++i) { - for (size_t j = 0, count = iftable->GetMethodArrayCount(i); j < count; ++j) { - auto* method_array = iftable->GetMethodArray(i); - auto* m = method_array->GetElementPtrSize<ArtMethod*>(j, image_pointer_size_); - DCHECK(m != nullptr) << PrettyClass(klass.Get()); - auto it = move_table.find(m); + // Fix up IMT next + for (size_t i = 0; i < mirror::Class::kImtSize; ++i) { + auto it = move_table.find(out_imt[i]); if (it != move_table.end()) { - auto* new_m = it->second; - DCHECK(new_m != nullptr) << PrettyClass(klass.Get()); - method_array->SetElementPtrSize(j, new_m, image_pointer_size_); + out_imt[i] = it->second; } } } - // Fix up IMT next - for (size_t i = 0; i < mirror::Class::kImtSize; ++i) { - auto it = move_table.find(out_imt[i]); - if (it != move_table.end()) { - out_imt[i] = it->second; - } - } + // Check that there are no stale methods are in the dex cache array. if (kIsDebugBuild) { auto* resolved_methods = klass->GetDexCache()->GetResolvedMethods(); @@ -6003,7 +6051,7 @@ bool ClassLinker::LinkInterfaceMethods( } else { self->EndAssertNoThreadSuspension(old_cause); } - if (kIsDebugBuild) { + if (kIsDebugBuild && !is_interface) { SanityCheckVTable(klass, image_pointer_size_); } return true; @@ -6393,7 +6441,13 @@ ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, DCHECK(resolved == nullptr || resolved->GetDeclaringClass()->IsInterface()); } break; - case kSuper: // Fall-through. + case kSuper: + if (klass->IsInterface()) { + resolved = klass->FindInterfaceMethod(dex_cache.Get(), method_idx, image_pointer_size_); + } else { + resolved = klass->FindVirtualMethod(dex_cache.Get(), method_idx, image_pointer_size_); + } + break; case kVirtual: resolved = klass->FindVirtualMethod(dex_cache.Get(), method_idx, image_pointer_size_); break; @@ -6415,7 +6469,13 @@ ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, resolved = klass->FindInterfaceMethod(name, signature, image_pointer_size_); DCHECK(resolved == nullptr || resolved->GetDeclaringClass()->IsInterface()); break; - case kSuper: // Fall-through. + case kSuper: + if (klass->IsInterface()) { + resolved = klass->FindInterfaceMethod(name, signature, image_pointer_size_); + } else { + resolved = klass->FindVirtualMethod(name, signature, image_pointer_size_); + } + break; case kVirtual: resolved = klass->FindVirtualMethod(name, signature, image_pointer_size_); break; |