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 Function<String, String[]> preRunActions;
  46     protected final String jtDriverOptions;
  47     private static final String DISABLE_WARNINGS = "-XX:-PrintWarnings";
  48 
  49     protected TestsGenerator(String suffix) {
  50         this(suffix, s -> new String[0], "");
  51     }
  52 
  53     protected TestsGenerator(String suffix, Function<String, String[]> preRunActions,
  54             String jtDriverOptions) {
  55         generatorDir = getRoot().resolve(suffix);
  56         this.preRunActions = preRunActions;
  57         this.jtDriverOptions = jtDriverOptions;
  58     }
  59 
  60     protected void generateGoldenOut(String mainClassName) {
  61         String classPath = getRoot().resolve(generatorDir)
  62                                     .toAbsolutePath()
  63                                     .toString();
  64         ProcessBuilder pb = new ProcessBuilder(JAVA, "-Xint", DISABLE_WARNINGS, "-Xverify",
  65                 "-cp", classPath, mainClassName);
  66         String goldFile = mainClassName + ".gold";
  67         try {
  68             runProcess(pb, generatorDir.resolve(goldFile).toString());
  69         } catch (IOException | InterruptedException e)  {
  70             throw new Error("Can't run generated test ", e);
  71         }
  72     }
  73 
  74     protected static int runProcess(ProcessBuilder pb, String name)
  75             throws IOException, InterruptedException {
  76         pb.redirectError(new File(name + ".err"));
  77         pb.redirectOutput(new File(name + ".out"));
  78         Process process = pb.start();
  79         try {
  80             if (process.waitFor(DEFAULT_JTREG_TIMEOUT, TimeUnit.SECONDS)) {
  81                 try (FileWriter file = new FileWriter(name + ".exit")) {
  82                     file.write(Integer.toString(process.exitValue()));
  83                 }
  84                 return process.exitValue();
  85             }
  86         } finally {
  87             process.destroyForcibly();
  88         }
  89         return -1;
  90     }
  91 
  92     protected static void compilePrinter() {
  93         Path root = getRoot();
  94         ProcessBuilder pbPrinter = new ProcessBuilder(JAVAC,
  95                 root.resolve("jdk")
  96                     .resolve("test")
  97                     .resolve("lib")
  98                     .resolve("jittester")
  99                     .resolve("jtreg")
 100                     .resolve("Printer.java")
 101                     .toString());
 102         try {
 103             int exitCode = runProcess(pbPrinter, root.resolve("Printer").toString());
 104             if (exitCode != 0) {
 105                 throw new Error("Printer compilation returned exit code " + exitCode);
 106             }
 107         } catch (IOException | InterruptedException e) {
 108             throw new Error("Can't compile printer", e);
 109         }
 110     }
 111 
 112     protected static void ensureExisting(Path path) {
 113         if (Files.notExists(path)) {
 114             try {
 115                 Files.createDirectories(path);
 116             } catch (IOException ex) {
 117                 ex.printStackTrace();
 118             }
 119         }
 120     }
 121 
 122     protected String getJtregHeader(String mainClassName) {
 123         String synopsis = "seed = '" + ProductionParams.seed.value() + "'"
 124                 + ", specificSeed = '" + PseudoRandom.getCurrentSeed() + "'";
 125         StringBuilder header = new StringBuilder();
 126         header.append("/*\n * @test\n * @summary ")
 127               .append(synopsis)
 128               .append(" \n * @library / ../\n");
 129         header.append(" * @run build jdk.test.lib.jittester.jtreg.JitTesterDriver "
 130                         + "jdk.test.lib.jittester.jtreg.Printer\n");
 131         for (String action : preRunActions.apply(mainClassName)) {
 132             header.append(" * ")
 133                   .append(action)
 134                   .append("\n");
 135         }
 136         header.append(" * @run driver jdk.test.lib.jittester.jtreg.JitTesterDriver ")
 137               .append(DISABLE_WARNINGS)
 138               .append(" ")
 139               .append(jtDriverOptions)
 140               .append(" ")
 141               .append(mainClassName)
 142               .append("\n */\n\n");
 143         if (ProductionParams.printHierarchy.value()) {
 144             header.append("/*\n")
 145                   .append(printHierarchy())
 146                   .append("*/\n");
 147         }
 148         return header.toString();
 149     }
 150 
 151     protected static Path getRoot() {
 152         return Paths.get(ProductionParams.testbaseDir.value());
 153     }
 154 
 155     protected static void writeFile(Path targetDir, String fileName, String content) {
 156         try (FileWriter file = new FileWriter(targetDir.resolve(fileName).toFile())) {
 157             file.write(content);
 158         } catch (IOException e) {
 159             e.printStackTrace();
 160         }
 161     }
 162 
 163     private static String printHierarchy() {
 164         return TypeList.getAll()
 165                 .stream()
 166                 .filter(t -> t instanceof TypeKlass)
 167                 .map(t -> typeDescription((TypeKlass) t))
 168                 .collect(Collectors.joining("\n","CLASS HIERARCHY:\n", "\n"));
 169     }
 170 
 171     private static String typeDescription(TypeKlass type) {
 172         StringBuilder result = new StringBuilder();
 173         String parents = type.getParentsNames().stream().collect(Collectors.joining(","));
 174         result.append(type.isAbstract() ? "abstract " : "")
 175               .append(type.isFinal() ? "final " : "")
 176               .append(type.isInterface() ? "interface " : "class ")
 177               .append(type.getName())
 178               .append(parents.isEmpty() ? "" : ": " + parents);
 179         return result.toString();
 180     }
 181 
 182     private static String getJavaPath() {
 183         String[] env = { "JDK_HOME", "JAVA_HOME", "BOOTDIR" };
 184         for (String name : env) {
 185             String path = System.getenv(name);
 186             if (path != null) {
 187                 return Paths.get(path)
 188                             .resolve("bin")
 189                             .toAbsolutePath()
 190                             .toString();
 191             }
 192         }
 193         return "";
 194     }
 195 }