changeset 39242:8ffd59d7bc52

8158065: [Jittester]: tests generation has tests generators hardcoded, blocking alternative tests generation Reviewed-by: iignatyev
author dpochepk
date Tue, 31 May 2016 15:48:47 +0300
parents 21f9f9db2c9e
children 58ef2d9356d2
files hotspot/test/testlibrary/jittester/Makefile hotspot/test/testlibrary/jittester/conf/default.properties hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/Automatic.java hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/ByteCodeGenerator.java hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/JavaCodeGenerator.java hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/ProductionParams.java hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/TestGeneratorsFactory.java hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/TestsGenerator.java hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/jtreg/JitTesterDriver.java
diffstat 9 files changed, 365 insertions(+), 218 deletions(-) [+]
line wrap: on
line diff
--- a/hotspot/test/testlibrary/jittester/Makefile	Mon May 30 23:33:00 2016 +0300
+++ b/hotspot/test/testlibrary/jittester/Makefile	Tue May 31 15:48:47 2016 +0300
@@ -44,6 +44,10 @@
 	APPLICATION_ARGS += --seed $(SEED)
 endif
 
+ifneq "x$(EXTRA_SRC_DIR)" "x"
+        EXTRA_SRC_FILES := $(shell find $(EXTRA_SRC_DIR) -name '*.java')
+endif
+
 JAVA = $(JDK_HOME)/bin/java
 JAVAC = $(JDK_HOME)/bin/javac
 JAR = $(JDK_HOME)/bin/jar
@@ -99,6 +103,7 @@
 filelist: $(SRC_FILES)
 		@rm -f $@
 		@echo $(SRC_FILES) > $@
+		@echo $(EXTRA_SRC_FILES) >> $@
 
 INIT: $(DIST_DIR)
 	$(shell if [ ! -d $(CLASSES_DIR) ]; then mkdir -p $(CLASSES_DIR); fi)
--- a/hotspot/test/testlibrary/jittester/conf/default.properties	Mon May 30 23:33:00 2016 +0300
+++ b/hotspot/test/testlibrary/jittester/conf/default.properties	Tue May 31 15:48:47 2016 +0300
@@ -9,3 +9,5 @@
 print-complexity=true
 print-hierarchy=true
 disable-static=true
+generatorsFactories=jdk.test.lib.jittester.TestGeneratorsFactory
+generators=JavaCode,ByteCode
--- a/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/Automatic.java	Mon May 30 23:33:00 2016 +0300
+++ b/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/Automatic.java	Tue May 31 15:48:47 2016 +0300
@@ -25,50 +25,19 @@
 
 import jdk.test.lib.Pair;
 import jdk.test.lib.jittester.factories.IRNodeBuilder;
-import jdk.test.lib.jittester.jtreg.Printer;
 import jdk.test.lib.jittester.types.TypeKlass;
 import jdk.test.lib.jittester.utils.FixedTrees;
 import jdk.test.lib.jittester.utils.OptionResolver;
 import jdk.test.lib.jittester.utils.OptionResolver.Option;
 import jdk.test.lib.jittester.utils.PseudoRandom;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.time.LocalTime;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
