changeset 12187:ceda33ff54a3

8012447: Java CTW implementation Reviewed-by: vlivanov, kvn, twisti
author iignatyev
date Thu, 05 Sep 2013 16:38:04 +0400
parents a9a968364704
children cd16d587b0fa
files test/gc/TestVerifyDuringStartup.java test/testlibrary/com/oracle/java/testlibrary/JDKToolFinder.java test/testlibrary/ctw/Makefile test/testlibrary/ctw/README test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathDirEntry.java test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarEntry.java test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarInDirEntry.java test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassesListInFile.java test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java test/testlibrary/ctw/src/sun/hotspot/tools/ctw/PathHandler.java test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java test/testlibrary/ctw/test/Bar.java test/testlibrary/ctw/test/ClassesDirTest.java test/testlibrary/ctw/test/ClassesListTest.java test/testlibrary/ctw/test/CtwTest.java test/testlibrary/ctw/test/Foo.java test/testlibrary/ctw/test/JarDirTest.java test/testlibrary/ctw/test/JarsTest.java test/testlibrary/ctw/test/classes.lst test/testlibrary/whitebox/Makefile
diffstat 21 files changed, 1752 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/test/gc/TestVerifyDuringStartup.java	Mon Sep 02 22:44:57 2013 +0200
+++ b/test/gc/TestVerifyDuringStartup.java	Thu Sep 05 16:38:04 2013 +0400
@@ -48,7 +48,7 @@
                                              "-XX:+VerifyDuringStartup",
                                              "-version"});
 
-    System.out.print("Testing:\n" + JDKToolFinder.getJDKTool("java"));
+    System.out.print("Testing:\n" + JDKToolFinder.getCurrentJDKTool("java"));
     for (int i = 0; i < vmOpts.size(); i += 1) {
       System.out.print(" " + vmOpts.get(i));
     }
