| // 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 java.nio.file.Path; | 
 | import java.nio.file.Paths; | 
 | import java.util.Arrays; | 
 | import java.util.List; | 
 | 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), | 
 |     JDK11("jdk11", 55); | 
 |  | 
 |     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"); | 
 |  | 
 |   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); | 
 |   } | 
 |  | 
 |   public static CfRuntime getCheckedInJdk9() { | 
 |     Path home; | 
 |     if (ToolHelper.isLinux()) { | 
 |       home = JDK9_PATH.resolve("linux"); | 
 |     } else if (ToolHelper.isMac()) { | 
 |       home = JDK9_PATH.resolve("osx"); | 
 |     } else { | 
 |       assert ToolHelper.isWindows(); | 
 |       home = JDK9_PATH.resolve("windows"); | 
 |     } | 
 |     return new CfRuntime(CfVm.JDK9, home); | 
 |   } | 
 |  | 
 |   public static CfRuntime getCheckedInJdk11() { | 
 |     Path home; | 
 |     if (ToolHelper.isLinux()) { | 
 |       home = JDK11_PATH.resolve("Linux"); | 
 |     } else if (ToolHelper.isMac()) { | 
 |       home = Paths.get(JDK11_PATH.toString(), "Mac", "Contents", "Home"); | 
 |     } else { | 
 |       assert ToolHelper.isWindows(); | 
 |       home = JDK11_PATH.resolve("Windows"); | 
 |     } | 
 |     return new CfRuntime(CfVm.JDK11, home); | 
 |   } | 
 |  | 
 |   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 List<TestRuntime> getCheckedInRuntimes() { | 
 |     return ImmutableList.<TestRuntime>builder() | 
 |         .addAll(getCheckedInCfRuntimes()) | 
 |         .addAll(getCheckedInDexRuntimes()) | 
 |         .build(); | 
 |   } | 
 |  | 
 |   public static TestRuntime 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 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; | 
 |     } | 
 |  | 
 |     @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 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 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); | 
 |   } | 
 |  | 
 |   @Override | 
 |   public abstract boolean equals(Object other); | 
 |  | 
 |   @Override | 
 |   public abstract int hashCode(); | 
 |  | 
 |   public abstract String name(); | 
 | } |