8184738: CTW fails with assert(!method->method_holder()->is_not_initialized()) failed: method holder must be initialized
authoriignatyev
Tue, 08 Aug 2017 12:39:18 -0700
changeset 46775 d0af9e47df69
parent 46774 427f3511c490
child 46777 02604fd56ae4
8184738: CTW fails with assert(!method->method_holder()->is_not_initialized()) failed: method holder must be initialized Reviewed-by: kvn
hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathDirEntry.java
hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarEntry.java
hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarInDirEntry.java
hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJimageEntry.java
hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassesListInFile.java
hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java
hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java
hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java
hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/PathHandler.java
hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathDirEntry.java	Tue Aug 08 11:44:23 2017 -0400
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathDirEntry.java	Tue Aug 08 12:39:18 2017 -0700
@@ -23,104 +23,73 @@
 
 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.*;
+import java.io.IOException;
+import java.nio.file.FileVisitOption;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.stream.Stream;
 
 /**
  * Handler for dirs containing classes to compile.
  */
-public class ClassPathDirEntry extends PathHandler {
-
-    private final int rootLength = root.toString().length();
+public class ClassPathDirEntry extends PathHandler.PathEntry {
+    private final int rootLength;
 
-    public ClassPathDirEntry(Path root, Executor executor) {
-        super(root, executor);
+    public ClassPathDirEntry(Path root) {
+        super(root);
+        if (!Files.exists(root)) {
+            throw new Error(root + " dir does not exist");
+        }
+        rootLength = root.toString()
+                         .length();
+    }
+
+    @Override
+    protected Stream<String> classes() {
         try {
-            URL url = root.toUri().toURL();
-            setLoader(new URLClassLoader(new URL[]{url}));
-        } catch (MalformedURLException e) {
-            e.printStackTrace();
+            return Files.walk(root, Integer.MAX_VALUE, FileVisitOption.FOLLOW_LINKS)
+                        .filter(p -> Utils.isClassFile(p.toString()))
+                        .map(this::pathToClassName);
+        } catch (IOException e) {
+            throw new Error("can not traverse " + root + " : " + e.getMessage(), e);
         }
     }
 
     @Override
-    public void process() {
-        CompileTheWorld.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();
-        }
+    protected String description() {
+        return "# dir: " + root;
     }
 
     @Override
-    public long classCount() {
+    protected byte[] findByteCode(String classname) {
+        Path path = root;
+        for (String c : Utils.classNameToFileName(classname).split("/")) {
+            path = path.resolve(c);
+        }
+        if (!path.toFile()
+                 .exists()) {
+            return null;
+        }
         try {
-            return Files.walk(root, FileVisitOption.FOLLOW_LINKS).count();
+            return Files.readAllBytes(path);
         } catch (IOException e) {
-            throw new Error("can not walk dir " + root + " : "
-                    + e.getMessage(), e);
-        }
-    }
-
-    private void processFile(Path file) {
-        if (Utils.isClassFile(file.toString())) {
-            processClass(pathToClassName(file));
+            e.printStackTrace(CompileTheWorld.ERR);
+            return null;
         }
     }
 
     private String pathToClassName(Path file) {
         String fileString;
         if (root == file) {
-            fileString = file.normalize().toString();
+            fileString = file.normalize()
+                             .toString();
         } else {
-            fileString = file.normalize().toString().substring(rootLength + 1);
+            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;
-        }
-    }
 }
 
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarEntry.java	Tue Aug 08 11:44:23 2017 -0400
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarEntry.java	Tue Aug 08 12:39:18 2017 -0700
@@ -23,69 +23,62 @@
 
 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.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Stream;
 
 /**
  * Handler for jar-files containing classes to compile.
  */
-public class ClassPathJarEntry extends PathHandler {
+public class ClassPathJarEntry extends PathHandler.PathEntry {
+    private final JarFile jarFile;
 
-    public ClassPathJarEntry(Path root, Executor executor) {
-        super(root, executor);
+    public ClassPathJarEntry(Path root) {
+        super(root);
+        if (!Files.exists(root)) {
+            throw new Error(root + " file not found");
+        }
         try {
-            URL url = root.toUri().toURL();
-            setLoader(new URLClassLoader(new URL[]{url}));
-        } catch (MalformedURLException e) {
-            e.printStackTrace();
+            jarFile = new JarFile(root.toFile());
+        } catch (IOException e) {
+            throw new Error("can not read " + root + " : " + e.getMessage(), e);
         }
     }
 
     @Override
-    public void process() {
-        CompileTheWorld.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();
-        }
+    protected Stream<String> classes() {
+        return jarFile.stream()
+                      .map(JarEntry::getName)
+                      .filter(Utils::isClassFile)
+                      .map(Utils::fileNameToClassName);
+    }
+
+    @Override
+    protected String description() {
+        return "# jar: " + root;
     }
 
     @Override
-    public long classCount() {
-        try (JarFile jarFile = new JarFile(root.toFile())) {
-            return jarFile.stream()
-                    .map(JarEntry::getName)
-                    .filter(Utils::isClassFile)
-                    .count();
+    protected byte[] findByteCode(String classname) {
+        try {
+            String filename = Utils.classNameToFileName(classname);
+            JarEntry entry = jarFile.getJarEntry(filename);
+
+            if (entry == null) {
+                return null;
+            }
+
+            try (InputStream is = jarFile.getInputStream(entry)) {
+                return is.readAllBytes();
+            }
+
         } catch (IOException e) {
-            throw new Error("can not open jar file " + root + " : "
-                    + e.getMessage() , e);
-        }
-    }
-
-    private void processJarEntry(JarEntry entry) {
-        String filename = entry.getName();
-        if (Utils.isClassFile(filename)) {
-            processClass(Utils.fileNameToClassName(filename));
+            e.printStackTrace(CompileTheWorld.ERR);
+            return null;
         }
     }
 }
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarInDirEntry.java	Tue Aug 08 11:44:23 2017 -0400
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarInDirEntry.java	Tue Aug 08 12:39:18 2017 -0700
@@ -27,46 +27,52 @@
 import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.util.concurrent.Executor;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * Handler for dirs containing jar-files with classes to compile.
  */
-public class ClassPathJarInDirEntry extends PathHandler {
-
-    public ClassPathJarInDirEntry(Path root, Executor executor) {
-        super(root, executor);
-    }
-
-    @Override
-    public void process() {
-        CompileTheWorld.OUT.println("# jar_in_dir: " + root);
-        if (!Files.exists(root)) {
-            return;
+public class ClassPathJarInDirEntry {
+    public static List<PathHandler> create(Path path) {
+        Objects.requireNonNull(path);
+        if (!Files.exists(path)) {
+            throw new Error(path + " directory not found");
         }
-        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();
+        try {
+            return Stream.concat(
+                    Stream.of(new PathHandler(new JarInDirEntry(path))),
+                    Files.list(path)
+                         .filter(p -> p.getFileName().toString().endsWith(".jar"))
+                         .map(ClassPathJarEntry::new)
+                         .map(PathHandler::new))
+                         .collect(Collectors.toList());
+        } catch (IOException e) {
+            throw new Error("can not read " + path + " directory : " + e.getMessage(), e);
         }
     }
 
-    @Override
-    public long classCount() {
-        try {
-            return Files.list(root)
-                    .filter(p -> p.getFileName().toString().endsWith(".jar"))
-                    .map(p -> new ClassPathJarEntry(p, executor))
-                    .mapToLong(ClassPathJarEntry::classCount).sum();
-        } catch (IOException e) {
-            throw new Error("can not walk dir " + root + " : "
-                    + e.getMessage(), e);
+    // dummy path handler, used just to print description before real handlers.
+    private static class JarInDirEntry extends PathHandler.PathEntry {
+        private JarInDirEntry(Path root) {
+            super(root);
+        }
+
+        @Override
+        protected byte[] findByteCode(String name) {
+            return null;
+        }
+
+        @Override
+        protected Stream<String> classes() {
+            return Stream.empty();
+        }
+
+        @Override
+        protected String description() {
+            return "# jar_in_dir: " + root;
         }
     }
 }
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJimageEntry.java	Tue Aug 08 11:44:23 2017 -0400
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJimageEntry.java	Tue Aug 08 12:39:18 2017 -0700
@@ -24,58 +24,69 @@
 package sun.hotspot.tools.ctw;
 
 import jdk.internal.jimage.ImageReader;
+import jdk.internal.jimage.ImageLocation;
 
 import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.concurrent.Executor;
+import java.util.stream.Stream;
 
 /**
  * Handler for jimage-files containing classes to compile.
  */
-public class ClassPathJimageEntry extends PathHandler {
-    public ClassPathJimageEntry(Path root, Executor executor) {
-        super(root, executor);
+public class ClassPathJimageEntry extends PathHandler.PathEntry {
+
+    @Override
+    protected Stream<String> classes() {
+        return Arrays.stream(reader.getEntryNames())
+                     .filter(name -> name.endsWith(".class"))
+                     .filter(name -> !name.endsWith("module-info.class"))
+                     .map(Utils::fileNameToClassName);
+    }
+
+    @Override
+    protected String description() {
+        return "# jimage: " + root;
+    }
+
+    @Override
+    public void close() {
         try {
-            URL url = root.toUri().toURL();
-            setLoader(new URLClassLoader(new URL[]{url}));
-        } catch (MalformedURLException e) {
-            e.printStackTrace();
+            reader.close();
+        } catch (IOException e) {
+            throw new Error("error on closing reader for " + root + " : "
+                    + e.getMessage(), e);
+        } finally {
+            super.close();
+        }
+    }
+
+    private final ImageReader reader;
+
+    public ClassPathJimageEntry(Path root) {
+        super(root);
+        if (!Files.exists(root)) {
+            throw new Error(root + " image file not found");
+        }
+        try {
+            reader = ImageReader.open(root);
+        } catch (IOException e) {
+            throw new Error("can not open " + root + " : " + e.getMessage(), e);
         }
     }
 
     @Override
-    public void process() {
-        CompileTheWorld.OUT.println("# jimage: " + root);
-        if (!Files.exists(root)) {
-            return;
+    protected byte[] findByteCode(String name) {
+        String resource = Utils.classNameToFileName(name);
+        for (String m : reader.getModuleNames()) {
+            ImageLocation location = reader.findLocation(m, resource);
+            if (location != null) {
+                return reader.getResource(location);
+            }
         }
-        try (ImageReader reader = ImageReader.open(root)) {
-            Arrays.stream(reader.getEntryNames())
-                    .filter(name -> name.endsWith(".class"))
-                    .filter(name -> !name.endsWith("module-info.class"))
-                    .map(Utils::fileNameToClassName)
-                    .forEach(this::processClass);
-        } catch (IOException ioe) {
-            ioe.printStackTrace();
-        }
+        return null;
     }
 
-    @Override
-    public long classCount() {
-        try (ImageReader reader = ImageReader.open(root)) {
-            return Arrays.stream(reader.getEntryNames())
-                    .filter(name -> name.endsWith(".class"))
-                    .filter(name -> !name.endsWith("module-info.class"))
-                    .map(Utils::fileNameToClassName)
-                    .count();
-        } catch (IOException e) {
-            throw new Error("can not open jimage file " + root + " : "
-                    + e.getMessage() , e);
-        }
-    }
 }
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassesListInFile.java	Tue Aug 08 11:44:23 2017 -0400
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassesListInFile.java	Tue Aug 08 12:39:18 2017 -0700
@@ -25,46 +25,52 @@
 
 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;
+import java.util.stream.Stream;
 
 /**
  * Handler for files containing a list of classes to compile.
  */
-public class ClassesListInFile extends PathHandler {
-    public ClassesListInFile(Path root, Executor executor) {
-        super(root, executor);
-    }
+public class ClassesListInFile extends PathHandler.PathEntry {
+    private final BufferedReader reader;
 
-    @Override
-    public void process() {
-        CompileTheWorld.OUT.println("# list: " + root);
+    public ClassesListInFile(Path root) {
+        super(root);
         if (!Files.exists(root)) {
-            return;
+            throw new Error(root + " file does not exist");
         }
         try {
-            try (BufferedReader reader = Files.newBufferedReader(root)) {
-                String line;
-                while (!isFinished() && ((line = reader.readLine()) != null)) {
-                    processClass(line);
-                }
-            }
+           reader = Files.newBufferedReader(root);
         } catch (IOException e) {
-            e.printStackTrace();
+            throw new Error("can not open " + root + " : " + e.getMessage(), e);
         }
     }
 
     @Override
-    public long classCount() {
+    protected byte[] findByteCode(String name) {
+        return null;
+    }
+
+    @Override
+    protected Stream<String> classes() {
+        return reader.lines();
+    }
+
+    @Override
+    protected String description() {
+        return "# list: " + root;
+    }
+
+    @Override
+    public void close() {
         try {
-            try (BufferedReader reader = Files.newBufferedReader(root)) {
-                return reader.lines().count();
-            }
+            reader.close();
         } catch (IOException e) {
-            throw new Error("can not read list " + root + " : "
-                    + e.getMessage(), e);
+            throw new Error("error on closing reader for " + root
+                    + " : "  + e.getMessage(), e);
+        } finally {
+            super.close();
         }
     }
 }
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java	Tue Aug 08 11:44:23 2017 -0400
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java	Tue Aug 08 12:39:18 2017 -0700
@@ -29,6 +29,7 @@
 import java.nio.file.Files;
 import java.nio.file.Paths;
 
+import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.*;
 
@@ -73,12 +74,16 @@
             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];
-                    PathHandler.create(path, executor).process();
-                }
+                Arrays.stream(paths)
+                      .map(PathHandler::create)
+                      .flatMap(List::stream)
+                      .forEach(p -> {
+                          try {
+                              p.process(executor);
+                          } finally {
+                              p.close();
+                          }
+                        });
             } finally {
                 await(executor);
             }
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java	Tue Aug 08 11:44:23 2017 -0400
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java	Tue Aug 08 12:39:18 2017 -0700
@@ -23,14 +23,17 @@
 
 package sun.hotspot.tools.ctw;
 
-import sun.hotspot.WhiteBox;
 import jdk.internal.misc.SharedSecrets;
+import jdk.internal.misc.Unsafe;
 import jdk.internal.reflect.ConstantPool;
+import sun.hotspot.WhiteBox;
+
 import java.lang.reflect.Executable;
-
+import java.util.Arrays;
 import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
 
 /**
  * Provide method to compile whole class.
@@ -38,6 +41,7 @@
  */
 public class Compiler {
 
+    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
     private static final AtomicLong METHOD_COUNT = new AtomicLong(0L);
 
@@ -62,35 +66,27 @@
     public static void compileClass(Class<?> aClass, long id, Executor executor) {
         Objects.requireNonNull(aClass);
         Objects.requireNonNull(executor);
-        try {
-            ConstantPool constantPool = SharedSecrets.getJavaLangAccess().
-                    getConstantPool(aClass);
-            if (Utils.COMPILE_THE_WORLD_PRELOAD_CLASSES) {
-                preloadClasses(aClass.getName(), id, constantPool);
-            }
-            int startLevel = Utils.INITIAL_COMP_LEVEL;
-            int endLevel = Utils.TIERED_COMPILATION ? Utils.TIERED_STOP_AT_LEVEL : startLevel;
-            for (int i = startLevel; i <= endLevel; ++i) {
-                WHITE_BOX.enqueueInitializerForCompilation(aClass, i);
-            }
-            long methodCount = 0;
-            for (Executable e : aClass.getDeclaredConstructors()) {
-                ++methodCount;
-                executor.execute(new CompileMethodCommand(id, e));
-            }
-            for (Executable e : aClass.getDeclaredMethods()) {
-                ++methodCount;
-                executor.execute(new CompileMethodCommand(id, e));
-            }
-            METHOD_COUNT.addAndGet(methodCount);
+        ConstantPool constantPool = SharedSecrets.getJavaLangAccess().
+                getConstantPool(aClass);
+        if (Utils.COMPILE_THE_WORLD_PRELOAD_CLASSES) {
+            preloadClasses(aClass.getName(), id, constantPool);
+        }
+        UNSAFE.ensureClassInitialized(aClass);
+        compileClinit(aClass, id);
+        long methodCount = 0;
+        for (Executable e : aClass.getDeclaredConstructors()) {
+            ++methodCount;
+            executor.execute(new CompileMethodCommand(id, e));
+        }
+        for (Executable e : aClass.getDeclaredMethods()) {
+            ++methodCount;
+            executor.execute(new CompileMethodCommand(id, 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) {
-            CompileTheWorld.OUT.printf("[%d]\t%s\tskipping %s%n", id, aClass.getName(), t);
-            t.printStackTrace();
+        if (Utils.DEOPTIMIZE_ALL_CLASSES_RATE > 0
+                && (id % Utils.DEOPTIMIZE_ALL_CLASSES_RATE == 0)) {
+            WHITE_BOX.deoptimizeAll();
         }
     }
 
@@ -104,12 +100,25 @@
                 }
             }
         } catch (Throwable t) {
-            CompileTheWorld.OUT.printf("[%d]\t%s\tpreloading failed : %s%n",
+            CompileTheWorld.OUT.printf("[%d]\t%s\tWARNING preloading failed : %s%n",
                     id, className, t);
+            t.printStackTrace(CompileTheWorld.ERR);
         }
     }
 
-
+    private static void compileClinit(Class<?> aClass, long id) {
+        int startLevel = Utils.INITIAL_COMP_LEVEL;
+        int endLevel = Utils.TIERED_COMPILATION ? Utils.TIERED_STOP_AT_LEVEL : startLevel;
+        for (int i = startLevel; i <= endLevel; ++i) {
+            try {
+                WHITE_BOX.enqueueInitializerForCompilation(aClass, i);
+            } catch (Throwable t) {
+                CompileTheWorld.OUT.printf("[%d]\t%s::<clinit>\tERROR at level %d : %s%n",
+                        id, aClass.getName(), i, t);
+                t.printStackTrace(CompileTheWorld.ERR);
+            }
+        }
+    }
 
     /**
      * Compilation of method.
@@ -168,41 +177,37 @@
                     waitCompilation();
                     int tmp = WHITE_BOX.getMethodCompilationLevel(method);
                     if (tmp != compLevel) {
-                        log("compilation level = " + tmp
+                        log("WARNING compilation level = " + tmp
                                 + ", but not " + compLevel);
                     } else if (Utils.IS_VERBOSE) {
                         log("compilation level = " + tmp + ". OK");
                     }
                 } catch (Throwable t) {
-                    log("error on compile at " + compLevel
-                            + " level");
-                    t.printStackTrace();
+                    log("ERROR at level " + compLevel);
+                    t.printStackTrace(CompileTheWorld.ERR);
                 }
             } else if (Utils.IS_VERBOSE) {
                 log("not compilable at " + compLevel);
             }
         }
 
+        private String methodName() {
+            return String.format("%s::%s(%s)",
+                    className,
+                    method.getName(),
+                    Arrays.stream(method.getParameterTypes())
+                          .map(Class::getName)
+                          .collect(Collectors.joining(", ")));
+        }
+
         private void log(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(')');
+            StringBuilder builder = new StringBuilder("[")
+                    .append(classId)
+                    .append("]\t")
+                    .append(methodName());
             if (message != null) {
-                builder.append('\t');
-                builder.append(message);
+                builder.append('\t')
+                       .append(message);
             }
             CompileTheWorld.ERR.println(builder);
         }
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java	Tue Aug 08 11:44:23 2017 -0400
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CtwRunner.java	Tue Aug 08 12:39:18 2017 -0700
@@ -162,8 +162,12 @@
     }
 
     private long classCount() {
-        return PathHandler.create(targetPath.toString(), Runnable::run)
-                .classCount();
+        List<PathHandler> phs = PathHandler.create(targetPath.toString());
+        long result = phs.stream()
+                         .mapToLong(PathHandler::classCount)
+                         .sum();
+        phs.forEach(PathHandler::close);
+        return result;
     }
 
     private Pair<String, Long> getLastClass(Path errFile) {
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/PathHandler.java	Tue Aug 08 11:44:23 2017 -0400
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/PathHandler.java	Tue Aug 08 12:39:18 2017 -0700
@@ -23,73 +23,118 @@
 
 package sun.hotspot.tools.ctw;
 
-import jdk.internal.misc.Unsafe;
-
+import java.io.Closeable;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Function;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Stream;
 
 /**
- * Abstract handler for path.
- * Concrete subclasses should implement method {@link #process()}.
+ * Handler for a path, responsible for processing classes in the path.
  */
-public abstract class PathHandler {
-    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+public class PathHandler implements Closeable {
+    public static abstract class PathEntry implements Closeable {
+        private final ClassLoader loader = new PathEntryClassLoader(this::findByteCode);
+
+        /**
+         * returns bytecode for the class
+         * @param name binary name of the class
+         * @return bytecode of the class or null if handler does not have any
+         * code for this name
+         */
+        protected abstract byte[] findByteCode(String name);
+
+        protected final Path root;
+
+        /**
+         * @param root path entry root
+         * @throws NullPointerException if {@code root} is {@code null}
+         */
+        protected PathEntry(Path root) {
+            Objects.requireNonNull(root, "root can not be null");
+            this.root = root.normalize();
+        }
+
+        /**
+         * @return classloader which will be used to define classes
+         */
+        protected final ClassLoader loader() {
+            return loader;
+        }
+
+        /**
+         * @return stream of all classes in the specified path.
+         */
+        protected abstract Stream<String> classes();
+
+        /**
+         * @return string description of the specific path.
+         */
+        protected abstract String description();
+
+        public void close() { }
+
+    }
+
+    private static class PathEntryClassLoader extends java.lang.ClassLoader {
+        private final Function<String, byte[]> findByteCode;
+
+        private PathEntryClassLoader(Function<String, byte[]> findByteCode) {
+            this.findByteCode = findByteCode;
+        }
+
+        @Override
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            byte[] code = findByteCode.apply(name);
+            if (code == null) {
+                return super.findClass(name);
+            } else {
+                return defineClass(name, code, 0, code.length);
+            }
+        }
+    }
+
     private static final AtomicLong CLASS_COUNT = new AtomicLong(0L);
     private static volatile boolean CLASSES_LIMIT_REACHED = false;
     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}.
+     * Factory method. Constructs list of handlers for {@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) {
+    public static List<PathHandler> create(String path) {
         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);
+            return ClassPathJarInDirEntry.create(Paths.get(path));
         } else {
             path = path.isEmpty() ? "." : path;
             Path p = Paths.get(path);
+            PathEntry entry;
             if (isJarFile(p)) {
-                return new ClassPathJarEntry(p, executor);
+                entry = new ClassPathJarEntry(p);
             } else if (isListFile(p)) {
-                return new ClassesListInFile(p, executor);
+                entry = new ClassesListInFile(p);
             } else if (isJimageFile(p)) {
-                return new ClassPathJimageEntry(p, executor);
+                entry = new ClassPathJimageEntry(p);
             } else {
-                return new ClassPathDirEntry(p, executor);
+                entry = new ClassPathDirEntry(p);
             }
+            return Collections.singletonList(new PathHandler(entry));
         }
     }
 
@@ -117,35 +162,42 @@
         return false;
     }
 
+    private final PathEntry entry;
+    protected PathHandler(PathEntry entry) {
+        Objects.requireNonNull(entry);
+        this.entry = entry;
+    }
+
+
+    @Override
+    public void close() {
+        entry.close();
+    }
+
     /**
      * Processes all classes in the specified path.
+     * @param executor executor used for process task invocation
      */
-    public abstract void process();
+    public final void process(Executor executor) {
+        CompileTheWorld.OUT.println(entry.description());
+        entry.classes().forEach(s -> processClass(s, executor));
+    }
 
     /**
      * @return count of all classes in the specified path.
      */
-    public abstract long classCount();
+    public long classCount() {
+        return entry.classes().count();
+    }
 
-    /**
-     * 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 specified class.
      * @param name fully qualified name of class to process
      */
-    protected final void processClass(String name) {
+    protected final void processClass(String name, Executor executor) {
         Objects.requireNonNull(name);
-        if (CLASSES_LIMIT_REACHED) {
+        if (isFinished()) {
             return;
         }
         long id = CLASS_COUNT.incrementAndGet();
@@ -154,18 +206,16 @@
             return;
         }
         if (id >= Utils.COMPILE_THE_WORLD_START_AT) {
+            Class<?> aClass;
+            Thread.currentThread().setContextClassLoader(entry.loader());
             try {
-                Class<?> aClass = loader.loadClass(name);
-                if (!"sun.reflect.misc.Trampoline".equals(name)
-                        // workaround for JDK-8159155
-                        && !"sun.tools.jconsole.OutputViewer".equals(name)) {
-                    UNSAFE.ensureClassInitialized(aClass);
-                }
                 CompileTheWorld.OUT.printf("[%d]\t%s%n", id, name);
+                aClass = entry.loader().loadClass(name);
                 Compiler.compileClass(aClass, id, executor);
-            } catch (ClassNotFoundException e) {
-                CompileTheWorld.OUT.printf("Class %s loading failed : %s%n",
-                        name, e.getMessage());
+            } catch (Throwable e) {
+                CompileTheWorld.OUT.printf("[%d]\t%s\tWARNING skipped: %s%n",
+                        id, name, e);
+                e.printStackTrace(CompileTheWorld.ERR);
             }
         }
     }
--- a/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java	Tue Aug 08 11:44:23 2017 -0400
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java	Tue Aug 08 12:39:18 2017 -0700
@@ -217,4 +217,9 @@
         return filename.substring(nameStart, filename.length() - CLASSFILE_EXT.length())
                        .replace(nameSeparator, '.');
     }
+
+    public static String classNameToFileName(String classname) {
+        return classname.replace('.', '/')
+                        .concat(CLASSFILE_EXT);
+    }
 }