Initial push.
diff --git a/src/test/examplesAndroidO/invokecustom/InvokeCustom.java b/src/test/examplesAndroidO/invokecustom/InvokeCustom.java
new file mode 100644
index 0000000..0d4d5c5
--- /dev/null
+++ b/src/test/examplesAndroidO/invokecustom/InvokeCustom.java
@@ -0,0 +1,177 @@
+// 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 invokecustom;
+
+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;
+
+interface J {
+
+ default void targetMethodTest8() {
+ System.out.println("targetMethodTest8 from J");
+ }
+
+ default void targetMethodTest7() {
+ System.out.println("targetMethodTest7 from J");
+ }
+
+ default void targetMethodTest6() {
+ System.out.println("targetMethodTest6 from J");
+ }
+}
+
+interface I extends J {
+ void targetMethodTest8();
+
+ default void targetMethodTest6() {
+ System.out.println("targetMethodTest6 from I");
+ }
+
+ default void targetMethodTest9() {
+ System.out.println("targetMethodTest9 from I");
+ }
+
+ default void targetMethodTest10() {
+ System.out.println("targetMethodTest10 from I");
+ }
+}
+
+abstract class Super {
+ public void targetMethodTest5() {
+ System.out.println("targetMethodTest5 from Super");
+ }
+
+ abstract void targetMethodTest10();
+}
+
+public class InvokeCustom extends Super implements I {
+
+ private static String staticField1 = "StaticField1";
+
+ private String instanceField1 = "instanceField1";
+
+ 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() {
+ }
+
+ public static CallSite bsmLookupStatic(MethodHandles.Lookup caller, String name, MethodType type)
+ throws NoSuchMethodException, IllegalAccessException {
+ 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(i);
+ System.out.println(l);
+ System.out.println(f);
+ System.out.println(d);
+ final MethodHandles.Lookup lookup = MethodHandles.lookup();
+ final MethodHandle targetMH = lookup.findStatic(lookup.lookupClass(), name, type);
+ return new ConstantCallSite(targetMH.asType(type));
+ }
+
+ @Override
+ public void targetMethodTest5() {
+ System.out.println("targetMethodTest5 from InvokeCustom");
+ }
+
+ private static void targetMethodTest4() {
+ 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(
+ 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
new file mode 100644
index 0000000..883106f
--- /dev/null
+++ b/src/test/examplesAndroidO/invokecustom/TestGenerator.java
@@ -0,0 +1,422 @@
+// 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 invokecustom;
+
+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);
+ generateMethodTest10(cw);
+ generateMethodTest11(cw);
+ generateMethodTest12(cw);
+ generateMethodTest13(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);
+ mv.visitMethodInsn(
+ 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.visitMethodInsn(
+ Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test5", "()V", false);
+ mv.visitMethodInsn(
+ Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test6", "()V", false);
+ mv.visitMethodInsn(
+ Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test7", "()V", false);
+ mv.visitMethodInsn(
+ Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test8", "()V", false);
+ mv.visitMethodInsn(
+ Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test9", "()V", false);
+ mv.visitMethodInsn(
+ Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test10", "()V", false);
+ mv.visitMethodInsn(
+ Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test11", "()V", false);
+ mv.visitMethodInsn(
+ Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test12", "()V", false);
+ mv.visitMethodInsn(
+ Opcodes.INVOKESTATIC, Type.getInternalName(InvokeCustom.class), "test13", "()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("targetMethodTest5", "(Linvokecustom/InvokeCustom;)V", bootstrap,
+ new Handle( Opcodes.H_INVOKESPECIAL, Type.getInternalName(Super.class),
+ "targetMethodTest5", "()V", false));
+ 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 invoke interface. The target method is a default method into an interface
+ * that shadows another default method from a super interface.
+ */
+ 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, MethodHandle.class);
+ Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class),
+ "bsmCreateCallCallingtargetMethodTest6", 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("targetMethodTest6", "(Linvokecustom/I;)V", bootstrap,
+ new Handle(Opcodes.H_INVOKEINTERFACE, Type.getInternalName(I.class),
+ "targetMethodTest6", "()V", true));
+ 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 invoke interface. The target method is a default method into an interface
+ * that is at the end of a chain of interfaces.
+ */
+ 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, MethodHandle.class);
+ Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class),
+ "bsmCreateCallCallingtargetMethodTest7", 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("targetMethodTest7", "(Linvokecustom/J;)V", bootstrap,
+ new Handle(Opcodes.H_INVOKEINTERFACE, Type.getInternalName(J.class),
+ "targetMethodTest7", "()V", true));
+ 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 invoke interface. The target method is a method into an interface
+ * that is shadowed by another definition into a sub interfaces.
+ */
+ 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, MethodHandle.class);
+ Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class),
+ "bsmCreateCallCallingtargetMethodTest8", 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("targetMethodTest8", "(Linvokecustom/J;)V", bootstrap,
+ new Handle(Opcodes.H_INVOKEINTERFACE, Type.getInternalName(J.class),
+ "targetMethodTest8", "()V", true));
+ 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 invoke virtual. The target method is a method into an interface that is
+ * not shadowed by an implementation into a classes implementing the interface.
+ */
+ 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, MethodHandle.class);
+ Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class),
+ "bsmCreateCallCallingtargetMethodTest9", 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("targetMethodTest9", "(Linvokecustom/InvokeCustom;)V", bootstrap,
+ new Handle(Opcodes.H_INVOKEVIRTUAL, Type.getInternalName(InvokeCustom.class),
+ "targetMethodTest9", "()V", false));
+ 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 invoke virtual. The target method is a method into a class implementing
+ * an abstract method and that shadows a default method from an interface.
+ */
+ 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);
+ Handle bootstrap = new Handle(Opcodes.H_INVOKESTATIC, Type.getInternalName(InvokeCustom.class),
+ "bsmCreateCallCallingtargetMethodTest10", 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("targetMethodTest10", "(Linvokecustom/InvokeCustom;)V", bootstrap,
+ new Handle(Opcodes.H_INVOKEVIRTUAL, Type.getInternalName(InvokeCustom.class),
+ "targetMethodTest10", "()V", false));
+ 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 get static. The method handle read a static field from a class.
+ */
+ private void generateMethodTest10(ClassVisitor cv) {
+ MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test10", "()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),
+ "bsmCreateCallCallingtargetMethod", mt.toMethodDescriptorString(), false);
+ mv.visitFieldInsn(Opcodes.GETSTATIC,
+ "java/lang/System",
+ "out",
+ "Ljava/io/PrintStream;");
+ mv.visitInvokeDynamicInsn("staticField1", "()Ljava/lang/String;", bootstrap,
+ new Handle(Opcodes.H_GETSTATIC, Type.getInternalName(InvokeCustom.class),
+ "staticField1", "Ljava/lang/String;", false));
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
+ "java/io/PrintStream",
+ "println",
+ "(Ljava/lang/String;)V", false);
+ 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 put static. The method handle write a static field in a class and then
+ * print its value.
+ */
+ private void generateMethodTest11(ClassVisitor cv) {
+ MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test11", "()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),
+ "bsmCreateCallCallingtargetMethod", 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),
+ "staticField1", "Ljava/lang/String;", false));
+ mv.visitFieldInsn(Opcodes.GETSTATIC,
+ "java/lang/System",
+ "out",
+ "Ljava/io/PrintStream;");
+ mv.visitFieldInsn(Opcodes.GETSTATIC,
+ Type.getInternalName(InvokeCustom.class),
+ "staticField1",
+ "Ljava/lang/String;");
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
+ "java/io/PrintStream",
+ "println",
+ "(Ljava/lang/String;)V", false);
+ 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 get instance. The method handle read an instance field from a class.
+ */
+ private void generateMethodTest12(ClassVisitor cv) {
+ MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test12", "()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),
+ "bsmCreateCallCallingtargetMethod", mt.toMethodDescriptorString(), false);
+ mv.visitFieldInsn(Opcodes.GETSTATIC,
+ "java/lang/System",
+ "out",
+ "Ljava/io/PrintStream;");
+ 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("instanceField1", "(Linvokecustom/InvokeCustom;)Ljava/lang/String;",
+ bootstrap, new Handle(Opcodes.H_GETFIELD, Type.getInternalName(InvokeCustom.class),
+ "instanceField1", "Ljava/lang/String;", false));
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
+ "java/io/PrintStream",
+ "println",
+ "(Ljava/lang/String;)V", false);
+ 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 put instance. The method handle write an instance field in a class and
+ * then print its value.
+ */
+ private void generateMethodTest13(ClassVisitor cv) {
+ MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "test13", "()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),
+ "bsmCreateCallCallingtargetMethod", 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.visitVarInsn(Opcodes.ASTORE, 0);
+ mv.visitVarInsn(Opcodes.ALOAD, 0);
+ mv.visitLdcInsn("Write instance field");
+ mv.visitInvokeDynamicInsn("instanceField1", "(Linvokecustom/InvokeCustom;Ljava/lang/String;)V",
+ bootstrap, new Handle(Opcodes.H_PUTFIELD, Type.getInternalName(InvokeCustom.class),
+ "instanceField1", "Ljava/lang/String;", false));
+ mv.visitFieldInsn(Opcodes.GETSTATIC,
+ "java/lang/System",
+ "out",
+ "Ljava/io/PrintStream;");
+ mv.visitVarInsn(Opcodes.ALOAD, 0);
+ mv.visitFieldInsn(Opcodes.GETFIELD,
+ Type.getInternalName(InvokeCustom.class),
+ "instanceField1",
+ "Ljava/lang/String;");
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
+ "java/io/PrintStream",
+ "println",
+ "(Ljava/lang/String;)V", false);
+ mv.visitInsn(Opcodes.RETURN);
+ mv.visitMaxs(-1, -1);
+ }
+}
diff --git a/src/test/examplesAndroidO/invokecustom/keep-rules.txt b/src/test/examplesAndroidO/invokecustom/keep-rules.txt
new file mode 100644
index 0000000..52fa2a7
--- /dev/null
+++ b/src/test/examplesAndroidO/invokecustom/keep-rules.txt
@@ -0,0 +1,17 @@
+# 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.
+
+# Keep the application entry point and the target methods of invoke-custom because these methods
+# can not be known at compile time. Get rid of everything that is not reachable from there.
+-keep public class invokecustom.InvokeCustom {
+ public static void main(...);
+}
+
+-keepclassmembers class * {
+ *** targetMethodTest*(...);
+}
+
+# allow access modification to enable minification
+-allowaccessmodification
+
diff --git a/src/test/examplesAndroidO/invokepolymorphic/InvokePolymorphic.java b/src/test/examplesAndroidO/invokepolymorphic/InvokePolymorphic.java
new file mode 100644
index 0000000..90cb064
--- /dev/null
+++ b/src/test/examplesAndroidO/invokepolymorphic/InvokePolymorphic.java
@@ -0,0 +1,104 @@
+// 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 invokepolymorphic;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+class Data {
+}
+
+public class InvokePolymorphic {
+
+ public String buildString(Integer i1, int i2, String s) {
+ return (i1 == null ? "N" : "!N") + "-" + i2 + "-" + s;
+ }
+
+ public void testInvokePolymorphic() {
+ MethodType mt = MethodType.methodType(String.class, Integer.class, int.class, String.class);
+ MethodHandles.Lookup lk = MethodHandles.lookup();
+
+ try {
+ MethodHandle mh = lk.findVirtual(getClass(), "buildString", mt);
+ System.out.println(mh.invoke(this, null, 1, "string"));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+
+ public String buildString(
+ byte b, char c, short s, float f, double d, long l, Integer i1, int i2, String str) {
+ return b + "-" + c + "-" + s + "-" + f + "-" + d + "-" + l + "-" + (i1 == null ? "N" : "!N")
+ + "-" + i2 + "-" + str;
+ }
+
+ public void testInvokePolymorphicRange() {
+ MethodType mt = MethodType.methodType(String.class, byte.class, char.class, short.class,
+ float.class, double.class, long.class, Integer.class, int.class, String.class);
+ MethodHandles.Lookup lk = MethodHandles.lookup();
+
+ try {
+ MethodHandle mh = lk.findVirtual(getClass(), "buildString", mt);
+ System.out.println(
+ mh.invoke(this, (byte) 2, 'a', (short) 0xFFFF, 1.1f, 2.24d, 12345678L, null,
+ 1, "string"));
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+
+ public static void testWithAllTypes(
+ boolean z, char a, short b, int c, long d, float e, double f, String g, Object h) {
+ System.out.println(z);
+ System.out.println(a);
+ System.out.println(b);
+ System.out.println(c);
+ System.out.println(d);
+ System.out.println(e);
+ System.out.println(f);
+ System.out.println(g);
+ System.out.println(h);
+ }
+
+ public void testInvokePolymorphicWithAllTypes() {
+ try {
+ MethodHandle mth =
+ MethodHandles.lookup()
+ .findStatic(
+ InvokePolymorphic.class,
+ "testWithAllTypes",
+ MethodType.methodType(
+ void.class, boolean.class, char.class, short.class, int.class, long.class,
+ float.class, double.class, String.class, Object.class));
+ mth.invokeExact(false,'h', (short) 56, 72, Integer.MAX_VALUE + 42l,
+ 0.56f, 100.0d, "hello", (Object) "goodbye");
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+ }
+
+ public MethodHandle testInvokePolymorphicWithConstructor() {
+ MethodHandle mh = null;
+ MethodType mt = MethodType.methodType(void.class);
+ MethodHandles.Lookup lk = MethodHandles.lookup();
+
+ try {
+ mh = lk.findConstructor(Data.class, mt);
+ System.out.println(mh.invoke().getClass() == Data.class);
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+
+ return mh;
+ }
+
+ public static void main(String[] args) {
+ InvokePolymorphic invokePolymorphic = new InvokePolymorphic();
+ invokePolymorphic.testInvokePolymorphic();
+ invokePolymorphic.testInvokePolymorphicRange();
+ invokePolymorphic.testInvokePolymorphicWithAllTypes();
+ invokePolymorphic.testInvokePolymorphicWithConstructor();
+ }
+}
diff --git a/src/test/examplesAndroidO/lambdadesugaring/LambdaDesugaring.java b/src/test/examplesAndroidO/lambdadesugaring/LambdaDesugaring.java
new file mode 100644
index 0000000..4b7ebd9
--- /dev/null
+++ b/src/test/examplesAndroidO/lambdadesugaring/LambdaDesugaring.java
@@ -0,0 +1,529 @@
+// 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 lambdadesugaring;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import lambdadesugaring.legacy.Legacy;
+import lambdadesugaring.other.OtherRefs;
+
+public class LambdaDesugaring {
+ interface I {
+ String foo();
+ }
+
+ interface V {
+ void foo();
+ }
+
+ interface VT<T> {
+ void foo(T t);
+ }
+
+ interface P1<X> {
+ X foo(int i);
+ }
+
+ interface I2 extends I {
+ }
+
+ interface I3 {
+ String foo();
+ }
+
+ interface M1 {
+ }
+
+ interface M2 {
+ }
+
+ interface J {
+ String foo(String a, int b, boolean c);
+ }
+
+ interface G {
+ A foo();
+ }
+
+ interface H<T extends A> {
+ T foo(T o);
+ }
+
+ interface K {
+ Object foo(String a, String b, String c);
+ }
+
+ interface ObjectProvider {
+ Object act();
+ }
+
+ interface S2Z {
+ boolean foo(String a);
+ }
+
+ interface SS2Z {
+ boolean foo(String a, String b);
+ }
+
+ interface ArrayTransformerA<T> {
+ T[] transform(T[] a);
+ }
+
+ @SuppressWarnings("unchecked")
+ interface ArrayTransformerB<T> {
+ T[] transform(T... a);
+ }
+
+ static <T> void print(T[] a) {
+ StringBuilder builder = new StringBuilder("{");
+ String sep = "";
+ for (T s : a) {
+ builder.append(sep).append(s.toString());
+ sep = ", ";
+ }
+ builder.append("}");
+ System.out.println(builder.toString());
+ }
+
+ <T> T[] reorder(T[] a) {
+ int size = a.length;
+ for (int x = 0; x < size / 2; x++) {
+ T t = a[x];
+ a[x] = a[size - 1 - x];
+ a[size - 1 - x] = t;
+ }
+ return a;
+ }
+
+ static void atA(ArrayTransformerA<Integer> f) {
+ print(f.transform(new Integer[] { 1, 2, 3 }));
+ }
+
+ static void atB(ArrayTransformerB<String> f) {
+ print(f.transform("A", "B", "C"));
+ }
+
+ public static String staticUnused() {
+ return "ReleaseTests::staticUnused";
+ }
+
+ public static void testUnusedLambdas() {
+ System.out.print("Before unused ... ");
+ Object o = (I) LambdaDesugaring::staticUnused;
+ System.out.println("after unused.");
+ }
+
+ class A {
+ final String toString;
+
+ A(String toString) {
+ this.toString = toString;
+ }
+
+ @Override
+ public String toString() {
+ return toString;
+ }
+ }
+
+ class B extends A {
+ B(String toString) {
+ super(toString);
+ }
+ }
+
+ class C extends B {
+ C(String toString) {
+ super(toString);
+ }
+ }
+
+ class D extends C {
+ D(String toString) {
+ super(toString);
+ }
+ }
+
+ public static class Refs {
+ public static String f(I i) {
+ return i.foo();
+ }
+
+ public static void v(V v) {
+ v.foo();
+ }
+
+ public static void vt(VT<String> v) {
+ v.foo(null);
+ }
+
+ public static String p1(P1 p) {
+ return p.foo(123).getClass().getCanonicalName();
+ }
+
+ public static String pSS2Z(SS2Z p) {
+ return "" + p.foo("123", "321");
+ }
+
+ public static String pS2Z(S2Z p) {
+ return "" + p.foo("123");
+ }
+
+ public static String p3(K k) {
+ return k.foo("A", "B", "C").toString();
+ }
+
+ public static String g(ObjectProvider op) {
+ return op.act().toString();
+ }
+
+ static class A extends OtherRefs {
+ String fooInternal() {
+ return "Refs::A::fooInternal()";
+ }
+
+ protected String fooProtected() {
+ return "Refs::A::fooProtected()";
+ }
+
+ protected String fooProtectedOverridden() {
+ return "Refs::A::fooProtectedOverridden()";
+ }
+
+ protected static String staticProtected() {
+ return "Refs::A::staticProtected()";
+ }
+
+ static String staticInternal() {
+ return "Refs::A::staticInternal()";
+ }
+ }
+
+ public static class B extends A {
+ public void test() {
+ System.out.println(f(new A()::fooInternal));
+ System.out.println(f(this::fooInternal));
+ System.out.println(f(this::fooProtected));
+ System.out.println(f(this::fooProtectedOverridden));
+ System.out.println(f(this::fooPublic));
+ System.out.println(f(this::fooInternal));
+
+ System.out.println(f(super::fooProtectedOverridden));
+ System.out.println(f(this::fooOtherProtected));
+ System.out.println(f(this::fooOtherPublic));
+
+ System.out.println(g(this::fooPrivate));
+ System.out.println(g(new Integer(123)::toString));
+ System.out.println(g(System::lineSeparator));
+
+ System.out.println(f(A::staticInternal));
+ System.out.println(f(A::staticProtected));
+ System.out.println(f(B::staticPrivate));
+ System.out.println(f(OtherRefs::staticOtherPublic));
+ System.out.println(f(OtherRefs::staticOtherProtected));
+
+ System.out.println(g(StringBuilder::new));
+ System.out.println(g(OtherRefs.PublicInit::new));
+ System.out.println(ProtectedInit.testProtected());
+ System.out.println(g(ProtectedInit::new));
+ System.out.println(g(InternalInit::new));
+ System.out.println(PrivateInit.testPrivate());
+ System.out.println(g(PrivateInit::new));
+
+ System.out.println(p1(D[]::new));
+ System.out.println(p1(Integer::new));
+ System.out.println(p1(B::staticArray));
+
+ System.out.println(pSS2Z(String::equalsIgnoreCase));
+ System.out.println(pS2Z("123321"::contains));
+ System.out.println(pS2Z(String::isEmpty));
+
+ System.out.println(p3(B::fooConcat));
+
+ v(D::new); // Discarding the return value
+ vt((new ArrayList<String>())::add);
+
+ I3 i3 = this::fooPrivate;
+ System.out.println(f(i3::foo));
+ }
+
+ private static String staticPrivate() {
+ return "Refs::B::staticPrivate()";
+ }
+
+ private String fooPrivate() {
+ return "Refs::B::fooPrivate()";
+ }
+
+ String fooInternal() {
+ return "Refs::B::fooInternal()";
+ }
+
+ public static StringBuilder fooConcat(Object... objs) {
+ StringBuilder builder = new StringBuilder("Refs::B::fooConcat(");
+ String sep = "";
+ for (Object obj : objs) {
+ builder.append(sep).append(obj.toString());
+ sep = ", ";
+ }
+ return builder.append(")");
+ }
+
+ @Override
+ protected String fooProtectedOverridden() {
+ return "Refs::B::fooProtectedOverridden()";
+ }
+
+ public String fooPublic() {
+ return "Refs::B::fooPublic()";
+ }
+
+ static int[] staticArray(int size) {
+ return new int[size];
+ }
+ }
+
+ static class D {
+ D() {
+ System.out.println("Refs::D::init()");
+ }
+ }
+
+ public static class ProtectedInit extends OtherRefs.PublicInit {
+ protected ProtectedInit() {
+ }
+
+ static String testProtected() {
+ return g(ProtectedInit::new);
+ }
+
+ @Override
+ public String toString() {
+ return "OtherRefs::ProtectedInit::init()";
+ }
+ }
+
+ static class InternalInit extends ProtectedInit {
+ InternalInit() {
+ }
+
+ @Override
+ public String toString() {
+ return "Refs::InternalInit::init()";
+ }
+ }
+
+ static class PrivateInit extends InternalInit {
+ private PrivateInit() {
+ }
+
+ static String testPrivate() {
+ return g(PrivateInit::new);
+ }
+
+ @Override
+ public String toString() {
+ return "Refs::PrivateInit::init()";
+ }
+ }
+ }
+
+ public void testLambdasSimple() {
+ System.out.println(f(() -> "testLambdasSimple#1"));
+ System.out.println(
+ g((a, b, c) -> "{" + a + ":" + b + ":" + c + "}",
+ "testLambdasSimple#2", 123, true));
+ }
+
+ public void testLambdasSimpleWithCaptures() {
+ String s = "<stirng>";
+ long l = 1234567890123456789L;
+ char c = '#';
+
+ System.out.println(
+ g((x, y, z) -> "{" + s + ":" + l + ":" + c + ":" + x + ":" + y + ":" + z + "}",
+ "param1", 2, false));
+
+ I i1 = () -> "i1";
+ I i2 = () -> i1.foo() + ":i2";
+ I i3 = () -> i2.foo() + ":i3";
+ System.out.println(f(() -> "{" + i3.foo() + ":anonymous}"));
+ }
+
+ public void testInstructionPatchingWithCatchHandlers() {
+ try {
+ int a = 1, b = 0;
+ System.out.println(f(() -> "testInstructionPatchingWithCatchHandlers:1"));
+ System.out.println(f(() -> ("does not matter " + (a / b))));
+ } catch (IndexOutOfBoundsException | ArithmeticException e) {
+ System.out.println("testInstructionPatchingWithCatchHandlers:Divide By Zero");
+ } catch (RuntimeException re) {
+ throw re;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ int changes = -1;
+ try {
+ if (f(() -> "").isEmpty()) {
+ changes = 32;
+ System.out.println(f(() -> "testInstructionPatchingWithCatchHandlers:lambda"));
+ throw new RuntimeException();
+ } else {
+ changes = 42;
+ throw new RuntimeException();
+ }
+ } catch (Throwable t) {
+ System.out.println("testInstructionPatchingWithCatchHandlers:changes=" + changes);
+ }
+ }
+
+ public void testInstanceLambdaMethods() {
+ Integer i = 12345;
+ System.out.println(h(() -> new A("{testInstanceLambdaMethods:" + i + "}")));
+ }
+
+ @SuppressWarnings("unchecked")
+ private void testEnforcedSignatureHelper() {
+ H h = ((H<B>) x -> new B("{testEnforcedSignature:" + x + "}"));
+ System.out.println(h.foo(new A("A")).toString());
+ }
+
+ public void testEnforcedSignature() {
+ String capture = "capture";
+ System.out.println(i(x -> new B("{testEnforcedSignature:" + x + "}")));
+ System.out.println(i(x -> new B("{testEnforcedSignature:" + capture + "}")));
+
+ try {
+ testEnforcedSignatureHelper();
+ } catch (Exception e) {
+ System.out.println(e.getMessage());
+ }
+
+ atA(t -> new LambdaDesugaring().reorder(t));
+ atB(t -> new LambdaDesugaring().reorder(t));
+ }
+
+ public void testMultipleInterfaces() {
+ System.out.println(j((I2 & M1 & I3 & M2) () -> "{testMultipleInterfaces:1}"));
+
+ Object o = (I2 & M1 & I3 & M2) () -> "{testMultipleInterfaces:2}";
+ M1 m1 = (M1) o;
+ M2 m2 = (M2) m1;
+ I i = (I) m2;
+ System.out.println(((I3) i).foo());
+
+ o = (I2 & Serializable & M2) () -> "{testMultipleInterfaces:3}";
+ m2 = (M2) o;
+ Serializable s = (Serializable) m2;
+ System.out.println(((I) s).foo());
+ }
+
+ public void testBridges() {
+ k((Legacy.BH) (x -> x), "{testBridges:1}");
+ k((Legacy.BK<Legacy.D> & Serializable) (x -> x), new Legacy.D("{testBridges:2}"));
+ // k((Legacy.BL) (x -> x), new Legacy.B("{testBridges:3}")); crashes javac
+ k((Legacy.BM) (x -> x), new Legacy.C("{testBridges:4}"));
+ }
+
+ public String f(I i) {
+ return i.foo();
+ }
+
+ String g(J j, String a, int b, boolean c) {
+ return j.foo(a, b, c);
+ }
+
+ String h(G g) {
+ return g.foo().toString();
+ }
+
+ String i(H<B> h) {
+ return h.foo(new B("i(H<B>)")).toString();
+ }
+
+ <T extends I2 & M1 & M2 & I3> String j(T l) {
+ return ((I3) ((M2) ((M1) (((I2) l))))).foo();
+ }
+
+ static <T> void k(Legacy.BI<T> i, T v) {
+ System.out.println(i.foo(v).toString());
+ }
+
+ static I statelessLambda() {
+ return InstanceAndClassChecks::staticProvider;
+ }
+
+ static I statefulLambda() {
+ return InstanceAndClassChecks.INSTANCE::instanceProvider;
+ }
+
+ static class InstanceAndClassChecks {
+ static final InstanceAndClassChecks INSTANCE = new InstanceAndClassChecks();
+
+ static void test() {
+ assertSameInstance(
+ InstanceAndClassChecks::staticProvider,
+ InstanceAndClassChecks::staticProvider,
+ "Instances must be same");
+ assertSameInstance(
+ InstanceAndClassChecks::staticProvider,
+ statelessLambda(),
+ "Instances must be same");
+
+ assertDifferentInstance(
+ INSTANCE::instanceProvider,
+ INSTANCE::instanceProvider,
+ "Instances must be different");
+ assertDifferentInstance(
+ INSTANCE::instanceProvider,
+ statefulLambda(), "Instances must be different");
+ }
+
+ public static String staticProvider() {
+ return "staticProvider";
+ }
+
+ public String instanceProvider() {
+ return "instanceProvider";
+ }
+
+ static void assertSameInstance(I a, I b, String msg) {
+ if (a != b) {
+ throw new AssertionError(msg);
+ }
+ }
+
+ static void assertDifferentInstance(I a, I b, String msg) {
+ if (a == b) {
+ throw new AssertionError(msg);
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ LambdaDesugaring tests = new LambdaDesugaring();
+ tests.testLambdasSimple();
+ LambdaDesugaring.testUnusedLambdas();
+ tests.testLambdasSimpleWithCaptures();
+ tests.testInstructionPatchingWithCatchHandlers();
+ tests.testInstanceLambdaMethods();
+ tests.testEnforcedSignature();
+ tests.testMultipleInterfaces();
+ tests.testBridges();
+ new Refs.B().test();
+ if (isAndroid()) {
+ InstanceAndClassChecks.test();
+ }
+ }
+
+ static boolean isAndroid() {
+ try {
+ Class.forName("dalvik.system.VMRuntime");
+ return true;
+ } catch (Exception ignored) {
+ }
+ return false;
+ }
+}
diff --git a/src/test/examplesAndroidO/lambdadesugaring/ValueAdjustments.java b/src/test/examplesAndroidO/lambdadesugaring/ValueAdjustments.java
new file mode 100644
index 0000000..b9d2752
--- /dev/null
+++ b/src/test/examplesAndroidO/lambdadesugaring/ValueAdjustments.java
@@ -0,0 +1,330 @@
+// 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 lambdadesugaring;
+
+public class ValueAdjustments {
+ interface B2i {
+ int foo(Byte i);
+ }
+
+ interface BnUnB {
+ Object foo(boolean z, Boolean Z, byte b, Byte B, char c, Character C, short s, Short S,
+ int i, Integer I, long l, Long L, float f, Float F, double d, Double D);
+ }
+
+ interface iz {
+ boolean f();
+ }
+
+ interface iZ {
+ Boolean f();
+ }
+
+ interface ib {
+ byte f();
+ }
+
+ interface iO {
+ Object f();
+ }
+
+ interface iN {
+ Number f();
+ }
+
+ interface iB {
+ Byte f();
+ }
+
+ interface ic {
+ char f();
+ }
+
+ interface iC {
+ Character f();
+ }
+
+ interface is {
+ short f();
+ }
+
+ interface iS {
+ Short f();
+ }
+
+ interface ii {
+ int f();
+ }
+
+ interface iI {
+ Integer f();
+ }
+
+ interface ij {
+ long f();
+ }
+
+ interface iJ {
+ Long f();
+ }
+
+ interface if_ {
+ float f();
+ }
+
+ interface iF {
+ Float f();
+ }
+
+ interface id {
+ double f();
+ }
+
+ interface iD {
+ Double f();
+ }
+
+ private static void checkObject(StringBuffer builder) {
+ builder
+ .append(((iO) ValueAdjustments::z).f()).append(' ')
+ .append(((iO) ValueAdjustments::Z).f()).append(' ')
+ .append(((iO) ValueAdjustments::b).f()).append(' ')
+ .append(((iO) ValueAdjustments::B).f()).append(' ')
+ .append(((iO) ValueAdjustments::c).f()).append(' ')
+ .append(((iO) ValueAdjustments::C).f()).append(' ')
+ .append(((iO) ValueAdjustments::s).f()).append(' ')
+ .append(((iO) ValueAdjustments::S).f()).append(' ')
+ .append(((iO) ValueAdjustments::i).f()).append(' ')
+ .append(((iO) ValueAdjustments::I).f()).append(' ')
+ .append(((iO) ValueAdjustments::j).f()).append(' ')
+ .append(((iO) ValueAdjustments::J).f()).append(' ')
+ .append(((iO) ValueAdjustments::f).f()).append(' ')
+ .append(((iO) ValueAdjustments::F).f()).append(' ')
+ .append(((iO) ValueAdjustments::d).f()).append(' ')
+ .append(((iO) ValueAdjustments::D).f()).append('\n');
+ }
+
+ private static void checkNumber(StringBuffer builder) {
+ builder
+ .append(((iN) ValueAdjustments::b).f()).append(' ')
+ .append(((iN) ValueAdjustments::B).f()).append(' ')
+ .append(((iN) ValueAdjustments::s).f()).append(' ')
+ .append(((iN) ValueAdjustments::S).f()).append(' ')
+ .append(((iN) ValueAdjustments::i).f()).append(' ')
+ .append(((iN) ValueAdjustments::I).f()).append(' ')
+ .append(((iN) ValueAdjustments::j).f()).append(' ')
+ .append(((iN) ValueAdjustments::J).f()).append(' ')
+ .append(((iN) ValueAdjustments::f).f()).append(' ')
+ .append(((iN) ValueAdjustments::F).f()).append(' ')
+ .append(((iN) ValueAdjustments::d).f()).append(' ')
+ .append(((iN) ValueAdjustments::D).f()).append('\n');
+ }
+
+ private static void checkBoxes(StringBuffer builder) {
+ builder
+ .append(((iZ) ValueAdjustments::z).f()).append(' ')
+ .append(((iB) ValueAdjustments::b).f()).append(' ')
+ .append(((iC) ValueAdjustments::c).f()).append(' ')
+ .append(((iS) ValueAdjustments::s).f()).append(' ')
+ .append(((iI) ValueAdjustments::i).f()).append(' ')
+ .append(((iJ) ValueAdjustments::j).f()).append(' ')
+ .append(((iF) ValueAdjustments::f).f()).append(' ')
+ .append(((iD) ValueAdjustments::d).f()).append('\n');
+ }
+
+ private static void checkDouble(StringBuffer builder) {
+ builder
+ .append(((id) ValueAdjustments::b).f()).append(' ')
+ .append(((id) ValueAdjustments::B).f()).append(' ')
+ .append(((id) ValueAdjustments::s).f()).append(' ')
+ .append(((id) ValueAdjustments::S).f()).append(' ')
+ .append(((id) ValueAdjustments::c).f()).append(' ')
+ .append(((id) ValueAdjustments::C).f()).append(' ')
+ .append(((id) ValueAdjustments::i).f()).append(' ')
+ .append(((id) ValueAdjustments::I).f()).append(' ')
+ .append(((id) ValueAdjustments::j).f()).append(' ')
+ .append(((id) ValueAdjustments::J).f()).append(' ')
+ .append(((id) ValueAdjustments::f).f()).append(' ')
+ .append(((id) ValueAdjustments::F).f()).append(' ')
+ .append(((id) ValueAdjustments::d).f()).append(' ')
+ .append(((id) ValueAdjustments::D).f()).append('\n');
+ }
+
+ private static void checkFloat(StringBuffer builder) {
+ builder
+ .append(((if_) ValueAdjustments::b).f()).append(' ')
+ .append(((if_) ValueAdjustments::B).f()).append(' ')
+ .append(((if_) ValueAdjustments::s).f()).append(' ')
+ .append(((if_) ValueAdjustments::S).f()).append(' ')
+ .append(((if_) ValueAdjustments::c).f()).append(' ')
+ .append(((if_) ValueAdjustments::C).f()).append(' ')
+ .append(((if_) ValueAdjustments::i).f()).append(' ')
+ .append(((if_) ValueAdjustments::I).f()).append(' ')
+ .append(((if_) ValueAdjustments::j).f()).append(' ')
+ .append(((if_) ValueAdjustments::J).f()).append(' ')
+ .append(((if_) ValueAdjustments::f).f()).append(' ')
+ .append(((if_) ValueAdjustments::F).f()).append('\n');
+ }
+
+ private static void checkLong(StringBuffer builder) {
+ builder
+ .append(((ij) ValueAdjustments::b).f()).append(' ')
+ .append(((ij) ValueAdjustments::B).f()).append(' ')
+ .append(((ij) ValueAdjustments::s).f()).append(' ')
+ .append(((ij) ValueAdjustments::S).f()).append(' ')
+ .append(((ij) ValueAdjustments::c).f()).append(' ')
+ .append(((ij) ValueAdjustments::C).f()).append(' ')
+ .append(((ij) ValueAdjustments::i).f()).append(' ')
+ .append(((ij) ValueAdjustments::I).f()).append(' ')
+ .append(((ij) ValueAdjustments::j).f()).append(' ')
+ .append(((ij) ValueAdjustments::J).f()).append('\n');
+ }
+
+ private static void checkInt(StringBuffer builder) {
+ builder
+ .append(((ii) ValueAdjustments::b).f()).append(' ')
+ .append(((ii) ValueAdjustments::B).f()).append(' ')
+ .append(((ii) ValueAdjustments::s).f()).append(' ')
+ .append(((ii) ValueAdjustments::S).f()).append(' ')
+ .append(((ii) ValueAdjustments::c).f()).append(' ')
+ .append(((ii) ValueAdjustments::C).f()).append(' ')
+ .append(((ii) ValueAdjustments::i).f()).append(' ')
+ .append(((ii) ValueAdjustments::I).f()).append('\n');
+ }
+
+ private static void checkShort(StringBuffer builder) {
+ builder
+ .append(((is) ValueAdjustments::b).f()).append(' ')
+ .append(((is) ValueAdjustments::B).f()).append(' ')
+ .append(((is) ValueAdjustments::s).f()).append(' ')
+ .append(((is) ValueAdjustments::S).f()).append('\n');
+ }
+
+ private static void checkChar(StringBuffer builder) {
+ builder
+ .append(((ic) ValueAdjustments::c).f()).append(' ')
+ .append(((ic) ValueAdjustments::C).f()).append('\n');
+ }
+
+ private static void checkByte(StringBuffer builder) {
+ builder
+ .append(((ib) ValueAdjustments::b).f()).append(' ')
+ .append(((ib) ValueAdjustments::B).f()).append('\n');
+ }
+
+ private static void checkBoolean(StringBuffer builder) {
+ builder
+ .append(((iz) ValueAdjustments::z).f()).append(' ')
+ .append(((iz) ValueAdjustments::Z).f()).append('\n');
+ }
+
+ private static void checkMisc(StringBuffer builder) {
+ builder
+ .append(((BnUnB) ValueAdjustments::boxingAndUnboxing).foo(true, false, (byte) 1, (byte) 2,
+ (char) 33, (char) 44, (short) 5, (short) 6, 7, 8, 9, 10L, 11, 12f, 13, 14d))
+ .append('\n')
+ .append(((BnUnB) ValueAdjustments::boxingAndUnboxingW).foo(true, false, (byte) 1, (byte) 2,
+ (char) 33, (char) 44, (short) 5, (short) 6, 7, 8, 9, 10L, 11, 12f, 13, 14d))
+ .append('\n')
+ .append(((B2i) (Integer::new)).foo(Byte.valueOf((byte) 44))).append('\n');
+ }
+
+ static String boxingAndUnboxing(Boolean Z, boolean z, Byte B, byte b, Character C, char c,
+ Short S, short s, Integer I, int i, Long L, long l, Float F, float f, Double D, double d) {
+ return "" + Z + ":" + z + ":" + B + ":" + b + ":" + C + ":" + c + ":" + S + ":" + s
+ + ":" + I + ":" + i + ":" + L + ":" + l + ":" + F + ":" + f + ":" + D + ":" + d;
+ }
+
+ static String boxingAndUnboxingW(boolean Z, boolean z, double B, double b,
+ double C, double c, double S, double s, double I, double i, double L, double l,
+ double F, double f, double D, double d) {
+ return "" + Z + ":" + z + ":" + B + ":" + b + ":" + C + ":" + c + ":" + S + ":" + s
+ + ":" + I + ":" + i + ":" + L + ":" + l + ":" + F + ":" + f + ":" + D + ":" + d;
+ }
+
+ static boolean z() {
+ return true;
+ }
+
+ static byte b() {
+ return 8;
+ }
+
+ static char c() {
+ return 'c';
+ }
+
+ static short s() {
+ return 16;
+ }
+
+ static int i() {
+ return 32;
+ }
+
+ static long j() {
+ return 64;
+ }
+
+ static float f() {
+ return 0.32f;
+ }
+
+ static double d() {
+ return 0.64;
+ }
+
+ static Boolean Z() {
+ return false;
+ }
+
+ static Byte B() {
+ return -8;
+ }
+
+ static Character C() {
+ return 'C';
+ }
+
+ static Short S() {
+ return -16;
+ }
+
+ static Integer I() {
+ return -32;
+ }
+
+ static Long J() {
+ return -64L;
+ }
+
+ static Float F() {
+ return -0.32f;
+ }
+
+ static Double D() {
+ return -0.64;
+ }
+
+ public static void main(String[] args) {
+ StringBuffer builder = new StringBuffer();
+
+ checkBoolean(builder);
+ checkByte(builder);
+ checkChar(builder);
+ checkShort(builder);
+ checkInt(builder);
+ checkLong(builder);
+ checkFloat(builder);
+ checkDouble(builder);
+
+ checkBoxes(builder);
+ checkNumber(builder);
+ checkObject(builder);
+
+ checkMisc(builder);
+
+ System.out.println(builder.toString());
+ }
+}
diff --git a/src/test/examplesAndroidO/lambdadesugaring/legacy/Legacy.java b/src/test/examplesAndroidO/lambdadesugaring/legacy/Legacy.java
new file mode 100644
index 0000000..aabd8d8
--- /dev/null
+++ b/src/test/examplesAndroidO/lambdadesugaring/legacy/Legacy.java
@@ -0,0 +1,56 @@
+// 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 lambdadesugaring.legacy;
+
+public class Legacy {
+ public static class A {
+ private final String toString;
+
+ public A(String toString) {
+ this.toString = toString;
+ }
+
+ @Override
+ public String toString() {
+ return toString;
+ }
+ }
+
+ public static class B extends A {
+ public B(String toString) {
+ super(toString);
+ }
+ }
+
+ public static class C extends B {
+ public C(String toString) {
+ super(toString);
+ }
+ }
+
+ public static class D extends C {
+ public D(String toString) {
+ super(toString);
+ }
+ }
+
+ public interface BI<T> {
+ T foo(T o1);
+ }
+
+ public interface BH extends BI<String> {
+ }
+
+ public interface BK<T extends A> extends BI<T> {
+ T foo(T o1);
+ }
+
+ public interface BL<T extends B> extends BK<T> {
+ T foo(T o1);
+ }
+
+ public interface BM extends BK<C> {
+ C foo(C o1);
+ }
+}
diff --git a/src/test/examplesAndroidO/lambdadesugaring/other/OtherRefs.java b/src/test/examplesAndroidO/lambdadesugaring/other/OtherRefs.java
new file mode 100644
index 0000000..e783be3
--- /dev/null
+++ b/src/test/examplesAndroidO/lambdadesugaring/other/OtherRefs.java
@@ -0,0 +1,32 @@
+// 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 lambdadesugaring.other;
+
+public class OtherRefs {
+ public static class PublicInit {
+ public PublicInit() {
+ }
+
+ @Override
+ public String toString() {
+ return "OtherRefs::PublicInit::init()";
+ }
+ }
+
+ protected String fooOtherProtected() {
+ return "OtherRefs::fooOtherProtected()";
+ }
+
+ public String fooOtherPublic() {
+ return "OtherRefs::fooOtherPublic()";
+ }
+
+ protected static String staticOtherProtected() {
+ return "OtherRefs::staticOtherProtected()";
+ }
+
+ public static String staticOtherPublic() {
+ return "OtherRefs::staticOtherPublic()";
+ }
+}
diff --git a/src/test/examplesAndroidO/lambdadesugaringnplus/LambdasWithStaticAndDefaultMethods.java b/src/test/examplesAndroidO/lambdadesugaringnplus/LambdasWithStaticAndDefaultMethods.java
new file mode 100644
index 0000000..d2e738d
--- /dev/null
+++ b/src/test/examplesAndroidO/lambdadesugaringnplus/LambdasWithStaticAndDefaultMethods.java
@@ -0,0 +1,405 @@
+// 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 lambdadesugaringnplus;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import lambdadesugaringnplus.other.ClassWithDefaultPackagePrivate;
+import lambdadesugaringnplus.other.InterfaceWithDefaultPackagePrivate;
+
+public class LambdasWithStaticAndDefaultMethods {
+ interface I {
+ String iRegular();
+
+ static String iStatic() {
+ return "I::iStatic()";
+ }
+
+ default String iDefault() {
+ return "I::iDefault()";
+ }
+
+ default String iDefaultOverridden() {
+ return "I::iDefaultOverridden()";
+ }
+
+ default II stateless() {
+ return () -> "I::stateless()";
+ }
+
+ default II stateful() {
+ return () -> "I::captureThis(" + stateless().iRegular() + ")";
+ }
+ }
+
+ static class C implements I {
+ @Override
+ public String iRegular() {
+ return "C::iRegular()";
+ }
+
+ @Override
+ public String iDefaultOverridden() {
+ return "C::iDefaultOverridden()";
+ }
+ }
+
+ interface II extends I {
+ static String iStatic() {
+ II ii = I::iStatic;
+ return "II::iStatic(" + ((I) I::iStatic).iRegular() +
+ "|" + ((II) ii::iDefaultOverridden).iRegular() +
+ "|" + ((II) String::new).iRegular() +
+ "|" + ((II) ii::iRegular).iRegular() + ")";
+ }
+
+ default String iDefaultOverridden() {
+ return "II::iDefault(" + ((I) this::iDefault).iRegular() +
+ "|" + ((II) "One-Two-Three"::intern).iRegular() +
+ "|" + ((II) this::iDefault).iRegular() + ")";
+ }
+ }
+
+ interface P {
+ String get();
+ }
+
+ static void p(P p) {
+ System.out.println(p.get());
+ }
+
+ interface X<T> {
+ String foo(T t);
+ }
+
+ interface Y<T extends I> extends X<T> {
+ String foo(T t);
+ }
+
+ interface Z extends Y<II> {
+ String foo(II t);
+ }
+
+ interface G<T> {
+ T foo(T t);
+ }
+
+ interface B38257361_I1<T extends Number> {
+ default T copy(T t) {
+ return t;
+ }
+ }
+
+ interface B38257361_I2 extends B38257361_I1<Integer> {
+ @Override
+ default Integer copy(Integer t) {
+ return B38257361_I1.super.copy(t);
+ }
+ }
+
+ static class B38257361_C implements B38257361_I2 {
+ }
+
+ static class B38257361 {
+ private B38257361_C c = new B38257361_C();
+
+ public Integer test(Integer i) {
+ return c.copy(i);
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public Number test(Number n) {
+ return ((B38257361_I1) c).copy(n);
+ }
+
+ public static void test() {
+ B38257361 l = new B38257361();
+ Integer i = new Integer(1);
+ if (i.equals(l.test(i))) {
+ System.out.println("Check 1: OK");
+ } else {
+ System.out.println("Check 1: NOT OK");
+ }
+ if (i.equals(l.test((Number) i))) {
+ System.out.println("Check 2: OK");
+ } else {
+ System.out.println("Check 2: NOT OK");
+ }
+ try {
+ Double d = new Double(1);
+ if (d.equals(l.test((Number) d))) {
+ System.out.println("Check 3: NOT OK, classCastException expected");
+ } else {
+ System.out.println("Check 3: NOT OK, classCastException expected");
+ }
+ System.out.println("Error, ClassCastException is expected");
+ } catch (ClassCastException e) {
+ // Class cast into the bridge method is expected
+ System.out.println("OK, ClassCastException is expected");
+ }
+ }
+ }
+
+ interface B38257037_I1 {
+ default Number getNumber() {
+ return new Integer(1);
+ }
+ }
+
+ interface B38257037_I2 extends B38257037_I1 {
+ @Override
+ default Double getNumber() {
+ return new Double(2.3);
+ }
+ }
+
+ static class B38257037_C implements B38257037_I2 {
+ }
+
+ /**
+ * Check that bridges are generated.
+ */
+ static class B38257037 {
+ private B38257037_C c = new B38257037_C();
+
+ public Double test1() {
+ return c.getNumber();
+ }
+
+ public Number test2() {
+ return ((B38257037_I1) c).getNumber();
+ }
+
+ public static void test() {
+ B38257037 l = new B38257037();
+ if (l.test1() == 2.3) {
+ System.out.println("Check 1: OK");
+ } else {
+ System.out.println("Check 1: NOT OK");
+ }
+ if (l.test2().equals(new Double(2.3))) {
+ System.out.println("Check 2: OK");
+ } else {
+ System.out.println("Check 2: NOT OK");
+ }
+ }
+ }
+
+ interface B38306708_I {
+ class $CC{
+ static void print() {
+ System.out.println("$CC");
+ }
+ }
+
+ default String m() {
+ return "ITop.m()";
+ }
+ }
+
+ static class B38306708 {
+ public static void test() {
+ B38306708_I.$CC.print();
+ }
+ }
+
+ interface B38308515_I {
+ default String m() {
+ return "m instance";
+ }
+
+ static String m(B38308515_I i) {
+ return "m static";
+ }
+ }
+
+ static class B38308515_C implements B38308515_I {
+ }
+
+ static class B38308515 {
+ static void test() {
+ B38308515_C c = new B38308515_C();
+ System.out.println(c.m());
+ System.out.println(B38308515_I.m(c));
+ }
+ }
+
+ static class B38302860 {
+
+ @SomeAnnotation(1)
+ private interface AnnotatedInterface {
+
+ @SomeAnnotation(2)
+ void annotatedAbstractMethod();
+
+ @SomeAnnotation(3)
+ default void annotatedDefaultMethod() {
+ }
+
+ @SomeAnnotation(4)
+ static void annotatedStaticMethod() {
+ }
+ }
+
+ @Retention(value = RetentionPolicy.RUNTIME)
+ private @interface SomeAnnotation {
+ int value();
+ }
+
+ private static boolean checkAnnotationValue(Annotation[] annotations, int value) {
+ if (annotations.length != 1) {
+ return false;
+ }
+ return annotations[0] instanceof SomeAnnotation
+ && ((SomeAnnotation) annotations[0]).value() == value;
+ }
+
+ @SuppressWarnings("unchecked")
+ static void test() throws Exception {
+ if (checkAnnotationValue(AnnotatedInterface.class.getAnnotations(), 1)) {
+ System.out.println("Check 1: OK");
+ } else {
+ System.out.println("Check 1: NOT OK");
+ }
+
+ if (checkAnnotationValue(
+ AnnotatedInterface.class.getMethod("annotatedAbstractMethod").getAnnotations(), 2)) {
+ System.out.println("Check 2: OK");
+ } else {
+ System.out.println("Check 2: NOT OK");
+ }
+
+ if (checkAnnotationValue(
+ AnnotatedInterface.class.getMethod("annotatedDefaultMethod").getAnnotations(), 3)) {
+ System.out.println("Check 3: OK");
+ } else {
+ System.out.println("Check 3: NOT OK");
+ }
+
+ if (checkAnnotationValue(
+ getCompanionClassOrInterface().getMethod("annotatedStaticMethod").getAnnotations(), 4)) {
+ System.out.println("Check 4: OK");
+ } else {
+ System.out.println("Check 4: NOT OK");
+ }
+ }
+
+ private static Class getCompanionClassOrInterface() {
+ try {
+ return Class.forName("lambdadesugaringnplus."
+ + "LambdasWithStaticAndDefaultMethods$B38302860$AnnotatedInterface-CC");
+ } catch (Exception e) {
+ return AnnotatedInterface.class;
+ }
+ }
+ }
+
+ static void z(Z p) {
+ System.out.println(p.foo(null));
+ }
+
+ static void g(G<String[]> g) {
+ StringBuilder builder = new StringBuilder("{");
+ String sep = "";
+ for (String s : g.foo(new String[] { "Arg0", "Arg1", "Arg2" })) {
+ builder.append(sep).append(s);
+ sep = ", ";
+ }
+ builder.append("}");
+ System.out.println(builder.toString());
+ }
+
+ interface SuperChain {
+ default String iMain() {
+ return "SuperChain::iMain()";
+ }
+ }
+
+ interface SuperChainDerived extends SuperChain {
+ default String iMain() {
+ return "SuperChainDerived::iMain(" + SuperChain.super.iMain() + ")";
+ }
+ }
+
+ interface OtherSuperChain {
+ default String iMain() {
+ return "OtherSuperChain::iMain()";
+ }
+ }
+
+ static class ClassWithSuperChain implements SuperChainDerived, OtherSuperChain {
+ public String iMain() {
+ return "ClassWithSuperChain::iMain(" + SuperChainDerived.super.iMain() + ")" + iMainImpl();
+ }
+
+ public String iMainImpl() {
+ return "ClassWithSuperChain::iMain(" + SuperChainDerived.super.iMain() +
+ " + " + OtherSuperChain.super.iMain() + ")";
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ C c = new C();
+ I i = c;
+
+ c.iRegular();
+ c.iDefault();
+ c.iDefaultOverridden();
+ I.iStatic();
+ i.iRegular();
+ i.iDefault();
+ i.iDefaultOverridden();
+
+ p(i.stateless()::iRegular);
+ p(i.stateful()::iRegular);
+
+ g(a -> a);
+ g(a -> {
+ int size = a.length;
+ for (int x = 0; x < size / 2; x++) {
+ String t = a[x];
+ a[x] = a[size - 1 - x];
+ a[size - 1 - x] = t;
+ }
+ return a;
+ });
+
+ p(c::iRegular);
+ p(c::iDefault);
+ p(c::iDefaultOverridden);
+ p(I::iStatic);
+ p(i::iRegular);
+ p(i::iDefault);
+ p(i::iDefaultOverridden);
+
+ II ii = i::iRegular;
+ p(II::iStatic);
+ p(ii::iRegular);
+ p(ii::iDefault);
+ p(ii::iDefaultOverridden);
+
+ z(s -> "From Interface With Bridges");
+
+ System.out.println(new ClassWithSuperChain().iMain());
+
+ ClassWithDefaultPackagePrivate c2 = new ClassWithDefaultPackagePrivate();
+ InterfaceWithDefaultPackagePrivate i2 = c2;
+
+ c2.defaultFoo();
+ i2.defaultFoo();
+ InterfaceWithDefaultPackagePrivate.staticFoo();
+
+ p(c2::defaultFoo);
+ p(i2::defaultFoo);
+ p(InterfaceWithDefaultPackagePrivate::staticFoo);
+ p(c2.lambda()::foo);
+
+ B38257361.test();
+ B38257037.test();
+ B38306708.test();
+ B38308515.test();
+ B38302860.test();
+ }
+}
diff --git a/src/test/examplesAndroidO/lambdadesugaringnplus/other/ClassWithDefaultPackagePrivate.java b/src/test/examplesAndroidO/lambdadesugaringnplus/other/ClassWithDefaultPackagePrivate.java
new file mode 100644
index 0000000..102b13b
--- /dev/null
+++ b/src/test/examplesAndroidO/lambdadesugaringnplus/other/ClassWithDefaultPackagePrivate.java
@@ -0,0 +1,15 @@
+// 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 lambdadesugaringnplus.other;
+
+public class ClassWithDefaultPackagePrivate implements InterfaceWithDefaultPackagePrivate {
+ public InterfaceWithDefaultPackagePrivate lambda() {
+ return () -> ("lambda(" + InterfaceWithDefaultPackagePrivate.super.defaultFoo() + ")");
+ }
+
+ @Override
+ public String foo() {
+ throw new RuntimeException("Don't call me!");
+ }
+}
diff --git a/src/test/examplesAndroidO/lambdadesugaringnplus/other/InterfaceWithDefaultPackagePrivate.java b/src/test/examplesAndroidO/lambdadesugaringnplus/other/InterfaceWithDefaultPackagePrivate.java
new file mode 100644
index 0000000..536bc29
--- /dev/null
+++ b/src/test/examplesAndroidO/lambdadesugaringnplus/other/InterfaceWithDefaultPackagePrivate.java
@@ -0,0 +1,23 @@
+// 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 lambdadesugaringnplus.other;
+
+class PackagePrivate {
+ @Override
+ public String toString() {
+ return "PackagePrivate::toString()";
+ }
+}
+
+public interface InterfaceWithDefaultPackagePrivate {
+ String foo();
+
+ default String defaultFoo() {
+ return "defaultFoo: " + new PackagePrivate().toString();
+ }
+
+ static String staticFoo() {
+ return "staticFoo: " + new PackagePrivate().toString();
+ }
+}
diff --git a/src/test/examplesAndroidO/paramnames/ParameterNames.java b/src/test/examplesAndroidO/paramnames/ParameterNames.java
new file mode 100644
index 0000000..e9d9334
--- /dev/null
+++ b/src/test/examplesAndroidO/paramnames/ParameterNames.java
@@ -0,0 +1,56 @@
+// 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 paramnames;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+
+public class ParameterNames {
+
+ private static final int MODIFIER_NONE = 0;
+ private static final int MODIFIER_FINAL = 0X10;
+
+ public ParameterNames(int a, final int b) {
+ }
+
+ public static void check(String expected, String checked) {
+ if (!expected.equals(checked)) {
+ throw new RuntimeException("Found '" + checked + "' while expecting '" + expected + "'");
+ }
+ }
+
+ public static void check(int expected, int checked) {
+ if (expected != checked) {
+ throw new RuntimeException("Found '" + checked + "' while expecting '" + expected + "'");
+ }
+ }
+
+ public static void myMethod(int a, final int b) throws NoSuchMethodException {
+ Class<ParameterNames> clazz = ParameterNames.class;
+ Method myMethod = clazz.getDeclaredMethod("myMethod", int.class, int.class);
+ Parameter[] parameters = myMethod.getParameters();
+ check(2, parameters.length);
+ check("a", parameters[0].getName());
+ check("b", parameters[1].getName());
+ check(MODIFIER_NONE, parameters[0].getModifiers());
+ check(MODIFIER_FINAL, parameters[1].getModifiers());
+ }
+
+ public static void myConstructor() throws NoSuchMethodException {
+ Class<ParameterNames> clazz = ParameterNames.class;
+ Constructor<?> myConstructor = clazz.getDeclaredConstructor(int.class, int.class);
+ Parameter[] parameters = myConstructor.getParameters();
+ check(2, parameters.length);
+ check("a", parameters[0].getName());
+ check("b", parameters[1].getName());
+ check(MODIFIER_NONE, parameters[0].getModifiers());
+ check(MODIFIER_FINAL, parameters[1].getModifiers());
+ }
+
+ public static void main(String[] args) throws NoSuchMethodException {
+ myMethod(0, 1);
+ myConstructor();
+ }
+}
diff --git a/src/test/examplesAndroidO/repeat_annotations/NumberAnnotation.java b/src/test/examplesAndroidO/repeat_annotations/NumberAnnotation.java
new file mode 100644
index 0000000..7e304b9
--- /dev/null
+++ b/src/test/examplesAndroidO/repeat_annotations/NumberAnnotation.java
@@ -0,0 +1,14 @@
+// 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 repeat_annotations;
+
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Repeatable(NumberAnnotations.class)
+public @interface NumberAnnotation {
+ int number() default 32;
+}
diff --git a/src/test/examplesAndroidO/repeat_annotations/NumberAnnotations.java b/src/test/examplesAndroidO/repeat_annotations/NumberAnnotations.java
new file mode 100644
index 0000000..a70587a
--- /dev/null
+++ b/src/test/examplesAndroidO/repeat_annotations/NumberAnnotations.java
@@ -0,0 +1,12 @@
+// 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 repeat_annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+public @interface NumberAnnotations {
+ NumberAnnotation[] value();
+}
diff --git a/src/test/examplesAndroidO/repeat_annotations/RepeatAnnotations.java b/src/test/examplesAndroidO/repeat_annotations/RepeatAnnotations.java
new file mode 100644
index 0000000..d55de94
--- /dev/null
+++ b/src/test/examplesAndroidO/repeat_annotations/RepeatAnnotations.java
@@ -0,0 +1,22 @@
+// 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 repeat_annotations;
+
+// Simple test of Java 8 repeated annotations.
+public class RepeatAnnotations {
+
+ @NumberAnnotation(number = 1)
+ @NumberAnnotation(number = 2)
+ @NumberAnnotation(number = 3)
+ class Inner {
+ }
+
+ public static void main(String[] args) {
+ NumberAnnotations annotations = Inner.class.getAnnotation(NumberAnnotations.class);
+ System.out.println(annotations.value().length);
+ for (NumberAnnotation annotation : annotations.value()) {
+ System.out.println("Number annotation value: " + annotation.number());
+ }
+ }
+}
diff --git a/src/test/examplesAndroidO/repeat_annotations/RepeatAnnotationsNewApi.java b/src/test/examplesAndroidO/repeat_annotations/RepeatAnnotationsNewApi.java
new file mode 100644
index 0000000..6d23706
--- /dev/null
+++ b/src/test/examplesAndroidO/repeat_annotations/RepeatAnnotationsNewApi.java
@@ -0,0 +1,23 @@
+// 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 repeat_annotations;
+
+// Simple test of Java 8 repeated annotations using the new getAnnotationsByType
+// API to access them.
+public class RepeatAnnotationsNewApi {
+
+ @NumberAnnotation(number = 1)
+ @NumberAnnotation(number = 2)
+ @NumberAnnotation(number = 3)
+ class Inner {
+ }
+
+ public static void main(String[] args) {
+ NumberAnnotation[] annotations = Inner.class.getAnnotationsByType(NumberAnnotation.class);
+ System.out.println(annotations.length);
+ for (NumberAnnotation annotation : annotations) {
+ System.out.println("Number annotation value: " + annotation.number());
+ }
+ }
+}