Add a DYNAMIC_Constant ICCE regression test
A DYNAMIC_Constant test where the bootstrap method handle
does not have the interface bit but targets a bootstrap method on an
interface.
Bug: 178172809
Change-Id: I729de5ad20c38cec77fea25b6f8ac4b3018598be
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
index a332828..48dca2d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
@@ -162,7 +162,11 @@
synthesizeConstantDynamicClass(builder);
} else {
// Unconditionally throw as the RI.
- behaviour = resolution.isFailedResolution() ? THROW_NSME : THROW_ICCE;
+ behaviour =
+ resolution.isNoSuchMethodErrorResult(
+ context.getContextClass(), appView.appInfoForDesugaring())
+ ? THROW_NSME
+ : THROW_ICCE;
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BasicConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BasicConstantDynamicTest.java
index d458f22..c5c6480 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BasicConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BasicConstantDynamicTest.java
@@ -109,9 +109,9 @@
return transformer(A.class)
.setVersion(CfVersion.V11)
.transformConstStringToConstantDynamic(
- "condy1", A.class, "myConstant", "constantName", Object.class)
+ "condy1", A.class, "myConstant", false, "constantName", Object.class)
.transformConstStringToConstantDynamic(
- "condy2", A.class, "myConstant", "constantName", Object.class)
+ "condy2", A.class, "myConstant", false, "constantName", Object.class)
.transform();
}
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodNotFoundConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodNotFoundConstantDynamicTest.java
index 7b204ac..4cea83c 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodNotFoundConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodNotFoundConstantDynamicTest.java
@@ -102,7 +102,7 @@
return transformer(A.class)
.setVersion(CfVersion.V11)
.transformConstStringToConstantDynamic(
- "condy1", A.class, "methodNotFound", "constantName", Object.class)
+ "condy1", A.class, "methodNotFound", false, "constantName", Object.class)
.transform();
}
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodPrivateConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodPrivateConstantDynamicTest.java
index 5f7e125..169a85d 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodPrivateConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodPrivateConstantDynamicTest.java
@@ -101,7 +101,7 @@
return transformer(A.class)
.setVersion(CfVersion.V11)
.transformConstStringToConstantDynamic(
- "condy1", A.class, "myConstant", "constantName", Object.class)
+ "condy1", A.class, "myConstant", false, "constantName", Object.class)
.transform();
}
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodVirtualConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodVirtualConstantDynamicTest.java
index 3f9a957..a693c21 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodVirtualConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/BootstrapMethodVirtualConstantDynamicTest.java
@@ -101,7 +101,7 @@
return transformer(A.class)
.setVersion(CfVersion.V11)
.transformConstStringToConstantDynamic(
- "condy1", A.class, "myConstant", "constantName", Object.class)
+ "condy1", A.class, "myConstant", false, "constantName", Object.class)
.transform();
}
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicGetDeclaredMethodsTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicGetDeclaredMethodsTest.java
index 4810b1d..7deff9c 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicGetDeclaredMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicGetDeclaredMethodsTest.java
@@ -126,7 +126,7 @@
return transformer(A.class)
.setVersion(CfVersion.V11)
.transformConstStringToConstantDynamic(
- "condy", A.class, "myConstant", "constantName", Object.class)
+ "condy", A.class, "myConstant", false, "constantName", Object.class)
.transform();
}
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodICCETest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodICCETest.java
new file mode 100644
index 0000000..feff719
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodICCETest.java
@@ -0,0 +1,141 @@
+// 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.constantdynamic;
+
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.DesugarTestConfiguration;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.cf.CfVersion;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.lang.invoke.MethodHandles;
+import java.util.List;
+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 ConstantDynamicInDefaultInterfaceMethodICCETest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+ }
+
+ private static final Class<?> MAIN_CLASS = A.class;
+
+ @Test
+ public void testReference() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ assumeTrue(parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11));
+ assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
+
+ testForJvm()
+ .addProgramClasses(MAIN_CLASS)
+ .addProgramClassFileData(getTransformedClasses())
+ .run(parameters.getRuntime(), MAIN_CLASS)
+ .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
+ }
+
+ @Test
+ public void testDesugaring() throws Exception {
+ testForDesugaring(parameters)
+ .addProgramClasses(MAIN_CLASS)
+ .addProgramClassFileData(getTransformedClasses())
+ .run(parameters.getRuntime(), MAIN_CLASS)
+ .applyIf(
+ // When not desugaring the CF code requires JDK 11.
+ DesugarTestConfiguration::isNotDesugared,
+ r -> {
+ if (parameters.isCfRuntime()
+ && parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11)) {
+ r.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
+ } else {
+ r.assertFailureWithErrorThatThrows(UnsupportedClassVersionError.class);
+ }
+ })
+ .applyIf(
+ DesugarTestConfiguration::isDesugared,
+ r -> r.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class));
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ assumeTrue(parameters.isDexRuntime() || parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
+
+ testForR8(parameters.getBackend())
+ .addProgramClasses(MAIN_CLASS)
+ .addProgramClassFileData(getTransformedClasses())
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(MAIN_CLASS)
+ // TODO(b/198142625): Support CONSTANT_Dynamic output for class files.
+ .applyIf(
+ parameters.isCfRuntime(),
+ b -> {
+ assertThrows(
+ CompilationFailedException.class,
+ () ->
+ b.compileWithExpectedDiagnostics(
+ diagnostics -> {
+ diagnostics.assertOnlyErrors();
+ diagnostics.assertErrorsMatch(
+ diagnosticMessage(
+ containsString(
+ "Unsupported dynamic constant (not desugaring)")));
+ }));
+ },
+ b ->
+ b.run(parameters.getRuntime(), MAIN_CLASS)
+ .assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class));
+ }
+
+ // Create a constant dynamic without the interface bit targeting an interface bootstrap method.
+ private byte[] getTransformedClasses() throws Exception {
+ return transformer(I.class)
+ .setVersion(CfVersion.V11)
+ .transformConstStringToConstantDynamic(
+ "condy1", I.class, "myConstant", false, "constantName", Object.class)
+ .transformConstStringToConstantDynamic(
+ "condy2", I.class, "myConstant", false, "constantName", Object.class)
+ .setPrivate(
+ I.class.getDeclaredMethod(
+ "myConstant", MethodHandles.Lookup.class, String.class, Class.class))
+ .transform();
+ }
+
+ public interface I {
+
+ default Object f() {
+ return "condy1"; // Will be transformed to Constant_DYNAMIC.
+ }
+
+ default Object g() {
+ return "condy2"; // Will be transformed to Constant_DYNAMIC.
+ }
+
+ /* private */ static Object myConstant(
+ MethodHandles.Lookup lookup, String name, Class<?> type) {
+ return new Object();
+ }
+ }
+
+ public static class A implements I {
+ public static void main(String[] args) {
+ A a = new A();
+ System.out.println(a.f() != null);
+ System.out.println(a.f() == a.g());
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodTest.java
index a09ae6a..ad46d90 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/ConstantDynamicInDefaultInterfaceMethodTest.java
@@ -116,9 +116,9 @@
return transformer(I.class)
.setVersion(CfVersion.V11)
.transformConstStringToConstantDynamic(
- "condy1", I.class, "myConstant", "constantName", Object.class)
+ "condy1", I.class, "myConstant", true, "constantName", Object.class)
.transformConstStringToConstantDynamic(
- "condy2", I.class, "myConstant", "constantName", Object.class)
+ "condy2", I.class, "myConstant", true, "constantName", Object.class)
.setPrivate(
I.class.getDeclaredMethod(
"myConstant", MethodHandles.Lookup.class, String.class, Class.class))
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/HierarchyConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/HierarchyConstantDynamicTest.java
index edc3cab..b7e540b 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/HierarchyConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/HierarchyConstantDynamicTest.java
@@ -102,12 +102,12 @@
transformer(A.class)
.setVersion(CfVersion.V11)
.transformConstStringToConstantDynamic(
- "condy1", A.class, "myConstant", "constantName", Object.class)
+ "condy1", A.class, "myConstant", false, "constantName", Object.class)
.transform(),
transformer(B.class)
.setVersion(CfVersion.V11)
.transformConstStringToConstantDynamic(
- "condy1", B.class, "myConstant", "constantName", Object.class)
+ "condy1", B.class, "myConstant", false, "constantName", Object.class)
.transform());
}
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleBootstrapMethodConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleBootstrapMethodConstantDynamicTest.java
index b3f900a..a7df375 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleBootstrapMethodConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleBootstrapMethodConstantDynamicTest.java
@@ -110,13 +110,13 @@
return transformer(A.class)
.setVersion(CfVersion.V11)
.transformConstStringToConstantDynamic(
- "condy1", A.class, "myConstant1", "constantName", Object.class)
+ "condy1", A.class, "myConstant1", false, "constantName", Object.class)
.transformConstStringToConstantDynamic(
- "condy2", A.class, "myConstant1", "constantName", Object.class)
+ "condy2", A.class, "myConstant1", false, "constantName", Object.class)
.transformConstStringToConstantDynamic(
- "condy3", A.class, "myConstant2", "constantName", Object.class)
+ "condy3", A.class, "myConstant2", false, "constantName", Object.class)
.transformConstStringToConstantDynamic(
- "condy4", A.class, "myConstant2", "constantName", Object.class)
+ "condy4", A.class, "myConstant2", false, "constantName", Object.class)
.transform();
}
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleNamedConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleNamedConstantDynamicTest.java
index 667473e..5ebc8da 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleNamedConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleNamedConstantDynamicTest.java
@@ -112,13 +112,13 @@
return transformer(A.class)
.setVersion(CfVersion.V11)
.transformConstStringToConstantDynamic(
- "condy1", A.class, "myConstant", "constantF", Object.class)
+ "condy1", A.class, "myConstant", false, "constantF", Object.class)
.transformConstStringToConstantDynamic(
- "condy2", A.class, "myConstant", "constantF", Object.class)
+ "condy2", A.class, "myConstant", false, "constantF", Object.class)
.transformConstStringToConstantDynamic(
- "condy3", A.class, "myConstant", "constantG", Object.class)
+ "condy3", A.class, "myConstant", false, "constantG", Object.class)
.transformConstStringToConstantDynamic(
- "condy4", A.class, "myConstant", "constantG", Object.class)
+ "condy4", A.class, "myConstant", false, "constantG", Object.class)
.transform();
}
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleTypesConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleTypesConstantDynamicTest.java
index 48e0aab..fab07ce 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleTypesConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/MultipleTypesConstantDynamicTest.java
@@ -111,13 +111,13 @@
return transformer(A.class)
.setVersion(CfVersion.V11)
.transformConstStringToConstantDynamic(
- "condy1", A.class, "myConstant", "constantName", Object.class)
+ "condy1", A.class, "myConstant", false, "constantName", Object.class)
.transformConstStringToConstantDynamic(
- "condy2", A.class, "myConstant", "constantName", Object.class)
+ "condy2", A.class, "myConstant", false, "constantName", Object.class)
.transformConstStringToConstantDynamic(
- "condy3", A.class, "myConstant", "constantName", boolean[].class)
+ "condy3", A.class, "myConstant", false, "constantName", boolean[].class)
.transformConstStringToConstantDynamic(
- "condy4", A.class, "myConstant", "constantName", boolean[].class)
+ "condy4", A.class, "myConstant", false, "constantName", boolean[].class)
.transform();
}
diff --git a/src/test/java/com/android/tools/r8/desugar/constantdynamic/SharedBootstrapMethodConstantDynamicTest.java b/src/test/java/com/android/tools/r8/desugar/constantdynamic/SharedBootstrapMethodConstantDynamicTest.java
index bff5968..1ae1ccf 100644
--- a/src/test/java/com/android/tools/r8/desugar/constantdynamic/SharedBootstrapMethodConstantDynamicTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/constantdynamic/SharedBootstrapMethodConstantDynamicTest.java
@@ -123,16 +123,16 @@
transformer(A.class)
.setVersion(CfVersion.V11)
.transformConstStringToConstantDynamic(
- "condy1", A.class, "myConstant", "constantName", Object.class)
+ "condy1", A.class, "myConstant", false, "constantName", Object.class)
.transformConstStringToConstantDynamic(
- "condy2", A.class, "myConstant", "constantName", Object.class)
+ "condy2", A.class, "myConstant", false, "constantName", Object.class)
.transform(),
transformer(B.class)
.setVersion(CfVersion.V11)
.transformConstStringToConstantDynamic(
- "condy3", A.class, "myConstant", "constantName", Object.class)
+ "condy3", A.class, "myConstant", false, "constantName", Object.class)
.transformConstStringToConstantDynamic(
- "condy4", A.class, "myConstant", "constantName", Object.class)
+ "condy4", A.class, "myConstant", false, "constantName", Object.class)
.transform());
}
diff --git a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
index 8644e9a..d8557a0 100644
--- a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
+++ b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
@@ -978,6 +978,7 @@
String constantName,
Class<?> bootstrapMethodHolder,
String bootstrapMethodName,
+ boolean isInterfaceInvoke,
String name,
Class<?> type) {
return addMethodTransformer(
@@ -996,7 +997,7 @@
DescriptorUtils.getClassBinaryName(bootstrapMethodHolder),
bootstrapMethodName,
bootstrapMethodSignature,
- bootstrapMethodHolder.isInterface()),
+ isInterfaceInvoke),
new Object[] {}));
} else {
super.visitLdcInsn(value);