diff options
author | 2023-02-03 10:31:19 +0000 | |
---|---|---|
committer | 2023-02-08 09:28:36 +0000 | |
commit | 347e4cf059cd39f2dcfd2709eadd2e82ccade58d (patch) | |
tree | 788547e84f11054b68b78f490a9ee3718c0b1cb3 /runtime/class_linker.cc | |
parent | d79af3d7c388c84c4f49eb0d4e0158656019fe83 (diff) |
Reland "Walk up the super chain to find an IMT to share."
This reverts commit ef0b1544519f91fc5663b06d433da474115feb5a.
Bug: 266937358
Reason for revert: Fix wrong assumption: an IMT being shared can be
updated for subclasses, but we need to use the right allocator.
Change-Id: I0055a81d30199e5cba53f21a5b759fe530a0dfa2
Diffstat (limited to 'runtime/class_linker.cc')
-rw-r--r-- | runtime/class_linker.cc | 44 |
1 files changed, 28 insertions, 16 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index c772a9c29a..08457852a4 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -5988,17 +5988,6 @@ ClassTable* ClassLinker::ClassTableForClassLoader(ObjPtr<mirror::ClassLoader> cl return class_loader == nullptr ? boot_class_table_.get() : class_loader->GetClassTable(); } -static ImTable* FindSuperImt(ObjPtr<mirror::Class> klass, PointerSize pointer_size) - REQUIRES_SHARED(Locks::mutator_lock_) { - while (klass->HasSuperClass()) { - klass = klass->GetSuperClass(); - if (klass->ShouldHaveImt()) { - return klass->GetImt(pointer_size); - } - } - return nullptr; -} - bool ClassLinker::LinkClass(Thread* self, const char* descriptor, Handle<mirror::Class> klass, @@ -6034,7 +6023,7 @@ bool ClassLinker::LinkClass(Thread* self, // will possibly create a table that is incorrect for either of the classes. // Same IMT with new_conflict does not happen very often. if (!new_conflict) { - ImTable* super_imt = FindSuperImt(klass.Get(), image_pointer_size_); + ImTable* super_imt = klass->FindSuperImt(image_pointer_size_); if (super_imt != nullptr) { bool imt_equals = true; for (size_t i = 0; i < ImTable::kSize && imt_equals; ++i) { @@ -6317,13 +6306,36 @@ class MethodNameAndSignatureComparator final : public ValueObject { std::string_view name_view_; }; +static ObjPtr<mirror::Class> GetImtOwner(ObjPtr<mirror::Class> klass) + REQUIRES_SHARED(Locks::mutator_lock_) { + ImTable* imt = klass->GetImt(kRuntimePointerSize); + DCHECK(imt != nullptr); + while (klass->HasSuperClass()) { + ObjPtr<mirror::Class> super_class = klass->GetSuperClass(); + if (super_class->ShouldHaveImt() && imt != super_class->GetImt(kRuntimePointerSize)) { + // IMT not shared with the super class, return the current class. + return klass; + } + klass = super_class; + } + return nullptr; +} + ArtMethod* ClassLinker::AddMethodToConflictTable(ObjPtr<mirror::Class> klass, ArtMethod* conflict_method, ArtMethod* interface_method, ArtMethod* method) { ImtConflictTable* current_table = conflict_method->GetImtConflictTable(kRuntimePointerSize); Runtime* const runtime = Runtime::Current(); - LinearAlloc* linear_alloc = GetAllocatorForClassLoader(klass->GetClassLoader()); + + // The IMT may be shared with a super class, in which case we need to use that + // super class's `LinearAlloc`. The conflict itself should be limited to + // methods at or higher up the chain of the IMT owner, otherwise class + // linker would have created a different IMT. + ObjPtr<mirror::Class> imt_owner = GetImtOwner(klass); + DCHECK(imt_owner != nullptr); + + LinearAlloc* linear_alloc = GetAllocatorForClassLoader(imt_owner->GetClassLoader()); // Create a new entry if the existing one is the shared conflict method. ArtMethod* new_conflict_method = (conflict_method == runtime->GetImtConflictMethod()) @@ -6408,9 +6420,8 @@ void ClassLinker::FillIMTAndConflictTables(ObjPtr<mirror::Class> klass) { // Compare the IMT with the super class including the conflict methods. If they are equivalent, // we can just use the same pointer. ImTable* imt = nullptr; - ObjPtr<mirror::Class> super_class = klass->GetSuperClass(); - if (super_class != nullptr && super_class->ShouldHaveImt()) { - ImTable* super_imt = super_class->GetImt(image_pointer_size_); + ImTable* super_imt = klass->FindSuperImt(image_pointer_size_); + if (super_imt != nullptr) { bool same = true; for (size_t i = 0; same && i < ImTable::kSize; ++i) { ArtMethod* method = imt_data[i]; @@ -6439,6 +6450,7 @@ void ClassLinker::FillIMTAndConflictTables(ObjPtr<mirror::Class> klass) { if (imt == nullptr) { imt = klass->GetImt(image_pointer_size_); DCHECK(imt != nullptr); + DCHECK_NE(imt, super_imt); imt->Populate(imt_data, image_pointer_size_); } else { klass->SetImt(imt, image_pointer_size_); |