+import java.util.function.Function;
 
 public class Automatic {
-    private static final int MINUTES_TO_WAIT = Integer.getInteger("jdk.test.lib.jittester", 3);
-
-    static String getJtregHeader(String mainClass, boolean addCompile) {
-        String synopsis = "seed = '" + ProductionParams.seed.value() + "'"
-                + ", specificSeed = '" + PseudoRandom.getCurrentSeed() + "'";
-        StringBuilder header = new StringBuilder();
-        header.append("/*\n * @test\n * @summary ")
-                .append(synopsis)
-                .append(" \n* @library / ../\n");
-        if (addCompile) {
-            header.append("\n * @compile ")
-                    .append(mainClass)
-                    .append(".java\n");
-        }
-        header.append(" * @run build jdk.test.lib.jittester.jtreg.JitTesterDriver "
-                        + "jdk.test.lib.jittester.jtreg.Printer\n")
-                .append(" * @run driver jdk.test.lib.jittester.jtreg.JitTesterDriver ")
-                .append(mainClass)
-                .append("\n */\n\n");
-        if (ProductionParams.printHierarchy.value()) {
-            header.append("/*\n")
-                .append(Automatic.printHierarchy())
-                .append("*/\n");
-        }
-        return header.toString();
-    }
+    public static final int MINUTES_TO_WAIT = Integer.getInteger("jdk.test.lib.jittester", 3);
 
     private static Pair<IRNode, IRNode> generateIRTree(String name) {
         SymbolTable.removeAll();
@@ -120,123 +89,48 @@
         }
     }
 
