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