Align method handle type with the runtime - Remove temporary hack in invoke-custom test due to runtime bug since an updated runtime fix it. Change-Id: I5424bacf7ca0e292974df7e81b35dea51d8a9b51
diff --git a/src/test/examplesAndroidO/invokecustom/InvokeCustom.java b/src/test/examplesAndroidO/invokecustom/InvokeCustom.java index 0d4d5c5..449d426 100644 --- a/src/test/examplesAndroidO/invokecustom/InvokeCustom.java +++ b/src/test/examplesAndroidO/invokecustom/InvokeCustom.java
@@ -102,74 +102,15 @@ System.out.println("targetMethodTest4"); } - public static CallSite bsmCreateCallSite( - MethodHandles.Lookup caller, String name, MethodType type, MethodHandle mh) - throws Throwable { - // Using mh to create the call site fails when run on Art. See b/36957105 for details. - final MethodHandle targetMH = MethodHandles.lookup().findSpecial(Super.class, - "targetMethodTest5", MethodType.methodType(void.class), InvokeCustom.class); - return new ConstantCallSite(targetMH); - } - - public static CallSite bsmCreateCallCallingtargetMethodTest6( - MethodHandles.Lookup caller, String name, MethodType type, MethodHandle mh) - throws Throwable { - // Using mh to create the call site fails when run on Art. See b/36957105 for details. - final MethodHandle targetMH = - MethodHandles.lookup().findVirtual( - I.class, "targetMethodTest6", MethodType.methodType(void.class)); - return new ConstantCallSite(targetMH); - } - - public static CallSite bsmCreateCallCallingtargetMethodTest7( - MethodHandles.Lookup caller, String name, MethodType type, MethodHandle mh) - throws Throwable { - // Using mh to create the call site fails when run on Art. See b/36957105 for details. - final MethodHandle targetMH = - MethodHandles.lookup().findVirtual( - J.class, "targetMethodTest7", MethodType.methodType(void.class)); - return new ConstantCallSite(targetMH); - } - public void targetMethodTest8() { System.out.println("targetMethodTest8 from InvokeCustom"); } - public static CallSite bsmCreateCallCallingtargetMethodTest8( - MethodHandles.Lookup caller, String name, MethodType type, MethodHandle mh) - throws Throwable { - // Using mh to create the call site fails when run on Art. See b/36957105 for details. - final MethodHandle targetMH = - MethodHandles.lookup().findVirtual( - J.class, "targetMethodTest8", MethodType.methodType(void.class)); - return new ConstantCallSite(targetMH); - } - - public static CallSite bsmCreateCallCallingtargetMethodTest9( - MethodHandles.Lookup caller, String name, MethodType type, MethodHandle mh) - throws Throwable { - // Using mh to create the call site fails when run on Art. See b/36957105 for details. - final MethodHandle targetMH = - MethodHandles.lookup().findVirtual( - InvokeCustom.class, "targetMethodTest9", MethodType.methodType(void.class)); - return new ConstantCallSite(targetMH); - } - public void targetMethodTest10() { System.out.println("targetMethodTest10 from InvokeCustom"); } - public static CallSite bsmCreateCallCallingtargetMethodTest10( - MethodHandles.Lookup caller, String name, MethodType type, MethodHandle mh) - throws Throwable { - // Using mh to create the call site fails when run on Art. See b/36957105 for details. - final MethodHandle targetMH = - MethodHandles.lookup().findVirtual( - InvokeCustom.class, "targetMethodTest10", MethodType.methodType(void.class)); - return new ConstantCallSite(targetMH); - } - - public static CallSite bsmCreateCallCallingtargetMethod( + public static CallSite bsmCreateCallSite( MethodHandles.Lookup caller, String name, MethodType type, MethodHandle mh) throws Throwable { return new ConstantCallSite(mh);
diff --git a/src/test/examplesAndroidO/invokecustom/TestGenerator.java b/src/test/examplesAndroidO/invokecustom/TestGenerator.java index 883106f..5c550e9 100644 --- a/src/test/examplesAndroidO/invokecustom/TestGenerator.java +++ b/src/test/examplesAndroidO/invokecustom/TestGenerator.java
@@ -189,7 +189,7 @@ MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, MethodHandle.class); Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class), - "bsmCreateCallCallingtargetMethodTest6", mt.toMethodDescriptorString(), false); + "bsmCreateCallSite", mt.toMethodDescriptorString(), false); mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(InvokeCustom.class)); mv.visitInsn(Opcodes.DUP); mv.visitMethodInsn( @@ -212,7 +212,7 @@ MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, MethodHandle.class); Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class), - "bsmCreateCallCallingtargetMethodTest7", mt.toMethodDescriptorString(), false); + "bsmCreateCallSite", mt.toMethodDescriptorString(), false); mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(InvokeCustom.class)); mv.visitInsn(Opcodes.DUP); mv.visitMethodInsn( @@ -235,7 +235,7 @@ MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, MethodHandle.class); Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class), - "bsmCreateCallCallingtargetMethodTest8", mt.toMethodDescriptorString(), false); + "bsmCreateCallSite", mt.toMethodDescriptorString(), false); mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(InvokeCustom.class)); mv.visitInsn(Opcodes.DUP); mv.visitMethodInsn( @@ -258,7 +258,7 @@ MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, MethodHandle.class); Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class), - "bsmCreateCallCallingtargetMethodTest9", mt.toMethodDescriptorString(), false); + "bsmCreateCallSite", mt.toMethodDescriptorString(), false); mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(InvokeCustom.class)); mv.visitInsn(Opcodes.DUP); mv.visitMethodInsn( @@ -281,7 +281,7 @@ MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, MethodHandle.class); Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class), - "bsmCreateCallCallingtargetMethodTest10", mt.toMethodDescriptorString(), false); + "bsmCreateCallSite", mt.toMethodDescriptorString(), false); mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(InvokeCustom.class)); mv.visitInsn(Opcodes.DUP); mv.visitMethodInsn( @@ -303,7 +303,7 @@ MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, MethodHandle.class); Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class), - "bsmCreateCallCallingtargetMethod", mt.toMethodDescriptorString(), false); + "bsmCreateCallSite", mt.toMethodDescriptorString(), false); mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", @@ -330,7 +330,7 @@ MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, MethodHandle.class); Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class), - "bsmCreateCallCallingtargetMethod", mt.toMethodDescriptorString(), false); + "bsmCreateCallSite", mt.toMethodDescriptorString(), false); mv.visitLdcInsn("Write static field"); mv.visitInvokeDynamicInsn("staticField1", "(Ljava/lang/String;)V", bootstrap, new Handle(Opcodes.H_PUTSTATIC, Type.getInternalName(InvokeCustom.class), @@ -361,7 +361,7 @@ MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, MethodHandle.class); Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class), - "bsmCreateCallCallingtargetMethod", mt.toMethodDescriptorString(), false); + "bsmCreateCallSite", mt.toMethodDescriptorString(), false); mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", @@ -392,7 +392,7 @@ MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, MethodHandle.class); Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class), - "bsmCreateCallCallingtargetMethod", mt.toMethodDescriptorString(), false); + "bsmCreateCallSite", mt.toMethodDescriptorString(), false); mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(InvokeCustom.class)); mv.visitInsn(Opcodes.DUP); mv.visitMethodInsn(
diff --git a/src/test/examplesAndroidO/invokecustom2/InvokeCustom.java b/src/test/examplesAndroidO/invokecustom2/InvokeCustom.java new file mode 100644 index 0000000..62048b0 --- /dev/null +++ b/src/test/examplesAndroidO/invokecustom2/InvokeCustom.java
@@ -0,0 +1,186 @@ +// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +package invokecustom2; + +import java.lang.invoke.CallSite; +import java.lang.invoke.ConstantCallSite; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.Arrays; +import java.util.List; + +abstract class Super { + public void targetMethodTest4() { + System.out.println("targetMethodTest4 from Super"); + } + + public abstract void helperMethodTest9(); +} + +public class InvokeCustom extends Super implements Runnable { + + public InvokeCustom() {} + public InvokeCustom(int i) { + System.out.println("InvokeCustom.<init>(" + i + ")"); + } + + private static void targetMethodTest1() { + System.out.println("Hello World!"); + } + + private static void targetMethodTest2(boolean z, byte b, char c, short s, int i, float f, long l, + double d, String str) { + System.out.println(z); + System.out.println(b); + System.out.println(c); + System.out.println(s); + System.out.println(i); + System.out.println(f); + System.out.println(l); + System.out.println(d); + System.out.println(str); + } + + private static void targetMethodTest3() { + System.out.println("targetMethodTest3 from InvokeCustom"); + } + + @Override + public void targetMethodTest4() { + // The generated code should be calling Super.targetMethodTest4. + System.out.println("targetMethodTest4 from InvokeCustom (oops!)"); + } + + public static int targetMethodTest5(int x, int y, int total) { + int calculated = x + y; + System.out.println("targetMethodTest5 " + x + " + " + y + " = " + calculated); + if (calculated != total) { + System.out.println("Failed " + calculated + " != " + total); + } + return calculated; + } + + public static long targetMethodTest6(long x, long y, long total) { + long calculated = x + y; + System.out.println("targetMethodTest6 " + x + " + " + y + " = " + calculated); + if (calculated != total) { + System.out.println("Failed " + calculated + " != " + total); + } + return calculated; + } + + public static double targetMethodTest7(float x, float y, double product) { + double calculated = x * y; + System.out.println("targetMethodTest7 " + x + " * " + y + " = " + calculated); + if (calculated != product) { + System.out.println("Failed " + calculated + " != " + product); + } + return calculated; + } + + public static void targetMethodTest8(String s) { + System.out.println("targetMethodTest8 " + s); + } + + private static int staticFieldTest9 = 0; + + private static void checkStaticFieldTest9(MethodHandle getter, MethodHandle setter) + throws Throwable { + final int NEW_VALUE = 0x76543210; + int oldValue = (int) getter.invokeExact(); + setter.invokeExact(NEW_VALUE); + int newValue = (int) getter.invokeExact(); + System.out.print("checkStaticFieldTest9: old " + oldValue + " new " + newValue + + " expected " + NEW_VALUE + " "); + System.out.println((newValue == NEW_VALUE) ? "OK" : "ERROR"); + } + + private float fieldTest9 = 0.0f; + + private void checkFieldTest9(MethodHandle getter, MethodHandle setter) + throws Throwable { + final float NEW_VALUE = 1.99e-19f; + float oldValue = (float) getter.invokeExact(this); + setter.invokeExact(this, NEW_VALUE); + float newValue = (float) getter.invokeExact(this); + System.out.print("checkFieldTest9: old " + oldValue + " new " + newValue + + " expected " + NEW_VALUE + " "); + System.out.println((newValue == NEW_VALUE) ? "OK" : "ERROR"); + } + + public void helperMethodTest9() { + System.out.println("helperMethodTest9 in " + InvokeCustom.class); + } + + private static void targetMethodTest9() { + System.out.println("targetMethodTest9()"); + } + + public void run() { + System.out.println("run() for Test9"); + } + + public static CallSite bsmLookupStatic(MethodHandles.Lookup caller, String name, MethodType type) + throws NoSuchMethodException, IllegalAccessException { + System.out.println("bsmLookupStatic []"); + final MethodHandles.Lookup lookup = MethodHandles.lookup(); + final MethodHandle targetMH = lookup.findStatic(lookup.lookupClass(), name, type); + return new ConstantCallSite(targetMH.asType(type)); + } + + public static CallSite bsmLookupStaticWithExtraArgs( + MethodHandles.Lookup caller, String name, MethodType type, int i, long l, float f, double d) + throws NoSuchMethodException, IllegalAccessException { + System.out.println("bsmLookupStaticWithExtraArgs [" + i + ", " + l + ", " + f + ", " + d + "]"); + final MethodHandles.Lookup lookup = MethodHandles.lookup(); + final MethodHandle targetMH = lookup.findStatic(lookup.lookupClass(), name, type); + return new ConstantCallSite(targetMH.asType(type)); + } + + public static CallSite bsmCreateCallSite( + MethodHandles.Lookup caller, String name, MethodType type, MethodHandle mh) + throws Throwable { + System.out.println("bsmCreateCallSite [" + mh + "]"); + return new ConstantCallSite(mh); + } + + private void privateMethodTest9() { + System.out.println("InvokeCustom.privateMethodTest9()"); + } + + public static CallSite bsmLookupTest9(MethodHandles.Lookup caller, String name, MethodType type, + MethodHandle staticGetter, MethodHandle staticSetter, + MethodHandle fieldGetter, MethodHandle fieldSetter, + MethodHandle instanceInvoke, MethodHandle constructor, + MethodHandle interfaceInvoke, MethodHandle privateInvoke) + throws Throwable { + System.out.println("bsmLookupTest9 [" + staticGetter + ", " + staticSetter + ", " + + fieldGetter + ", " + fieldSetter + "]"); + System.out.println(name + " " + type); + + // Check constant method handles passed can be invoked. + checkStaticFieldTest9(staticGetter, staticSetter); + InvokeCustom instance = new InvokeCustom(); + instance.checkFieldTest9(fieldGetter, fieldSetter); + + // Check virtual method. + instanceInvoke.invokeExact(instance); + + InvokeCustom instance2 = (InvokeCustom) constructor.invokeExact(3); + interfaceInvoke.invoke(instance2); + privateInvoke.invoke(instance2); + + final MethodHandles.Lookup lookup = MethodHandles.lookup(); + final MethodHandle targetMH = lookup.findStatic(lookup.lookupClass(), name, type); + return new ConstantCallSite(targetMH.asType(type)); + } + + public static void lambdaTest() { + List<String> strings = Arrays.asList(new String[] { "Three", "One", "FortyTwo" }); + String sample = strings.stream().filter(x -> "One".equals(x.trim())) + .map(String::trim).findAny().orElse(""); + strings.stream().forEach(System.out::println); + } +} \ No newline at end of file
diff --git a/src/test/examplesAndroidO/invokecustom2/TestGenerator.java b/src/test/examplesAndroidO/invokecustom2/TestGenerator.java new file mode 100644 index 0000000..e9cbf7e --- /dev/null +++ b/src/test/examplesAndroidO/invokecustom2/TestGenerator.java
@@ -0,0 +1,343 @@ +// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package invokecustom2; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.invoke.CallSite; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.nio.file.Path; +import java.nio.file.Paths; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Handle; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +public class TestGenerator { + + private final Path classNamePath; + + public static void main(String[] args) throws IOException { + assert args.length == 1; + TestGenerator testGenerator = new TestGenerator(Paths.get(args[0], + TestGenerator.class.getPackage().getName(), InvokeCustom.class.getSimpleName() + ".class")); + testGenerator.generateTests(); + } + + public TestGenerator(Path classNamePath) { + this.classNamePath = classNamePath; + } + + private void generateTests() throws IOException { + ClassReader cr = new ClassReader(new FileInputStream(classNamePath.toFile())); + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + cr.accept( + new ClassVisitor(Opcodes.ASM5, cw) { + @Override + public void visitEnd() { + generateMethodTest1(cw); + generateMethodTest2(cw); + generateMethodTest3(cw); + generateMethodTest4(cw); + generateMethodTest5(cw); + generateMethodTest6(cw); + generateMethodTest7(cw); + generateMethodTest8(cw); + generateMethodTest9(cw); + generateMethodMain(cw); + super.visitEnd(); + } + }, 0); + new FileOutputStream(classNamePath.toFile()).write(cw.toByteArray()); + } + + /* generate main method that only call all test methods. */ + private void generateMethodMain(ClassVisitor cv) { + MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, + "main", "([Ljava/lang/String;)V", null, null); + String internalName = Type.getInternalName(InvokeCustom.class); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "test1", "()V", false); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "test2", "()V", false); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "test3", "()V", false); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "test4", "()V", false); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "test5", "()V", false); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "test6", "()V", false); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "test7", "()V", false); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "test8", "()V", false); + mv.visitMethodInsn(Opcodes.INVOKESTATIC, internalName, "test9", "()V", false); + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(-1, -1); + } + + /** + * Generate test with an invokedynamic, a static bootstrap method without extra args and no arg + * 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), + "bsmLookupStatic", mt.toMethodDescriptorString(), false); + mv.visitInvokeDynamicInsn("targetMethodTest1", "()V", bootstrap); + 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. + */ + 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), + "bsmLookupStatic", mt.toMethodDescriptorString(), false); + mv.visitLdcInsn(new Boolean(true)); + mv.visitLdcInsn(new Byte((byte) 127)); + mv.visitLdcInsn(new Character('c')); + mv.visitLdcInsn(new Short((short) 1024)); + mv.visitLdcInsn(new Integer(123456)); + mv.visitLdcInsn(new Float(1.2f)); + mv.visitLdcInsn(new Long(123456789)); + mv.visitLdcInsn(new Double(3.5123456789)); + mv.visitLdcInsn("String"); + mv.visitInvokeDynamicInsn("targetMethodTest2", "(ZBCSIFJDLjava/lang/String;)V", bootstrap); + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(-1, -1); + } + + /** + * Generate test with an invokedynamic, a static bootstrap method with extra args and no arg + * to the target method. + */ + private void generateMethodTest3(ClassVisitor cv) { + MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test3", "()V", + null, null); + MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, + MethodType.class, int.class, + long.class, float.class, double.class); + Handle bootstrap = new Handle( Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class), + "bsmLookupStaticWithExtraArgs", mt.toMethodDescriptorString(), false); + mv.visitInvokeDynamicInsn("targetMethodTest3", "()V", bootstrap, new Integer(1), + new Long(123456789), new Float(123.456), new Double(123456.789123)); + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(-1, -1); + } + + /** + * Generate test with an invokedynamic, a static bootstrap method with an extra arg that is a + * MethodHandle of kind invokespecial. + */ + private void generateMethodTest4(ClassVisitor cv) { + MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test4", "()V", + null, null); + MethodType mt = + MethodType.methodType( + CallSite.class, + MethodHandles.Lookup.class, + String.class, + MethodType.class, + MethodHandle.class); + Handle bootstrap = new Handle( Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class), + "bsmCreateCallSite", mt.toMethodDescriptorString(), false); + mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(InvokeCustom.class)); + mv.visitInsn(Opcodes.DUP); + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(InvokeCustom.class), + "<init>", "()V", false); + mv.visitInvokeDynamicInsn("targetMethodTest4", "(Linvokecustom2/InvokeCustom;)V", bootstrap, + new Handle(Opcodes.H_INVOKESPECIAL, Type.getInternalName(Super.class), + "targetMethodTest4", "()V", false)); + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(-1, -1); + } + + /** + * Generate a test with an invokedynamic where the target generates + * a result that the call site prints out. + */ + private void generateMethodTest5(ClassVisitor cv) { + MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test5", "()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), + "bsmLookupStatic", mt.toMethodDescriptorString(), false); + mv.visitIntInsn(Opcodes.SIPUSH, 1000); + mv.visitIntInsn(Opcodes.SIPUSH, -923); + mv.visitIntInsn(Opcodes.SIPUSH, 77); + mv.visitInvokeDynamicInsn("targetMethodTest5", "(III)I", bootstrap); + mv.visitVarInsn(Opcodes.ISTORE, 0); + mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + mv.visitTypeInsn(Opcodes.NEW, "java/lang/StringBuilder"); + mv.visitInsn(Opcodes.DUP); + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V"); + mv.visitLdcInsn("targetMethodTest5 returned: "); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", + "(Ljava/lang/String;)Ljava/lang/StringBuilder;"); + mv.visitVarInsn(Opcodes.ILOAD, 0); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", + "(I)Ljava/lang/StringBuilder;"); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", + "()Ljava/lang/String;"); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", + "(Ljava/lang/String;)V"); + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(-1, -1); + } + + /** + * Generate a test with an invokedynamic where the call site invocation tests the summation of + * two long values and returns a long. + */ + private void generateMethodTest6(ClassVisitor cv) { + MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test6", "()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), + "bsmLookupStatic", mt.toMethodDescriptorString(), false); + mv.visitLdcInsn(0x77777777777l); + mv.visitLdcInsn(-0x11111111111l); + mv.visitLdcInsn(0x66666666666l); + mv.visitInvokeDynamicInsn("targetMethodTest6", "(JJJ)J", bootstrap); + mv.visitVarInsn(Opcodes.LSTORE, 0); + mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + mv.visitTypeInsn(Opcodes.NEW, "java/lang/StringBuilder"); + mv.visitInsn(Opcodes.DUP); + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V"); + mv.visitLdcInsn("targetMethodTest6 returned: "); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", + "(Ljava/lang/String;)Ljava/lang/StringBuilder;"); + mv.visitVarInsn(Opcodes.LLOAD, 0); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", + "(J)Ljava/lang/StringBuilder;"); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", + "()Ljava/lang/String;"); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", + "(Ljava/lang/String;)V"); + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(-1, -1); + } + + /** + * Generate a test with an invokedynamic where the call site invocation tests the product of + * two float values and returns a double. + */ + private void generateMethodTest7(ClassVisitor cv) { + MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test7", "()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), + "bsmLookupStatic", mt.toMethodDescriptorString(), false); + double x = 0.5009765625; + double y = -x; + mv.visitLdcInsn((float) x); + mv.visitLdcInsn((float) y); + mv.visitLdcInsn(x * y); + mv.visitInvokeDynamicInsn("targetMethodTest7", "(FFD)D", bootstrap); + mv.visitVarInsn(Opcodes.DSTORE, 0); + mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); + mv.visitTypeInsn(Opcodes.NEW, "java/lang/StringBuilder"); + mv.visitInsn(Opcodes.DUP); + mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "()V"); + mv.visitLdcInsn("targetMethodTest6 returned: "); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", + "(Ljava/lang/String;)Ljava/lang/StringBuilder;"); + mv.visitVarInsn(Opcodes.DLOAD, 0); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", + "(D)Ljava/lang/StringBuilder;"); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", + "()Ljava/lang/String;"); + mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", + "(Ljava/lang/String;)V"); + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(-1, -1); + } + + /** + * Generate a test with multiple invokedynamic bytecodes operating on the same parameters. + * These invocations should each produce invoke-custom bytecodes with unique call site ids. + */ + private void generateMethodTest8(ClassVisitor cv) { + MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test8", "()V", + null, null); + MethodType mt = MethodType.methodType(CallSite.class, MethodHandles.Lookup.class, String.class, + MethodType.class); + // These should be two distinct call sites and both invoke the + // bootstrap method. An erroneous implementation might treat them + // as the same call site because the handle arguments are the same. + Handle bootstrap1 = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class), + "bsmLookupStatic", mt.toMethodDescriptorString(), false); + mv.visitLdcInsn("First invokedynamic invocation"); + mv.visitInvokeDynamicInsn("targetMethodTest8", "(Ljava/lang/String;)V", bootstrap1); + + Handle bootstrap2 = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class), + "bsmLookupStatic", mt.toMethodDescriptorString(), false); + mv.visitLdcInsn("Second invokedynamic invocation"); + mv.visitInvokeDynamicInsn("targetMethodTest8", "(Ljava/lang/String;)V", bootstrap2); + + // Using same handle again creates a new call site so invokes the bootstrap method. + mv.visitLdcInsn("Dupe first invokedynamic invocation"); + mv.visitInvokeDynamicInsn("targetMethodTest8", "(Ljava/lang/String;)V", bootstrap1); + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(-1, -1); + } + + /** + * Generate a test with different kinds of constant method handles. + */ + private void generateMethodTest9(ClassVisitor cv) { + MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test9", "()V", + null, null); + MethodType mt = + MethodType.methodType(CallSite.class, + MethodHandles.Lookup.class, String.class, MethodType.class, + MethodHandle.class, MethodHandle.class, + MethodHandle.class, MethodHandle.class, + MethodHandle.class, MethodHandle.class, + MethodHandle.class, MethodHandle.class); + String internalName = Type.getInternalName(InvokeCustom.class); + Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, internalName, "bsmLookupTest9", + mt.toMethodDescriptorString(), false); + Handle staticSetter = + new Handle(Opcodes.H_GETSTATIC, internalName, "staticFieldTest9", "I", false); + Handle staticGetter = + new Handle(Opcodes.H_PUTSTATIC, internalName, "staticFieldTest9", "I", false); + Handle setter = + new Handle(Opcodes.H_GETFIELD, internalName, "fieldTest9", "F", false); + Handle getter = + new Handle(Opcodes.H_PUTFIELD, internalName, "fieldTest9", "F", false); + Handle instanceInvoke = + new Handle(Opcodes.H_INVOKEVIRTUAL, internalName, "helperMethodTest9", "()V", false); + Handle constructor = + new Handle(Opcodes.H_NEWINVOKESPECIAL, internalName, "<init>", "(I)V", false); + Handle interfaceInvoke = + new Handle(Opcodes.H_INVOKEINTERFACE, + Type.getInternalName(Runnable.class), + "run", "()V", true); + // test4 covers invokespecial for a super method. This covers invokespecial of a private method. + Handle privateInvoke = + new Handle(Opcodes.H_INVOKESPECIAL, internalName, "privateMethodTest9", "()V", false); + + mv.visitInvokeDynamicInsn("targetMethodTest9", "()V", bootstrap, + staticSetter, staticGetter, + setter, getter, + instanceInvoke, constructor, + interfaceInvoke, privateInvoke); + mv.visitInsn(Opcodes.RETURN); + mv.visitMaxs(-1, -1); + } +} \ No newline at end of file