From ca754cfeb7497ba6740cb8a4c1a82e0bbaea2d94 Mon Sep 17 00:00:00 2001 From: mchung Date: Mon, 5 Oct 2009 18:15:32 -0700 Subject: [PATCH] 6612680: Remove classloader dependency on jkernel Summary: Add a new sun.misc.BootClassLoaderHook that DownloadManager will implement Reviewed-by: alanb, forax, igor --- make/sun/jkernel/Makefile | 4 - .../classes/java/awt/color/ICC_Profile.java | 11 +- src/share/classes/java/lang/ClassLoader.java | 37 +---- src/share/classes/java/util/zip/ZipEntry.java | 17 +- .../classes/sun/jkernel/DownloadManager.java | 77 ++++++++- .../classes/sun/misc/BootClassLoaderHook.java | 153 ++++++++++++++++++ src/share/classes/sun/misc/Launcher.java | 35 ++-- src/share/classes/sun/misc/VM.java | 5 - src/share/native/sun/misc/VM.c | 11 -- 9 files changed, 260 insertions(+), 90 deletions(-) create mode 100644 src/share/classes/sun/misc/BootClassLoaderHook.java diff --git a/make/sun/jkernel/Makefile b/make/sun/jkernel/Makefile index 047efeae5..97f2f38ac 100644 --- a/make/sun/jkernel/Makefile +++ b/make/sun/jkernel/Makefile @@ -35,10 +35,6 @@ include $(BUILDDIR)/common/Defs.gmk # _OPT = $(CC_HIGHEST_OPT) -# This re-directs all the class files to a separate location -CLASSDESTDIR = $(TEMPDIR)/classes - - # # Java source files # diff --git a/src/share/classes/java/awt/color/ICC_Profile.java b/src/share/classes/java/awt/color/ICC_Profile.java index 44f285087..78ba43d4b 100644 --- a/src/share/classes/java/awt/color/ICC_Profile.java +++ b/src/share/classes/java/awt/color/ICC_Profile.java @@ -58,6 +58,8 @@ import java.util.StringTokenizer; 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 @@ public class ICC_Profile implements Serializable { 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); + } } } diff --git a/src/share/classes/java/lang/ClassLoader.java b/src/share/classes/java/lang/ClassLoader.java index 9fec9b570..bd59d9566 100644 --- a/src/share/classes/java/lang/ClassLoader.java +++ b/src/share/classes/java/lang/ClassLoader.java @@ -51,6 +51,7 @@ import java.util.Vector; 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.URLClassPath; 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 @@ public abstract class ClassLoader { * 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 @@ public abstract class ClassLoader { // 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) { diff --git a/src/share/classes/java/util/zip/ZipEntry.java b/src/share/classes/java/util/zip/ZipEntry.java index 0e2ddaec3..8da5a4f54 100644 --- a/src/share/classes/java/util/zip/ZipEntry.java +++ b/src/share/classes/java/util/zip/ZipEntry.java @@ -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 @@ class ZipEntry implements ZipConstants, Cloneable { * @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); } diff --git a/src/share/classes/sun/jkernel/DownloadManager.java b/src/share/classes/sun/jkernel/DownloadManager.java index e945380eb..b93f51c68 100644 --- a/src/share/classes/sun/jkernel/DownloadManager.java +++ b/src/share/classes/sun/jkernel/DownloadManager.java @@ -31,6 +31,7 @@ import java.util.concurrent.*; 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 @@ import sun.misc.Launcher; * *@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 @@ public class DownloadManager { /** * Returns true 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 @@ public class DownloadManager { 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()); diff --git a/src/share/classes/sun/misc/BootClassLoaderHook.java b/src/share/classes/sun/misc/BootClassLoaderHook.java new file mode 100644 index 000000000..28c187ead --- /dev/null +++ b/src/share/classes/sun/misc/BootClassLoaderHook.java @@ -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); +} diff --git a/src/share/classes/sun/misc/Launcher.java b/src/share/classes/sun/misc/Launcher.java index 2793f14f0..5ebd10fbd 100644 --- a/src/share/classes/sun/misc/Launcher.java +++ b/src/share/classes/sun/misc/Launcher.java @@ -50,8 +50,6 @@ import java.security.CodeSource; 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 @@ public class Launcher { } 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 Launcher { 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 @@ public class Launcher { } bootstrapClassPath = new URLClassPath(urls, factory); - if (VM.isBootedKernelVM()) { - final File[] additionalBootStrapPaths = - DownloadManager.getAdditionalBootStrapPaths(); - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - for (int i=0; iGetStaticFieldID(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); - } - } } } -- GitLab