--- old/src/java.base/share/classes/java/lang/ClassLoader.java 2020-03-09 16:05:50.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/ClassLoader.java 2020-03-09 16:05:50.000000000 -0700 @@ -39,11 +39,8 @@ import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.security.cert.Certificate; -import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; -import java.util.Deque; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; @@ -59,13 +56,14 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; -import jdk.internal.loader.BuiltinClassLoader; -import jdk.internal.perf.PerfCounter; import jdk.internal.loader.BootLoader; +import jdk.internal.loader.BuiltinClassLoader; import jdk.internal.loader.ClassLoaders; +import jdk.internal.loader.NativeLibrary; +import jdk.internal.loader.NativeLibraries; +import jdk.internal.perf.PerfCounter; import jdk.internal.misc.Unsafe; import jdk.internal.misc.VM; -import jdk.internal.ref.CleanerFactory; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import jdk.internal.util.StaticProperty; @@ -2377,328 +2375,64 @@ return null; } - /** - * The inner class NativeLibrary denotes a loaded native library instance. - * Every classloader contains a vector of loaded native libraries in the - * private field {@code nativeLibraries}. The native libraries loaded - * into the system are entered into the {@code systemNativeLibraries} - * vector. - * - *

Every native library requires a particular version of JNI. This is - * denoted by the private {@code jniVersion} field. This field is set by - * the VM when it loads the library, and used by the VM to pass the correct - * version of JNI to the native methods.

- * - * @see ClassLoader - * @since 1.2 - */ - static class NativeLibrary { - // the class from which the library is loaded, also indicates - // the loader this native library belongs. - final Class fromClass; - // the canonicalized name of the native library. - // or static library name - final String name; - // Indicates if the native library is linked into the VM - final boolean isBuiltin; - - // opaque handle to native library, used in native code. - long handle; - // the version of JNI environment the native library requires. - int jniVersion; - - native boolean load0(String name, boolean isBuiltin); - - native long findEntry(String name); - - NativeLibrary(Class fromClass, String name, boolean isBuiltin) { - this.name = name; - this.fromClass = fromClass; - this.isBuiltin = isBuiltin; - } - - /* - * Loads the native library and registers for cleanup when its - * associated class loader is unloaded - */ - boolean load() { - if (handle != 0) { - throw new InternalError("Native library " + name + " has been loaded"); - } - - if (!load0(name, isBuiltin)) return false; - - // register the class loader for cleanup when unloaded - // builtin class loaders are never unloaded - ClassLoader loader = fromClass.getClassLoader(); - if (loader != null && - loader != getBuiltinPlatformClassLoader() && - loader != getBuiltinAppClassLoader()) { - CleanerFactory.cleaner().register(loader, - new Unloader(name, handle, isBuiltin)); - } - return true; - } - - static boolean loadLibrary(Class fromClass, String name, boolean isBuiltin) { - ClassLoader loader = - fromClass == null ? null : fromClass.getClassLoader(); - - synchronized (loadedLibraryNames) { - Map libs = - loader != null ? loader.nativeLibraries() : systemNativeLibraries(); - if (libs.containsKey(name)) { - return true; - } - - if (loadedLibraryNames.contains(name)) { - throw new UnsatisfiedLinkError("Native Library " + name + - " already loaded in another classloader"); - } - - /* - * When a library is being loaded, JNI_OnLoad function can cause - * another loadLibrary invocation that should succeed. - * - * We use a static stack to hold the list of libraries we are - * loading because this can happen only when called by the - * same thread because this block is synchronous. - * - * If there is a pending load operation for the library, we - * immediately return success; otherwise, we raise - * UnsatisfiedLinkError. - */ - for (NativeLibrary lib : nativeLibraryContext) { - if (name.equals(lib.name)) { - if (loader == lib.fromClass.getClassLoader()) { - return true; - } else { - throw new UnsatisfiedLinkError("Native Library " + - name + " is being loaded in another classloader"); - } - } - } - NativeLibrary lib = new NativeLibrary(fromClass, name, isBuiltin); - // load the native library - nativeLibraryContext.push(lib); - try { - if (!lib.load()) return false; - } finally { - nativeLibraryContext.pop(); - } - // register the loaded native library - loadedLibraryNames.add(name); - libs.put(name, lib); - } - return true; - } - - // Invoked in the VM to determine the context class in JNI_OnLoad - // and JNI_OnUnload - static Class getFromClass() { - return nativeLibraryContext.peek().fromClass; - } - - // native libraries being loaded - static Deque nativeLibraryContext = new ArrayDeque<>(8); - - /* - * The run() method will be invoked when this class loader becomes - * phantom reachable to unload the native library. - */ - static class Unloader implements Runnable { - // This represents the context when a native library is unloaded - // and getFromClass() will return null, - static final NativeLibrary UNLOADER = - new NativeLibrary(null, "dummy", false); - final String name; - final long handle; - final boolean isBuiltin; - - Unloader(String name, long handle, boolean isBuiltin) { - if (handle == 0) { - throw new IllegalArgumentException( - "Invalid handle for native library " + name); - } - - this.name = name; - this.handle = handle; - this.isBuiltin = isBuiltin; - } - - @Override - public void run() { - synchronized (loadedLibraryNames) { - /* remove the native library name */ - loadedLibraryNames.remove(name); - nativeLibraryContext.push(UNLOADER); - try { - unload(name, isBuiltin, handle); - } finally { - nativeLibraryContext.pop(); - } - - } - } - } - - // JNI FindClass expects the caller class if invoked from JNI_OnLoad - // and JNI_OnUnload is NativeLibrary class - static native void unload(String name, boolean isBuiltin, long handle); - } - - /** - * Holds system and user library paths derived from the - * {@code java.library.path} and {@code sun.boot.library.path} system - * properties. The system properties are eagerly read at bootstrap, then - * lazily parsed on first use to avoid initialization ordering issues. - */ - private static class LibraryPaths { - static final String[] USER = - ClassLoaderHelper.parsePath(StaticProperty.javaLibraryPath()); - static final String[] SYS = - ClassLoaderHelper.parsePath(StaticProperty.sunBootLibraryPath()); - } + private final NativeLibraries libraries = new NativeLibraries(this); // Invoked in the java.lang.Runtime class to implement load and loadLibrary. - static void loadLibrary(Class fromClass, String name, - boolean isAbsolute) { - ClassLoader loader = - (fromClass == null) ? null : fromClass.getClassLoader(); - - if (isAbsolute) { - if (loadLibrary0(fromClass, new File(name))) { - return; - } - throw new UnsatisfiedLinkError("Can't load library: " + name); - } - if (loader != null) { - String libfilename = loader.findLibrary(name); - if (libfilename != null) { - File libfile = new File(libfilename); - if (!libfile.isAbsolute()) { - throw new UnsatisfiedLinkError( + static NativeLibrary loadLibrary(Class fromClass, File file) { + ClassLoader loader = (fromClass == null) ? null : fromClass.getClassLoader(); + NativeLibraries libs = loader != null ? loader.libraries : BootLoader.getNativeLibraries(); + NativeLibrary nl = libs.loadLibrary(fromClass, file); + if (nl != null) { + return nl; + } + throw new UnsatisfiedLinkError("Can't load library: " + file); + } + static NativeLibrary loadLibrary(Class fromClass, String name) { + ClassLoader loader = (fromClass == null) ? null : fromClass.getClassLoader(); + if (loader == null) { + NativeLibrary nl = BootLoader.getNativeLibraries().loadLibrary(fromClass, name); + if (nl != null) { + return nl; + } + throw new UnsatisfiedLinkError("no " + name + + " in java.library.path: " + StaticProperty.sunBootLibraryPath()); + } + + NativeLibraries libs = loader.libraries; + // First load from the file returned from ClassLoader::findLibrary, if found. + String libfilename = loader.findLibrary(name); + if (libfilename != null) { + File libfile = new File(libfilename); + if (!libfile.isAbsolute()) { + throw new UnsatisfiedLinkError( "ClassLoader.findLibrary failed to return an absolute path: " + libfilename); - } - if (loadLibrary0(fromClass, libfile)) { - return; - } - throw new UnsatisfiedLinkError("Can't load " + libfilename); - } - } - for (String sysPath : LibraryPaths.SYS) { - File libfile = new File(sysPath, System.mapLibraryName(name)); - if (loadLibrary0(fromClass, libfile)) { - return; - } - libfile = ClassLoaderHelper.mapAlternativeName(libfile); - if (libfile != null && loadLibrary0(fromClass, libfile)) { - return; - } - } - if (loader != null) { - for (String userPath : LibraryPaths.USER) { - File libfile = new File(userPath, System.mapLibraryName(name)); - if (loadLibrary0(fromClass, libfile)) { - return; - } - libfile = ClassLoaderHelper.mapAlternativeName(libfile); - if (libfile != null && loadLibrary0(fromClass, libfile)) { - return; - } } + NativeLibrary nl = libs.loadLibrary(fromClass, libfile); + if (nl != null) { + return nl; + } + throw new UnsatisfiedLinkError("Can't load " + libfilename); + } + // Then load from system library path and java library path + NativeLibrary nl = libs.loadLibrary(fromClass, name); + if (nl != null) { + return nl; } + // Oops, it failed throw new UnsatisfiedLinkError("no " + name + - " in java.library.path: " + Arrays.toString(LibraryPaths.USER)); - } - - private static native String findBuiltinLib(String name); - - private static boolean loadLibrary0(Class fromClass, final File file) { - // Check to see if we're attempting to access a static library - String name = findBuiltinLib(file.getName()); - boolean isBuiltin = (name != null); - if (!isBuiltin) { - name = AccessController.doPrivileged( - new PrivilegedAction<>() { - public String run() { - try { - return file.exists() ? file.getCanonicalPath() : null; - } catch (IOException e) { - return null; - } - } - }); - if (name == null) { - return false; - } - } - return NativeLibrary.loadLibrary(fromClass, name, isBuiltin); + " in java.library.path: " + StaticProperty.javaLibraryPath()); } /* * Invoked in the VM class linking code. */ private static long findNative(ClassLoader loader, String entryName) { - Map libs = - loader != null ? loader.nativeLibraries() : systemNativeLibraries(); - if (libs.isEmpty()) - return 0; - - // the native libraries map may be updated in another thread - // when a native library is being loaded. No symbol will be - // searched from it yet. - for (NativeLibrary lib : libs.values()) { - long entry = lib.findEntry(entryName); - if (entry != 0) return entry; - } - return 0; - } - - // All native library names we've loaded. - // This also serves as the lock to obtain nativeLibraries - // and write to nativeLibraryContext. - private static final Set loadedLibraryNames = new HashSet<>(); - - // Native libraries belonging to system classes. - private static volatile Map systemNativeLibraries; - - // Native libraries associated with the class loader. - private volatile Map nativeLibraries; - - /* - * Returns the native libraries map associated with bootstrap class loader - * This method will create the map at the first time when called. - */ - private static Map systemNativeLibraries() { - Map libs = systemNativeLibraries; - if (libs == null) { - synchronized (loadedLibraryNames) { - libs = systemNativeLibraries; - if (libs == null) { - libs = systemNativeLibraries = new ConcurrentHashMap<>(); - } - } - } - return libs; - } - - /* - * Returns the native libraries map associated with this class loader - * This method will create the map at the first time when called. - */ - private Map nativeLibraries() { - Map libs = nativeLibraries; - if (libs == null) { - synchronized (loadedLibraryNames) { - libs = nativeLibraries; - if (libs == null) { - libs = nativeLibraries = new ConcurrentHashMap<>(); - } - } + if (loader == null) { + return BootLoader.getNativeLibraries().lookup(entryName); + } else { + return loader.libraries.lookup(entryName); } - return libs; } // -- Assertion management --