ART: fix method handle invocation of abstract & interface methods
Bug: 35422408
Test: m test-art-host
Change-Id: I1f60501a7d2e9d8c8b935709ae2d624af9f882ef
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 6ecfd8c..58c5d17 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -419,6 +419,32 @@
JValue* result,
const mirror::MethodHandle::Kind handle_kind)
REQUIRES_SHARED(Locks::mutator_lock_) {
+ // For virtual and interface methods ensure called_method points to
+ // the actual method to invoke.
+ if (handle_kind == mirror::MethodHandle::Kind::kInvokeVirtual ||
+ handle_kind == mirror::MethodHandle::Kind::kInvokeInterface) {
+ uint32_t receiver_reg = is_range ? first_arg : args[0];
+ ObjPtr<mirror::Object> receiver(shadow_frame.GetVRegReference(receiver_reg));
+ if (IsCallerTransformer(callsite_type)) {
+ // The current receiver is an emulated stack frame, the method's
+ // receiver needs to be fetched from there as the emulated frame
+ // will be unpacked into a new frame.
+ receiver = ObjPtr<mirror::EmulatedStackFrame>::DownCast(receiver)->GetReceiver();
+ }
+
+ ObjPtr<mirror::Class> declaring_class(called_method->GetDeclaringClass());
+ if (receiver == nullptr || receiver->GetClass() != declaring_class) {
+ // Verify that _vRegC is an object reference and of the type expected by
+ // the receiver.
+ if (!VerifyObjectIsClass(receiver, declaring_class)) {
+ DCHECK(self->IsExceptionPending());
+ return false;
+ }
+ called_method = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(
+ called_method, kRuntimePointerSize);
+ }
+ }
+
// Compute method information.
const DexFile::CodeItem* code_item = called_method->GetCodeItem();
@@ -502,24 +528,6 @@
}
}
- // See TODO in DoInvokePolymorphic : We need to perform this dynamic, receiver
- // based dispatch right before we perform the actual call, because the
- // receiver isn't known very early.
- if (handle_kind == mirror::MethodHandle::Kind::kInvokeVirtual ||
- handle_kind == mirror::MethodHandle::Kind::kInvokeInterface) {
- ObjPtr<mirror::Object> receiver(new_shadow_frame->GetVRegReference(first_dest_reg));
- ObjPtr<mirror::Class> declaring_class(called_method->GetDeclaringClass());
- // Verify that _vRegC is an object reference and of the type expected by
- // the receiver.
- if (!VerifyObjectIsClass(receiver, declaring_class)) {
- DCHECK(self->IsExceptionPending());
- return false;
- }
-
- called_method = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(
- called_method, kRuntimePointerSize);
- }
-
PerformCall(self, code_item, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, result);
if (self->IsExceptionPending()) {
return false;
diff --git a/runtime/mirror/emulated_stack_frame.h b/runtime/mirror/emulated_stack_frame.h
index ddd84a1..76859ef 100644
--- a/runtime/mirror/emulated_stack_frame.h
+++ b/runtime/mirror/emulated_stack_frame.h
@@ -62,6 +62,10 @@
return GetFieldObject<MethodType>(OFFSET_OF_OBJECT_MEMBER(EmulatedStackFrame, type_));
}
+ mirror::Object* GetReceiver() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetReferences()->Get(0);
+ }
+
static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_);
static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/test/956-methodhandles/src/Main.java b/test/956-methodhandles/src/Main.java
index fc9f030..cb06e42 100644
--- a/test/956-methodhandles/src/Main.java
+++ b/test/956-methodhandles/src/Main.java
@@ -183,15 +183,23 @@
public String bar();
}
- public static class BarSuper {
+ public static abstract class BarAbstractSuper {
+ public abstract String abstractSuperPublicMethod();
+ }
+
+ public static class BarSuper extends BarAbstractSuper {
public String superPublicMethod() {
return "superPublicMethod";
}
- public String superProtectedMethod() {
+ protected String superProtectedMethod() {
return "superProtectedMethod";
}
+ public String abstractSuperPublicMethod() {
+ return "abstractSuperPublicMethod";
+ }
+
String superPackageMethod() {
return "superPackageMethod";
}
@@ -288,15 +296,19 @@
System.out.println("Unexpected return value for BarImpl#bar: " + str);
}
- // TODO(narayan): Fix this case, we're using the wrong ArtMethod for the
- // invoke resulting in a failing check in the interpreter.
- //
- // mh = MethodHandles.lookup().findVirtual(Bar.class, "bar",
- // MethodType.methodType(String.class));
- // str = (String) mh.invoke(new BarImpl());
- // if (!"bar".equals(str)) {
- // System.out.println("Unexpected return value for BarImpl#bar: " + str);
- // }
+ mh = MethodHandles.lookup().findVirtual(Bar.class, "bar",
+ MethodType.methodType(String.class));
+ str = (String) mh.invoke(new BarImpl());
+ if (!"bar".equals(str)) {
+ System.out.println("Unexpected return value for BarImpl#bar: " + str);
+ }
+
+ mh = MethodHandles.lookup().findVirtual(BarAbstractSuper.class, "abstractSuperPublicMethod",
+ MethodType.methodType(String.class));
+ str = (String) mh.invoke(new BarImpl());
+ if (!"abstractSuperPublicMethod".equals(str)) {
+ System.out.println("Unexpected return value for BarImpl#abstractSuperPublicMethod: " + str);
+ }
// We should also be able to lookup public / protected / package methods in
// the super class, given sufficient access privileges.