ART: Fix MethodHandle invoke-super

Adds test for MethodHandles.unreflectSpecial() and fixes the
associated method refinement in the method handle dispatch.

Bug: 77729852
Test: art/test/run-test --host --64 956

(cherry picked from commit d7959c2abe72629581f7465500b95a3d4e57e7ca)

Change-Id: Idf022997a3d34b75428cac0bc539f6ea4bb1bc94
Merged-In: I6c364a5a6edaa9e9d04ae96683d5bb3e6adbcb6e
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 82370c4..64ab789 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -674,13 +674,15 @@
       return WellKnownClasses::StringInitToStringFactory(target_method);
     }
   } else if (handle_kind == mirror::MethodHandle::Kind::kInvokeSuper) {
-    ObjPtr<mirror::Class> declaring_class = target_method->GetDeclaringClass();
-
     // Note that we're not dynamically dispatching on the type of the receiver
     // here. We use the static type of the "receiver" object that we've
     // recorded in the method handle's type, which will be the same as the
     // special caller that was specified at the point of lookup.
     ObjPtr<mirror::Class> referrer_class = handle_type->GetPTypes()->Get(0);
+    ObjPtr<mirror::Class> declaring_class = target_method->GetDeclaringClass();
+    if (referrer_class == declaring_class) {
+      return target_method;
+    }
     if (!declaring_class->IsInterface()) {
       ObjPtr<mirror::Class> super_class = referrer_class->GetSuperClass();
       uint16_t vtable_index = target_method->GetMethodIndex();
@@ -690,8 +692,6 @@
       // will always be declared by super_class (or one of its super classes).
       DCHECK_LT(vtable_index, super_class->GetVTableLength());
       return super_class->GetVTableEntry(vtable_index, kRuntimePointerSize);
-    } else {
-      return referrer_class->FindVirtualMethodForInterfaceSuper(target_method, kRuntimePointerSize);
     }
   }
   return target_method;
diff --git a/test/956-methodhandles/expected.txt b/test/956-methodhandles/expected.txt
index 9b09327..6954c22 100644
--- a/test/956-methodhandles/expected.txt
+++ b/test/956-methodhandles/expected.txt
@@ -3,7 +3,17 @@
 foo_A
 foo_B
 privateRyan_D
-Received exception: Expected (java.lang.String, java.lang.String)java.lang.String but was (java.lang.String, java.lang.Object)void
+Received WrongMethodTypeException exception
+G.sayHi()
+G.sayHi()
+G.sayHi()
+F.sayHi()
+F.sayHi()
+H.chatter()
+H.chatter()
+H.chatter()
+Chatty.chatter()
+Chatty.chatter()
 String constructors done.
 testReferenceReturnValueConversions done.
 testPrimitiveReturnValueConversions done.
diff --git a/test/956-methodhandles/src/Main.java b/test/956-methodhandles/src/Main.java
index 1ddef03..dee818a 100644
--- a/test/956-methodhandles/src/Main.java
+++ b/test/956-methodhandles/src/Main.java
@@ -30,6 +30,8 @@
 import java.util.Arrays;
 import java.util.List;
 
+import other.Chatty;
+
 public class Main {
 
   public static class A {
@@ -66,6 +68,30 @@
     public static final Lookup lookup = MethodHandles.lookup();
   }
 
+  private interface F {
+    public default void sayHi() {
+      System.out.println("F.sayHi()");
+    }
+  }
+
+  public static class G implements F {
+    public void sayHi() {
+      System.out.println("G.sayHi()");
+    }
+    public MethodHandles.Lookup getLookup() {
+      return MethodHandles.lookup();
+    }
+  }
+
+  public static class H implements Chatty {
+    public void chatter() {
+      System.out.println("H.chatter()");
+    }
+    public MethodHandles.Lookup getLookup() {
+      return MethodHandles.lookup();
+    }
+  }
+
   public static void main(String[] args) throws Throwable {
     testfindSpecial_invokeSuperBehaviour();
     testfindSpecial_invokeDirectBehaviour();
@@ -173,7 +199,7 @@
       handle.invokeExact("a", new Object());
       System.out.println("invokeExact(\"a\", new Object()) unexpectedly succeeded.");
     } catch (WrongMethodTypeException ex) {
-      System.out.println("Received exception: " + ex.getMessage());
+      System.out.println("Received WrongMethodTypeException exception");
     }
   }
 
@@ -528,6 +554,34 @@
     privateStaticField.set(null, "updatedStaticValue");
     mh.invokeExact("updatedStaticValue2");
     assertEquals("updatedStaticValue2", (String) privateStaticField.get(null));
+
+    // unreflectSpecial testing - F is an interface that G implements
+
+    G g = new G();
+    g.sayHi();  // prints "G.sayHi()"
+
+    MethodHandles.Lookup lookupInG = g.getLookup();
+    Method methodInG = G.class.getDeclaredMethod("sayHi");
+    lookupInG.unreflectSpecial(methodInG, G.class).invoke(g); // prints "G.sayHi()"
+
+    Method methodInF = F.class.getDeclaredMethod("sayHi");
+    lookupInG.unreflect(methodInF).invoke(g);  // prints "G.sayHi()"
+    lookupInG.in(G.class).unreflectSpecial(methodInF, G.class).invoke(g);  // prints "F.sayHi()"
+    lookupInG.unreflectSpecial(methodInF, G.class).bindTo(g).invokeWithArguments();
+
+    // unreflectSpecial testing - other.Chatty is an interface that H implements
+
+    H h = new H();
+    h.chatter();
+
+    MethodHandles.Lookup lookupInH = h.getLookup();
+    Method methodInH = H.class.getDeclaredMethod("chatter");
+    lookupInH.unreflectSpecial(methodInH, H.class).invoke(h);
+
+    Method methodInChatty = Chatty.class.getDeclaredMethod("chatter");
+    lookupInH.unreflect(methodInChatty).invoke(h);
+    lookupInH.in(H.class).unreflectSpecial(methodInChatty, H.class).invoke(h);
+    lookupInH.unreflectSpecial(methodInChatty, H.class).bindTo(h).invokeWithArguments();
   }
 
   // This method only exists to fool Jack's handling of types. See b/32536744.
diff --git a/test/956-methodhandles/src/other/Chatty.java b/test/956-methodhandles/src/other/Chatty.java
new file mode 100644
index 0000000..98aef14
--- /dev/null
+++ b/test/956-methodhandles/src/other/Chatty.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package other;
+
+public interface Chatty {
+  public default void chatter() {
+    System.out.println("Chatty.chatter()");
+  }
+}