Treat non-lambda metafactory argument method handles specially.

They can reach MethodHandle.invokeExact calls which match exact
method signatures. Therefore, we cannot perform member rebinding
on the methods in method handles because that could (and likely
would) change the receiver type making the matching fail.

Therefore, we keep the original receiver type for all such
method handles. That also means that we need to keep those
receiver types in the output and cannot perform merging or
other operations that would make those types disappear.

R=christofferqa@google.com, sgjesse@google.com, tamaskenez@google.com

Change-Id: Ic31373f574493b6941acca176f39decf0ef12182
diff --git a/src/test/examplesAndroidP/invokecustom/TestGenerator.java b/src/test/examplesAndroidP/invokecustom/TestGenerator.java
index 7ee4bdc..495f080 100644
--- a/src/test/examplesAndroidP/invokecustom/TestGenerator.java
+++ b/src/test/examplesAndroidP/invokecustom/TestGenerator.java
@@ -46,6 +46,8 @@
             public void visitEnd() {
               generateMethodTest1(cw);
               generateMethodTest2(cw);
+              generateMethodTest3(cw);
+              generateMethodTest4(cw);
               generateMethodMain(cw);
               super.visitEnd();
             }
@@ -64,20 +66,24 @@
         Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test1", "()V", false);
     mv.visitMethodInsn(
         Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test2", "()V", false);
+    mv.visitMethodInsn(
+        Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test3", "()V", false);
+    mv.visitMethodInsn(
+        Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test4", "()V", false);
     mv.visitInsn(Opcodes.RETURN);
     mv.visitMaxs(-1, -1);
   }
 
   /**
-   *  Generate test with an invokedynamic, a static bootstrap method without extra args and
-   *  args to the target method.
+   * Generate test with an invokedynamic, a static bootstrap method without extra args and
+   * args to the target method.
    */
   private void generateMethodTest1(ClassVisitor cv) {
     MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test1", "()V",
         null, null);
     MethodType mt = MethodType.methodType(
             CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class);
-    Handle bootstrap = new Handle( Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class),
+    Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class),
         "bsmLookupStatic", mt.toMethodDescriptorString(), false);
     mv.visitLdcInsn(new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class),
         "targetMethodTest1", "()V", false));
@@ -91,15 +97,15 @@
   }
 
   /**
-   *  Generate test with an invokedynamic, a static bootstrap method without extra args and
-   *  args to the target method.
+   * Generate test with an invokedynamic, a static bootstrap method without extra args and
+   * args to the target method.
    */
   private void generateMethodTest2(ClassVisitor cv) {
     MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test2", "()V",
         null, null);
     MethodType mt = MethodType.methodType(
         CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class);
-    Handle bootstrap = new Handle( Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class),
+    Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class),
         "bsmLookupStatic", mt.toMethodDescriptorString(), false);
     mv.visitLdcInsn(Type.getMethodType("(ZBSCIFJDLjava/lang/String;)Ljava/lang/Object;"));
     mv.visitInvokeDynamicInsn("targetMethodTest3", "(Ljava/lang/invoke/MethodType;)V",
@@ -107,4 +113,59 @@
     mv.visitInsn(Opcodes.RETURN);
     mv.visitMaxs(-1, -1);
   }
+
+  /**
+   * Generate test with a const method handle pointing to the middle of a class hierarchy.
+   * Call a static method with the method handle which will do a MethodHandle.invoke call on
+   * a sub class instance.
+   *
+   * Tests that the const method handle is rewritten when renaming. Also tests that the
+   * middle class does not disappear (for instance via class merging).
+   */
+  private void generateMethodTest3(ClassVisitor cv) {
+    MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test3", "()V",
+        null, null);
+    MethodType mt = MethodType.methodType(ReturnType.class, ArgumentType.class);
+    Handle invokeWithArg = new Handle(
+        Opcodes.H_INVOKEVIRTUAL,
+        Type.getInternalName(Middle.class),
+        "targetMethodTest4",
+        mt.toMethodDescriptorString(),
+        false);
+    mv.visitLdcInsn(invokeWithArg);
+    mv.visitMethodInsn(
+        Opcodes.INVOKESTATIC,
+        Type.getInternalName(InvokeCustom.class),
+        "doInvokeSubWithArg",
+        "(Ljava/lang/invoke/MethodHandle;)V",
+        false);
+    mv.visitInsn(Opcodes.RETURN);
+    mv.visitMaxs(-1, -1);
+  }
+
+  /**
+   * Generate test with a const method handle pointing to a class which inherits the method from
+   * the super class. Call a static method with the method handle which will do a
+   * MethodHandle.invokeExact.
+   */
+  private void generateMethodTest4(ClassVisitor cv) {
+    MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test4", "()V",
+        null, null);
+    MethodType mt = MethodType.methodType(ReturnType.class, ArgumentType.class);
+    Handle invokeExactWithArg = new Handle(
+        Opcodes.H_INVOKEVIRTUAL,
+        Type.getInternalName(Impl.class),
+        "targetMethodTest5",
+        mt.toMethodDescriptorString(),
+        false);
+    mv.visitLdcInsn(invokeExactWithArg);
+    mv.visitMethodInsn(
+        Opcodes.INVOKESTATIC,
+        Type.getInternalName(InvokeCustom.class),
+        "doInvokeExactImplWithArg",
+        "(Ljava/lang/invoke/MethodHandle;)V",
+        false);
+    mv.visitInsn(Opcodes.RETURN);
+    mv.visitMaxs(-1, -1);
+  }
 }