blob: a4b8697a67e94ca9f3156ff0fd226162f7c28b80 [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;
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.ListUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableMap;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
// Base class for the runtime structure in the test parameters.
public abstract class TestRuntime {
// Enum describing the possible/supported CF runtimes.
public enum CfVm {
JDK8("jdk8", 52),
JDK9("jdk9", 53),
JDK10("jdk10", 54),
JDK11("jdk11", 55),
JDK17("jdk17", 61),
;
/** This should generally be the latest checked in CF runtime we fully support. */
private static final CfVm DEFAULT = JDK9;
private final String name;
private final int classfileVersion;
CfVm(String name, int classfileVersion) {
this.name = name;
this.classfileVersion = classfileVersion;
}
public int getClassfileVersion() {
return classfileVersion;
}
public static CfVm first() {
return JDK8;
}
public static CfVm last() {
return JDK11;
}
public boolean lessThan(CfVm other) {
return this.ordinal() < other.ordinal();
}
public boolean lessThanOrEqual(CfVm other) {
return this.ordinal() <= other.ordinal();
}
@Override
public String toString() {
return name;
}
}
private static final Path JDK8_PATH = Paths.get(ToolHelper.THIRD_PARTY_DIR, "openjdk", "jdk8");
private static final Path JDK9_PATH =
Paths.get(ToolHelper.THIRD_PARTY_DIR, "openjdk", "openjdk-9.0.4");
private static final Path JDK11_PATH = Paths.get(ToolHelper.THIRD_PARTY_DIR, "openjdk", "jdk-11");
private static final Path JDK17_PATH = Paths.get(ToolHelper.THIRD_PARTY_DIR, "openjdk", "jdk-17");
private static final Map<CfVm, Path> jdkPaths =
ImmutableMap.of(
CfVm.JDK8, JDK8_PATH,
CfVm.JDK9, JDK9_PATH,
CfVm.JDK11, JDK11_PATH,
CfVm.JDK17, JDK17_PATH);
public static CfRuntime getCheckedInJdk(CfVm vm) {
if (vm == CfVm.JDK8) {
return getCheckedInJdk8();
}
return new CfRuntime(vm, getCheckedInJdkHome(vm));
}
public static CfRuntime getCheckedInJdk8() {
Path home;
if (ToolHelper.isLinux()) {
home = JDK8_PATH.resolve("linux-x86");
} else if (ToolHelper.isMac()) {
home = JDK8_PATH.resolve("darwin-x86");
} else {
assert ToolHelper.isWindows();
return null;
}
return new CfRuntime(CfVm.JDK8, home);
}
private static Path getCheckedInJdkHome(CfVm vm) {
Path path = jdkPaths.get(vm);
assert path != null : "No JDK path defined for " + vm;
if (ToolHelper.isLinux()) {
return path.resolve("linux");
} else if (ToolHelper.isMac()) {
return vm.lessThanOrEqual(CfVm.JDK9)
? path.resolve("osx")
: path.resolve("osx/Contents/Home");
} else {
assert ToolHelper.isWindows();
return path.resolve("windows");
}
}
public static CfRuntime getCheckedInJdk9() {
return new CfRuntime(CfVm.JDK9, getCheckedInJdkHome(CfVm.JDK9));
}
public static CfRuntime getCheckedInJdk11() {
return new CfRuntime(CfVm.JDK11, getCheckedInJdkHome(CfVm.JDK11));
}
// TODO(b/169692487): Add this to 'getCheckedInCfRuntimes' when we start having support for JDK17.
public static CfRuntime getCheckedInJdk17() {
return new CfRuntime(CfVm.JDK17, getCheckedInJdkHome(CfVm.JDK17));
}
public static List<CfRuntime> getCheckedInCfRuntimes() {
CfRuntime[] jdks =
new CfRuntime[] {getCheckedInJdk8(), getCheckedInJdk9(), getCheckedInJdk11()};
Builder<CfRuntime> builder = ImmutableList.builder();
for (CfRuntime jdk : jdks) {
if (jdk != null) {
builder.add(jdk);
}
}
return builder.build();
}
private static List<DexRuntime> getCheckedInDexRuntimes() {
if (ToolHelper.isLinux()) {
return ListUtils.map(Arrays.asList(DexVm.Version.values()), DexRuntime::new);
}
assert ToolHelper.isMac() || ToolHelper.isWindows();
return ImmutableList.of();
}
// For compatibility with old tests not specifying a Java runtime
@Deprecated
public static TestRuntime getDefaultJavaRuntime() {
return getCheckedInJdk9();
}
public static CfRuntime getDefaultCfRuntime() {
return TestRuntime.getCheckedInJdk(CfVm.DEFAULT);
}
public static DexRuntime getDefaultDexRuntime() {
return new DexRuntime(DexVm.Version.NEW_DEFAULT);
}
public static List<TestRuntime> getCheckedInRuntimes() {
return ImmutableList.<TestRuntime>builder()
.addAll(getCheckedInCfRuntimes())
.addAll(getCheckedInDexRuntimes())
.build();
}
public static CfRuntime getSystemRuntime() {
String version = System.getProperty("java.version");
String home = System.getProperty("java.home");
if (version == null || version.isEmpty() || home == null || home.isEmpty()) {
throw new Unimplemented("Unable to create a system runtime");
}
if (version.startsWith("1.8.")) {
return new CfRuntime(CfVm.JDK8, Paths.get(home));
}
if (version.startsWith("9.")) {
return new CfRuntime(CfVm.JDK9, Paths.get(home));
}
if (version.startsWith("11.")) {
return new CfRuntime(CfVm.JDK11, Paths.get(home));
}
throw new Unimplemented("No support for JDK version: " + version);
}
public static class NoneRuntime extends TestRuntime {
private static final String NAME = "none";
private static final NoneRuntime INSTANCE = new NoneRuntime();
private NoneRuntime() {}
public static NoneRuntime getInstance() {
return INSTANCE;
}
@Override
public String name() {
return NAME;
}
@Override
public AndroidApiLevel maxSupportedApiLevel() {
// The "none" runtime trivally supports all api levels as nothing is run.
return AndroidApiLevel.LATEST;
}
@Override
public String toString() {
return NAME;
}
@Override
public boolean equals(Object other) {
return this == other;
}
@Override
public int hashCode() {
return System.identityHashCode(this);
}
}
// Wrapper for the DEX runtimes.
public static class DexRuntime extends TestRuntime {
private final DexVm vm;
public DexRuntime(DexVm.Version version) {
this(DexVm.fromVersion(version));
}
public DexRuntime(DexVm vm) {
assert vm != null;
this.vm = vm;
}
@Override
public String name() {
return "dex-" + vm.getVersion().toString();
}
@Override
public boolean isDex() {
return true;
}
@Override
public DexRuntime asDex() {
return this;
}
public DexVm getVm() {
return vm;
}
public DexVm.Version getVersion() {
return vm.getVersion();
}
@Override
public AndroidApiLevel maxSupportedApiLevel() {
return getMinApiLevel();
}
@Override
public boolean equals(Object other) {
if (!(other instanceof DexRuntime)) {
return false;
}
DexRuntime dexRuntime = (DexRuntime) other;
return vm == dexRuntime.vm;
}
@Override
public int hashCode() {
return vm.hashCode();
}
@Override
public String toString() {
return "dex-" + vm.getVersion().toString();
}
public AndroidApiLevel getMinApiLevel() {
return ToolHelper.getMinApiLevelForDexVm(vm);
}
}
// Wrapper for the CF runtimes.
public static class CfRuntime extends TestRuntime {
private final CfVm vm;
private final Path home;
public CfRuntime(CfVm vm, Path home) {
assert vm != null;
this.vm = vm;
this.home = home.toAbsolutePath();
}
@Override
public String name() {
return vm.name().toLowerCase();
}
public Path getJavaHome() {
return home;
}
public Path getJavaExecutable() {
return home.resolve("bin").resolve("java");
}
@Override
public boolean isCf() {
return true;
}
@Override
public CfRuntime asCf() {
return this;
}
public CfVm getVm() {
return vm;
}
@Override
public AndroidApiLevel maxSupportedApiLevel() {
// TODO: define the mapping from android API levels back to JDKs.
return AndroidApiLevel.LATEST;
}
@Override
public String toString() {
return vm.toString();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof CfRuntime)) {
return false;
}
CfRuntime cfRuntime = (CfRuntime) obj;
return vm == cfRuntime.vm && home.equals(cfRuntime.home);
}
@Override
public int hashCode() {
return Objects.hash(vm, home);
}
public boolean isOlderThan(CfVm version) {
return vm.lessThan(version);
}
public boolean isNewerThan(CfVm version) {
return !vm.lessThanOrEqual(version);
}
public boolean isNewerThanOrEqual(CfVm version) {
return vm == version || !vm.lessThanOrEqual(version);
}
}
public boolean isDex() {
return false;
}
public boolean isCf() {
return false;
}
public DexRuntime asDex() {
return null;
}
public CfRuntime asCf() {
return null;
}
public Backend getBackend() {
if (isDex()) {
return Backend.DEX;
}
if (isCf()) {
return Backend.CF;
}
throw new Unreachable("Unexpected runtime without backend: " + this);
}
public abstract AndroidApiLevel maxSupportedApiLevel();
@Override
public abstract boolean equals(Object other);
@Override
public abstract int hashCode();
public abstract String name();
}