Add reproduction of failures with javac code with fix for JDK-8272564

Bug: 217106437
Bug: 218298666
Change-Id: I73b427bbd15bf4503d68b633c9850af8dd07742a
diff --git a/src/test/examplesJava18/jdk8272564/A.java b/src/test/examplesJava18/jdk8272564/A.java
new file mode 100644
index 0000000..f548fc0
--- /dev/null
+++ b/src/test/examplesJava18/jdk8272564/A.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2022, 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 jdk8272564;
+
+public class A implements I {}
diff --git a/src/test/examplesJava18/jdk8272564/B.java b/src/test/examplesJava18/jdk8272564/B.java
new file mode 100644
index 0000000..678d2d5
--- /dev/null
+++ b/src/test/examplesJava18/jdk8272564/B.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2022, 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 jdk8272564;
+
+public class B implements J {}
diff --git a/src/test/examplesJava18/jdk8272564/C.java b/src/test/examplesJava18/jdk8272564/C.java
new file mode 100644
index 0000000..3308d8e
--- /dev/null
+++ b/src/test/examplesJava18/jdk8272564/C.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2022, 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 jdk8272564;
+
+public class C implements K {}
diff --git a/src/test/examplesJava18/jdk8272564/I.java b/src/test/examplesJava18/jdk8272564/I.java
new file mode 100644
index 0000000..ba9e252
--- /dev/null
+++ b/src/test/examplesJava18/jdk8272564/I.java
@@ -0,0 +1,9 @@
+// Copyright (c) 2022, 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 jdk8272564;
+
+interface I {
+  public String toString();
+}
diff --git a/src/test/examplesJava18/jdk8272564/J.java b/src/test/examplesJava18/jdk8272564/J.java
new file mode 100644
index 0000000..38b2551
--- /dev/null
+++ b/src/test/examplesJava18/jdk8272564/J.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2022, 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 jdk8272564;
+
+interface J extends I {}
diff --git a/src/test/examplesJava18/jdk8272564/K.java b/src/test/examplesJava18/jdk8272564/K.java
new file mode 100644
index 0000000..726f781
--- /dev/null
+++ b/src/test/examplesJava18/jdk8272564/K.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2022, 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 jdk8272564;
+
+interface K {}
diff --git a/src/test/examplesJava18/jdk8272564/Main.java b/src/test/examplesJava18/jdk8272564/Main.java
new file mode 100644
index 0000000..cc759ca
--- /dev/null
+++ b/src/test/examplesJava18/jdk8272564/Main.java
@@ -0,0 +1,20 @@
+// Copyright (c) 2022, 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 jdk8272564;
+
+public class Main {
+  // From javac in JDK-18 all of the following three invokes of toString are compiled to
+  // invokeinterface. Prior to JDK 18 the last two where compiled to invokevirtual.
+  // See https://bugs.openjdk.java.net/browse/JDK-8272564.
+  static void f(I i, J j, K k) {
+    i.toString();
+    j.toString();
+    k.toString();
+  }
+
+  public static void main(String[] args) {
+    f(new A(), new B(), new C());
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java b/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java
new file mode 100644
index 0000000..5bce7b7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java
@@ -0,0 +1,119 @@
+// Copyright (c) 2022, 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 com.android.tools.r8.desugar.jdk8272564;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.examples.jdk18.jdk8272564.Jdk8272564;
+import com.android.tools.r8.utils.InternalOptions.TestingOptions;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class Jdk8272564Test extends TestBase {
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    // TODO(b/218293990): Right now the JDK 18 tests are built with -target 17, as our Gradle
+    //  version does not know of -target 18.
+    // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk17).
+    return getTestParameters()
+        .withCustomRuntime(TestRuntime.getCheckedInJdk17())
+        .withDexRuntimes()
+        .withAllApiLevelsAlsoForCf()
+        .build();
+  }
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  // With the fix for JDK-8272564 there are no invokevirtual instructions.
+  private void assertJdk8272564FixedCode(CodeInspector inspector) throws Exception {
+    assertTrue(
+        inspector
+            .clazz(Jdk8272564.Main.typeName())
+            .uniqueMethodWithName("f")
+            .streamInstructions()
+            .noneMatch(InstructionSubject::isInvokeVirtual));
+  }
+
+  // Without the fix for JDK-8272564 there is one invokeinterface and 2 invokevirtual instructions.
+  private void assertJdk8272564NotFixedCode(CodeInspector inspector) throws Exception {
+    assertEquals(
+        1,
+        inspector
+            .clazz(Jdk8272564.Main.typeName())
+            .uniqueMethodWithName("f")
+            .streamInstructions()
+            .filter(InstructionSubject::isInvokeInterface)
+            .count());
+    assertEquals(
+        2,
+        inspector
+            .clazz(Jdk8272564.Main.typeName())
+            .uniqueMethodWithName("f")
+            .streamInstructions()
+            .filter(InstructionSubject::isInvokeVirtual)
+            .count());
+  }
+
+  @Test
+  // See https://bugs.openjdk.java.net/browse/JDK-8272564.
+  public void testJdk8272564Compiler() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
+    // Ensure that the test is running with CF input from fixing JDK-8272564.
+    assertJdk8272564FixedCode(new CodeInspector(Jdk8272564.jar()));
+  }
+
+  @Test
+  public void testJvm() throws Exception {
+    assumeTrue(parameters.isCfRuntime());
+    testForJvm()
+        .addRunClasspathFiles(Jdk8272564.jar())
+        .run(TestRuntime.getCheckedInJdk17(), Jdk8272564.Main.typeName())
+        .assertSuccess();
+  }
+
+  @Test
+  public void testD8() throws Exception {
+    testForDesugaring(parameters)
+        .addProgramFiles(Jdk8272564.jar())
+        .run(parameters.getRuntime(), Jdk8272564.Main.typeName())
+        .applyIf(
+            parameters.getRuntime().isDex()
+                && parameters.getRuntime().asDex().getVersion().isOlderThanOrEqual(Version.V4_4_4),
+            r -> r.assertFailureWithErrorThatThrows(NoSuchMethodError.class),
+            parameters.getRuntime().isDex()
+                && parameters.getRuntime().asDex().getVersion().isOlderThanOrEqual(Version.V7_0_0),
+            r -> r.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class),
+            r -> r.assertSuccess());
+  }
+
+  @Test
+  public void testR8() throws Exception {
+    // The R8 lens code rewriter rewrites to the code prior to fixing JDK-8272564.
+    testForR8(parameters.getBackend())
+        .addProgramFiles(Jdk8272564.jar())
+        .setMinApi(parameters.getApiLevel())
+        .noTreeShaking()
+        .addKeepClassAndMembersRules(Jdk8272564.Main.typeName())
+        .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
+        .run(parameters.getRuntime(), Jdk8272564.Main.typeName())
+        .inspect(this::assertJdk8272564NotFixedCode)
+        .assertSuccess();
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/examples/jdk18/jdk8272564/Jdk8272564.java b/src/test/java/com/android/tools/r8/examples/jdk18/jdk8272564/Jdk8272564.java
new file mode 100644
index 0000000..5e891aa
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/jdk18/jdk8272564/Jdk8272564.java
@@ -0,0 +1,32 @@
+// Copyright (c) 2022, 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 com.android.tools.r8.examples.jdk18.jdk8272564;
+
+import com.android.tools.r8.examples.JavaExampleClassProxy;
+import java.nio.file.Path;
+
+public class Jdk8272564 {
+
+  private static final String EXAMPLE_FILE = "examplesJava18/jdk8272564";
+
+  public static final JavaExampleClassProxy A =
+      new JavaExampleClassProxy(EXAMPLE_FILE, "jdk8272564/A");
+  public static final JavaExampleClassProxy B =
+      new JavaExampleClassProxy(EXAMPLE_FILE, "jdk8272564/B");
+  public static final JavaExampleClassProxy C =
+      new JavaExampleClassProxy(EXAMPLE_FILE, "jdk8272564/C");
+  public static final JavaExampleClassProxy I =
+      new JavaExampleClassProxy(EXAMPLE_FILE, "jdk8272564/I");
+  public static final JavaExampleClassProxy J =
+      new JavaExampleClassProxy(EXAMPLE_FILE, "jdk8272564/J");
+  public static final JavaExampleClassProxy K =
+      new JavaExampleClassProxy(EXAMPLE_FILE, "jdk8272564/K");
+  public static final JavaExampleClassProxy Main =
+      new JavaExampleClassProxy(EXAMPLE_FILE, "jdk8272564/Main");
+
+  public static Path jar() {
+    return JavaExampleClassProxy.examplesJar(EXAMPLE_FILE);
+  }
+}