blob: 229ccfe5463de598c8101fc9c12d3b99e64658ab [file] [log] [blame]
// Copyright (c) 2023, 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.desugaredlibrary.jdktests;
import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_MINIMAL;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
import com.android.tools.r8.desugar.desugaredlibrary.test.DesugaredLibraryTestCompileResult;
import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.ZipUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.BeforeClass;
import org.junit.Ignore;
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 Jdk11Jsr166Tests extends DesugaredLibraryTestBase {
private static Path jsr166Suite;
private static Path jsr166SuitePreN;
@Parameter(0)
public static TestParameters parameters;
@Parameter(1)
public static LibraryDesugaringSpecification libraryDesugaringSpecification;
@Parameter(2)
public static CompilationSpecification compilationSpecification;
@Parameters(name = "{0}, spec: {1}, {2}")
public static List<Object[]> data() {
return buildParameters(
// TODO(134732760): Support Dalvik VMs, currently fails because libjavacrypto is required
// and present only in ART runtimes.
getTestParameters()
.withDexRuntimesStartingFromIncluding(Version.V5_1_1)
.withAllApiLevels()
.withApiLevel(AndroidApiLevel.N)
.build(),
ImmutableList.of(JDK11_MINIMAL, JDK11, JDK11_PATH),
ImmutableSet.of(D8_L8DEBUG, D8_L8SHRINK));
}
@BeforeClass
public static void compileJsr166Suite() throws Exception {
// Build the JSR166 test suite.
Path jsr166SuiteClasses = getStaticTemp().newFolder("jsr166SuiteClasses").toPath();
javac(TestRuntime.getCheckedInJdk11(), getStaticTemp())
.addClasspathFiles(Paths.get(ToolHelper.THIRD_PARTY_DIR + "junit/junit-4.13-beta-2.jar"))
.addSourceFiles(
Files.walk(
Paths.get(
ToolHelper.THIRD_PARTY_DIR
+ "openjdk/jdk-11-test/java/util/concurrent/tck"))
.filter(path -> path.getFileName().toString().endsWith(".java"))
.collect(Collectors.toList()))
.setOutputPath(jsr166SuiteClasses)
.compile();
Path jars = jsr166Suite = getStaticTemp().newFolder("jars").toPath();
jsr166Suite = jars.resolve("jsr166Suite.jar");
ZipUtils.zip(jsr166Suite, jsr166SuiteClasses);
// Transform the test suite to be able to run on pre N devices.
jsr166SuitePreN = jars.resolve("jsr166SuitePreN.jar");
makeTransformedJar(jsr166Suite, jsr166SuitePreN);
}
public static void makeTransformedJar(Path in, Path out) throws IOException {
ZipUtils.map(
in,
out,
(entry, bytes) ->
entry.getName().equals("ConcurrentLinkedDequeTest.class")
? transformConcurrentLinkedDequeTestForPreN(bytes)
: bytes);
}
public static byte[] transformConcurrentLinkedDequeTestForPreN(
byte[] concurrentLinkedDequeTestClassBytes) {
// Remove methods using java.util.concurrent.CompletableFuture and
// java.util.concurrent.atomic.LongAdder introduced as API level 24.
return transformer(
concurrentLinkedDequeTestClassBytes,
Reference.classFromDescriptor("LConcurrentLinkedDequeTest;"))
.removeMethods(
(access, name, descriptor, signature, exceptions) ->
name.contains("testBug8188900")
|| name.contains("testBug8188900_reverse")
|| name.contains("testBug8189387"))
.transform();
}
private void inspect(CodeInspector inspector) {
// Right now we only expect one backport coming out of DesugarVarHandle - the backport with
// forwarding of Unsafe.compareAndSwapObject.
MethodReference firstBackportFromDesugarVarHandle =
SyntheticItemsTestUtils.syntheticBackportWithForwardingMethod(
Reference.classFromDescriptor("Lj$/com/android/tools/r8/DesugarVarHandle;"),
0,
Reference.method(
Reference.classFromDescriptor("Lsun/misc/Unsafe;"),
"compareAndSwapObject",
ImmutableList.of(
Reference.typeFromDescriptor("Ljava/lang/Object;"),
Reference.LONG,
Reference.typeFromDescriptor("Ljava/lang/Object;"),
Reference.typeFromDescriptor("Ljava/lang/Object;")),
Reference.BOOL));
assertThat(
inspector.clazz(
DescriptorUtils.descriptorToJavaType(DexItemFactory.varHandleDescriptorString)),
not(isPresent()));
assertThat(
inspector.clazz(
DescriptorUtils.descriptorToJavaType(
DexItemFactory.methodHandlesLookupDescriptorString)),
not(isPresent()));
assertThat(
inspector.clazz(
"j$." + DescriptorUtils.descriptorToJavaType(DexItemFactory.varHandleDescriptorString)),
not(isPresent()));
assertThat(
inspector.clazz(
"j$."
+ DescriptorUtils.descriptorToJavaType(
DexItemFactory.methodHandlesLookupDescriptorString)),
not(isPresent()));
assertThat(
inspector.clazz(
DescriptorUtils.descriptorToJavaType(DexItemFactory.desugarVarHandleDescriptorString)),
not(isPresent()));
assertThat(
inspector.clazz(
DescriptorUtils.descriptorToJavaType(
DexItemFactory.desugarMethodHandlesLookupDescriptorString)),
not(isPresent()));
boolean usesNativeVarHandle =
parameters.asDexRuntime().getVersion().isNewerThanOrEqual(Version.V13_0_0)
&& parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.T);
assertThat(
inspector.clazz(
"j$."
+ DescriptorUtils.descriptorToJavaType(
DexItemFactory.desugarVarHandleDescriptorString)),
usesNativeVarHandle ? not(isPresent()) : isPresent());
assertThat(
inspector.clazz(firstBackportFromDesugarVarHandle.getHolderClass()),
usesNativeVarHandle ? not(isPresent()) : isPresent());
// Currently DesugarMethodHandlesLookup this is fully inlined by R8.
assertThat(
inspector.clazz(
"j$."
+ DescriptorUtils.descriptorToJavaType(
DexItemFactory.desugarMethodHandlesLookupDescriptorString)),
usesNativeVarHandle || compilationSpecification.isL8Shrink()
? not(isPresent())
: isPresent());
}
void runTest(List<TestInfo> toRun) throws Exception {
DesugaredLibraryTestCompileResult<?> compileResult =
testForDesugaredLibrary(
parameters, libraryDesugaringSpecification, compilationSpecification)
.addProgramFiles(Paths.get("third_party/junit/junit-4.13-beta-2.jar"))
.addProgramFiles(
parameters.getDexRuntimeVersion().isOlderThan(Version.V7_0_0)
? jsr166SuitePreN
: jsr166Suite)
.compile()
.inspectL8(this::inspect)
.withArt6Plus64BitsLib();
for (TestInfo testInfo : toRun) {
SingleTestRunResult<?> result =
compileResult.run(parameters.getRuntime(), testInfo.getName());
assertTrue(
"Failure in " + testInfo.getName() + "\n" + result,
result.getStdOut().startsWith(testInfo.getStartsWith()));
}
}
private static class TestInfo {
private final String name;
private final String startsWith;
public TestInfo(String name, String startsWith) {
this.name = name;
this.startsWith = startsWith;
}
public String getName() {
return name;
}
public String getStartsWith() {
return startsWith;
}
}
@Test
@Ignore("b/267483394")
public void test() throws Exception {
runTest(
ImmutableList.of(
new TestInfo("ConcurrentLinkedQueueTest", "OK (38 tests)"),
new TestInfo(
"ConcurrentLinkedDequeTest",
parameters.getDexRuntimeVersion().isOlderThan(Version.V7_0_0)
? "OK (62 tests)"
: "OK (65 tests)")));
}
}