changeset 1811:c499401bc138

6612680: Remove classloader dependency on jkernel Summary: Add a new sun.misc.BootClassLoaderHook that DownloadManager will implement Reviewed-by: alanb, forax, igor
author mchung
date Mon, 05 Oct 2009 18:15:32 -0700
parents 54118c8e0ebe
children 572791538be5 bd68e9dd50c8
files make/sun/jkernel/Makefile src/share/classes/java/awt/color/ICC_Profile.java src/share/classes/java/lang/ClassLoader.java src/share/classes/java/util/zip/ZipEntry.java src/share/classes/sun/jkernel/DownloadManager.java src/share/classes/sun/misc/BootClassLoaderHook.java src/share/classes/sun/misc/Launcher.java src/share/classes/sun/misc/VM.java src/share/native/sun/misc/VM.c
diffstat 9 files changed, 260 insertions(+), 90 deletions(-) [+]
line wrap: on
line diff
--- a/make/sun/jkernel/Makefile	Mon Oct 05 23:42:48 2009 +0100
+++ b/make/sun/jkernel/Makefile	Mon Oct 05 18:15:32 2009 -0700
@@ -35,10 +35,6 @@
 #
 _OPT = $(CC_HIGHEST_OPT)
 
-# This re-directs all the class files to a separate location
-CLASSDESTDIR = $(TEMPDIR)/classes
-
-
 #
 # Java source files
 #
