blob: 8c1d8f14f53963fa178dfc661ccc28e2d2c2a799 [file] [log] [blame]
// Copyright (c) 2019, 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 com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
import static org.objectweb.asm.Opcodes.H_INVOKESTATIC;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.DiagnosticsLevel;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.errors.ConstantDynamicDesugarDiagnostic;
import com.android.tools.r8.errors.UnsupportedConstDynamicDiagnostic;
import com.android.tools.r8.errors.UnsupportedFeatureDiagnostic;
import com.android.tools.r8.utils.AndroidApiLevel;
import java.io.IOException;
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;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.Handle;
@RunWith(Parameterized.class)
public class ConstantDynamicHolderTest extends TestBase {
@Parameter() public TestParameters parameters;
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
}
@Test
public void testReference() throws Exception {
assumeTrue(parameters.isCfRuntime());
assumeTrue(parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK11));
assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
testForJvm()
.addProgramClassFileData(getTransformedMain())
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("null");
}
@Test
public void testD8() throws Exception {
assumeTrue(parameters.isDexRuntime());
testForD8()
.addProgramClassFileData(getTransformedMain())
.setMinApi(parameters.getApiLevel())
.setDiagnosticsLevelModifier(
(level, diagnostic) ->
(diagnostic instanceof UnsupportedFeatureDiagnostic
|| diagnostic instanceof ConstantDynamicDesugarDiagnostic)
? DiagnosticsLevel.WARNING
: level)
.compileWithExpectedDiagnostics(
diagnostics ->
diagnostics.assertWarningsMatch(
diagnosticType(UnsupportedConstDynamicDiagnostic.class),
allOf(
diagnosticType(ConstantDynamicDesugarDiagnostic.class),
diagnosticMessage(
containsString(
"Unsupported dynamic constant (runtime provided bootstrap"
+ " method)")))))
.run(parameters.getRuntime(), Main.class)
.assertFailureWithErrorThatThrows(RuntimeException.class)
.assertFailureWithErrorThatMatches(containsString("const-dynamic"));
}
// TODO(b/198142625): Support const-dynamic in IR CF/CF.
@Test(expected = CompilationFailedException.class)
public void testR8Cf() throws Exception {
assumeTrue(parameters.isCfRuntime());
assumeTrue(parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK11));
assumeTrue(parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
testForR8(parameters.getBackend())
.addProgramClassFileData(getTransformedMain())
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(Main.class)
.compile();
}
@Test
public void testR8() throws Exception {
assumeTrue(parameters.isDexRuntime());
testForR8(parameters.getBackend())
.addProgramClassFileData(getTransformedMain())
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(Main.class)
.allowDiagnosticWarningMessages()
.mapUnsupportedFeaturesToWarnings()
.compileWithExpectedDiagnostics(
diagnostics -> {
if (parameters.isDexRuntime()) {
diagnostics.assertWarningsMatch(
allOf(
diagnosticType(UnsupportedFeatureDiagnostic.class),
diagnosticMessage(containsString("const-dynamic"))));
}
})
.run(parameters.getRuntime(), Main.class)
.assertFailureWithErrorThatThrows(RuntimeException.class)
.assertFailureWithErrorThatMatches(containsString("const-dynamic"));
}
private byte[] getTransformedMain() throws IOException {
return transformer(Main.class)
.setMinVersion(CfVm.JDK11)
.transformLdcInsnInMethod(
"main",
(value, continuation) -> {
assertEquals("replaced by dynamic null constant", value);
continuation.visitLdcInsn(getDynamicConstant());
})
.transform();
}
private ConstantDynamic getDynamicConstant() {
return new ConstantDynamic(
"dynamicnull",
"Ljava/lang/String;",
new Handle(
H_INVOKESTATIC,
"java/lang/invoke/ConstantBootstraps",
"nullConstant",
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)"
+ "Ljava/lang/Object;",
false));
}
static class Main {
public static void main(String[] args) {
System.out.println("replaced by dynamic null constant");
}
}
}