1 /*
   2  * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package jdk.test.lib.jittester;
  25 
  26 import java.io.File;
  27 import java.io.FileWriter;
  28 import java.io.IOException;
  29 import java.nio.file.Files;
  30 import java.nio.file.Path;
  31 import java.nio.file.Paths;
  32 import java.util.concurrent.TimeUnit;
  33 import java.util.function.BiConsumer;
  34 import java.util.function.Function;
  35 import java.util.stream.Collectors;
  36 import jdk.test.lib.jittester.types.TypeKlass;
  37 import jdk.test.lib.jittester.utils.PseudoRandom;
  38 
  39 public abstract class TestsGenerator implements BiConsumer<IRNode, IRNode> {
  40     private static final int DEFAULT_JTREG_TIMEOUT = 120;
  41     protected static final String JAVA_BIN = getJavaPath();
  42     protected static final String JAVAC = Paths.get(JAVA_BIN, "javac").toString();
  43     protected static final String JAVA = Paths.get(JAVA_BIN, "java").toString();
  44     protected final Path generatorDir;
  45     protected final Path tmpDir;
  46     protected final Function<String, String[]> preRunActions;
  47     protected final String jtDriverOptions;
  48     private static final String DISABLE_WARNINGS = "-XX:-PrintWarnings";
  49 
  50     protected TestsGenerator(String suffix) {
  51         this(suffix, s -> new String[0], "");
  52     }
  53 
  54     protected TestsGenerator(String suffix, Function<String, String[]> preRunActions,
  55             String jtDriverOptions) {
  56         generatorDir = getRoot().resolve(suffix).toAbsolutePath();
  57         try {
  58             tmpDir = Files.createTempDirectory(suffix).toAbsolutePath();
  59         } catch (IOException e) {
  60             throw new Error("Can't get a tmp dir for " + suffix, e);
  61         }
  62         this.preRunActions = preRunActions;
  63         this.jtDriverOptions = jtDriverOptions;
  64     }
  65 
  66     protected void generateGoldenOut(String mainClassName) {
  67         String classPath = tmpDir.toString() + File.pathSeparator
  68                 + generatorDir.toString();
  69         ProcessBuilder pb = new ProcessBuilder(JAVA, "-Xint", DISABLE_WARNINGS, "-Xverify",
  70                 "-cp", classPath, mainClassName);
  71         String goldFile = mainClassName + ".gold";
  72         try {
  73             runProcess(pb, generatorDir.resolve(goldFile).toString());
  74         } catch (IOException | InterruptedException e)  {
  75             throw new Error("Can't run generated test ", e);
  76         }
  77     }
  78 
  79     protected static int runProcess(ProcessBuilder pb, String name)
  80             throws IOException, InterruptedException {
  81         pb.redirectError(new File(name + ".err"));
  82         pb.redirectOutput(new File(name + ".out"));
  83         Process process = pb.start();
  84         try {
  85             if (process.waitFor(DEFAULT_JTREG_TIMEOUT, TimeUnit.SECONDS)) {
  86                 try (FileWriter file = new FileWriter(name + ".exit")) {
  87                     file.write(Integer.toString(process.exitValue()));
  88                 }
  89                 return process.exitValue();
  90             }
  91         } finally {
  92             process.destroyForcibly();
  93         }
  94         return -1;
  95     }
  96 
  97     protected void compilePrinter() {
  98         Path root = getRoot();
  99         ProcessBuilder pbPrinter = new ProcessBuilder(JAVAC,
 100                 "-d", tmpDir.toString(),
 101                 root.resolve("jdk")
 102                     .resolve("test")
 103                     .resolve("lib")
 104                     .resolve("jittester")
 105                     .resolve("jtreg")
 106                     .resolve("Printer.java")
 107                     .toString());
 108         try {
 109             int exitCode = runProcess(pbPrinter, root.resolve("Printer").toString());
 110             if (exitCode != 0) {
 111                 throw new Error("Printer compilation returned exit code " + exitCode);
 112             }
 113         } catch (IOException | InterruptedException e) {
 114             throw new Error("Can't compile printer", e);
 115         }
 116     }
 117 
 118     protected static void ensureExisting(Path path) {
 119         if (Files.notExists(path)) {
 120             try {
 121                 Files.createDirectories(path);
 122             } catch (IOException ex) {
 123                 ex.printStackTrace();
 124             }
 125         }
 126     }
 127 
 128     protected String getJtregHeader(String mainClassName) {
 129         String synopsis = "seed = '" + ProductionParams.seed.value() + "'"
 130                 + ", specificSeed = '" + PseudoRandom.getCurrentSeed() + "'";
 131         StringBuilder header = new StringBuilder();
 132         header.append("/*\n * @test\n * @summary ")
 133               .append(synopsis)
 134               .append(" \n * @library / ../\n");
 135         header.append(" * @run build jdk.test.lib.jittester.jtreg.JitTesterDriver "
 136                         + "jdk.test.lib.jittester.jtreg.Printer\n");
 137         for (String action : preRunActions.apply(mainClassName)) {
 138             header.append(" * ")
 139                   .append(action)
 140                   .append("\n");
 141         }
 142         header.append(" * @run driver jdk.test.lib.jittester.jtreg.JitTesterDriver ")
 143               .append(DISABLE_WARNINGS)
 144               .append(" ")
 145               .append(jtDriverOptions)
 146               .append(" ")
 147               .append(mainClassName)
 148               .append("\n */\n\n");
 149         if (ProductionParams.printHierarchy.value()) {
 150             header.append("/*\n")
 151                   .append(printHierarchy())
 152                   .append("*/\n");
 153         }
 154         return header.toString();
 155     }
 156 
 157     protected static Path getRoot() {
 158         return Paths.get(ProductionParams.testbaseDir.value());
 159     }
 160 
 161     protected static void writeFile(Path targetDir, String fileName, String content) {
 162         try (FileWriter file = new FileWriter(targetDir.resolve(fileName).toFile())) {
 163             file.write(content);
 164         } catch (IOException e) {
 165             e.printStackTrace();
 166         }
 167     }
 168 
 169     private static String printHierarchy() {
 170         return TypeList.getAll()
 171                 .stream()
 172                 .filter(t -> t instanceof TypeKlass)
 173                 .map(t -> typeDescription((TypeKlass) t))
 174                 .collect(Collectors.joining("\n","CLASS HIERARCHY:\n", "\n"));
 175     }
 176 
 177     private static String typeDescription(TypeKlass type) {
 178         StringBuilder result = new StringBuilder();
 179         String parents = type.getParentsNames().stream().collect(Collectors.joining(","));
 180         result.append(type.isAbstract() ? "abstract " : "")
 181               .append(type.isFinal() ? "final " : "")
 182               .append(type.isInterface() ? "interface " : "class ")
 183               .append(type.getName())
 184               .append(parents.isEmpty() ? "" : ": " + parents);
 185         return result.toString();
 186     }
 187 
 188     private static String getJavaPath() {
 189         String[] env = { "JDK_HOME", "JAVA_HOME", "BOOTDIR" };
 190         for (String name : env) {
 191             String path = System.getenv(name);
 192             if (path != null) {
 193                 return Paths.get(path)
 194                             .resolve("bin")
 195                             .toAbsolutePath()
 196                             .toString();
 197             }
 198         }
 199         return "";
 200     }
 201 }