--- old/make/mapfiles/libjava/mapfile-vers 2017-10-04 16:16:00.000000000 -0700 +++ new/make/mapfiles/libjava/mapfile-vers 2017-10-04 16:16:00.000000000 -0700 @@ -130,8 +130,8 @@ Java_java_lang_ClassLoader_defineClass2; Java_java_lang_ClassLoader_findBuiltinLib; Java_java_lang_ClassLoader_findLoadedClass0; - Java_java_lang_ClassLoader_00024NativeLibrary_find; - Java_java_lang_ClassLoader_00024NativeLibrary_load; + Java_java_lang_ClassLoader_00024NativeLibrary_findEntry; + Java_java_lang_ClassLoader_00024NativeLibrary_load0; Java_java_lang_ClassLoader_00024NativeLibrary_unload; Java_java_lang_ClassLoader_registerNatives; Java_java_lang_Double_longBitsToDouble; --- old/make/mapfiles/libjava/reorder-sparc 2017-10-04 16:16:01.000000000 -0700 +++ new/make/mapfiles/libjava/reorder-sparc 2017-10-04 16:16:01.000000000 -0700 @@ -48,8 +48,8 @@ text: .text%Java_java_io_FileInputStream_close0; text: .text%Java_java_lang_System_mapLibraryName; text: .text%Java_java_io_UnixFileSystem_getBooleanAttributes0; -text: .text%Java_java_lang_ClassLoader_00024NativeLibrary_load; -text: .text%Java_java_lang_ClassLoader_00024NativeLibrary_find; +text: .text%Java_java_lang_ClassLoader_00024NativeLibrary_load0; +text: .text%Java_java_lang_ClassLoader_00024NativeLibrary_findEntry; text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2; text: .text%Java_java_io_UnixFileSystem_list; text: .text%JNU_ClassString; --- old/make/mapfiles/libjava/reorder-sparcv9 2017-10-04 16:16:02.000000000 -0700 +++ new/make/mapfiles/libjava/reorder-sparcv9 2017-10-04 16:16:02.000000000 -0700 @@ -57,8 +57,8 @@ text: .text%Java_java_io_UnixFileSystem_getBooleanAttributes0; text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2Ljava_security_AccessControlContext_2; text: .text%Java_java_lang_System_mapLibraryName; -text: .text%Java_java_lang_ClassLoader_00024NativeLibrary_load; -text: .text%Java_java_lang_ClassLoader_00024NativeLibrary_find; +text: .text%Java_java_lang_ClassLoader_00024NativeLibrary_load0; +text: .text%Java_java_lang_ClassLoader_00024NativeLibrary_findEntry; text: .text%Java_java_io_UnixFileSystem_getLength; text: .text%Java_java_lang_Object_getClass; text: .text%Java_java_lang_ClassLoader_defineClass0; --- old/make/mapfiles/libjava/reorder-x86 2017-10-04 16:16:03.000000000 -0700 +++ new/make/mapfiles/libjava/reorder-x86 2017-10-04 16:16:03.000000000 -0700 @@ -50,8 +50,8 @@ text: .text%Java_java_security_AccessController_doPrivileged__Ljava_security_PrivilegedExceptionAction_2Ljava_security_AccessControlContext_2; text: .text%Java_java_lang_System_mapLibraryName; text: .text%cpchars: OUTPUTDIR/System.o; -text: .text%Java_java_lang_ClassLoader_00024NativeLibrary_load; -text: .text%Java_java_lang_ClassLoader_00024NativeLibrary_find; +text: .text%Java_java_lang_ClassLoader_00024NativeLibrary_load0; +text: .text%Java_java_lang_ClassLoader_00024NativeLibrary_findEntry; text: .text%Java_java_lang_Float_floatToRawIntBits; text: .text%Java_java_lang_Double_doubleToRawLongBits; text: .text%Java_java_io_FileInputStream_open0; --- old/make/test/JtregNativeJdk.gmk 2017-10-04 16:16:04.000000000 -0700 +++ new/make/test/JtregNativeJdk.gmk 2017-10-04 16:16:04.000000000 -0700 @@ -44,6 +44,7 @@ # Add more directories here when needed. BUILD_JDK_JTREG_NATIVE_SRC += \ $(TOPDIR)/test/jdk/native_sanity \ + $(TOPDIR)/test/jdk/java/lang/ClassLoader/nativeLibrary \ $(TOPDIR)/test/jdk/java/lang/String/nativeEncoding \ # --- old/src/java.base/share/classes/java/lang/ClassLoader.java 2017-10-04 16:16:06.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/ClassLoader.java 2017-10-04 16:16:05.000000000 -0700 @@ -37,17 +37,20 @@ import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.security.cert.Certificate; +import java.util.Arrays; import java.util.Collections; +import java.util.Deque; import java.util.Enumeration; import java.util.HashMap; +import java.util.HashSet; import java.util.Hashtable; +import java.util.LinkedList; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import java.util.Set; import java.util.Spliterator; import java.util.Spliterators; -import java.util.Stack; import java.util.Vector; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; @@ -58,9 +61,9 @@ import jdk.internal.perf.PerfCounter; import jdk.internal.loader.BootLoader; import jdk.internal.loader.ClassLoaders; -import jdk.internal.misc.SharedSecrets; 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 sun.reflect.misc.ReflectUtil; @@ -2375,72 +2378,157 @@ * @since 1.2 */ static class NativeLibrary { - // opaque handle to native library, used in native code. - long handle; - // the version of JNI environment the native library requires. - private int jniVersion; // the class from which the library is loaded, also indicates // the loader this native library belongs. - private final Class fromClass; + final Class fromClass; // the canonicalized name of the native library. // or static library name - String name; + final String name; // Indicates if the native library is linked into the VM - boolean isBuiltin; - // Indicates if the native library is loaded - boolean loaded; - native void load(String name, boolean isBuiltin); + 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 find(String name); - native void unload(String name, boolean isBuiltin); + native long findEntry(String name); - public NativeLibrary(Class fromClass, String name, boolean isBuiltin) { + NativeLibrary(Class fromClass, String name, boolean isBuiltin) { this.name = name; this.fromClass = fromClass; this.isBuiltin = isBuiltin; } - @SuppressWarnings("deprecation") - protected void finalize() { + /* + * 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 + // built 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(); + Map libs = + loader != null ? loader.nativeLibraries : systemNativeLibraries; + if (libs.containsKey(name)) { + return true; + } synchronized (loadedLibraryNames) { - if (fromClass.getClassLoader() != null && loaded) { - /* remove the native library name */ - int size = loadedLibraryNames.size(); - for (int i = 0; i < size; i++) { - if (name.equals(loadedLibraryNames.elementAt(i))) { - loadedLibraryNames.removeElementAt(i); - break; + if (loadedLibraryNames.contains(name)) { + throw new UnsatisfiedLinkError("Native Library " + name + + " already loaded in another classloader"); + } + + /* If the library is being loaded (must be by the same thread, + * because Runtime.load and Runtime.loadLibrary are + * synchronous). The reason it can occur is that the JNI_OnLoad + * function can cause another loadLibrary invocation. + * + * Thus we can use a static stack to hold the list of libraries + * we are loading. + * + * 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"); } } - /* unload the library. */ - ClassLoader.nativeLibraryContext.push(this); - try { - unload(name, isBuiltin); - } finally { - ClassLoader.nativeLibraryContext.pop(); - } } + 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_Load/JNI_Unload + + // Invoked in the VM to determine the context class in JNI_OnLoad + // and JNI_OnUnload static Class getFromClass() { - return ClassLoader.nativeLibraryContext.peek().fromClass; + return nativeLibraryContext.peek().fromClass; } - } - // All native library names we've loaded. - private static Vector loadedLibraryNames = new Vector<>(); + // native libraries being loaded + static Deque nativeLibraryContext = new LinkedList<>(); - // Native libraries belonging to system classes. - private static Vector systemNativeLibraries - = new Vector<>(); + /* + * 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); + } - // Native libraries associated with the class loader. - private Vector nativeLibraries = new Vector<>(); + this.name = name; + this.handle = handle; + this.isBuiltin = isBuiltin; + } - // native libraries being loaded/unloaded. - private static Stack nativeLibraryContext = new Stack<>(); + @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); + } // The paths searched for libraries private static String usr_paths[]; @@ -2453,7 +2541,7 @@ int psCount = 0; if (ClassLoaderHelper.allowsQuotedPathElements && - ldPath.indexOf('\"') >= 0) { + ldPath.indexOf('\"') >= 0) { // First, remove quotes put around quoted parts of paths. // Second, use a quotation mark as a new path separator. // This will preserve any quoted old path separators. @@ -2463,7 +2551,7 @@ char ch = ldPath.charAt(i); if (ch == '\"') { while (++i < ldLen && - (ch = ldPath.charAt(i)) != '\"') { + (ch = ldPath.charAt(i)) != '\"') { buf[bufLen++] = ch; } } else { @@ -2479,7 +2567,7 @@ ps = '\"'; } else { for (int i = ldPath.indexOf(ps); i >= 0; - i = ldPath.indexOf(ps, i + 1)) { + i = ldPath.indexOf(ps, i + 1)) { psCount++; } } @@ -2489,11 +2577,11 @@ for (int j = 0; j < psCount; ++j) { int pathEnd = ldPath.indexOf(ps, pathStart); paths[j] = (pathStart < pathEnd) ? - ldPath.substring(pathStart, pathEnd) : "."; + ldPath.substring(pathStart, pathEnd) : "."; pathStart = pathEnd + 1; } paths[psCount] = (pathStart < ldLen) ? - ldPath.substring(pathStart, ldLen) : "."; + ldPath.substring(pathStart, ldLen) : "."; return paths; } @@ -2518,7 +2606,7 @@ File libfile = new File(libfilename); if (!libfile.isAbsolute()) { throw new UnsatisfiedLinkError( - "ClassLoader.findLibrary failed to return an absolute path: " + libfilename); + "ClassLoader.findLibrary failed to return an absolute path: " + libfilename); } if (loadLibrary0(fromClass, libfile)) { return; @@ -2549,10 +2637,11 @@ } } // Oops, it failed - throw new UnsatisfiedLinkError("no " + name + " in java.library.path"); + throw new UnsatisfiedLinkError("no " + name + + " in java.library.path: " + Arrays.toString(usr_paths)); } - static native String findBuiltinLib(String name); + 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 @@ -2573,85 +2662,36 @@ return false; } } - ClassLoader loader = - (fromClass == null) ? null : fromClass.getClassLoader(); - Vector libs = - loader != null ? loader.nativeLibraries : systemNativeLibraries; - synchronized (libs) { - int size = libs.size(); - for (int i = 0; i < size; i++) { - NativeLibrary lib = libs.elementAt(i); - if (name.equals(lib.name)) { - return true; - } - } - - synchronized (loadedLibraryNames) { - if (loadedLibraryNames.contains(name)) { - throw new UnsatisfiedLinkError - ("Native Library " + - name + - " already loaded in another classloader"); - } - /* If the library is being loaded (must be by the same thread, - * because Runtime.load and Runtime.loadLibrary are - * synchronous). The reason is can occur is that the JNI_OnLoad - * function can cause another loadLibrary invocation. - * - * Thus we can use a static stack to hold the list of libraries - * we are loading. - * - * If there is a pending load operation for the library, we - * immediately return success; otherwise, we raise - * UnsatisfiedLinkError. - */ - int n = nativeLibraryContext.size(); - for (int i = 0; i < n; i++) { - NativeLibrary lib = nativeLibraryContext.elementAt(i); - 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); - nativeLibraryContext.push(lib); - try { - lib.load(name, isBuiltin); - } finally { - nativeLibraryContext.pop(); - } - if (lib.loaded) { - loadedLibraryNames.addElement(name); - libs.addElement(lib); - return true; - } - return false; - } - } + return NativeLibrary.loadLibrary(fromClass, name, isBuiltin); } - // Invoked in the VM class linking code. - static long findNative(ClassLoader loader, String name) { - Vector libs = + /* + * Invoked in the VM class linking code. + */ + private static long findNative(ClassLoader loader, String name) { + Map libs = loader != null ? loader.nativeLibraries : systemNativeLibraries; - synchronized (libs) { - int size = libs.size(); - for (int i = 0; i < size; i++) { - NativeLibrary lib = libs.elementAt(i); - long entry = lib.find(name); - if (entry != 0) - return entry; - } + + // 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(name); + if (entry != 0) return entry; } return 0; } + // All native library names we've loaded. + private static Set loadedLibraryNames = new HashSet<>(); + + // Native libraries belonging to system classes. + private static Map systemNativeLibraries + = new ConcurrentHashMap<>(); + + // Native libraries associated with the class loader. + private Map nativeLibraries = new ConcurrentHashMap<>(); + // -- Assertion management -- --- old/src/java.base/share/classes/java/lang/Runtime.java 2017-10-04 16:16:07.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/Runtime.java 2017-10-04 16:16:07.000000000 -0700 @@ -765,7 +765,9 @@ * with the VM, then the JNI_OnLoad_L function exported by the library * is invoked rather than attempting to load a dynamic library. * A filename matching the argument does not have to exist in the file - * system. See the JNI Specification for more details. + * system. + * See the JNI Specification + * for more details. * * Otherwise, the filename argument is mapped to a native library image in * an implementation-dependent manner. @@ -818,7 +820,8 @@ * specific prefix, file extension or path. If a native library * called {@code libname} is statically linked with the VM, then the * JNI_OnLoad_{@code libname} function exported by the library is invoked. - * See the JNI Specification for more details. + * See the JNI Specification + * for more details. * * Otherwise, the libname argument is loaded from a system library * location and mapped to a native library image in an implementation- --- old/src/java.base/share/classes/java/lang/System.java 2017-10-04 16:16:08.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/System.java 2017-10-04 16:16:08.000000000 -0700 @@ -1799,7 +1799,8 @@ * is invoked rather than attempting to load a dynamic library. * A filename matching the argument does not have to exist in the * file system. - * See the JNI Specification for more details. + * See the JNI Specification + * for more details. * * Otherwise, the filename argument is mapped to a native library image in * an implementation-dependent manner. @@ -1835,7 +1836,8 @@ * specific prefix, file extension or path. If a native library * called libname is statically linked with the VM, then the * JNI_OnLoad_libname function exported by the library is invoked. - * See the JNI Specification for more details. + * See the JNI Specification + * for more details. * * Otherwise, the libname argument is loaded from a system library * location and mapped to a native library image in an implementation- --- old/src/java.base/share/native/libjava/ClassLoader.c 2017-10-04 16:16:09.000000000 -0700 +++ new/src/java.base/share/native/libjava/ClassLoader.c 2017-10-04 16:16:09.000000000 -0700 @@ -260,7 +260,6 @@ static jfieldID handleID; static jfieldID jniVersionID; -static jfieldID loadedID; static void *procHandle; static jboolean initIDs(JNIEnv *env) @@ -276,9 +275,6 @@ jniVersionID = (*env)->GetFieldID(env, this, "jniVersion", "I"); if (jniVersionID == 0) return JNI_FALSE; - loadedID = (*env)->GetFieldID(env, this, "loaded", "Z"); - if (loadedID == 0) - return JNI_FALSE; procHandle = getProcessHandle(); } return JNI_TRUE; @@ -335,30 +331,31 @@ /* * Class: java_lang_ClassLoader_NativeLibrary - * Method: load - * Signature: (Ljava/lang/String;Z)V + * Method: load0 + * Signature: (Ljava/lang/String;Z)Z */ -JNIEXPORT void JNICALL -Java_java_lang_ClassLoader_00024NativeLibrary_load +JNIEXPORT jboolean JNICALL +Java_java_lang_ClassLoader_00024NativeLibrary_load0 (JNIEnv *env, jobject this, jstring name, jboolean isBuiltin) { const char *cname; jint jniVersion; jthrowable cause; void * handle; + jboolean loaded = JNI_FALSE; if (!initIDs(env)) - return; + return JNI_FALSE; cname = JNU_GetStringPlatformChars(env, name, 0); if (cname == 0) - return; + return JNI_FALSE; handle = isBuiltin ? procHandle : JVM_LoadLibrary(cname); if (handle) { JNI_OnLoad_t JNI_OnLoad; JNI_OnLoad = (JNI_OnLoad_t)findJniFunction(env, handle, - isBuiltin ? cname : NULL, - JNI_TRUE); + isBuiltin ? cname : NULL, + JNI_TRUE); if (JNI_OnLoad) { JavaVM *jvm; (*env)->GetJavaVM(env, &jvm); @@ -400,20 +397,21 @@ goto done; } (*env)->SetLongField(env, this, handleID, ptr_to_jlong(handle)); - (*env)->SetBooleanField(env, this, loadedID, JNI_TRUE); + loaded = JNI_TRUE; done: JNU_ReleaseStringPlatformChars(env, name, cname); + return loaded; } /* * Class: java_lang_ClassLoader_NativeLibrary * Method: unload - * Signature: (Z)V + * Signature: (Ljava/lang/String;ZJ)V */ JNIEXPORT void JNICALL Java_java_lang_ClassLoader_00024NativeLibrary_unload -(JNIEnv *env, jobject this, jstring name, jboolean isBuiltin) +(JNIEnv *env, jclass cls, jstring name, jboolean isBuiltin, jlong address) { const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS; void *handle; @@ -426,10 +424,10 @@ if (cname == NULL) { return; } - handle = jlong_to_ptr((*env)->GetLongField(env, this, handleID)); + handle = jlong_to_ptr(address); JNI_OnUnload = (JNI_OnUnload_t )findJniFunction(env, handle, - isBuiltin ? cname : NULL, - JNI_FALSE); + isBuiltin ? cname : NULL, + JNI_FALSE); if (JNI_OnUnload) { JavaVM *jvm; (*env)->GetJavaVM(env, &jvm); @@ -443,11 +441,11 @@ /* * Class: java_lang_ClassLoader_NativeLibrary - * Method: find + * Method: findEntry * Signature: (Ljava/lang/String;)J */ JNIEXPORT jlong JNICALL -Java_java_lang_ClassLoader_00024NativeLibrary_find +Java_java_lang_ClassLoader_00024NativeLibrary_findEntry (JNIEnv *env, jobject this, jstring name) { jlong handle; --- /dev/null 2017-10-04 16:16:10.000000000 -0700 +++ new/test/jdk/java/lang/ClassLoader/nativeLibrary/NativeLibraryTest.java 2017-10-04 16:16:10.000000000 -0700 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. 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. + * + * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8164512 + * @build p.Test + * @run main/othervm/native -Xcheck:jni NativeLibraryTest + */ + +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class NativeLibraryTest { + static final Path CLASSES = Paths.get("classes"); + + public static void main(String... args) throws Exception { + String dir = System.getProperty("test.classes", "."); + Path file = Paths.get("p", "Test.class"); + Files.createDirectories(CLASSES.resolve("p")); + Files.copy(Paths.get(dir).resolve(file), + CLASSES.resolve("p").resolve("Test.class")); + + int count = 3; + for (int i=0; i < count; i++) { + loadClass(); + System.gc(); + // give Cleaner thread a chance to unload the native library + Thread.sleep(100); + } + } + + static void loadClass() throws Exception { + TestLoader loader = new TestLoader(); + Class c = Class.forName("p.Test", true, loader); + } + + static class TestLoader extends URLClassLoader { + static URL[] toURLs() { + try { + return new URL[] { CLASSES.toUri().toURL() }; + } catch (MalformedURLException e) { + throw new Error(e); + } + } + + TestLoader() { + super("testloader", toURLs(), ClassLoader.getPlatformClassLoader()); + } + } +} --- /dev/null 2017-10-04 16:16:11.000000000 -0700 +++ new/test/jdk/java/lang/ClassLoader/nativeLibrary/libnativeLibraryTest.c 2017-10-04 16:16:11.000000000 -0700 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. 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. + * + * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include + +#include "jni.h" +#include "jni_util.h" + +JNIEXPORT jint JNICALL +JNI_OnLoad(JavaVM *vm, void *reserved) { + JNIEnv *env; + + if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_9) != JNI_OK) { + printf("Not able to get JNIEnv\n"); + return JNI_FALSE; + } + + return JNI_VERSION_9; +} + +JNIEXPORT void JNICALL +JNI_OnUnload(JavaVM *vm, void *reserved) { + JNIEnv *env; + + if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_9) != JNI_OK) { + printf("Not able to get JNIEnv\n"); + } + + jclass excls = (*env)->FindClass(env, "java/lang/Error"); + + jclass cl = (*env)->FindClass(env, "p/Test"); + if (cl != NULL) { + (*env)->ThrowNew(env, excls, "p.Test should not be found"); + return; + } + + cl = (*env)->FindClass(env, "java/lang/ClassLoader"); + if (cl == NULL) { + (*env)->ThrowNew(env, excls, "ClassLoader class not found"); + return; + } +} --- /dev/null 2017-10-04 16:16:13.000000000 -0700 +++ new/test/jdk/java/lang/ClassLoader/nativeLibrary/p/Test.java 2017-10-04 16:16:12.000000000 -0700 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. 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. + * + * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package p; + +public class Test { + static { + System.out.println("loading libnativeLibraryTest library"); + System.loadLibrary("nativeLibraryTest"); + } + +}