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);
+ }
+}