--- a/src/share/classes/java/awt/color/ICC_Profile.java	Mon Oct 05 23:42:48 2009 +0100
+++ b/src/share/classes/java/awt/color/ICC_Profile.java	Mon Oct 05 18:15:32 2009 -0700
@@ -58,6 +58,8 @@
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 
+import sun.misc.BootClassLoaderHook;
+
 /**
  * A representation of color profile data for device independent and
  * device dependent color spaces based on the International Color
@@ -1850,11 +1852,10 @@
                 f = new File(fullPath);
                 if (!f.isFile()) {
                     //make sure file was installed in the kernel mode
-                    try {
-                        //kernel uses platform independent paths =>
-                        //   should not use platform separator char
-                        sun.jkernel.DownloadManager.downloadFile("lib/cmm/"+fileName);
-                    } catch (IOException ioe) {}
+                    BootClassLoaderHook hook = BootClassLoaderHook.getHook();
+                    if (hook.getHook() != null) {
+                        hook.prefetchFile("lib/cmm/"+fileName);
+                    }
                 }
             }
 
--- a/src/share/classes/java/lang/ClassLoader.java	Mon Oct 05 23:42:48 2009 +0100
+++ b/src/share/classes/java/lang/ClassLoader.java	Mon Oct 05 18:15:32 2009 -0700
@@ -51,6 +51,7 @@
 import java.util.Hashtable;
 import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentHashMap;
+import sun.misc.BootClassLoaderHook;
 import sun.misc.ClassFileTransformer;
 import sun.misc.CompoundEnumeration;
 import sun.misc.Resource;
@@ -58,7 +59,6 @@
 import sun.misc.VM;
 import sun.reflect.Reflection;
 import sun.security.util.SecurityConstants;
-import sun.jkernel.DownloadManager;
 
 /**
  * A class loader is an object that is responsible for loading classes. The
@@ -1300,21 +1300,7 @@
      * Find resources from the VM's built-in classloader.
      */
     private static URL getBootstrapResource(String name) {
-        try {
-            // If this is a known JRE resource, ensure that its bundle is
-            // downloaded.  If it isn't known, we just ignore the download
-            // failure and check to see if we can find the resource anyway
-            // (which is possible if the boot class path has been modified).
-            if (sun.misc.VM.isBootedKernelVM()) {
-                sun.jkernel.DownloadManager.getBootClassPathEntryForResource(
-                    name);
-            }
-        } catch (NoClassDefFoundError e) {
-            // This happens while Java itself is being compiled; DownloadManager
-            // isn't accessible when this code is first invoked.  It isn't an
-            // issue, as if we can't find DownloadManager, we can safely assume
-            // that additional code is not available for download.
-        }
+        BootClassLoaderHook.preLoadResource(name);
         URLClassPath ucp = getBootstrapClassPath();
         Resource res = ucp.getResource(name);
         return res != null ? res.getURL() : null;
@@ -1831,24 +1817,7 @@
     // Invoked in the java.lang.Runtime class to implement load and loadLibrary.
     static void loadLibrary(Class fromClass, String name,
                             boolean isAbsolute) {
-        try {
-            if (VM.isBootedKernelVM() && !DownloadManager.isJREComplete() &&
-                    !DownloadManager.isCurrentThreadDownloading()) {
-                DownloadManager.downloadFile("bin/" +
-                    System.mapLibraryName(name));
-                // it doesn't matter if the downloadFile call returns false --
-                // it probably just means that this is a user library, as
-                // opposed to a JRE library
-            }
-        } catch (IOException e) {
-            throw new UnsatisfiedLinkError("Error downloading library " +
-                                                name + ": " + e);
-        } catch (NoClassDefFoundError e) {
-            // This happens while Java itself is being compiled; DownloadManager
-            // isn't accessible when this code is first invoked.  It isn't an
-            // issue, as if we can't find DownloadManager, we can safely assume
-            // that additional code is not available for download.
-        }
+        BootClassLoaderHook.preLoadLibrary(name);
         ClassLoader loader =
             (fromClass == null) ? null : fromClass.getClassLoader();
         if (sys_paths == null) {
--- a/src/share/classes/java/util/zip/ZipEntry.java	Mon Oct 05 23:42:48 2009 +0100
+++ b/src/share/classes/java/util/zip/ZipEntry.java	Mon Oct 05 18:15:32 2009 -0700
@@ -26,6 +26,7 @@
 package java.util.zip;
 
 import java.util.Date;
+import sun.misc.BootClassLoaderHook;
 
 /**
  * This class is used to represent a ZIP file entry.
@@ -109,12 +110,16 @@
      * @see #getTime()
      */
     public void setTime(long time) {
-        // fix for bug 6625963: we bypass time calculations while Kernel is
-        // downloading bundles, since they aren't necessary and would cause
-        // the Kernel core to depend upon the (very large) time zone data
-        if (sun.misc.VM.isBootedKernelVM() &&
-            sun.jkernel.DownloadManager.isCurrentThreadDownloading()) {
-            this.time = sun.jkernel.DownloadManager.KERNEL_STATIC_MODTIME;
+        // Same value as defined in sun.jkernel.DownloadManager.KERNEL_STATIC_MODTIME
+        // to avoid direct reference to DownoadManager class.  Need to revisit
+        // if this is needed any more (see comment in the DownloadManager class)
+        final int KERNEL_STATIC_MODTIME = 10000000;
+        BootClassLoaderHook hook = BootClassLoaderHook.getHook();
+        if (hook != null && hook.isCurrentThreadPrefetching()) {
+            // fix for bug 6625963: we bypass time calculations while Kernel is
+            // downloading bundles, since they aren't necessary and would cause
+            // the Kernel core to depend upon the (very large) time zone data
+            this.time = KERNEL_STATIC_MODTIME;
         } else {
             this.time = javaToDosTime(time);
         }
--- a/src/share/classes/sun/jkernel/DownloadManager.java	Mon Oct 05 23:42:48 2009 +0100
+++ b/src/share/classes/sun/jkernel/DownloadManager.java	Mon Oct 05 18:15:32 2009 -0700
@@ -31,6 +31,7 @@
 import java.util.jar.*;
 import java.util.zip.*;
 import sun.misc.Launcher;
+import sun.misc.BootClassLoaderHook;
 
 /**
  * Handles the downloading of additional JRE components.  The bootstrap class
@@ -39,7 +40,7 @@
  *
  *@author Ethan Nicholas
  */
-public class DownloadManager {
+public class DownloadManager extends BootClassLoaderHook {
     public static final String KERNEL_DOWNLOAD_URL_PROPERTY =
             "kernel.download.url";
     public static final String KERNEL_DOWNLOAD_ENABLED_PROPERTY =
@@ -1023,7 +1024,8 @@
 
     /**
      * Returns <code>true</code> if the current thread is in the process of
-     * downloading a bundle.  This is called by ClassLoader.loadLibrary(), so
+     * downloading a bundle.  This is called by DownloadManager.loadLibrary()
+     * that is called by System.loadLibrary(), so
      * that when we run into a library required by the download process itself,
      * we don't call back into DownloadManager in an attempt to download it
      * (which would lead to infinite recursion).
@@ -1614,6 +1616,77 @@
 
     static native int getCurrentProcessId();
 
+    private DownloadManager() {
+    }
+
+    // Invoked by jkernel VM after the VM is initialized
+    static void setBootClassLoaderHook() {
+        if (!isJREComplete()) {
+            sun.misc.BootClassLoaderHook.setHook(new DownloadManager());
+        }
+    }
+
+    // Implementation of the BootClassLoaderHook interface
+    public String loadBootstrapClass(String name) {
+        // Check for download before we look for it.  If
+        // DownloadManager ends up downloading it, it will add it to
+        // our search path before we proceed to the findClass().
+        return DownloadManager.getBootClassPathEntryForClass(name);
+    }
+
+    public boolean loadLibrary(String name) {
+       try {
+            if (!DownloadManager.isJREComplete() &&
+                    !DownloadManager.isCurrentThreadDownloading()) {
+                return DownloadManager.downloadFile("bin/" +
+                    System.mapLibraryName(name));
+                // it doesn't matter if the downloadFile call returns false --
+                // it probably just means that this is a user library, as
+                // opposed to a JRE library
+            }
+        } catch (IOException e) {
+            throw new UnsatisfiedLinkError("Error downloading library " +
+                                                name + ": " + e);
+        } catch (NoClassDefFoundError e) {
+            // This happens while Java itself is being compiled; DownloadManager
+            // isn't accessible when this code is first invoked.  It isn't an
+            // issue, as if we can't find DownloadManager, we can safely assume
+            // that additional code is not available for download.
+        }
+        return false;
+    }
+
+    public boolean prefetchFile(String name) {
+        try {
+            return sun.jkernel.DownloadManager.downloadFile(name);
+        } catch (IOException ioe) {
+            return false;
+        }
+    }
+
+    public String getBootstrapResource(String name) {
+        try {
+            // If this is a known JRE resource, ensure that its bundle is
+            // downloaded.  If it isn't known, we just ignore the download
+            // failure and check to see if we can find the resource anyway
+            // (which is possible if the boot class path has been modified).
+            return DownloadManager.getBootClassPathEntryForResource(name);
+        } catch (NoClassDefFoundError e) {
+            // This happens while Java itself is being compiled; DownloadManager
+            // isn't accessible when this code is first invoked.  It isn't an
+            // issue, as if we can't find DownloadManager, we can safely assume
+            // that additional code is not available for download.
+            return null;
+        }
+    }
+
+    public File[] getAdditionalBootstrapPaths() {
+        return DownloadManager.getAdditionalBootStrapPaths();
+    }
+
+    public boolean isCurrentThreadPrefetching() {
+        return DownloadManager.isCurrentThreadDownloading();
+    }
 
     public static void main(String[] arg) throws Exception {
         AccessController.checkPermission(new AllPermission());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/misc/BootClassLoaderHook.java	Mon Oct 05 18:15:32 2009 -0700
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.misc;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * BootClassLoaderHook defines an interface for a hook to inject
+ * into the bootstrap class loader.
+ *
+ * In jkernel build, the sun.jkernel.DownloadManager is set as
+ * a BootClassLoaderHook by the jkernel VM after the VM is initialized.
+ *
+ * In other JDK builds, no hook is set.
+ */
+public abstract class BootClassLoaderHook {
+    private static BootClassLoaderHook bootLoaderHook = null;
+    public static synchronized BootClassLoaderHook getHook() {
+        return bootLoaderHook;
+    }
+
+    public static synchronized void setHook(BootClassLoaderHook hook) {
+        if (!VM.isBooted()) {
+            throw new InternalError("hook can only be set after VM is booted");
+        }
+        if (bootLoaderHook != null) {
+            throw new InternalError("hook should not be reinitialized");
+        }
+        bootLoaderHook = hook;
+    }
+
+    protected BootClassLoaderHook() {
+    }
+
+    /**
+     * A method to be invoked before a class loader loads
+     * a bootstrap class.
+     *
+     * @param classname the binary name of the class
+     */
+    public static void preLoadClass(String classname) {
+        BootClassLoaderHook hook = getHook();
+        if (hook != null) {
+            hook.loadBootstrapClass(classname);
+        }
+    }
+
+    /**
+     * A method to be invoked before a class loader loads
+     * a resource.
+     *
+     * @param resourcename the resource name
+     */
+    public static void preLoadResource(String resourcename) {
+        BootClassLoaderHook hook = getHook();
+        if (hook != null) {
+            hook.getBootstrapResource(resourcename);
+        }
+    }
+
+    /**
+     * A method to be invoked before a library is loaded.
+     *
+     * @param libname the name of the library
+     */
+    public static void preLoadLibrary(String libname) {
+        BootClassLoaderHook hook = getHook();
+        if (hook != null) {
+            hook.loadLibrary(libname);
+        }
+    }
+
+    private static final File[] EMPTY_FILE_ARRAY = new File[0];
+
+    /**
+     * Returns bootstrap class paths added by the hook.
+     */
+    public static File[] getBootstrapPaths() {
+        BootClassLoaderHook hook = getHook();
+        if (hook != null) {
+            return hook.getBootstrapPaths();
+        } else {
+            return EMPTY_FILE_ARRAY;
+        }
+    }
+
+    /**
+     * Returns a pathname of a JAR or class that the hook loads
+     * per this loadClass request; or null.
+     *
+     * @param classname the binary name of the class
+     */
+    public abstract String loadBootstrapClass(String className);
+
+    /**
+     * Returns a pathname of a resource file that the hook loads
+     * per this getResource request; or null.
+     *
+     * @param resourceName the resource name
+     */
+    public abstract String getBootstrapResource(String resourceName);
+
+    /**
+     * Returns true if the hook successfully performs an operation per
+     * this loadLibrary request; or false if it fails.
+     *
+     * @param libname the name of the library
+     */
+    public abstract boolean loadLibrary(String libname);
+
+    /**
+     * Returns additional boot class paths added by the hook that
+     * should be searched by the boot class loader.
+     */
+    public abstract File[] getAdditionalBootstrapPaths();
+
+    /**
+     * Returns true if the current thread is in the process of doing
+     * a prefetching operation.
+     */
+    public abstract boolean isCurrentThreadPrefetching();
+
+    /**
+     * Returns true if the hook successfully prefetches the specified file.
+     *
+     * @param name a platform independent pathname
+     */
+    public abstract boolean prefetchFile(String name);
+}
--- a/src/share/classes/sun/misc/Launcher.java	Mon Oct 05 23:42:48 2009 +0100
+++ b/src/share/classes/sun/misc/Launcher.java	Mon Oct 05 18:15:32 2009 -0700
@@ -50,8 +50,6 @@
 import sun.security.action.GetPropertyAction;
 import sun.security.util.SecurityConstants;
 import sun.net.www.ParseUtil;
-import sun.jkernel.Bundle;
-import sun.jkernel.DownloadManager;
 
 /**
  * This class is used by the system to launch the main application.
@@ -248,12 +246,7 @@
         }
 
         protected Class findClass(String name) throws ClassNotFoundException {
-            if (VM.isBootedKernelVM()) {
-                // Check for download before we look for it.  If
-                // DownloadManager ends up downloading it, it will add it to
-                // our search path before we proceed to the findClass().
-                DownloadManager.getBootClassPathEntryForClass(name);
-            }
+            BootClassLoaderHook.preLoadClass(name);
             return super.findClass(name);
         }
 
@@ -321,9 +314,7 @@
         public Class loadClass(String name, boolean resolve)
             throws ClassNotFoundException
         {
-            if (VM.isBootedKernelVM()) {
-                DownloadManager.getBootClassPathEntryForClass(name);
-            }
+            BootClassLoaderHook.preLoadClass(name);
             int i = name.lastIndexOf('.');
             if (i != -1) {
                 SecurityManager sm = System.getSecurityManager();
@@ -421,19 +412,17 @@
             }
 
             bootstrapClassPath = new URLClassPath(urls, factory);
-            if (VM.isBootedKernelVM()) {
-                final File[] additionalBootStrapPaths =
-                    DownloadManager.getAdditionalBootStrapPaths();
-                AccessController.doPrivileged(new PrivilegedAction() {
-                    public Object run() {
-                        for (int i=0; i<additionalBootStrapPaths.length; i++) {
-                            bootstrapClassPath.addURL(
-                                getFileURL(additionalBootStrapPaths[i]));
-                        }
-                        return null;
+            final File[] additionalBootStrapPaths =
+                BootClassLoaderHook.getBootstrapPaths();
+            AccessController.doPrivileged(new PrivilegedAction() {
+                public Object run() {
+                    for (int i=0; i<additionalBootStrapPaths.length; i++) {
+                        bootstrapClassPath.addURL(
+                            getFileURL(additionalBootStrapPaths[i]));
                     }
-                });
-            }
+                    return null;
+                }
+            });
         }
         return bootstrapClassPath;
     }
--- a/src/share/classes/sun/misc/VM.java	Mon Oct 05 23:42:48 2009 +0100
+++ b/src/share/classes/sun/misc/VM.java	Mon Oct 05 18:15:32 2009 -0700
@@ -346,11 +346,6 @@
     private native static void getThreadStateValues(int[][] vmThreadStateValues,
                                                     String[][] vmThreadStateNames);
 
-    private static boolean kernelVM;
-    public static boolean isBootedKernelVM() {
-        return booted && kernelVM;
-    }
-
     static {
         initialize();
     }
--- a/src/share/native/sun/misc/VM.c	Mon Oct 05 23:42:48 2009 +0100
+++ b/src/share/native/sun/misc/VM.c	Mon Oct 05 18:15:32 2009 -0700
@@ -131,17 +131,6 @@
 
         /* obtain the JVM version info */
         (*func_p)(env, &info, sizeof(info));
-
-        if (info.is_kernel_jvm == 1) {
-            /* set the static field VM.kernelVM to true for kernel VM */
-            fid = (*env)->GetStaticFieldID(env, cls, "kernelVM", "Z");
-            if (fid != 0) {
-                (*env)->SetStaticBooleanField(env, cls, fid, info.is_kernel_jvm);
-            } else {
-                sprintf(errmsg, "Static kernelVM boolean field not found");
-                JNU_ThrowInternalError(env, errmsg);
-            }
-        }
     }
 }