src/hotspot/share/jvmci/jvmciEnv.cpp
changeset 54732 2d012a75d35c
parent 54669 ad45b3802d4e
child 54786 ebf733a324d4
--- a/src/hotspot/share/jvmci/jvmciEnv.cpp	Tue May 07 10:21:04 2019 +0800
+++ b/src/hotspot/share/jvmci/jvmciEnv.cpp	Mon May 06 20:05:19 2019 -0700
@@ -129,11 +129,10 @@
   }
 }
 
-JNIEnv* JVMCIEnv::attach_shared_library() {
+JNIEnv* JVMCIEnv::init_shared_library(JavaThread* thread) {
   if (_shared_library_javavm == NULL) {
     MutexLocker locker(JVMCI_lock);
     if (_shared_library_javavm == NULL) {
-
       char path[JVM_MAXPATHLEN];
       char ebuf[1024];
       if (JVMCILibPath != NULL) {
@@ -179,85 +178,107 @@
       }
     }
   }
-  JNIEnv* env;
-  if (_shared_library_javavm->AttachCurrentThread((void**)&env, NULL) == JNI_OK) {
-    guarantee(env != NULL, "missing env");
-    return env;
-  }
-  fatal("Error attaching current thread to JVMCI shared library JNI interface");
   return NULL;
 }
 
-void JVMCIEnv::init_env_mode_runtime(JNIEnv* parent_env) {
+void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) {
+  assert(thread != NULL, "npe");
   // By default there is only one runtime which is the compiler runtime.
   _runtime = JVMCI::compiler_runtime();
+  _env = NULL;
+  _pop_frame_on_close = false;
+  _detach_on_close = false;
   if (!UseJVMCINativeLibrary) {
     // In HotSpot mode, JNI isn't used at all.
     _is_hotspot = true;
-    _env = NULL;
     return;
   }
 
   if (parent_env != NULL) {
     // If the parent JNI environment is non-null then figure out whether it
     // is a HotSpot or shared library JNIEnv and set the state appropriately.
-    JavaThread* thread = JavaThread::current();
-    if (thread->jni_environment() == parent_env) {
+    _is_hotspot = thread->jni_environment() == parent_env;
+    if (_is_hotspot) {
       // Select the Java runtime
       _runtime = JVMCI::java_runtime();
-      _is_hotspot = true;
-      _env = NULL;
       return;
     }
+    _env = parent_env;
+    return;
+  }
+
+  // Running in JVMCI shared library mode so ensure the shared library
+  // is loaded and initialized and get a shared library JNIEnv
+  _is_hotspot = false;
+  _env = init_shared_library(thread);
+
+  if (_env != NULL) {
+    // Creating the JVMCI shared library VM also attaches the current thread
+    _detach_on_close = true;
+  } else {
+    _shared_library_javavm->GetEnv((void**)&parent_env, JNI_VERSION_1_2);
+    if (parent_env != NULL) {
+      // Even though there's a parent JNI env, there's no guarantee
+      // it was opened by a JVMCIEnv scope and thus may not have
+      // pushed a local JNI frame. As such, we use a new JNI local
+      // frame in this scope to ensure local JNI refs are collected
+      // in a timely manner after leaving this scope.
+      _env = parent_env;
+    } else {
+      ResourceMark rm; // Thread name is resource allocated
+      JavaVMAttachArgs attach_args;
+      attach_args.version = JNI_VERSION_1_2;
+      attach_args.name = thread->name();
+      attach_args.group = NULL;
+      if (_shared_library_javavm->AttachCurrentThread((void**)&_env, &attach_args) != JNI_OK) {
+        fatal("Error attaching current thread (%s) to JVMCI shared library JNI interface", attach_args.name);
+      }
+      _detach_on_close = true;
+    }
   }
 
-  // Running in JVMCI shared library mode so get a shared library JNIEnv
-  _is_hotspot = false;
-  _env = attach_shared_library();
-  assert(parent_env == NULL || _env == parent_env, "must be");
+  assert(_env != NULL, "missing env");
+  assert(_throw_to_caller == false, "must be");
 
-  if (parent_env == NULL) {
-    // There is no parent shared library JNI env so push
-    // a JNI local frame to release all local handles in
-    // this JVMCIEnv scope when it's closed.
-    assert(_throw_to_caller == false, "must be");
-    JNIAccessMark jni(this);
-    jint result = _env->PushLocalFrame(32);
-    if (result != JNI_OK) {
-      char message[256];
-      jio_snprintf(message, 256, "Uncaught exception pushing local frame for JVMCIEnv scope entered at %s:%d", _file, _line);
-      JVMCIRuntime::exit_on_pending_exception(this, message);
-    }
+  JNIAccessMark jni(this);
+  jint result = _env->PushLocalFrame(32);
+  if (result != JNI_OK) {
+    char message[256];
+    jio_snprintf(message, 256, "Uncaught exception pushing local frame for JVMCIEnv scope entered at %s:%d", _file, _line);
+    JVMCIRuntime::exit_on_pending_exception(this, message);
   }
+  _pop_frame_on_close = true;
 }
 
-JVMCIEnv::JVMCIEnv(JVMCICompileState* compile_state, const char* file, int line):
+JVMCIEnv::JVMCIEnv(JavaThread* thread, JVMCICompileState* compile_state, const char* file, int line):
     _throw_to_caller(false), _file(file), _line(line), _compile_state(compile_state) {
-  init_env_mode_runtime(NULL);
+  init_env_mode_runtime(thread, NULL);
 }
 
 JVMCIEnv::JVMCIEnv(JavaThread* thread, const char* file, int line):
     _throw_to_caller(false), _file(file), _line(line), _compile_state(NULL) {
-  init_env_mode_runtime(NULL);
+  init_env_mode_runtime(thread, NULL);
 }
 
-JVMCIEnv::JVMCIEnv(JNIEnv* parent_env, const char* file, int line):
+JVMCIEnv::JVMCIEnv(JavaThread* thread, JNIEnv* parent_env, const char* file, int line):
     _throw_to_caller(true), _file(file), _line(line), _compile_state(NULL) {
-  init_env_mode_runtime(parent_env);
+  init_env_mode_runtime(thread, parent_env);
   assert(_env == NULL || parent_env == _env, "mismatched JNIEnvironment");
 }
 
-void JVMCIEnv::init(bool is_hotspot, const char* file, int line) {
+void JVMCIEnv::init(JavaThread* thread, bool is_hotspot, const char* file, int line) {
   _compile_state = NULL;
   _throw_to_caller = false;
   _file = file;
   _line = line;
   if (is_hotspot) {
     _env = NULL;
+    _pop_frame_on_close = false;
+    _detach_on_close = false;
     _is_hotspot = true;
     _runtime = JVMCI::java_runtime();
   } else {
-    init_env_mode_runtime(NULL);
+    init_env_mode_runtime(thread, NULL);
   }
 }
 
@@ -324,7 +345,7 @@
       }
     }
   } else {
-    if (!is_hotspot()) {
+    if (_pop_frame_on_close) {
       // Pop the JNI local frame that was pushed when entering this JVMCIEnv scope.
       JNIAccessMark jni(this);
       jni()->PopLocalFrame(NULL);
@@ -335,6 +356,10 @@
       jio_snprintf(message, 256, "Uncaught exception exiting JVMCIEnv scope entered at %s:%d", _file, _line);
       JVMCIRuntime::exit_on_pending_exception(this, message);
     }
+
+    if (_detach_on_close) {
+      get_shared_library_javavm()->DetachCurrentThread();
+    }
   }
 }
 
@@ -463,26 +488,38 @@
   }
 }
 
