1 /* 2 * Copyright (c) 2005, 2015, 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 jdk.test.lib.Pair; 27 import jdk.test.lib.jittester.factories.IRNodeBuilder; 28 import jdk.test.lib.jittester.jtreg.Printer; 29 import jdk.test.lib.jittester.types.TypeKlass; 30 import jdk.test.lib.jittester.utils.FixedTrees; 31 import jdk.test.lib.jittester.utils.OptionResolver; 32 import jdk.test.lib.jittester.utils.OptionResolver.Option; 33 import jdk.test.lib.jittester.utils.PseudoRandom; 34 35 import java.io.File; 36 import java.io.FileWriter; 37 import java.io.IOException; 38 import java.nio.file.Files; 39 import java.nio.file.Path; 40 import java.nio.file.Paths; 41 import java.time.LocalTime; 42 import java.util.concurrent.TimeUnit; 43 import java.util.stream.Collectors; 44 45 public class Automatic { 46 private static final int MINUTES_TO_WAIT = Integer.getInteger("jdk.test.lib.jittester", 3); 47 48 static String getJtregHeader(String mainClass, boolean addCompile) { 49 String synopsis = "seed = '" + ProductionParams.seed.value() + "'" 50 + ", specificSeed = '" + PseudoRandom.getCurrentSeed() + "'"; 51 StringBuilder header = new StringBuilder(); 52 header.append("/*\n * @test\n * @summary ") 53 .append(synopsis) 54 .append(" \n* @library / ../\n"); 55 if (addCompile) { 56 header.append("\n * @compile ") 57 .append(mainClass) 58 .append(".java\n"); 59 } 60 header.append(" * @run build jdk.test.lib.jittester.jtreg.JitTesterDriver " 61 + "jdk.test.lib.jittester.jtreg.Printer\n") 62 .append(" * @run driver jdk.test.lib.jittester.jtreg.JitTesterDriver ") 63 .append(mainClass) 64 .append("\n */\n\n"); 65 if (ProductionParams.printHierarchy.value()) { 66 header.append("/*\n") 67 .append(Automatic.printHierarchy()) 68 .append("*/\n"); 69 } 70 return header.toString(); 71 } 72 73 private static Pair<IRNode, IRNode> generateIRTree(String name) { 74 SymbolTable.removeAll(); 75 TypeList.removeAll(); 76 77 IRNodeBuilder builder = new IRNodeBuilder() 78 .setPrefix(name) 79 .setName(name) 80 .setLevel(0); 81 82 Long complexityLimit = ProductionParams.complexityLimit.value(); 83 IRNode privateClasses = null; 84 if (!ProductionParams.disableClasses.value()) { 85 long privateClassComlexity = (long) (complexityLimit * PseudoRandom.random()); 86 try { 87 privateClasses = builder.setComplexityLimit(privateClassComlexity) 88 .getClassDefinitionBlockFactory() 89 .produce(); 90 } catch (ProductionFailedException ex) { 91 ex.printStackTrace(System.out); 92 } 93 } 94 long mainClassComplexity = (long) (complexityLimit * PseudoRandom.random()); 95 IRNode mainClass = null; 96 try { 97 mainClass = builder.setComplexityLimit(mainClassComplexity) 98 .getMainKlassFactory() 99 .produce(); 100 TypeKlass aClass = new TypeKlass(name); 101 mainClass.getChild(1).addChild(FixedTrees.generateMainOrExecuteMethod(aClass, true)); 102 mainClass.getChild(1).addChild(FixedTrees.generateMainOrExecuteMethod(aClass, false)); 103 } catch (ProductionFailedException ex) { 104 ex.printStackTrace(System.out); 105 } 106 return new Pair<>(mainClass, privateClasses); 107 } 108 109 private static void initializeTestGenerator(String[] params) { 110 OptionResolver parser = new OptionResolver(); 111 Option<String> propertyFileOpt = parser.addStringOption('p', "property-file", 112 "conf/default.properties", "File to read properties from"); 113 ProductionParams.register(parser); 114 parser.parse(params, propertyFileOpt); 115 PseudoRandom.reset(ProductionParams.seed.value()); 116 TypesParser.parseTypesAndMethods(ProductionParams.classesFile.value(), 117 ProductionParams.excludeMethodsFile.value()); 118 if (ProductionParams.specificSeed.isSet()) { 119 PseudoRandom.setCurrentSeed(ProductionParams.specificSeed.value()); 120 } 121 } 122 123 public static void main(String[] args) { 124 initializeTestGenerator(args); 125 int counter = 0; 126 try { 127 Path testbaseDir = Paths.get(ProductionParams.testbaseDir.value()); 128 System.out.printf(" %13s | %8s | %8s | %8s |%n", "start time", "count", "generat", 129 "running"); 130 System.out.printf(" %13s | %8s | %8s | %8s |%n", "---", "---", "---","---"); 131 String path = getJavaPath(); 132 String javacPath = Paths.get(path, "javac").toString(); 133 String javaPath = Paths.get(path, "java").toString(); 134 135 // compile Printer class first. A common one for all tests 136 ensureExisting(testbaseDir); 137 ProcessBuilder pbPrinter = new ProcessBuilder(javacPath, 138 Paths.get(testbaseDir.toString(), "jdk", "test", "lib", "jittester", 139 "jtreg", "Printer.java").toString()); 140 runProcess(pbPrinter, testbaseDir.resolve("Printer").toString()); 141 do { 142 double start = System.currentTimeMillis(); 143 System.out.print("[" + LocalTime.now() + "] |"); 144 String name = "Test_" + counter; 145 Pair<IRNode, IRNode> irTree = generateIRTree(name); 146 System.out.printf(" %8d |", counter); 147 double generationTime = System.currentTimeMillis() - start; 148 System.out.printf(" %8.0f |", generationTime); 149 if (!ProductionParams.disableJavacodeGeneration.value()) { 150 JavaCodeGenerator generator = new JavaCodeGenerator(); 151 String javaFile = generator.apply(irTree.first, irTree.second); 152 ProcessBuilder pb = new ProcessBuilder(javacPath, "-cp", testbaseDir.toString() 153 + ":" + generator.getTestbase().toString(), javaFile); 154 runProcess(pb, generator.getTestbase().resolve(name).toString()); 155 start = System.currentTimeMillis(); 156 157 // Run compiled class files 158 pb = new ProcessBuilder(javaPath, "-Xint", "-cp", testbaseDir.toString() 159 + ":" + generator.getTestbase().toString(), name); 160 String goldFile = name + ".gold"; 161 runProcess(pb, generator.getTestbase().resolve(goldFile).toString()); 162 } 163 164 if (!ProductionParams.disableBytecodeGeneration.value()) { 165 ByteCodeGenerator generator = new ByteCodeGenerator(); 166 generator.apply(irTree.first, irTree.second); 167 generator.writeJtregBytecodeRunner(name); 168 // Run generated bytecode 169 ProcessBuilder pb = new ProcessBuilder(javaPath, "-Xint", "-Xverify", "-cp", 170 testbaseDir.toString() + ":" + generator.getTestbase().toString(), 171 name); 172 String goldFile = name + ".gold"; 173 start = System.currentTimeMillis(); 174 runProcess(pb, generator.getTestbase().resolve(goldFile).toString()); 175 } 176 177 double runningTime = System.currentTimeMillis() - start; 178 System.out.printf(" %8.0f |%n", runningTime); 179 if (runningTime < TimeUnit.MINUTES.toMillis(MINUTES_TO_WAIT)) { 180 ++counter; 181 } 182 } while (counter < ProductionParams.numberOfTests.value()); 183 } catch (IOException | InterruptedException ex) { 184 ex.printStackTrace(); 185 } 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 path + "/bin/"; 194 } 195 } 196 return ""; 197 } 198 199 private static int runProcess(ProcessBuilder pb, String name) 200 throws IOException, InterruptedException { 201 pb.redirectError(new File(name + ".err")); 202 pb.redirectOutput(new File(name + ".out")); 203 Process process = pb.start(); 204 if (process.waitFor(MINUTES_TO_WAIT, TimeUnit.MINUTES)) { 205 try (FileWriter file = new FileWriter(name + ".exit")) { 206 file.write(Integer.toString(process.exitValue())); 207 } 208 return process.exitValue(); 209 } else { 210 process.destroyForcibly(); 211 return -1; 212 } 213 } 214 215 private static String printHierarchy() { 216 return TypeList.getAll().stream() 217 .filter(t -> t instanceof TypeKlass) 218 .map(t -> typeDescription((TypeKlass) t)) 219 .collect(Collectors.joining("\n","CLASS HIERARCHY:\n", "\n")); 220 } 221 222 private static String typeDescription(TypeKlass type) { 223 StringBuilder result = new StringBuilder(); 224 String parents = type.getParentsNames().stream().collect(Collectors.joining(",")); 225 result.append(type.isAbstract() ? "abstract " : "") 226 .append(type.isFinal() ? "final " : "") 227 .append(type.isInterface() ? "interface " : "class ") 228 .append(type.getName()) 229 .append(parents.isEmpty() ? "" : ": " + parents); 230 return result.toString(); 231 } 232 233 static void ensureExisting(Path path) { 234 if (Files.notExists(path)) { 235 try { 236 Files.createDirectories(path); 237 } catch (IOException ex) { 238 ex.printStackTrace(); 239 } 240 } 241 } 242 }