+    private static List<TestsGenerator> getTestGenerators() {
+        List<TestsGenerator> result = new ArrayList<>();
+        Class<?> factoryClass;
+        Function<String[], List<TestsGenerator>> factory;
+        String[] factoryClassNames = ProductionParams.generatorsFactories.value().split(",");
+        String[] generatorNames = ProductionParams.generators.value().split(",");
+        for (String factoryClassName : factoryClassNames) {
+            try {
+                factoryClass = Class.forName(factoryClassName);
+                factory = (Function<String[], List<TestsGenerator>>) factoryClass.newInstance();
+            } catch (ReflectiveOperationException roe) {
+                throw new Error("Can't instantiate generators factory", roe);
+            }
+            result.addAll(factory.apply(generatorNames));
+        }
+        return result;
+    }
+
     public static void main(String[] args) {
         initializeTestGenerator(args);
         int counter = 0;
-        try {
-            Path testbaseDir = Paths.get(ProductionParams.testbaseDir.value());
-            System.out.printf(" %13s | %8s | %8s | %8s |%n", "start time", "count", "generat",
-                              "running");
-            System.out.printf(" %13s | %8s | %8s | %8s |%n", "---", "---", "---","---");
-            String path = getJavaPath();
-            String javacPath = Paths.get(path, "javac").toString();
-            String javaPath = Paths.get(path, "java").toString();
-
-            // compile Printer class first. A common one for all tests
-            ensureExisting(testbaseDir);
-            ProcessBuilder pbPrinter = new ProcessBuilder(javacPath,
-                    Paths.get(testbaseDir.toString(), "jdk", "test", "lib", "jittester",
-                            "jtreg", "Printer.java").toString());
-            runProcess(pbPrinter, testbaseDir.resolve("Printer").toString());
-            do {
-                double start = System.currentTimeMillis();
-                System.out.print("[" + LocalTime.now() + "] |");
-                String name = "Test_" + counter;
-                Pair<IRNode, IRNode> irTree = generateIRTree(name);
-                System.out.printf(" %8d |", counter);
-                double generationTime = System.currentTimeMillis() - start;
-                System.out.printf(" %8.0f |", generationTime);
-                if (!ProductionParams.disableJavacodeGeneration.value()) {
-                    JavaCodeGenerator generator = new JavaCodeGenerator();
-                    String javaFile = generator.apply(irTree.first, irTree.second);
-                    ProcessBuilder pb = new ProcessBuilder(javacPath, "-cp", testbaseDir.toString()
-                            + ":" + generator.getTestbase().toString(), javaFile);
-                    runProcess(pb, generator.getTestbase().resolve(name).toString());
-                    start = System.currentTimeMillis();
-
-                    // Run compiled class files
-                    pb = new ProcessBuilder(javaPath, "-Xint", "-cp", testbaseDir.toString()
-                            + ":" + generator.getTestbase().toString(), name);
-                    String goldFile = name + ".gold";
-                    runProcess(pb, generator.getTestbase().resolve(goldFile).toString());
-                }
-
-                if (!ProductionParams.disableBytecodeGeneration.value()) {
-                    ByteCodeGenerator generator = new ByteCodeGenerator();
-                    generator.apply(irTree.first, irTree.second);
-                    generator.writeJtregBytecodeRunner(name);
-                    // Run generated bytecode
-                    ProcessBuilder pb = new ProcessBuilder(javaPath, "-Xint", "-Xverify", "-cp",
-                            testbaseDir.toString() + ":" + generator.getTestbase().toString(),
-                            name);
-                    String goldFile = name + ".gold";
-                    start = System.currentTimeMillis();
-                    runProcess(pb, generator.getTestbase().resolve(goldFile).toString());
-                }
-
-                double runningTime = System.currentTimeMillis() - start;
-                System.out.printf(" %8.0f |%n", runningTime);
-                if (runningTime < TimeUnit.MINUTES.toMillis(MINUTES_TO_WAIT)) {
-                    ++counter;
-                }
-            } while (counter < ProductionParams.numberOfTests.value());
-        } catch (IOException | InterruptedException ex) {
-            ex.printStackTrace();
-        }
-    }
-
-    private static String getJavaPath() {
-        String[] env = { "JDK_HOME", "JAVA_HOME", "BOOTDIR" };
-        for (String name : env) {
-            String path = System.getenv(name);
-            if (path != null) {
-                return path + "/bin/";
+        System.out.printf(" %13s | %8s | %8s | %8s |%n", "start time", "count", "generat",
+                "running");
+        System.out.printf(" %13s | %8s | %8s | %8s |%n", "---", "---", "---", "---");
+        List<TestsGenerator> generators = getTestGenerators();
+        do {
+            double start = System.currentTimeMillis();
+            System.out.print("[" + LocalTime.now() + "] |");
+            String name = "Test_" + counter;
+            Pair<IRNode, IRNode> irTree = generateIRTree(name);
+            System.out.printf(" %8d |", counter);
+            double generationTime = System.currentTimeMillis() - start;
+            System.out.printf(" %8.0f |", generationTime);
+            start = System.currentTimeMillis();
+            for (TestsGenerator generator : generators) {
+                generator.accept(irTree.first, irTree.second);
             }
-        }
-        return "";
-    }
-
-    private static int runProcess(ProcessBuilder pb, String name)
-            throws IOException, InterruptedException {
-        pb.redirectError(new File(name + ".err"));
-        pb.redirectOutput(new File(name + ".out"));
-        Process process = pb.start();
-        if (process.waitFor(MINUTES_TO_WAIT, TimeUnit.MINUTES)) {
-            try (FileWriter file = new FileWriter(name + ".exit")) {
-                file.write(Integer.toString(process.exitValue()));
+            double runningTime = System.currentTimeMillis() - start;
+            System.out.printf(" %8.0f |%n", runningTime);
+            if (runningTime < TimeUnit.MINUTES.toMillis(MINUTES_TO_WAIT)) {
+                ++counter;
             }
-            return process.exitValue();
-        } else {
-            process.destroyForcibly();
-            return -1;
-        }
-    }
-
-    private static String printHierarchy() {
-        return TypeList.getAll().stream()
-                .filter(t -> t instanceof TypeKlass)
-                .map(t -> typeDescription((TypeKlass) t))
-                .collect(Collectors.joining("\n","CLASS HIERARCHY:\n", "\n"));
-    }
-
-    private static String typeDescription(TypeKlass type) {
-        StringBuilder result = new StringBuilder();
-        String parents = type.getParentsNames().stream().collect(Collectors.joining(","));
-        result.append(type.isAbstract() ? "abstract " : "")
-              .append(type.isFinal() ? "final " : "")
-              .append(type.isInterface() ? "interface " : "class ")
-              .append(type.getName())
-              .append(parents.isEmpty() ? "" : ": " + parents);
-        return result.toString();
-    }
-
-    static void ensureExisting(Path path) {
-        if (Files.notExists(path)) {
-            try {
-                Files.createDirectories(path);
-            } catch (IOException ex) {
-                ex.printStackTrace();
-            }
-        }
+        } while (counter < ProductionParams.numberOfTests.value());
     }
 }
--- a/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/ByteCodeGenerator.java	Mon May 30 23:33:00 2016 +0300
+++ b/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/ByteCodeGenerator.java	Tue May 31 15:48:47 2016 +0300
@@ -23,54 +23,60 @@
 
 package jdk.test.lib.jittester;
 
-import jdk.test.lib.jittester.visitors.ByteCodeVisitor;
-
 import java.io.FileOutputStream;
-import java.io.FileWriter;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.nio.file.StandardOpenOption;
-import java.util.function.BiFunction;
+import java.util.function.Function;
+import jdk.test.lib.jittester.visitors.ByteCodeVisitor;
 
 /**
- * Generates class files from bytecode
+ * Generates class files from IRTree
  */
-class ByteCodeGenerator implements BiFunction<IRNode, IRNode, String> {
-    private final Path testbase = Paths.get(ProductionParams.testbaseDir.value(),
-            "bytecode_tests");
+class ByteCodeGenerator extends TestsGenerator {
+    private static final String DEFAULT_SUFFIX = "bytecode_tests";
 
-    public void writeJtregBytecodeRunner(String name) {
-        try (FileWriter file = new FileWriter(testbase.resolve(name + ".java").toFile())) {
-            file.write(Automatic.getJtregHeader(name, false));
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
+    ByteCodeGenerator() {
+        super(DEFAULT_SUFFIX);
     }
 
-    public String apply(IRNode mainClass, IRNode privateClasses) {
-        Automatic.ensureExisting(testbase);
+    ByteCodeGenerator(String suffix, Function<String, String[]> preRunActions, String jtDriverOptions) {
+        super(suffix, preRunActions, jtDriverOptions);
+    }
+
+    @Override
+    public void accept(IRNode mainClass, IRNode privateClasses) {
+        generateClassFiles(mainClass, privateClasses);
+        generateSeparateJtregHeader(mainClass);
+        compilePrinter();
+        generateGoldenOut(mainClass.getName());
+    }
+
+    private void generateSeparateJtregHeader(IRNode mainClass) {
+        String mainClassName = mainClass.getName();
+        writeFile(generatorDir, mainClassName + ".java", getJtregHeader(mainClassName));
+    }
+
+    private void generateClassFiles(IRNode mainClass, IRNode privateClasses) {
+        String mainClassName = mainClass.getName();
+        ensureExisting(generatorDir);
         try {
             ByteCodeVisitor vis = new ByteCodeVisitor();
             if (privateClasses != null) {
                 privateClasses.accept(vis);
             }
             mainClass.accept(vis);
-
-            Path mainClassPath = testbase.resolve(mainClass.getName() + ".class");
-            writeToClassFile(mainClassPath, vis.getByteCode(mainClass.getName()));
+            writeFile(mainClassName + ".class", vis.getByteCode(mainClassName));
             if (privateClasses != null) {
                 privateClasses.getChildren().forEach(c -> {
                     String name = c.getName();
-                    Path classPath = testbase.resolve(name + ".class");
-                    writeToClassFile(classPath, vis.getByteCode(name));
+                    writeFile(name + ".class", vis.getByteCode(name));
                 });
             }
-            return mainClassPath.toString();
         } catch (Throwable t) {
-            Path errFile = testbase.resolve(mainClass.getName() + ".err");
+            Path errFile = generatorDir.resolve(mainClassName + ".err");
             try (PrintWriter pw = new PrintWriter(Files.newOutputStream(errFile,
                     StandardOpenOption.CREATE_NEW))) {
                 t.printStackTrace(pw);
@@ -78,16 +84,11 @@
                 t.printStackTrace();
                 throw new Error("can't write error to error file " + errFile, e);
             }
-            return null;
         }
     }
 
-    public Path getTestbase() {
-        return testbase;
-    }
-
-    private void writeToClassFile(Path path, byte[] bytecode) {
-        try (FileOutputStream file = new FileOutputStream(path.toString())) {
+    private void writeFile(String fileName, byte[] bytecode) {
+        try (FileOutputStream file = new FileOutputStream(generatorDir.resolve(fileName).toFile())) {
             file.write(bytecode);
         } catch (IOException ex) {
             ex.printStackTrace();
--- a/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/JavaCodeGenerator.java	Mon May 30 23:33:00 2016 +0300
+++ b/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/JavaCodeGenerator.java	Tue May 31 15:48:47 2016 +0300
@@ -23,48 +23,59 @@
 
 package jdk.test.lib.jittester;
 
+import java.io.File;
+import java.io.IOException;
+import java.util.function.Function;
 import jdk.test.lib.jittester.visitors.JavaCodeVisitor;
 
-import java.io.FileWriter;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.function.BiFunction;
+/**
+ * Generates java source code from IRTree
+ */
+public class JavaCodeGenerator extends TestsGenerator {
+    private static final String DEFAULT_SUFFIX = "java_tests";
 
-/**
- * Generates class files from java source code
- */
-class JavaCodeGenerator implements BiFunction<IRNode, IRNode, String> {
-    private final Path testbase = Paths.get(ProductionParams.testbaseDir.value(), "java_tests");
+    JavaCodeGenerator() {
+        this(DEFAULT_SUFFIX, JavaCodeGenerator::generatePrerunAction, "");
+    }
 
-    private String generateJavaCode(IRNode mainClass, IRNode privateClasses) {
+    JavaCodeGenerator(String prefix, Function<String, String[]> preRunActions, String jtDriverOptions) {
+        super(prefix, preRunActions, jtDriverOptions);
+    }
+
+    @Override
+    public void accept(IRNode mainClass, IRNode privateClasses) {
+        String mainClassName = mainClass.getName();
+        generateSources(mainClass, privateClasses);
+        compilePrinter();
+        compileJavaFile(mainClassName);
+        generateGoldenOut(mainClassName);
+    }
+
+    private void generateSources(IRNode mainClass, IRNode privateClasses) {
+        String mainClassName = mainClass.getName();
         StringBuilder code = new StringBuilder();
         JavaCodeVisitor vis = new JavaCodeVisitor();
-
-        code.append(Automatic.getJtregHeader(mainClass.getName(), true));
+        code.append(getJtregHeader(mainClassName));
         if (privateClasses != null) {
             code.append(privateClasses.accept(vis));
         }
         code.append(mainClass.accept(vis));
-
-        return code.toString();
+        ensureExisting(generatorDir);
+        writeFile(generatorDir, mainClassName + ".java", code.toString());
     }
 
-    public Path getTestbase() {
-        return testbase;
+    private void compileJavaFile(String mainClassName) {
+        String classPath = getRoot() + File.pathSeparator + generatorDir;
+        ProcessBuilder pb = new ProcessBuilder(JAVAC, "-cp", classPath,
+                generatorDir.resolve(mainClassName + ".java").toString());
+        try {
+            runProcess(pb, generatorDir.resolve(mainClassName).toString());
+        } catch (IOException | InterruptedException e) {
+            throw new Error("Can't compile sources ", e);
+        }
     }
 
-    @Override
-    public String apply(IRNode mainClass, IRNode privateClasses) {
-        String code = generateJavaCode(mainClass, privateClasses);
-        Automatic.ensureExisting(testbase);
-        Path fileName = testbase.resolve(mainClass.getName() + ".java");
-        try (FileWriter file = new FileWriter(fileName.toFile())) {
-            file.write(code);
-            return fileName.toString();
-        } catch (IOException ex) {
-            ex.printStackTrace();
-        }
-        return "";
+    private static String[] generatePrerunAction(String mainClassName) {
+        return new String[] {"@compile " + mainClassName + ".java"};
     }
 }
--- a/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/ProductionParams.java	Mon May 30 23:33:00 2016 +0300
+++ b/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/ProductionParams.java	Tue May 31 15:48:47 2016 +0300
@@ -68,8 +68,6 @@
     public static Option<Boolean> disableNestedBlocks = null;
     public static Option<Boolean> disableArrays = null;
     public static Option<Boolean> enableFinalizers = null;
-    public static Option<Boolean> disableBytecodeGeneration = null;
-    public static Option<Boolean> disableJavacodeGeneration = null;
     // workaraound: to reduce chance throwing ArrayIndexOutOfBoundsException
     public static Option<Integer> chanceExpressionIndex = null;
     public static Option<String> testbaseDir = null;
@@ -78,6 +76,8 @@
     public static Option<Long> specificSeed = null;
     public static Option<String> classesFile = null;
     public static Option<String> excludeMethodsFile = null;
+    public static Option<String> generators = null;
+    public static Option<String> generatorsFactories = null;
 
     public static void register(OptionResolver optionResolver) {
         productionLimit = optionResolver.addIntegerOption('l', "production-limit", 100, "Limit on steps in the production of an expression");
@@ -120,8 +120,6 @@
         disableNestedBlocks = optionResolver.addBooleanOption("disable-nested-blocks", "Disable generation of nested blocks");
         disableArrays = optionResolver.addBooleanOption("disable-arrays", "Disable generation of arrays");
         enableFinalizers = optionResolver.addBooleanOption("enable-finalizers", "Enable finalizers (for stress testing)");
-        disableBytecodeGeneration = optionResolver.addBooleanOption("disable-bytecode-generation", "Disable generation of bytecode output");
-        disableJavacodeGeneration = optionResolver.addBooleanOption("disable-javacode-generation", "Disable generation of java source code output");
         chanceExpressionIndex = optionResolver.addIntegerOption("chance-expression-index", 0, "A non negative decimal integer used to restrict chane of generating expression in array index while creating or accessing by index");
         testbaseDir = optionResolver.addStringOption("testbase-dir", ".", "Testbase dir");
         numberOfTests = optionResolver.addIntegerOption('n', "number-of-tests", 0, "Number of test classes to generate");
@@ -129,5 +127,7 @@
         specificSeed = optionResolver.addLongOption('z', "specificSeed", 0L, "A seed to be set for specific test generation(regular seed still needed for initialization)");
         classesFile = optionResolver.addStringOption('f', "classes-file", "conf/classes.lst", "File to read classes from");
         excludeMethodsFile = optionResolver.addStringOption('r', "exclude-methods-file", "conf/exclude.methods.lst", "File to read excluded methods from");
+        generators = optionResolver.addStringOption("generators", "", "Comma-separated list of generator names");
+        generatorsFactories = optionResolver.addStringOption("generatorsFactories", "", "Comma-separated list of generators factories class names");
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/TestGeneratorsFactory.java	Tue May 31 15:48:47 2016 +0300
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.jittester;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+public class TestGeneratorsFactory implements Function<String[], List<TestsGenerator>> {
+
+    @Override
+    public List<TestsGenerator> apply(String[] input) {
+        List<TestsGenerator> result = new ArrayList<>();
+        for (String generatorName : input) {
+            switch (generatorName) {
+                case "JavaCode":
+                    result.add(new JavaCodeGenerator());
+                    break;
+                case "ByteCode":
+                    result.add(new ByteCodeGenerator());
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unknown generator: " + generatorName);
+            }
+        }
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/TestsGenerator.java	Tue May 31 15:48:47 2016 +0300
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.lib.jittester;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.concurrent.TimeUnit;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import jdk.test.lib.jittester.types.TypeKlass;
+import jdk.test.lib.jittester.utils.PseudoRandom;
+
+public abstract class TestsGenerator implements BiConsumer<IRNode, IRNode> {
+    protected static final String JAVA_BIN = getJavaPath();
+    protected static final String JAVAC = Paths.get(JAVA_BIN, "javac").toString();
+    protected static final String JAVA = Paths.get(JAVA_BIN, "java").toString();
+    protected final Path generatorDir;
+    protected final Function<String, String[]> preRunActions;
+    protected final String jtDriverOptions;
+
+    protected TestsGenerator(String suffix) {
+        this(suffix, s -> new String[0], "");
+    }
+
+    protected TestsGenerator(String suffix, Function<String, String[]> preRunActions,
+            String jtDriverOptions) {
+        generatorDir = getRoot().resolve(suffix);
+        this.preRunActions = preRunActions;
+        this.jtDriverOptions = jtDriverOptions;
+    }
+
+    protected void generateGoldenOut(String mainClassName) {
+        String classPath = getRoot() + File.pathSeparator + generatorDir;
+        ProcessBuilder pb = new ProcessBuilder(JAVA, "-Xint", "-Xverify", "-cp", classPath,
+                mainClassName);
+        String goldFile = mainClassName + ".gold";
+        try {
+            runProcess(pb, generatorDir.resolve(goldFile).toString());
+        } catch (IOException | InterruptedException e)  {
+            throw new Error("Can't run generated test ", e);
+        }
+    }
+
+    protected static int runProcess(ProcessBuilder pb, String name)
+            throws IOException, InterruptedException {
+        pb.redirectError(new File(name + ".err"));
+        pb.redirectOutput(new File(name + ".out"));
+        Process process = pb.start();
+        if (process.waitFor(Automatic.MINUTES_TO_WAIT, TimeUnit.MINUTES)) {
+            try (FileWriter file = new FileWriter(name + ".exit")) {
+                file.write(Integer.toString(process.exitValue()));
+            }
+            return process.exitValue();
+        } else {
+            process.destroyForcibly();
+            return -1;
+        }
+    }
+
+    protected static void compilePrinter() {
+        Path root = getRoot();
+        ProcessBuilder pbPrinter = new ProcessBuilder(JAVAC,
+                root.resolve("jdk")
+                    .resolve("test")
+                    .resolve("lib")
+                    .resolve("jittester")
+                    .resolve("jtreg")
+                    .resolve("Printer.java")
+                    .toString());
+        try {
+            int exitCode = runProcess(pbPrinter, root.resolve("Printer").toString());
+            if (exitCode != 0) {
+                throw new Error("Printer compilation returned exit code " + exitCode);
+            }
+        } catch (IOException | InterruptedException e) {
+            throw new Error("Can't compile printer", e);
+        }
+    }
+
+    protected static void ensureExisting(Path path) {
+        if (Files.notExists(path)) {
+            try {
+                Files.createDirectories(path);
+            } catch (IOException ex) {
+                ex.printStackTrace();
+            }
+        }
+    }
+
+    protected String getJtregHeader(String mainClassName) {
+        String synopsis = "seed = '" + ProductionParams.seed.value() + "'"
+                + ", specificSeed = '" + PseudoRandom.getCurrentSeed() + "'";
+        StringBuilder header = new StringBuilder();
+        header.append("/*\n * @test\n * @summary ")
+              .append(synopsis)
+              .append(" \n * @library / ../\n");
+        header.append(" * @run build jdk.test.lib.jittester.jtreg.JitTesterDriver "
+                        + "jdk.test.lib.jittester.jtreg.Printer\n");
+        for (String action : preRunActions.apply(mainClassName)) {
+            header.append(" * ")
+                  .append(action)
+                  .append("\n");
+        }
+        header.append(" * @run driver jdk.test.lib.jittester.jtreg.JitTesterDriver ")
+              .append(jtDriverOptions)
+              .append(" ")
+              .append(mainClassName)
+              .append("\n */\n\n");
+        if (ProductionParams.printHierarchy.value()) {
+            header.append("/*\n")
+                  .append(printHierarchy())
+                  .append("*/\n");
+        }
+        return header.toString();
+    }
+
+    protected static Path getRoot() {
+        return Paths.get(ProductionParams.testbaseDir.value());
+    }
+
+    protected static void writeFile(Path targetDir, String fileName, String content) {
+        try (FileWriter file = new FileWriter(targetDir.resolve(fileName).toFile())) {
+            file.write(content);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private static String printHierarchy() {
+        return TypeList.getAll()
+                .stream()
+                .filter(t -> t instanceof TypeKlass)
+                .map(t -> typeDescription((TypeKlass) t))
+                .collect(Collectors.joining("\n","CLASS HIERARCHY:\n", "\n"));
+    }
+
+    private static String typeDescription(TypeKlass type) {
+        StringBuilder result = new StringBuilder();
+        String parents = type.getParentsNames().stream().collect(Collectors.joining(","));
+        result.append(type.isAbstract() ? "abstract " : "")
+              .append(type.isFinal() ? "final " : "")
+              .append(type.isInterface() ? "interface " : "class ")
+              .append(type.getName())
+              .append(parents.isEmpty() ? "" : ": " + parents);
+        return result.toString();
+    }
+
+    private static String getJavaPath() {
+        String[] env = { "JDK_HOME", "JAVA_HOME", "BOOTDIR" };
+        for (String name : env) {
+            String path = System.getenv(name);
+            if (path != null) {
+                return path + "/bin/";
+            }
+        }
+        return "";
+    }
+}
--- a/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/jtreg/JitTesterDriver.java	Mon May 30 23:33:00 2016 +0300
+++ b/hotspot/test/testlibrary/jittester/src/jdk/test/lib/jittester/jtreg/JitTesterDriver.java	Tue May 31 15:48:47 2016 +0300
@@ -40,30 +40,31 @@
 public class JitTesterDriver {
 
     public static void main(String[] args) {
-        if (args.length != 1) {
+        if (args.length < 1) {
             throw new IllegalArgumentException(
                     "[TESTBUG]: wrong number of argument : " + args.length
-                    + ". Expected 1 argument -- jit-tester test name.");
+                    + ". Expected at least 1 argument -- jit-tester test name.");
         }
         OutputAnalyzer oa;
         try {
-            ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, args[0]);
+            ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true, args);
             oa = new OutputAnalyzer(pb.start());
         } catch (Exception e) {
             throw new Error("Unexpected exception on test jvm start :" + e, e);
         }
 
+        String name = args[args.length - 1];
         Pattern splitOut = Pattern.compile("\\n"); // tests use \n only in stdout
         Pattern splitErr = Pattern.compile("\\r?\\n"); // can handle both \r\n and \n
         Path testDir = Paths.get(Utils.TEST_SRC);
-        String goldOut = formatOutput(streamGoldFile(testDir, args[0], "out"));
+        String goldOut = formatOutput(streamGoldFile(testDir, name, "out"));
         String anlzOut = formatOutput(Arrays.stream(splitOut.split(oa.getStdout())));
         Asserts.assertEQ(anlzOut, goldOut, "Actual stdout isn't equal to golden one");
-        String goldErr = formatOutput(streamGoldFile(testDir, args[0], "err"));
+        String goldErr = formatOutput(streamGoldFile(testDir, name, "err"));
         String anlzErr = formatOutput(Arrays.stream(splitErr.split(oa.getStderr())));
         Asserts.assertEQ(anlzErr, goldErr, "Actual stderr isn't equal to golden one");
 
-        int exitValue = Integer.parseInt(streamGoldFile(testDir, args[0], "exit").findFirst().get());
+        int exitValue = Integer.parseInt(streamGoldFile(testDir, name, "exit").findFirst().get());
         oa.shouldHaveExitValue(exitValue);
     }