-void JVMCIEnv::copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, int size_in_bytes) {
-  if (size_in_bytes == 0) {
+void JVMCIEnv::copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, jsize length) {
+  if (length == 0) {
+    return;
+  }
+  if (is_hotspot()) {
+    memcpy(dest, HotSpotJVMCI::resolve(src)->byte_at_addr(offset), length);
+  } else {
+    JNIAccessMark jni(this);
+    jni()->GetByteArrayRegion(src.as_jbyteArray(), offset, length, dest);
+  }
+}
+void JVMCIEnv::copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, jsize length) {
+  if (length == 0) {
     return;
   }
   if (is_hotspot()) {
-    memcpy(dest, HotSpotJVMCI::resolve(src)->byte_at_addr(offset), size_in_bytes);
+    memcpy(HotSpotJVMCI::resolve(dest)->byte_at_addr(offset), src, length);
   } else {
     JNIAccessMark jni(this);
-    jni()->GetByteArrayRegion(src.as_jbyteArray(), offset, size_in_bytes, dest);
+    jni()->SetByteArrayRegion(dest.as_jbyteArray(), offset, length, src);
   }
 }
-void JVMCIEnv::copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, int size_in_bytes) {
-  if (size_in_bytes == 0) {
+
+void JVMCIEnv::copy_longs_from(jlong* src, JVMCIPrimitiveArray dest, int offset, jsize length) {
+  if (length == 0) {
     return;
   }
   if (is_hotspot()) {
-    memcpy(HotSpotJVMCI::resolve(dest)->byte_at_addr(offset), src, size_in_bytes);
+    memcpy(HotSpotJVMCI::resolve(dest)->long_at_addr(offset), src, length * sizeof(jlong));
   } else {
     JNIAccessMark jni(this);
-    jni()->SetByteArrayRegion(dest.as_jbyteArray(), offset, size_in_bytes, src);
+    jni()->SetLongArrayRegion(dest.as_jlongArray(), offset, length, src);
   }
 }
 
@@ -612,6 +649,8 @@
 DO_THROW(IllegalArgumentException)
 DO_THROW(InvalidInstalledCodeException)
 DO_THROW(UnsatisfiedLinkError)
+DO_THROW(UnsupportedOperationException)
+DO_THROW(ClassNotFoundException)
 
 #undef DO_THROW
 
@@ -888,7 +927,7 @@
       return JVMCIObject();
     }
     jobject file_name = NULL;
-    if (file_name != NULL) {
+    if (file_name_sym != NULL) {
       file_name = jni()->NewStringUTF(file_name_sym->as_C_string());
       if (jni()->ExceptionCheck()) {
         return JVMCIObject();
@@ -1323,14 +1362,15 @@
     assert(HotSpotJVMCI::DirectHotSpotObjectConstantImpl::is_instance(this, constant), "wrong type");
     oop obj = HotSpotJVMCI::DirectHotSpotObjectConstantImpl::object(this, HotSpotJVMCI::resolve(constant));
     return Handle(THREAD, obj);
-  } else {
-    assert(isa_IndirectHotSpotObjectConstantImpl(constant), "wrong type");
+  } else if (isa_IndirectHotSpotObjectConstantImpl(constant)) {
     jlong object_handle = get_IndirectHotSpotObjectConstantImpl_objectHandle(constant);
     oop result = resolve_handle(object_handle);
     if (result == NULL) {
       JVMCI_THROW_MSG_(InternalError, "Constant was unexpectedly NULL", Handle());
     }
     return Handle(THREAD, result);
+  } else {
+    JVMCI_THROW_MSG_(IllegalArgumentException, "DirectHotSpotObjectConstantImpl shouldn't reach JVMCI in SVM mode", Handle());
   }
 }