changeset 22797:9329eb8678f7

fixed CompileTheWorld functionality for jdk9
author Doug Simon <doug.simon@oracle.com>
date Mon, 12 Oct 2015 01:45:13 +0200
parents ed5fd346003c
children 509a9eadd120
files graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorldOptions.java mx.graal/mx_graal.py
diffstat 4 files changed, 185 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java	Sun Oct 11 14:50:24 2015 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java	Mon Oct 12 01:45:13 2015 +0200
@@ -42,10 +42,8 @@
     public void testRtJar() throws Throwable {
         boolean originalSetting = ExitVMOnException.getValue();
         // Compile a couple classes in rt.jar
-        String file = System.getProperty("java.home") + "/lib/rt.jar";
         HotSpotJVMCIRuntimeProvider runtime = HotSpotJVMCIRuntime.runtime();
-        new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), file, new Config(null), 1, 5, null, null, false).compile();
+        new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), CompileTheWorld.SUN_BOOT_CLASS_PATH, new Config(null), 1, 5, null, null, false).compile();
         assert ExitVMOnException.getValue() == originalSetting;
     }
-
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Sun Oct 11 14:50:24 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Mon Oct 12 01:45:13 2015 +0200
@@ -34,6 +34,7 @@
 import static jdk.vm.ci.compiler.Compiler.PrintStackTraceOnException;
 import static jdk.vm.ci.hotspot.HotSpotVMConfig.config;
 
+import java.io.Closeable;
 import java.io.File;
 import java.io.IOException;
 import java.lang.annotation.Annotation;
