Fix issue with IMT dispatch.
If a default and an abstract method map to the same IMT slot one could
end up invoking the default method when one invokes the abstract
method.
Bug: 24618811
Bug: 26827549
Change-Id: I2ccb8e8b5362eb4961531b63e7b946ad8ef936a6
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index bb709e8..080cfb4 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -6245,15 +6245,7 @@
} // case kAbstractFound
}
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) {
+ if (current_method == nullptr && !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.
@@ -6269,7 +6261,17 @@
new(miranda_method) ArtMethod(interface_method, image_pointer_size_);
miranda_methods.push_back(miranda_method);
}
- method_array->SetElementPtrSize(j, miranda_method, image_pointer_size_);
+ current_method = miranda_method;
+ }
+
+ 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);
}
}
} // For each method in interface end.