--- a/test/testlibrary/com/oracle/java/testlibrary/JDKToolFinder.java	Mon Sep 02 22:44:57 2013 +0200
+++ b/test/testlibrary/com/oracle/java/testlibrary/JDKToolFinder.java	Thu Sep 05 16:38:04 2013 +0400
@@ -27,24 +27,43 @@
 
 public final class JDKToolFinder {
 
-  private JDKToolFinder() {
-  }
-
-  /**
-   * Returns the full path to an executable in jdk/bin based on System property
-   * test.jdk (set by jtreg test suite)
-   *
-   * @return Full path to an executable in jdk/bin
-   */
-  public static String getJDKTool(String tool) {
-    String binPath = System.getProperty("test.jdk");
-    if (binPath == null) {
-      throw new RuntimeException("System property 'test.jdk' not set. This property is normally set by jtreg. "
-          + "When running test separately, set this property using '-Dtest.jdk=/path/to/jdk'.");
+    private JDKToolFinder() {
     }
 
-    binPath += File.separatorChar + "bin" + File.separatorChar + tool;
+    /**
+     * Returns the full path to an executable in jdk/bin based on System
+     * property {@code compile.jdk} (set by jtreg test suite)
+     *
+     * @return Full path to an executable in jdk/bin
+     */
+    public static String getJDKTool(String tool) {
+        String binPath = System.getProperty("compile.jdk");
+        if (binPath == null) {
+            throw new RuntimeException("System property 'compile.jdk' not set. "
+                    + "This property is normally set by jtreg. "
+                    + "When running test separately, set this property using "
+                    + "'-Dcompile.jdk=/path/to/jdk'.");
+        }
+        binPath += File.separatorChar + "bin" + File.separatorChar + tool;
 
-    return binPath;
-  }
+        return binPath;
+    }
+    /**
+     * Returns the full path to an executable in &lt;current jdk&gt;/bin based
+     * on System property {@code test.jdk} (set by jtreg test suite)
+     *
+     * @return Full path to an executable in jdk/bin
+     */
+    public static String getCurrentJDKTool(String tool) {
+        String binPath = System.getProperty("test.jdk");
+        if (binPath == null) {
+            throw new RuntimeException("System property 'test.jdk' not set. "
+                + "This property is normally set by jtreg. "
+                + "When running test separately, set this property using "
+                + "'-Dtest.jdk=/path/to/jdk'.");
+        }
+        binPath += File.separatorChar + "bin" + File.separatorChar + tool;
+
+        return binPath;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/Makefile	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,73 @@
+#
+# Copyright (c) 2013, 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.
+#
+#
+
+ifneq "x$(ALT_BOOTDIR)" "x"
+	BOOTDIR := $(ALT_BOOTDIR)
+endif
+
+ifeq "x$(BOOTDIR)" "x"
+	JDK_HOME := $(shell dirname $(shell which java))/..
+else
+	JDK_HOME := $(BOOTDIR)
+endif
+
+SRC_DIR = src
+BUILD_DIR = build
+OUTPUT_DIR = $(BUILD_DIR)/classes
+WHITEBOX_DIR = ../whitebox
+
+JAVAC = $(JDK_HOME)/bin/javac
+JAR = $(JDK_HOME)/bin/jar
+
+SRC_FILES = $(shell find $(SRC_DIR) -name '*.java')
+
+MAIN_CLASS = sun.hotspot.tools.ctw.CompileTheWorld
+
+.PHONY: clean cleantmp
+
+all: ctw.jar cleantmp
+
+clean: cleantmp
+	@rm -rf ctw.jar wb.jar
+
+cleantmp:
+	@rm -rf filelist manifest.mf
+	@rm -rf $(BUILD_DIR)
+
+ctw.jar: filelist wb.jar manifest.mf
+	@mkdir -p $(OUTPUT_DIR)
+	$(JAVAC) -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) -cp wb.jar @filelist
+	$(JAR) cfm ctw.jar manifest.mf -C $(OUTPUT_DIR) .
+
+wb.jar: 
+	make -C ${WHITEBOX_DIR} wb.jar
+	cp ${WHITEBOX_DIR}/wb.jar ./
+	make -C ${WHITEBOX_DIR} clean
+
+filelist: $(SRC_FILES)
+	@rm -f $@
+	@echo $(SRC_FILES) > $@
+
+manifest.mf:
+	@echo "Main-Class: ${MAIN_CLASS}" > manifest.mf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/README	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,93 @@
+#
+# Copyright (c) 2013, 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.
+#
+#
+
+DESCRIPTION
+
+This is replacement for CompileTheWorld (CTW) written on java. Its purpose is
+to make possible the use of CTW in product builds.
+
+DEPENDENCES
+
+The tool depends on Whitebox API. Assumed, that the sources of whitebox are
+located in '../whitebox' directory.
+
+BUILDING
+
+Simple way to build, just type 'make'.
+
+Makefile uses environment variables 'ALT_BOOTDIR', 'BOOTDIR' as root-dir of jdk
+that will be used for compilation and creating jar.
+
+On successful building 'ctw.jar' will be created.
+
+RUNNING
+
+Since the tool uses WhiteBox API, options 'UnlockDiagnosticVMOptions' and
+'WhiteBoxAPI' should be specified, and 'wb.jar' should be added to
+boot-classpath:
+  $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar 
+
+Arguments can be paths to '.jar, '.zip', '.lst' files or directories with
+classes, that define which classes will be compiled:
+  - '.jar', '.zip' files and directories are interpreted like in classpath
+(including '<dir>/*' syntax)
+  - '.lst' files -- files with class names (in java notation) to compile.
+CTW will try to find these classes with default class loader, so they should
+be located in classpath.
+
+Without arguments it would work as old version of CTW: all classes in
+boot-classpath will be compiled, excluding classes in 'rt.jar' if 'rt.jar' isn't
+first in boot-classpath.
+
+Due CTW's flags also are not available in product builds, the tool uses
+properties with the same names:
+  - 'CompileTheWorldPreloadClasses' -- type:boolean, default:true, description:
+Preload all classes used by a class before start loading
+  - 'CompileTheWorldStartAt' -- type:long, default:1, description: First class
+to consider
+  - 'CompileTheWorldStopAt' -- type:long, default:Long.MAX_VALUE, description:
+Last class to consider
+
+Also it uses additional properties:
+  - 'sun.hotspot.tools.ctw.verbose' -- type:boolean, default:false,
+description: Verbose output, adds additional information about compilation
+  - 'sun.hotspot.tools.ctw.logfile' -- type:string, default:null,
+description: Path to logfile, if it's null, cout will be used.
+
+EXAMPLES
+
+compile classes from 'rt.jar':
+  $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar ${JAVA_HOME}/jre/lib/rt.jar
+
+compile classes from all '.jar' in './testjars' directory:
+  $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar ./testjars/*
+
+compile classes from './build/classes' directory:
+  $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar ./build/classes
+
+compile only java.lang.String, java.lang.Object classes:
+  $ echo java.lang.String > classes.lst
+  $ echo java.lang.Object >> classes.lst
+  $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar classes.lst
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathDirEntry.java	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2013, 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 sun.hotspot.tools.ctw;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Set;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.concurrent.Executor;
+
+import java.io.*;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+
+/**
+ * * Handler for dirs containing classes to compile.
+ * @author igor.ignatyev@oracle.com
+ */
+public class ClassPathDirEntry extends PathHandler {
+
+    private final int rootLength = root.toString().length();
+
+    public ClassPathDirEntry(Path root, Executor executor) {
+        super(root, executor);
+        try {
+            URL url = root.toUri().toURL();
+            setLoader(new URLClassLoader(new URL[]{url}));
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void process() {
+        System.out.println("# dir: " + root);
+        if (!Files.exists(root)) {
+            return;
+        }
+        try {
+            Files.walkFileTree(root, EnumSet.of(FileVisitOption.FOLLOW_LINKS),
+                    Integer.MAX_VALUE, new CompileFileVisitor());
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        }
+    }
+
+    private void processFile(Path file) {
+        if (Utils.isClassFile(file.toString())) {
+            processClass(pathToClassName(file));
+        }
+    }
+
+    private String pathToClassName(Path file) {
+        String fileString;
+        if (root == file) {
+            fileString = file.normalize().toString();
+        } else {
+            fileString = file.normalize().toString().substring(rootLength + 1);
+        }
+        return Utils.fileNameToClassName(fileString);
+    }
+
+    private class CompileFileVisitor extends SimpleFileVisitor<Path> {
+
+        private final Set<Path> ready = new HashSet<>();
+
+        @Override
+        public FileVisitResult preVisitDirectory(Path dir,
+                BasicFileAttributes attrs) throws IOException {
+            if (ready.contains(dir)) {
+                return FileVisitResult.SKIP_SUBTREE;
+            }
+            ready.add(dir);
+            return super.preVisitDirectory(dir, attrs);
+        }
+
+        @Override
+        public FileVisitResult visitFile(Path file,
+                BasicFileAttributes attrs) throws IOException {
+            if (!ready.contains(file)) {
+                processFile(file);
+            }
+            return isFinished() ? FileVisitResult.TERMINATE
+                    : FileVisitResult.CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult visitFileFailed(Path file,
+                IOException exc) throws IOException {
+            return FileVisitResult.CONTINUE;
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarEntry.java	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013, 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 sun.hotspot.tools.ctw;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.*;
+import java.util.jar.*;
+import java.util.concurrent.Executor;
+
+import java.io.*;
+import java.nio.file.*;
+
+/**
+ * Handler for jar-files containing classes to compile.
+ * @author igor.ignatyev@oracle.com
+ */
+public class ClassPathJarEntry extends PathHandler {
+
+    public ClassPathJarEntry(Path root, Executor executor) {
+        super(root, executor);
+        try {
+            URL url = root.toUri().toURL();
+            setLoader(new URLClassLoader(new URL[]{url}));
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void process() {
+        System.out.println("# jar: " + root);
+        if (!Files.exists(root)) {
+            return;
+        }
+        try {
+            JarFile jarFile = new JarFile(root.toFile());
+            JarEntry entry;
+            for (Enumeration<JarEntry> e = jarFile.entries();
+                    e.hasMoreElements(); ) {
+                entry = e.nextElement();
+                processJarEntry(entry);
+                if (isFinished()) {
+                    return;
+                }
+            }
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        }
+    }
+
+     private void processJarEntry(JarEntry entry) {
+        String filename = entry.getName();
+        if (Utils.isClassFile(filename)) {
+            processClass(Utils.fileNameToClassName(filename));
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarInDirEntry.java	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013, 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 sun.hotspot.tools.ctw;
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.Executor;
+
+/**
+ * Handler for dirs containing jar-files with classes to compile.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public class ClassPathJarInDirEntry extends PathHandler {
+
+    public ClassPathJarInDirEntry(Path root, Executor executor) {
+        super(root, executor);
+    }
+
+    @Override
+    public void process() {
+        System.out.println("# jar_in_dir: " + root);
+        if (!Files.exists(root)) {
+            return;
+        }
+        try (DirectoryStream<Path> ds
+                = Files.newDirectoryStream(root, "*.jar")) {
+            for (Path p : ds) {
+                new ClassPathJarEntry(p, executor).process();
+                if (isFinished()) {
+                    return;
+                }
+            }
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassesListInFile.java	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, 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 sun.hotspot.tools.ctw;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.Executor;
+
+/**
+ * Handler for files containing a list of classes to compile.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public class ClassesListInFile extends PathHandler {
+    public ClassesListInFile(Path root, Executor executor) {
+        super(root, executor);
+    }
+
+    @Override
+    public void process() {
+        System.out.println("# list: " + root);
+        if (!Files.exists(root)) {
+            return;
+        }
+        try {
+            try (BufferedReader reader = Files.newBufferedReader(root,
+                    StandardCharsets.UTF_8)) {
+                String line;
+                while (!isFinished() && ((line = reader.readLine()) != null)) {
+                    processClass(line);
+                }
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2013, 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 sun.hotspot.tools.ctw;
+
+import sun.management.ManagementFactoryHelper;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * @author igor.ignatyev@oracle.com
+ */
+public class CompileTheWorld {
+    /**
+     * Entry point. Compiles classes in {@code args}, or all classes in
+     * boot-classpath if args is empty
+     *
+     * @param args paths to jar/zip, dir contains classes, or to .lst file
+     *             contains list of classes to compile
+     */
+    public static void main(String[] args) {
+        String logfile = Utils.LOG_FILE;
+        PrintStream os = null;
+        if (logfile != null) {
+            try {
+                os = new PrintStream(Files.newOutputStream(Paths.get(logfile)));
+            } catch (IOException io) {
+            }
+        }
+        if (os != null) {
+            System.setOut(os);
+        }
+
+        try {
+            try {
+                if (ManagementFactoryHelper.getCompilationMXBean() == null) {
+                    throw new RuntimeException(
+                            "CTW can not work in interpreted mode");
+                }
+            } catch (java.lang.NoClassDefFoundError e) {
+                // compact1, compact2 support
+            }
+            String[] paths = args;
+            boolean skipRtJar = false;
+            if (args.length == 0) {
+                paths = getDefaultPaths();
+                skipRtJar = true;
+            }
+            ExecutorService executor = createExecutor();
+            long start = System.currentTimeMillis();
+            try {
+                String path;
+                for (int i = 0, n = paths.length; i < n
+                        && !PathHandler.isFinished(); ++i) {
+                    path = paths[i];
+                    if (skipRtJar && i > 0 && isRtJar(path)) {
+                        // rt.jar is not first, so skip it
+                        continue;
+                    }
+                    PathHandler.create(path, executor).process();
+                }
+            } finally {
+                await(executor);
+            }
+            System.out.printf("Done (%d classes, %d methods, %d ms)%n",
+                    Compiler.getClassCount(),
+                    Compiler.getMethodCount(),
+                    System.currentTimeMillis() - start);
+        } finally {
+            if (os != null) {
+                os.close();
+            }
+        }
+    }
+
+    private static ExecutorService createExecutor() {
+        final int threadsCount = Math.min(
+                Runtime.getRuntime().availableProcessors(),
+                Utils.CI_COMPILER_COUNT);
+        ExecutorService result;
+        if (threadsCount > 1) {
+            result = new ThreadPoolExecutor(threadsCount, threadsCount,
+                    /* keepAliveTime */ 0L, TimeUnit.MILLISECONDS,
+                    new ArrayBlockingQueue<>(threadsCount),
+                    new ThreadPoolExecutor.CallerRunsPolicy());
+        } else {
+            result = new CurrentThreadExecutor();
+        }
+        return result;
+    }
+
+    private static String[] getDefaultPaths() {
+        String property = System.getProperty("sun.boot.class.path");
+        System.out.println(
+                "# use 'sun.boot.class.path' as args: " + property);
+        return Utils.PATH_SEPARATOR.split(property);
+    }
+
+    private static void await(ExecutorService executor) {
+        executor.shutdown();
+        while (!executor.isTerminated()) {
+            try {
+                executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
+            } catch (InterruptedException ie) {
+                Thread.currentThread().interrupt();
+                break;
+            }
+        }
+    }
+
+    private static boolean isRtJar(String path) {
+        return Utils.endsWithIgnoreCase(path, File.separator + "rt.jar");
+    }
+
+    private static class CurrentThreadExecutor extends AbstractExecutorService {
+        private boolean isShutdown;
+
+        @Override
+        public void shutdown() {
+            this.isShutdown = true;
+        }
+
+        @Override
+        public List<Runnable> shutdownNow() {
+            return null;
+        }
+
+        @Override
+        public boolean isShutdown() {
+            return isShutdown;
+        }
+
+        @Override
+        public boolean isTerminated() {
+            return isShutdown;
+        }
+
+        @Override
+        public boolean awaitTermination(long timeout, TimeUnit unit)
+                throws InterruptedException {
+            return isShutdown;
+        }
+
+        @Override
+        public void execute(Runnable command) {
+            command.run();
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2013, 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 sun.hotspot.tools.ctw;
+
+import sun.hotspot.WhiteBox;
+import sun.misc.SharedSecrets;
+import sun.reflect.ConstantPool;
+
+import java.lang.reflect.Executable;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Provide method to compile whole class.
+ * Also contains compiled methods and classes counters.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public class Compiler {
+    private Compiler() { }
+    private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+    private static final AtomicLong CLASS_COUNT = new AtomicLong(0L);
+    private static final AtomicLong METHOD_COUNT = new AtomicLong(0L);
+    private static volatile boolean CLASSES_LIMIT_REACHED = false;
+
+    /**
+     * @return count of processed classes
+     */
+    public static long getClassCount() {
+        return CLASS_COUNT.get();
+    }
+
+    /**
+     * @return count of processed methods
+     */
+    public static long getMethodCount() {
+        return METHOD_COUNT.get();
+    }
+
+    /**
+     * @return {@code true} if classes limit is reached
+     */
+    public static boolean isLimitReached() {
+        return CLASSES_LIMIT_REACHED;
+    }
+
+    /**
+     * Compiles all methods and constructors.
+     *
+     * @param aClass class to compile
+     * @param executor executor used for compile task invocation
+     * @throws NullPointerException if {@code class} or {@code executor}
+     *                              is {@code null}
+     */
+    public static void compileClass(Class aClass, Executor executor) {
+        Objects.requireNonNull(aClass);
+        Objects.requireNonNull(executor);
+        long id = CLASS_COUNT.incrementAndGet();
+        if (id > Utils.COMPILE_THE_WORLD_STOP_AT) {
+            CLASS_COUNT.decrementAndGet();
+            CLASSES_LIMIT_REACHED = true;
+            return;
+        }
+
+        if (id >= Utils.COMPILE_THE_WORLD_START_AT) {
+            String name = aClass.getName();
+            try {
+                System.out.printf("[%d]\t%s%n", id, name);
+                ConstantPool constantPool = SharedSecrets.getJavaLangAccess().
+                        getConstantPool(aClass);
+                if (Utils.COMPILE_THE_WORLD_PRELOAD_CLASSES) {
+                    preloadClasses(name, id, constantPool);
+                }
+                long methodCount = 0;
+                for (Executable e : aClass.getDeclaredConstructors()) {
+                    ++methodCount;
+                    executor.execute(new CompileMethodCommand(id, name, e));
+                }
+                for (Executable e : aClass.getDeclaredMethods()) {
+                    ++methodCount;
+                    executor.execute(new CompileMethodCommand(id, name, e));
+                }
+                METHOD_COUNT.addAndGet(methodCount);
+
+                if (Utils.DEOPTIMIZE_ALL_CLASSES_RATE > 0
+                        && (id % Utils.DEOPTIMIZE_ALL_CLASSES_RATE == 0)) {
+                    WHITE_BOX.deoptimizeAll();
+                }
+            } catch (Throwable t) {
+                System.out.printf("[%d]\t%s\tskipping %s%n", id, name, t);
+                t.printStackTrace();
+            }
+        }
+    }
+
+    private static void preloadClasses(String className, long id,
+            ConstantPool constantPool) {
+        try {
+            for (int i = 0, n = constantPool.getSize(); i < n; ++i) {
+                try {
+                    constantPool.getClassAt(i);
+                } catch (IllegalArgumentException ignore) {
+                }
+            }
+        } catch (Throwable t) {
+            System.out.printf("[%d]\t%s\tpreloading failed : %s%n", id,
+                    className, t);
+        }
+    }
+
+
+
+    /**
+     * Compilation of method.
+     * Will compile method on all available comp levels.
+     */
+    private static class CompileMethodCommand implements Runnable {
+        private final long classId;
+        private final String className;
+        private final Executable method;
+
+        /**
+         * @param classId   id of class
+         * @param className name of class
+         * @param method    compiled for compilation
+         */
+        public CompileMethodCommand(long classId, String className,
+                Executable method) {
+            this.classId = classId;
+            this.className = className;
+            this.method = method;
+        }
+
+        @Override
+        public final void run() {
+            int compLevel = Utils.INITIAL_COMP_LEVEL;
+            if (Utils.TIERED_COMPILATION) {
+                for (int i = compLevel; i <= Utils.TIERED_STOP_AT_LEVEL; ++i) {
+                    WHITE_BOX.deoptimizeMethod(method);
+                    compileMethod(method, i);
+                }
+            } else {
+                compileMethod(method, compLevel);
+            }
+        }
+
+        private void waitCompilation() {
+            if (!Utils.BACKGROUND_COMPILATION) {
+                return;
+            }
+            final Object obj = new Object();
+            synchronized (obj) {
+                for (int i = 0;
+                     i < 10 && WHITE_BOX.isMethodQueuedForCompilation(method);
+                     ++i) {
+                    try {
+                        obj.wait(1000);
+                    } catch (InterruptedException e) {
+                        Thread.currentThread().interrupt();
+                    }
+                }
+            }
+        }
+
+        private void compileMethod(Executable method, int compLevel) {
+            if (WHITE_BOX.isMethodCompilable(method, compLevel)) {
+                try {
+                    WHITE_BOX.enqueueMethodForCompilation(method, compLevel);
+                    waitCompilation();
+                    int tmp = WHITE_BOX.getMethodCompilationLevel(method);
+                    if (tmp != compLevel) {
+                        logMethod(method, "compilation level = " + tmp
+                                + ", but not " + compLevel);
+                    } else if (Utils.IS_VERBOSE) {
+                        logMethod(method, "compilation level = " + tmp + ". OK");
+                    }
+                } catch (Throwable t) {
+                    logMethod(method, "error on compile at " + compLevel
+                            + " level");
+                    t.printStackTrace();
+                }
+            } else if (Utils.IS_VERBOSE) {
+                logMethod(method, "not compilable at " + compLevel);
+            }
+        }
+
+        private void logMethod(Executable method, String message) {
+            StringBuilder builder = new StringBuilder("[");
+            builder.append(classId);
+            builder.append("]\t");
+            builder.append(className);
+            builder.append("::");
+            builder.append(method.getName());
+            builder.append('(');
+            Class[] params = method.getParameterTypes();
+            for (int i = 0, n = params.length - 1; i < n; ++i) {
+                builder.append(params[i].getName());
+                builder.append(", ");
+            }
+            if (params.length != 0) {
+                builder.append(params[params.length - 1].getName());
+            }
+            builder.append(')');
+            if (message != null) {
+                builder.append('\t');
+                builder.append(message);
+            }
+            System.err.println(builder);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/PathHandler.java	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2013, 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 sun.hotspot.tools.ctw;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.io.File;
+
+import java.util.Objects;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.concurrent.Executor;
+
+/**
+ * Abstract handler for path.
+ * <p/>
+ * Concrete subclasses should implement method {@link #process()}.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public abstract class PathHandler {
+    private static final Pattern JAR_IN_DIR_PATTERN
+            = Pattern.compile("^(.*[/\\\\])?\\*$");
+    protected final Path root;
+    protected final Executor executor;
+    private ClassLoader loader;
+
+    /**
+     * @param root     root path to process
+     * @param executor executor used for process task invocation
+     * @throws NullPointerException if {@code root} or {@code executor} is
+     *                              {@code null}
+     */
+    protected PathHandler(Path root, Executor executor) {
+        Objects.requireNonNull(root);
+        Objects.requireNonNull(executor);
+        this.root = root.normalize();
+        this.executor = executor;
+        this.loader = ClassLoader.getSystemClassLoader();
+    }
+
+   /**
+     * Factory method. Construct concrete handler in depends from {@code path}.
+     *
+     * @param path     the path to process
+     * @param executor executor used for compile task invocation
+     * @throws NullPointerException if {@code path} or {@code executor} is
+     *                              {@code null}
+     */
+    public static PathHandler create(String path, Executor executor) {
+        Objects.requireNonNull(path);
+        Objects.requireNonNull(executor);
+        Matcher matcher = JAR_IN_DIR_PATTERN.matcher(path);
+        if (matcher.matches()) {
+            path = matcher.group(1);
+            path = path.isEmpty() ? "." : path;
+            return new ClassPathJarInDirEntry(Paths.get(path), executor);
+        } else {
+            path = path.isEmpty() ? "." : path;
+            Path p = Paths.get(path);
+            if (isJarFile(p)) {
+                return new ClassPathJarEntry(p, executor);
+            } else if (isListFile(p)) {
+                return new ClassesListInFile(p, executor);
+            } else {
+                return new ClassPathDirEntry(p, executor);
+            }
+        }
+    }
+
+    private static boolean isJarFile(Path path) {
+        if (Files.isRegularFile(path)) {
+            String name = path.toString();
+            return Utils.endsWithIgnoreCase(name, ".zip")
+                    || Utils.endsWithIgnoreCase(name, ".jar");
+        }
+        return false;
+    }
+
+    private static boolean isListFile(Path path) {
+        if (Files.isRegularFile(path)) {
+            String name = path.toString();
+            return Utils.endsWithIgnoreCase(name, ".lst");
+        }
+        return false;
+    }
+
+    /**
+     * Processes all classes in specified path.
+     */
+    public abstract void process();
+
+   /**
+     * Sets class loader, that will be used to define class at
+     * {@link #processClass(String)}.
+     *
+     * @param loader class loader
+     * @throws NullPointerException if {@code loader} is {@code null}
+     */
+    protected final void setLoader(ClassLoader loader) {
+        Objects.requireNonNull(loader);
+        this.loader = loader;
+    }
+
+    /**
+     * Processes specificed class.
+     * @param name fully qualified name of class to process
+     */
+    protected final void processClass(String name) {
+        try {
+            Class aClass = Class.forName(name, true, loader);
+            Compiler.compileClass(aClass, executor);
+        } catch (ClassNotFoundException | LinkageError e) {
+            System.out.printf("Class %s loading failed : %s%n", name,
+                e.getMessage());
+        }
+    }
+
+    /**
+     * @return {@code true} if processing should be stopped
+     */
+    public static boolean isFinished() {
+        return Compiler.isLimitReached();
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2013, 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 sun.hotspot.tools.ctw;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import sun.management.ManagementFactoryHelper;
+
+import java.io.File;
+import java.util.regex.Pattern;
+
+/**
+ * Auxiliary methods.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public class Utils {
+    /**
+     * Value of {@code -XX:CompileThreshold}
+     */
+    public static final boolean TIERED_COMPILATION
+            = Boolean.parseBoolean(getVMOption("TieredCompilation", "false"));
+    /**
+     * Value of {@code -XX:BackgroundCompilation}
+     */
+    public static final boolean BACKGROUND_COMPILATION
+            = Boolean.parseBoolean(getVMOption("BackgroundCompilation",
+            "false"));
+    /**
+     * Value of {@code -XX:TieredStopAtLevel}
+     */
+    public static final int TIERED_STOP_AT_LEVEL;
+    /**
+     * Value of {@code -XX:CICompilerCount}
+     */
+    public static final Integer CI_COMPILER_COUNT
+            = Integer.valueOf(getVMOption("CICompilerCount", "1"));
+    /**
+     * Initial compilation level.
+     */
+    public static final int INITIAL_COMP_LEVEL;
+    /**
+     * Compiled path-separator regexp.
+     */
+    public static final Pattern PATH_SEPARATOR = Pattern.compile(
+            File.pathSeparator, Pattern.LITERAL);
+    /**
+     * Value of {@code -DDeoptimizeAllClassesRate}. Frequency of
+     * {@code WB.deoptimizeAll()} invocation If it less that {@code 0},
+     * {@code WB.deoptimizeAll()} will not be invoked.
+     */
+    public static final int DEOPTIMIZE_ALL_CLASSES_RATE
+            = Integer.getInteger("DeoptimizeAllClassesRate", -1);
+    /**
+     * Value of {@code -DCompileTheWorldStopAt}. Last class to consider.
+     */
+    public static final long COMPILE_THE_WORLD_STOP_AT
+            = Long.getLong("CompileTheWorldStopAt", Long.MAX_VALUE);
+    /**
+     * Value of {@code -DCompileTheWorldStartAt}. First class to consider.
+     */
+    public static final long COMPILE_THE_WORLD_START_AT
+            = Long.getLong("CompileTheWorldStartAt", 1);
+    /**
+     * Value of {@code -DCompileTheWorldPreloadClasses}. Preload all classes
+     * used by a class before start loading.
+     */
+    public static final boolean COMPILE_THE_WORLD_PRELOAD_CLASSES;
+    /**
+     * Value of {@code -Dsun.hotspot.tools.ctw.verbose}. Verbose output,
+     * adds additional information about compilation.
+     */
+    public static final boolean IS_VERBOSE
+            = Boolean.getBoolean("sun.hotspot.tools.ctw.verbose");
+    /**
+     * Value of {@code -Dsun.hotspot.tools.ctw.logfile}.Path to logfile, if
+     * it's null, cout will be used.
+     */
+    public static final String LOG_FILE
+            = System.getProperty("sun.hotspot.tools.ctw.logfile");
+    static {
+        if (Utils.TIERED_COMPILATION) {
+            INITIAL_COMP_LEVEL = 1;
+        } else {
+            String vmName = System.getProperty("java.vm.name");
+            if (Utils.endsWithIgnoreCase(vmName, " Server VM")) {
+                INITIAL_COMP_LEVEL = 4;
+            } else if (Utils.endsWithIgnoreCase(vmName, " Client VM")
+                    || Utils.endsWithIgnoreCase(vmName, " Minimal VM")) {
+                INITIAL_COMP_LEVEL = 1;
+            } else {
+                throw new RuntimeException("Unknown VM: " + vmName);
+            }
+        }
+
+        TIERED_STOP_AT_LEVEL = Integer.parseInt(getVMOption("TieredStopAtLevel",
+                String.valueOf(INITIAL_COMP_LEVEL)));
+    }
+
+    static {
+        String tmp = System.getProperty("CompileTheWorldPreloadClasses");
+        if (tmp == null) {
+            COMPILE_THE_WORLD_PRELOAD_CLASSES = true;
+        } else {
+            COMPILE_THE_WORLD_PRELOAD_CLASSES = Boolean.parseBoolean(tmp);
+        }
+    }
+
+    public static final String CLASSFILE_EXT = ".class";
+
+    private Utils() {
+    }
+
+    /**
+     * Tests if the string ends with the suffix, ignoring case
+     * considerations
+     *
+     * @param string the tested string
+     * @param suffix the suffix
+     * @return {@code true} if {@code string} ends with the {@code suffix}
+     * @see String#endsWith(String)
+     */
+    public static boolean endsWithIgnoreCase(String string, String suffix) {
+        if (string == null || suffix == null) {
+            return false;
+        }
+        int length = suffix.length();
+        int toffset = string.length() - length;
+        if (toffset < 0) {
+            return false;
+        }
+        return string.regionMatches(true, toffset, suffix, 0, length);
+    }
+
+    /**
+     * Returns value of VM option.
+     *
+     * @param name option's name
+     * @return value of option or {@code null}, if option doesn't exist
+     * @throws NullPointerException if name is null
+     */
+    public static String getVMOption(String name) {
+        String result;
+        HotSpotDiagnosticMXBean diagnostic
+                = ManagementFactoryHelper.getDiagnosticMXBean();
+        result = diagnostic.getVMOption(name).getValue();
+        return result;
+    }
+
+    /**
+     * Returns value of VM option or default value.
+     *
+     * @param name         option's name
+     * @param defaultValue default value
+     * @return value of option or {@code defaultValue}, if option doesn't exist
+     * @throws NullPointerException if name is null
+     * @see #getVMOption(String)
+     */
+    public static String getVMOption(String name, String defaultValue) {
+        String result;
+        try {
+            result = getVMOption(name);
+        } catch (NoClassDefFoundError e) {
+            // compact1, compact2 support
+            result = defaultValue;
+        }
+        return result == null ? defaultValue : result;
+    }
+
+    /**
+     * Tests if the filename is valid filename for class file.
+     *
+     * @param filename tested filename
+     */
+    public static boolean isClassFile(String filename) {
+        // If the filename has a period after removing '.class', it's not valid class file
+        return endsWithIgnoreCase(filename, CLASSFILE_EXT)
+                && (filename.indexOf('.')
+                == (filename.length() - CLASSFILE_EXT.length()));
+    }
+
+    /**
+     * Converts the filename to classname.
+     *
+     * @param filename filename to convert
+     * @return corresponding classname.
+     * @throws AssertionError if filename isn't valid filename for class file -
+     *                        {@link #isClassFile(String)}
+     */
+    public static String fileNameToClassName(String filename) {
+        assert isClassFile(filename);
+        return filename.substring(0, filename.length() - CLASSFILE_EXT.length())
+                       .replace(File.separatorChar, '.');
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/test/Bar.java	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,5 @@
+public class Bar {
+  private static void staticMethod() { }
+  public void method() { }
+  protected Bar() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/test/ClassesDirTest.java	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+/*
+ * @test ClassesDirTest
+ * @bug 8012447
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src
+ * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox ClassesDirTest Foo Bar
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * @run main ClassesDirTest prepare
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes
+ * @run main ClassesDirTest check ctw.log
+ * @summary testing of CompileTheWorld :: classes in directory
+ * @author igor.ignatyev@oracle.com
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+
+public class ClassesDirTest extends CtwTest {
+    private static final String[] SHOULD_CONTAIN
+            = {"# dir: classes", "Done (2 classes, 6 methods, "};
+
+    private ClassesDirTest() {
+        super(SHOULD_CONTAIN);
+    }
+
+    public static void main(String[] args) throws Exception {
+        new ClassesDirTest().run(args);
+    }
+
+    protected void prepare() throws Exception {
+        String path = "classes";
+        Files.createDirectory(Paths.get(path));
+        Files.move(Paths.get("Foo.class"), Paths.get(path, "Foo.class"),
+                StandardCopyOption.REPLACE_EXISTING);
+        Files.move(Paths.get("Bar.class"), Paths.get(path, "Bar.class"),
+                StandardCopyOption.REPLACE_EXISTING);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/test/ClassesListTest.java	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+/*
+ * @test ClassesListTest
+ * @bug 8012447
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src
+ * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox ClassesListTest Foo Bar
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * @run main ClassesListTest prepare
+ * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes.lst
+ * @run main ClassesListTest check ctw.log
+ * @summary testing of CompileTheWorld :: list of classes in file
+ * @author igor.ignatyev@oracle.com
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+
+public class ClassesListTest extends CtwTest {
+    private static final String[] SHOULD_CONTAIN
+            = {"# list: classes.lst", "Done (4 classes, "};
+
+    private ClassesListTest() {
+        super(SHOULD_CONTAIN);
+    }
+
+    public static void main(String[] args) throws Exception {
+        new ClassesListTest().run(args);
+    }
+
+    protected void prepare() throws Exception {
+        String path = "classes.lst";
+        Files.copy(Paths.get(System.getProperty("test.src"), path),
+                Paths.get(path), StandardCopyOption.REPLACE_EXISTING);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/test/CtwTest.java	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+import java.util.List;
+import java.util.Collections;
+import java.util.ArrayList;
+
+import java.io.File;
+import java.io.Writer;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.BufferedReader;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.nio.charset.Charset;
+
+import com.oracle.java.testlibrary.JDKToolFinder;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+public abstract class CtwTest {
+    protected final String[] shouldContain;
+    protected CtwTest(String[] shouldContain) {
+        this.shouldContain = shouldContain;
+    }
+
+    public void run(String[] args) throws Exception {
+        if (args.length == 0) {
+            throw new Error("args is empty");
+        }
+        switch (args[0]) {
+            case "prepare":
+                prepare();
+                break;
+            case "check":
+                check(args);
+                break;
+            default:
+                throw new Error("unregonized action -- " + args[0]);
+        }
+    }
+
+    protected void prepare() throws Exception { }
+
+    protected void check(String[] args) throws Exception  {
+        if (args.length < 2) {
+            throw new Error("logfile isn't specified");
+        }
+        String logfile = args[1];
+        try (BufferedReader r = Files.newBufferedReader(Paths.get(logfile),
+                Charset.defaultCharset())) {
+            OutputAnalyzer output = readOutput(r);
+           for (String test : shouldContain) {
+                output.shouldContain(test);
+            }
+        }
+    }
+
+    private static OutputAnalyzer readOutput(BufferedReader reader)
+            throws IOException {
+        StringBuilder builder = new StringBuilder();
+        String eol = String.format("%n");
+        String line;
+
+        while ((line = reader.readLine()) != null) {
+            builder.append(line);
+            builder.append(eol);
+        }
+        return new OutputAnalyzer(builder.toString(), "");
+    }
+
+    protected void dump(OutputAnalyzer output, String name) {
+        try (Writer w = new FileWriter(name + ".out")) {
+            String s = output.getStdout();
+            w.write(s, s.length(), 0);
+        } catch (IOException io) {
+            io.printStackTrace();
+        }
+        try (Writer w = new FileWriter(name + ".err")) {
+            String s = output.getStderr();
+            w.write(s, s.length(), 0);
+        } catch (IOException io) {
+            io.printStackTrace();
+        }
+    }
+
+    protected ProcessBuilder createJarProcessBuilder(String... command)
+            throws Exception {
+        String javapath = JDKToolFinder.getJDKTool("jar");
+
+        ArrayList<String> args = new ArrayList<>();
+        args.add(javapath);
+        Collections.addAll(args, command);
+
+        return new ProcessBuilder(args.toArray(new String[args.size()]));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/test/Foo.java	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,5 @@
+public class Foo {
+  private static void staticMethod() { }
+  public void method() { }
+  protected Foo() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/test/JarDirTest.java	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+/*
+ * @test JarDirTest
+ * @bug 8012447
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src
+ * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox JarDirTest Foo Bar
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * @run main JarDirTest prepare
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld jars/*
+ * @run main JarDirTest check ctw.log
+ * @summary testing of CompileTheWorld :: jars in directory
+ * @author igor.ignatyev@oracle.com
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+public class JarDirTest extends CtwTest {
+    private static final String[] SHOULD_CONTAIN
+            = {"# jar_in_dir: jars",
+                    "# jar: jars" + File.separator +"foo.jar",
+                    "# jar: jars" + File.separator +"bar.jar",
+                    "Done (4 classes, 12 methods, "};
+
+    private JarDirTest() {
+        super(SHOULD_CONTAIN);
+    }
+
+    public static void main(String[] args) throws Exception {
+        new JarDirTest().run(args);
+    }
+
+    protected void prepare() throws Exception {
+        String path = "jars";
+        Files.createDirectory(Paths.get(path));
+
+        ProcessBuilder pb = createJarProcessBuilder("cf", "jars/foo.jar",
+                "Foo.class", "Bar.class");
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        dump(output, "ctw-foo.jar");
+        output.shouldHaveExitValue(0);
+
+        pb = createJarProcessBuilder("cf", "jars/bar.jar", "Foo.class",
+                "Bar.class");
+        output = new OutputAnalyzer(pb.start());
+        dump(output, "ctw-bar.jar");
+        output.shouldHaveExitValue(0);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/test/JarsTest.java	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, 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.
+ */
+
+/*
+ * @test JarsTest
+ * @bug 8012447
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src
+ * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox JarsTest Foo Bar
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * @run main JarsTest prepare
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld foo.jar bar.jar
+ * @run main JarsTest check ctw.log
+ * @summary testing of CompileTheWorld :: jars
+ * @author igor.ignatyev@oracle.com
+ */
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+public class JarsTest extends CtwTest {
+    private static final String[] SHOULD_CONTAIN
+            = {"# jar: foo.jar", "# jar: bar.jar",
+                    "Done (4 classes, 12 methods, "};
+
+    private JarsTest() {
+        super(SHOULD_CONTAIN);
+    }
+
+    public static void main(String[] args) throws Exception {
+        new JarsTest().run(args);
+    }
+
+    protected void prepare() throws Exception {
+        ProcessBuilder pb = createJarProcessBuilder("cf", "foo.jar",
+                "Foo.class", "Bar.class");
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        dump(output, "ctw-foo.jar");
+        output.shouldHaveExitValue(0);
+
+        pb = createJarProcessBuilder("cf", "bar.jar", "Foo.class", "Bar.class");
+        output = new OutputAnalyzer(pb.start());
+        dump(output, "ctw-bar.jar");
+        output.shouldHaveExitValue(0);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/ctw/test/classes.lst	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,4 @@
+java.lang.String
+java.lang.Object
+Foo
+Bar
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testlibrary/whitebox/Makefile	Thu Sep 05 16:38:04 2013 +0400
@@ -0,0 +1,63 @@
+#
+# Copyright (c) 2013, 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.
+#
+#
+
+ifneq "x$(ALT_BOOTDIR)" "x"
+	BOOTDIR := $(ALT_BOOTDIR)
+endif
+
+ifeq "x$(BOOTDIR)" "x"
+	JDK_HOME := $(shell dirname $(shell which java))/..
+else
+	JDK_HOME := $(BOOTDIR)
+endif
+
+SRC_DIR = ./
+BUILD_DIR = build
+OUTPUT_DIR = $(BUILD_DIR)/classes
+
+JAVAC = $(JDK_HOME)/bin/javac
+JAR = $(JDK_HOME)/bin/jar
+
+SRC_FILES = $(shell find $(SRC_DIR) -name '*.java')
+
+.PHONY: filelist clean cleantmp
+
+all: wb.jar cleantmp
+
+wb.jar: filelist
+	@mkdir -p $(OUTPUT_DIR)
+	$(JAVAC) -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) -cp $(OUTPUT_DIR) @filelist
+	$(JAR) cf wb.jar -C $(OUTPUT_DIR) .
+	@rm -rf $(OUTPUT_DIR)
+
+filelist: $(SRC_FILES)
+	@rm -f $@
+	@echo $(SRC_FILES) > $@
+
+clean: cleantmp
+	@rm -rf wb.jar
+
+cleantmp:
+	@rm -rf filelist
+	@rm -rf $(BUILD_DIR)