summaryrefslogtreecommitdiff
path: root/runtime/class_linker.cc
diff options
context:
space:
mode:
author Nicolas Geoffray <ngeoffray@google.com> 2023-02-03 10:31:19 +0000
committer Nicolas Geoffray <ngeoffray@google.com> 2023-02-08 09:28:36 +0000
commit347e4cf059cd39f2dcfd2709eadd2e82ccade58d (patch)
tree788547e84f11054b68b78f490a9ee3718c0b1cb3 /runtime/class_linker.cc
parentd79af3d7c388c84c4f49eb0d4e0158656019fe83 (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.cc44
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_);