8188052: JNI FindClass needs to specify the class loading context used for library lifecycle hooks
authormchung
Tue, 10 Oct 2017 11:52:42 -0700
changeset 47613 af241e3e5a13
parent 47612 b512c5781ca1
child 47614 0ecfd6c951a6
8188052: JNI FindClass needs to specify the class loading context used for library lifecycle hooks Reviewed-by: alanb, coleenp, dholmes
src/hotspot/share/prims/jni.cpp
src/hotspot/share/prims/jni.h
src/hotspot/share/runtime/thread.cpp
src/java.base/share/classes/java/lang/ClassLoader.java
src/java.base/share/native/include/jni.h
src/jdk.management.agent/unix/native/libmanagement_agent/FileSystemImpl.c
src/jdk.management.agent/windows/native/libmanagement_agent/FileSystemImpl.c
test/hotspot/jtreg/native_sanity/JniVersion.java
--- a/src/hotspot/share/prims/jni.cpp	Tue Oct 10 16:29:04 2017 +0200
+++ b/src/hotspot/share/prims/jni.cpp	Tue Oct 10 11:52:42 2017 -0700
@@ -92,7 +92,7 @@
 #include "jvmci/jvmciRuntime.hpp"
 #endif
 
-static jint CurrentVersion = JNI_VERSION_9;
+static jint CurrentVersion = JNI_VERSION_10;
 
 #ifdef _WIN32
 extern LONG WINAPI topLevelExceptionFilter(_EXCEPTION_POINTERS* );
@@ -401,29 +401,31 @@
   // Find calling class
   Klass* k = thread->security_get_caller_class(0);
   if (k != NULL) {
-    loader = Handle(THREAD, k->class_loader());
     // Special handling to make sure JNI_OnLoad and JNI_OnUnload are executed
     // in the correct class context.
-    if (loader.is_null() &&
+    if (k->class_loader() == NULL &&
         k->name() == vmSymbols::java_lang_ClassLoader_NativeLibrary()) {
       JavaValue result(T_OBJECT);
       JavaCalls::call_static(&result, k,
                              vmSymbols::getFromClass_name(),
                              vmSymbols::void_class_signature(),
-                             thread);
-      if (HAS_PENDING_EXCEPTION) {
-        Handle ex(thread, thread->pending_exception());
-        CLEAR_PENDING_EXCEPTION;
-        THROW_HANDLE_0(ex);
-      }
+                             CHECK_NULL);
+      // When invoked from JNI_OnLoad, NativeLibrary::getFromClass returns
+      // a non-NULL Class object.  When invoked from JNI_OnUnload,
+      // it will return NULL to indicate no context.
       oop mirror = (oop) result.get_jobject();
-      loader = Handle(THREAD,
-        InstanceKlass::cast(java_lang_Class::as_Klass(mirror))->class_loader());
-      protection_domain = Handle(THREAD,
-        InstanceKlass::cast(java_lang_Class::as_Klass(mirror))->protection_domain());
+      if (mirror != NULL) {
+        Klass* fromClass = java_lang_Class::as_Klass(mirror);
+        loader = Handle(THREAD, fromClass->class_loader());
+        protection_domain = Handle(THREAD, fromClass->protection_domain());
+      }
+    } else {
+      loader = Handle(THREAD, k->class_loader());
     }
-  } else {
-    // We call ClassLoader.getSystemClassLoader to obtain the system class loader.
+  }
+
+  if (loader.is_null()) {
+    // No context and use the system class loader
     loader = Handle(THREAD, SystemDictionary::java_system_loader());
   }
 
--- a/src/hotspot/share/prims/jni.h	Tue Oct 10 16:29:04 2017 +0200
+++ b/src/hotspot/share/prims/jni.h	Tue Oct 10 11:52:42 2017 -0700
@@ -1964,6 +1964,7 @@
 #define JNI_VERSION_1_6 0x00010006
 #define JNI_VERSION_1_8 0x00010008
 #define JNI_VERSION_9   0x00090000