@@ -42,9 +43,16 @@
 import java.lang.reflect.Modifier;
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.List;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -87,8 +95,11 @@
  */
 public final class CompileTheWorld {
 
+    private static final String JAVA_VERSION = System.getProperty("java.specification.version");
+
     /**
-     * Magic token to trigger reading files from the boot class path.
+     * Magic token to trigger reading files from {@code rt.jar} if {@link #JAVA_VERSION} denotes a
+     * JDK earlier than 9 otherwise from {@code java.base} module.
      */
     public static final String SUN_BOOT_CLASS_PATH = "sun.boot.class.path";
 
@@ -144,20 +155,23 @@
     private final HotSpotGraalCompiler compiler;
 
     /**
-     * List of Zip/Jar files to compile (see {@link CompileTheWorldOptions#CompileTheWorldClasspath}
-     * ).
+     * Class path denoting classes to compile.
+     *
+     * @see CompileTheWorldOptions#CompileTheWorldClasspath
      */
-    private final String files;
+    private final String inputClassPath;
 
     /**
-     * Class index to start compilation at (see
-     * {@link CompileTheWorldOptions#CompileTheWorldStartAt}).
+     * Class index to start compilation at.
+     *
+     * @see CompileTheWorldOptions#CompileTheWorldStartAt
      */
     private final int startAt;
 
     /**
-     * Class index to stop compilation at (see {@link CompileTheWorldOptions#CompileTheWorldStopAt}
-     * ).
+     * Class index to stop compilation at.
+     *
+     * @see CompileTheWorldOptions#CompileTheWorldStopAt
      */
     private final int stopAt;
 
@@ -196,7 +210,7 @@
                     String excludeMethodFilters, boolean verbose) {
         this.jvmciRuntime = jvmciRuntime;
         this.compiler = compiler;
-        this.files = files;
+        this.inputClassPath = files;
         this.startAt = startAt;
         this.stopAt = stopAt;
         this.methodFilters = methodFilters == null || methodFilters.isEmpty() ? null : MethodFilter.parse(methodFilters);
@@ -219,36 +233,35 @@
     }
 
     /**
-     * Compiles all methods in all classes in the Zip/Jar archive files in
-     * {@link CompileTheWorldOptions#CompileTheWorldClasspath}. If
-     * {@link CompileTheWorldOptions#CompileTheWorldClasspath} contains the magic token
-     * {@link #SUN_BOOT_CLASS_PATH} passed up from HotSpot we take the files from the boot class
-     * path.
+     * Compiles all methods in all classes in {@link #inputClassPath}. If {@link #inputClassPath}
+     * equals {@link #SUN_BOOT_CLASS_PATH} the boot class path is used.
      */
     public void compile() throws Throwable {
         // By default only report statistics for the CTW threads themselves
         if (GraalDebugConfig.Options.DebugValueThreadFilter.hasDefaultValue()) {
             GraalDebugConfig.Options.DebugValueThreadFilter.setValue("^CompileTheWorld");
         }
-
-        if (SUN_BOOT_CLASS_PATH.equals(files)) {
+        if (SUN_BOOT_CLASS_PATH.equals(inputClassPath)) {
             final String[] entries = System.getProperty(SUN_BOOT_CLASS_PATH).split(File.pathSeparator);
-            String bcpFiles = "";
-            for (int i = 0; i < entries.length; i++) {
-                final String entry = entries[i];
-
-                // We stop at rt.jar, unless it is the first boot class path entry.
-                if (entry.endsWith("rt.jar") && (i > 0)) {
-                    break;
+            String bcpEntry = null;
+            boolean useRtJar = JAVA_VERSION.compareTo("1.9") < 0;
+            for (int i = 0; i < entries.length && bcpEntry == null; i++) {
+                String entry = entries[i];
+                File entryFile = new File(entry);
+                if (useRtJar) {
+                    // We stop at rt.jar, unless it is the first boot class path entry.
+                    if (entryFile.getName().endsWith("rt.jar") && entryFile.isFile()) {
+                        bcpEntry = entry;
+                    }
+                } else {
+                    if (entryFile.getName().endsWith("java.base") && entryFile.isDirectory()) {
+                        bcpEntry = entry;
+                    }
                 }
-                if (i > 0) {
-                    bcpFiles += File.pathSeparator;
-                }
-                bcpFiles += entry;
             }
-            compile(bcpFiles);
+            compile(bcpEntry);
         } else {
-            compile(files);
+            compile(inputClassPath);
         }
     }
 
@@ -270,15 +283,111 @@
     private static void dummy() {
     }
 
+    abstract static class ClassPathEntry implements Closeable {
+        final String name;
+
+        public ClassPathEntry(String name) {
+            this.name = name;
+        }
+
+        public abstract ClassLoader createClassLoader() throws IOException;
+
+        public abstract List<String> getClassNames() throws IOException;
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+
+    static class DirClassPathEntry extends ClassPathEntry {
+
+        private final File dir;
+
+        public DirClassPathEntry(String name) {
+            super(name);
+            dir = new File(name);
+            assert dir.isDirectory();
+        }
+
+        @Override
+        public ClassLoader createClassLoader() throws IOException {
+            URL url = dir.toURI().toURL();
+            return new URLClassLoader(new URL[]{url});
+        }
+
+        @Override
+        public List<String> getClassNames() throws IOException {
+            List<String> classNames = new ArrayList<>();
+            String root = dir.getPath();
+            SimpleFileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                    if (attrs.isRegularFile()) {
+                        File path = file.toFile();
+                        if (path.getName().endsWith(".class")) {
+                            String pathString = path.getPath();
+                            assert pathString.startsWith(root);
+                            String classFile = pathString.substring(root.length() + 1);
+                            String className = classFile.replace(File.separatorChar, '.');
+                            classNames.add(className.replace('/', '.').substring(0, className.length() - ".class".length()));
+                        }
+                    }
+                    return super.visitFile(file, attrs);
+                }
+            };
+            Files.walkFileTree(dir.toPath(), visitor);
+            return classNames;
+        }
+
+        public void close() throws IOException {
+        }
+    }
+
+    static class JarClassPathEntry extends ClassPathEntry {
+
+        private final JarFile jarFile;
+
+        public JarClassPathEntry(String name) throws IOException {
+            super(name);
+            jarFile = new JarFile(name);
+        }
+
+        @Override
+        public ClassLoader createClassLoader() throws IOException {
+            URL url = new URL("jar", "", "file:" + name + "!/");
+            return new URLClassLoader(new URL[]{url});
+        }
+
+        @Override
+        public List<String> getClassNames() throws IOException {
+            Enumeration<JarEntry> e = jarFile.entries();
+            List<String> classNames = new ArrayList<>(jarFile.size());
+            while (e.hasMoreElements()) {
+                JarEntry je = e.nextElement();
+                if (je.isDirectory() || !je.getName().endsWith(".class")) {
+                    continue;
+                }
+                String className = je.getName().substring(0, je.getName().length() - ".class".length());
+                classNames.add(className.replace('/', '.'));
+            }
+            return classNames;
+        }
+
+        public void close() throws IOException {
+            jarFile.close();
+        }
+    }
+
     /**
-     * Compiles all methods in all classes in the Zip/Jar files passed.
+     * Compiles all methods in all classes in a given class path.
      *
-     * @param fileList {@link File#pathSeparator} separated list of Zip/Jar files to compile
+     * @param classPath class path denoting classes to compile
      * @throws IOException
      */
     @SuppressWarnings("try")
-    private void compile(String fileList) throws IOException {
-        final String[] entries = fileList.split(File.pathSeparator);
+    private void compile(String classPath) throws IOException {
+        final String[] entries = classPath.split(File.pathSeparator);
         long start = System.currentTimeMillis();
 
         CompilerThreadFactory factory = new CompilerThreadFactory("CompileTheWorld", new DebugConfigAccess() {
@@ -291,7 +400,8 @@
         });
 
         try {
-            // compile dummy method to get compiler initilized outside of the config debug override.
+            // compile dummy method to get compiler initialized outside of the
+            // config debug override.
             HotSpotResolvedJavaMethod dummyMethod = (HotSpotResolvedJavaMethod) JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(
                             CompileTheWorld.class.getDeclaredMethod("dummy"));
             int entryBCI = Compiler.INVOCATION_ENTRY_BCI;
@@ -320,11 +430,16 @@
             for (int i = 0; i < entries.length; i++) {
                 final String entry = entries[i];
 
-                // For now we only compile all methods in all classes in zip/jar files.
+                ClassPathEntry cpe;
                 if (!entry.endsWith(".zip") && !entry.endsWith(".jar")) {
-                    println("CompileTheWorld : Skipped classes in " + entry);
-                    println();
-                    continue;
+                    if (!new File(entry).isDirectory()) {
+                        println("CompileTheWorld : Skipped classes in " + entry);
+                        println();
+                        continue;
+                    }
+                    cpe = new DirClassPathEntry(entry);
+                } else {
+                    cpe = new JarClassPathEntry(entry);
                 }
 
                 if (methodFilters == null || methodFilters.length == 0) {
@@ -339,41 +454,31 @@
                 }
                 println();
 
-                URL url = new URL("jar", "", "file:" + entry + "!/");
-                ClassLoader loader = new URLClassLoader(new URL[]{url});
-
-                JarFile jarFile = new JarFile(entry);
-                Enumeration<JarEntry> e = jarFile.entries();
+                ClassLoader loader = cpe.createClassLoader();
 
-                while (e.hasMoreElements()) {
-                    JarEntry je = e.nextElement();
-                    if (je.isDirectory() || !je.getName().endsWith(".class")) {
-                        continue;
-                    }
+                for (String className : cpe.getClassNames()) {
 
                     // Are we done?
                     if (classFileCounter >= stopAt) {
                         break;
                     }
 
-                    String className = je.getName().substring(0, je.getName().length() - ".class".length());
-                    String dottedClassName = className.replace('/', '.');
                     classFileCounter++;
 
-                    if (methodFilters != null && !MethodFilter.matchesClassName(methodFilters, dottedClassName)) {
+                    if (methodFilters != null && !MethodFilter.matchesClassName(methodFilters, className)) {
                         continue;
                     }
-                    if (excludeMethodFilters != null && MethodFilter.matchesClassName(excludeMethodFilters, dottedClassName)) {
+                    if (excludeMethodFilters != null && MethodFilter.matchesClassName(excludeMethodFilters, className)) {
                         continue;
                     }
 
-                    if (dottedClassName.startsWith("jdk.management.") || dottedClassName.startsWith("jdk.internal.cmm.*")) {
+                    if (className.startsWith("jdk.management.") || className.startsWith("jdk.internal.cmm.*")) {
                         continue;
                     }
 
                     try {
                         // Load and initialize class
-                        Class<?> javaClass = Class.forName(dottedClassName, true, loader);
+                        Class<?> javaClass = Class.forName(className, true, loader);
 
                         // Pre-load all classes in the constant pool.
                         try {
@@ -411,7 +516,7 @@
                         t.printStackTrace();
                     }
                 }
-                jarFile.close();
+                cpe.close();
             }
         }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorldOptions.java	Sun Oct 11 14:50:24 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorldOptions.java	Mon Oct 12 01:45:13 2015 +0200
@@ -35,7 +35,7 @@
  */
 public class CompileTheWorldOptions {
     // @formatter:off
-    @Option(help = "Compile all methods in all classes on given class path", type = OptionType.Debug)
+    @Option(help = "Class path denoting methods to compile", type = OptionType.Debug)
     public static final OptionValue<String> CompileTheWorldClasspath = new OptionValue<>(CompileTheWorld.SUN_BOOT_CLASS_PATH);
     @Option(help = "Verbose CompileTheWorld operation", type = OptionType.Debug)
     public static final OptionValue<Boolean> CompileTheWorldVerbose = new OptionValue<>(true);
--- a/mx.graal/mx_graal.py	Sun Oct 11 14:50:24 2015 +0200
+++ b/mx.graal/mx_graal.py	Mon Oct 12 01:45:13 2015 +0200
@@ -33,13 +33,13 @@
 import re
 
 import mx
-from mx_jvmci import JvmciJDKDeployedDist, add_bootclasspath_prepend, buildvms
+from mx_jvmci import JvmciJDKDeployedDist, add_bootclasspath_prepend, buildvms, get_jvmci_jdk, get_vm, run_vm, VM
 from mx_jvmci import jdkDeployedDists #pylint: disable=unused-import
 from mx_gate import Task
 from sanitycheck import _noneAsEmptyList
 
 try:
-    from mx_jvmci import run_vm, VM, get_vm, isJVMCIEnabled, relativeVmLibDirInJdk, get_jvmci_jdk, get_jvmci_jdk_dir #pylint: disable=no-name-in-module
+    from mx_jvmci import isJVMCIEnabled, relativeVmLibDirInJdk, get_jvmci_jdk_dir #pylint: disable=no-name-in-module
 except ImportError:
     pass
 from mx_unittest import unittest
@@ -204,7 +204,7 @@
 
     parser = ArgumentParser(prog='mx ctw')
     parser.add_argument('--ctwopts', action='store', help='space separated JVMCI options used for CTW compilations (default: --ctwopts="' + defaultCtwopts + '")', default=defaultCtwopts, metavar='<options>')
-    parser.add_argument('--jar', action='store', help='jar of classes to compiled instead of rt.jar', metavar='<path>')
+    parser.add_argument('--cp', '--jar', action='store', help='jar or class path denoting classes to compile', metavar='<path>')
 
     args, vmargs = parser.parse_known_args(args)
 
@@ -213,22 +213,33 @@
         # when they are collated in the "jvmci.options" system property
         vmargs.append('-G:CompileTheWorldConfig=' + re.sub(r'\s+', '#', args.ctwopts))
 
-    if args.jar:
-        jar = os.path.abspath(args.jar)
+    if args.cp:
+        cp = os.path.abspath(args.cp)
     else:
-        jar = join(get_jvmci_jdk_dir(deployDists=False), 'jre', 'lib', 'rt.jar')
+        if get_jvmci_jdk().javaCompliance < '9':
+            cp = join(get_jvmci_jdk().home, 'jre', 'lib', 'rt.jar')
+        else:
+            cp = join(get_jvmci_jdk().home, 'modules', 'java.base')
         vmargs.append('-G:CompileTheWorldExcludeMethodFilter=sun.awt.X11.*.*')
 
     # suppress menubar and dock when running on Mac; exclude x11 classes as they may cause vm crashes (on Solaris)
     vmargs = ['-Djava.awt.headless=true'] + vmargs
 
-    vm_ = get_vm()
-    if isJVMCIEnabled(vm_):
-        if vm_ == 'jvmci':
-            vmargs += ['-XX:+BootstrapJVMCI']
-        vmargs += ['-G:CompileTheWorldClasspath=' + jar, '-XX:-UseJVMCIClassLoader', 'com.oracle.graal.hotspot.CompileTheWorld']
+    vm = get_vm()
+    if isinstance(vm, VM):
+        if vm.jvmciMode == 'disabled':
+            vmargs += ['-XX:+CompileTheWorld', '-Xbootclasspath/p:' + cp]
+        else:
+            if vm.jvmciMode == 'jit':
+                vmargs += ['-XX:+BootstrapJVMCI']
+            vmargs += ['-G:CompileTheWorldClasspath=' + cp, 'com.oracle.graal.hotspot.CompileTheWorld']
     else:
-        vmargs += ['-XX:+CompileTheWorld', '-Xbootclasspath/p:' + jar]
+        if isJVMCIEnabled(vm):
+            if vm == 'jvmci':
+                vmargs += ['-XX:+BootstrapJVMCI']
+            vmargs += ['-G:CompileTheWorldClasspath=' + cp, '-XX:-UseJVMCIClassLoader', 'com.oracle.graal.hotspot.CompileTheWorld']
+        else:
+            vmargs += ['-XX:+CompileTheWorld', '-Xbootclasspath/p:' + cp]
 
     run_vm(vmargs + _noneAsEmptyList(extraVMarguments))