+#define JNI_VERSION_10  0x000a0000
 
 #ifdef __cplusplus
 } /* extern "C" */
--- a/src/hotspot/share/runtime/thread.cpp	Tue Oct 10 16:29:04 2017 +0200
+++ b/src/hotspot/share/runtime/thread.cpp	Tue Oct 10 11:52:42 2017 -0700
@@ -4195,6 +4195,7 @@
   if (version == JNI_VERSION_1_6) return JNI_TRUE;
   if (version == JNI_VERSION_1_8) return JNI_TRUE;
   if (version == JNI_VERSION_9) return JNI_TRUE;
+  if (version == JNI_VERSION_10) return JNI_TRUE;
   return JNI_FALSE;
 }
 
--- a/src/java.base/share/classes/java/lang/ClassLoader.java	Tue Oct 10 16:29:04 2017 +0200
+++ b/src/java.base/share/classes/java/lang/ClassLoader.java	Tue Oct 10 11:52:42 2017 -0700
@@ -2381,7 +2381,7 @@
         private int jniVersion;
         // the class from which the library is loaded, also indicates
         // the loader this native library belongs.
-        private final Class<?> fromClass;
+        private Class<?> fromClass;
         // the canonicalized name of the native library.
         // or static library name
         String name;
@@ -2404,6 +2404,8 @@
         protected void finalize() {
             synchronized (loadedLibraryNames) {
                 if (fromClass.getClassLoader() != null && loaded) {
+                    this.fromClass = null;   // no context when unloaded
+
                     /* remove the native library name */
                     int size = loadedLibraryNames.size();
                     for (int i = 0; i < size; i++) {
--- a/src/java.base/share/native/include/jni.h	Tue Oct 10 16:29:04 2017 +0200
+++ b/src/java.base/share/native/include/jni.h	Tue Oct 10 11:52:42 2017 -0700
@@ -1964,6 +1964,7 @@
 #define JNI_VERSION_1_6 0x00010006
 #define JNI_VERSION_1_8 0x00010008
 #define JNI_VERSION_9   0x00090000
+#define JNI_VERSION_10  0x000a0000
 
 #ifdef __cplusplus
 } /* extern "C" */
--- a/src/jdk.management.agent/unix/native/libmanagement_agent/FileSystemImpl.c	Tue Oct 10 16:29:04 2017 +0200
+++ b/src/jdk.management.agent/unix/native/libmanagement_agent/FileSystemImpl.c	Tue Oct 10 11:52:42 2017 -0700
@@ -45,7 +45,7 @@
         return JNI_EVERSION; /* JNI version not supported */
     }
 
-    return JNI_VERSION_9;
+    return JNI_VERSION_10;
 }
 
 /*
--- a/src/jdk.management.agent/windows/native/libmanagement_agent/FileSystemImpl.c	Tue Oct 10 16:29:04 2017 +0200
+++ b/src/jdk.management.agent/windows/native/libmanagement_agent/FileSystemImpl.c	Tue Oct 10 11:52:42 2017 -0700
@@ -39,7 +39,7 @@
         return JNI_EVERSION; /* JNI version not supported */
     }
 
-    return JNI_VERSION_9;
+    return JNI_VERSION_10;
 }
 
 
--- a/test/hotspot/jtreg/native_sanity/JniVersion.java	Tue Oct 10 16:29:04 2017 +0200
+++ b/test/hotspot/jtreg/native_sanity/JniVersion.java	Tue Oct 10 11:52:42 2017 -0700
@@ -27,12 +27,12 @@
  */
 public class JniVersion {
 
-    public static final int JNI_VERSION_9 = 0x00090000;
+    public static final int JNI_VERSION_10 = 0x000a0000;
 
     public static void main(String... args) throws Exception {
         System.loadLibrary("JniVersion");
         int res = getJniVersion();
-        if (res != JNI_VERSION_9) {
+        if (res != JNI_VERSION_10) {
             throw new Exception("Unexpected value returned from getJniVersion(): 0x" + Integer.toHexString(res));
         }
     }