changeset 54732:2d012a75d35c

8223332: Update JVMCI Reviewed-by: never, dnsimon
author kvn
date Mon, 06 May 2019 20:05:19 -0700
parents 81de17a33575
children 28dd27202591
files src/hotspot/share/compiler/compileBroker.cpp src/hotspot/share/jvmci/jvmciCompilerToVM.cpp src/hotspot/share/jvmci/jvmciCompilerToVM.hpp src/hotspot/share/jvmci/jvmciEnv.cpp src/hotspot/share/jvmci/jvmciEnv.hpp src/hotspot/share/jvmci/jvmciExceptions.hpp src/hotspot/share/jvmci/jvmciJavaClasses.cpp src/hotspot/share/jvmci/jvmciJavaClasses.hpp src/hotspot/share/jvmci/jvmciRuntime.cpp src/hotspot/share/jvmci/jvmci_globals.cpp src/hotspot/share/jvmci/jvmci_globals.hpp src/hotspot/share/jvmci/vmStructs_jvmci.cpp src/hotspot/share/runtime/objectMonitor.hpp src/hotspot/share/runtime/thread.cpp src/hotspot/share/runtime/thread.hpp src/hotspot/share/runtime/vmOperations.cpp src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigStore.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/SuppressFBWarnings.java src/jdk.internal.vm.ci/share/classes/module-info.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotJVMCIRuntime.java test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestServices.java test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java
diffstat 30 files changed, 1040 insertions(+), 347 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/compiler/compileBroker.cpp	Tue May 07 10:21:04 2019 +0800
+++ b/src/hotspot/share/compiler/compileBroker.cpp	Mon May 06 20:05:19 2019 -0700
@@ -70,7 +70,6 @@
 #if INCLUDE_JVMCI
 #include "jvmci/jvmciEnv.hpp"
 #include "jvmci/jvmciRuntime.hpp"
-#include "runtime/vframe.hpp"
 #endif
 #ifdef COMPILER2
 #include "opto/c2compiler.hpp"
@@ -1063,20 +1062,22 @@
     }
 
 #if INCLUDE_JVMCI
-    if (UseJVMCICompiler && blocking && !UseJVMCINativeLibrary) {
+    if (UseJVMCICompiler && blocking) {
       // Don't allow blocking compiles for requests triggered by JVMCI.
       if (thread->is_Compiler_thread()) {
         blocking = false;
       }
 
-      // Don't allow blocking compiles if inside a class initializer or while performing class loading
-      vframeStream vfst((JavaThread*) thread);
-      for (; !vfst.at_end(); vfst.next()) {
-        if (vfst.method()->is_static_initializer() ||
-            (vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) &&
-                vfst.method()->name() == vmSymbols::loadClass_name())) {
-          blocking = false;
-          break;
+      if (!UseJVMCINativeLibrary) {
+        // Don't allow blocking compiles if inside a class initializer or while performing class loading
+        vframeStream vfst((JavaThread*) thread);
+        for (; !vfst.at_end(); vfst.next()) {
+          if (vfst.method()->is_static_initializer() ||
+              (vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) &&
+                  vfst.method()->name() == vmSymbols::loadClass_name())) {
+            blocking = false;
+            break;
+          }
         }
       }
 
@@ -2063,7 +2064,7 @@
       compilable = ciEnv::MethodCompilable_never;
     } else {
       JVMCICompileState compile_state(task, system_dictionary_modification_counter);
-      JVMCIEnv env(&compile_state, __FILE__, __LINE__);
+      JVMCIEnv env(thread, &compile_state, __FILE__, __LINE__);
       methodHandle method(thread, target_handle);
       env.runtime()->compile_method(&env, jvmci, method, osr_bci);
 
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	Tue May 07 10:21:04 2019 +0800
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	Mon May 06 20:05:19 2019 -0700
@@ -62,12 +62,17 @@
   return *this;
 }
 
-void JNIHandleMark::push_jni_handle_block() {
-  JavaThread* thread = JavaThread::current();
+static void requireInHotSpot(const char* caller, JVMCI_TRAPS) {
+  if (!JVMCIENV->is_hotspot()) {
+    JVMCI_THROW_MSG(IllegalStateException, err_msg("Cannot call %s from JVMCI shared library", caller));
+  }
+}
+
+void JNIHandleMark::push_jni_handle_block(JavaThread* thread) {
   if (thread != NULL) {
     // Allocate a new block for JNI handles.
     // Inlined code from jni_PushLocalFrame()
-    JNIHandleBlock* java_handles = ((JavaThread*)thread)->active_handles();
+    JNIHandleBlock* java_handles = thread->active_handles();
     JNIHandleBlock* compile_handles = JNIHandleBlock::allocate_block(thread);
     assert(compile_handles != NULL && java_handles != NULL, "should not be NULL");
     compile_handles->set_pop_frame_link(java_handles);
@@ -75,8 +80,7 @@
   }
 }
 
-void JNIHandleMark::pop_jni_handle_block() {
-  JavaThread* thread = JavaThread::current();
+void JNIHandleMark::pop_jni_handle_block(JavaThread* thread) {
   if (thread != NULL) {
     // Release our JNI handle block
     JNIHandleBlock* compile_handles = thread->active_handles();
@@ -111,25 +115,88 @@
   return Handle(Thread::current(), arg);
 }
 
-// Entry to native method implementation that transitions current thread to '_thread_in_vm'.
+// Bring the JVMCI compiler thread into the VM state.
+#define JVMCI_VM_ENTRY_MARK                   \
+  ThreadInVMfromNative __tiv(thread);         \
+  ResetNoHandleMark rnhm;                     \
+  HandleMarkCleaner __hm(thread);             \
+  Thread* THREAD = thread;                    \
+  debug_only(VMNativeEntryWrapper __vew;)
+
+// Native method block that transitions current thread to '_thread_in_vm'.
+#define C2V_BLOCK(result_type, name, signature)      \
+  TRACE_CALL(result_type, jvmci_ ## name signature)  \
+  JVMCI_VM_ENTRY_MARK;                               \
+  ResourceMark rm;                                   \
+  JNI_JVMCIENV(thread, env);
+
+static Thread* get_current_thread() {
+  return Thread::current_or_null_safe();
+}
+
+// Entry to native method implementation that transitions
+// current thread to '_thread_in_vm'.
 #define C2V_VMENTRY(result_type, name, signature)        \
   JNIEXPORT result_type JNICALL c2v_ ## name signature { \
+  Thread* base_thread = get_current_thread();            \
+  if (base_thread == NULL) {                             \
+    env->ThrowNew(JNIJVMCI::InternalError::clazz(),      \
+        err_msg("Cannot call into HotSpot from JVMCI shared library without attaching current thread")); \
+    return;                                              \
+  }                                                      \
+  assert(base_thread->is_Java_thread(), "just checking");\
+  JavaThread* thread = (JavaThread*) base_thread;        \
   JVMCITraceMark jtm("CompilerToVM::" #name);            \
-  TRACE_CALL(result_type, jvmci_ ## name signature)      \
-  JVMCI_VM_ENTRY_MARK;                                   \
-  ResourceMark rm;                                       \
-  JNI_JVMCIENV(env);
+  C2V_BLOCK(result_type, name, signature)
+
+#define C2V_VMENTRY_(result_type, name, signature, result) \
+  JNIEXPORT result_type JNICALL c2v_ ## name signature { \
+  Thread* base_thread = get_current_thread();            \
+  if (base_thread == NULL) {                             \
+    env->ThrowNew(JNIJVMCI::InternalError::clazz(),      \
+        err_msg("Cannot call into HotSpot from JVMCI shared library without attaching current thread")); \
+    return result;                                       \
+  }                                                      \
+  assert(base_thread->is_Java_thread(), "just checking");\
+  JavaThread* thread = (JavaThread*) base_thread;        \
+  JVMCITraceMark jtm("CompilerToVM::" #name);            \
+  C2V_BLOCK(result_type, name, signature)
+
+#define C2V_VMENTRY_NULL(result_type, name, signature) C2V_VMENTRY_(result_type, name, signature, NULL)
+#define C2V_VMENTRY_0(result_type, name, signature) C2V_VMENTRY_(result_type, name, signature, 0)
+
+// Entry to native method implementation that does not transition
+// current thread to '_thread_in_vm'.
+#define C2V_VMENTRY_PREFIX(result_type, name, signature) \
+  JNIEXPORT result_type JNICALL c2v_ ## name signature { \
+  Thread* base_thread = get_current_thread();
 
 #define C2V_END }
 
+#define JNI_THROW(caller, name, msg) do {                                         \
+    jint __throw_res = env->ThrowNew(JNIJVMCI::name::clazz(), msg);               \
+    if (__throw_res != JNI_OK) {                                                  \
+      tty->print_cr("Throwing " #name " in " caller " returned %d", __throw_res); \
+    }                                                                             \
+    return;                                                                       \
+  } while (0);
+
+#define JNI_THROW_(caller, name, msg, result) do {                                \
+    jint __throw_res = env->ThrowNew(JNIJVMCI::name::clazz(), msg);               \
+    if (__throw_res != JNI_OK) {                                                  \
+      tty->print_cr("Throwing " #name " in " caller " returned %d", __throw_res); \
+    }                                                                             \
+    return result;                                                                \
+  } while (0)
+
 jobjectArray readConfiguration0(JNIEnv *env, JVMCI_TRAPS);
 
-C2V_VMENTRY(jobjectArray, readConfiguration, (JNIEnv* env))
+C2V_VMENTRY_NULL(jobjectArray, readConfiguration, (JNIEnv* env))
   jobjectArray config = readConfiguration0(env, JVMCI_CHECK_NULL);
   return config;
 }
 
-C2V_VMENTRY(jobject, getFlagValue, (JNIEnv* env, jobject c2vm, jobject name_handle))
+C2V_VMENTRY_NULL(jobject, getFlagValue, (JNIEnv* env, jobject c2vm, jobject name_handle))
 #define RETURN_BOXED_LONG(value) jvalue p; p.j = (jlong) (value); JVMCIObject box = JVMCIENV->create_box(T_LONG, &p, JVMCI_CHECK_NULL); return box.as_jobject();
 #define RETURN_BOXED_DOUBLE(value) jvalue p; p.d = (jdouble) (value); JVMCIObject box = JVMCIENV->create_box(T_DOUBLE, &p, JVMCI_CHECK_NULL); return box.as_jobject();
   JVMCIObject name = JVMCIENV->wrap(name_handle);
@@ -170,10 +237,8 @@
 #undef RETURN_BOXED_DOUBLE
 C2V_END
 
-C2V_VMENTRY(jobject, getObjectAtAddress, (JNIEnv* env, jobject c2vm, jlong oop_address))
-  if (env != JavaThread::current()->jni_environment()) {
-    JVMCI_THROW_MSG_NULL(InternalError, "Only supported when running in HotSpot");
-  }
+C2V_VMENTRY_NULL(jobject, getObjectAtAddress, (JNIEnv* env, jobject c2vm, jlong oop_address))
+  requireInHotSpot("getObjectAtAddress", JVMCI_CHECK_NULL);
   if (oop_address == 0) {
     JVMCI_THROW_MSG_NULL(InternalError, "Handle must be non-zero");
   }
@@ -184,7 +249,7 @@
   return JNIHandles::make_local(obj);
 C2V_END
 
-C2V_VMENTRY(jbyteArray, getBytecode, (JNIEnv* env, jobject, jobject jvmci_method))
+C2V_VMENTRY_NULL(jbyteArray, getBytecode, (JNIEnv* env, jobject, jobject jvmci_method))
   methodHandle method = JVMCIENV->asMethod(jvmci_method);
 
   int code_size = method->code_size();
@@ -262,12 +327,12 @@
   return JVMCIENV->get_jbyteArray(result);
 C2V_END
 
-C2V_VMENTRY(jint, getExceptionTableLength, (JNIEnv* env, jobject, jobject jvmci_method))
+C2V_VMENTRY_0(jint, getExceptionTableLength, (JNIEnv* env, jobject, jobject jvmci_method))
   methodHandle method = JVMCIENV->asMethod(jvmci_method);
   return method->exception_table_length();
 C2V_END
 
-C2V_VMENTRY(jlong, getExceptionTableStart, (JNIEnv* env, jobject, jobject jvmci_method))
+C2V_VMENTRY_0(jlong, getExceptionTableStart, (JNIEnv* env, jobject, jobject jvmci_method))
   methodHandle method = JVMCIENV->asMethod(jvmci_method);
   if (method->exception_table_length() == 0) {
     return 0L;
@@ -275,11 +340,8 @@
   return (jlong) (address) method->exception_table_start();
 C2V_END
 
-C2V_VMENTRY(jobject, asResolvedJavaMethod, (JNIEnv* env, jobject, jobject executable_handle))
-  if (env != JavaThread::current()->jni_environment()) {
-    JVMCI_THROW_MSG_NULL(InternalError, "Only supported when running in HotSpot");
-  }
-
+C2V_VMENTRY_NULL(jobject, asResolvedJavaMethod, (JNIEnv* env, jobject, jobject executable_handle))
+  requireInHotSpot("asResolvedJavaMethod", JVMCI_CHECK_NULL);
   oop executable = JNIHandles::resolve(executable_handle);
   oop mirror = NULL;
   int slot = 0;
@@ -298,7 +360,7 @@
   return JVMCIENV->get_jobject(result);
 }
 
-C2V_VMENTRY(jobject, getResolvedJavaMethod, (JNIEnv* env, jobject, jobject base, jlong offset))
+C2V_VMENTRY_NULL(jobject, getResolvedJavaMethod, (JNIEnv* env, jobject, jobject base, jlong offset))
   methodHandle method;
   JVMCIObject base_object = JVMCIENV->wrap(base);
   if (base_object.is_null()) {
@@ -321,7 +383,7 @@
   return JVMCIENV->get_jobject(result);
 }
 
-C2V_VMENTRY(jobject, getConstantPool, (JNIEnv* env, jobject, jobject object_handle))
+C2V_VMENTRY_NULL(jobject, getConstantPool, (JNIEnv* env, jobject, jobject object_handle))
   constantPoolHandle cp;
   JVMCIObject object = JVMCIENV->wrap(object_handle);
   if (object.is_null()) {
@@ -341,7 +403,7 @@
   return JVMCIENV->get_jobject(result);
 }
 
-C2V_VMENTRY(jobject, getResolvedJavaType0, (JNIEnv* env, jobject, jobject base, jlong offset, jboolean compressed))
+C2V_VMENTRY_NULL(jobject, getResolvedJavaType0, (JNIEnv* env, jobject, jobject base, jlong offset, jboolean compressed))
   JVMCIKlassHandle klass(THREAD);
   JVMCIObject base_object = JVMCIENV->wrap(base);
   jlong base_address = 0;
@@ -384,7 +446,7 @@
   return JVMCIENV->get_jobject(result);
 }
 
-C2V_VMENTRY(jobject, findUniqueConcreteMethod, (JNIEnv* env, jobject, jobject jvmci_type, jobject jvmci_method))
+C2V_VMENTRY_NULL(jobject, findUniqueConcreteMethod, (JNIEnv* env, jobject, jobject jvmci_type, jobject jvmci_method))
   methodHandle method = JVMCIENV->asMethod(jvmci_method);
   Klass* holder = JVMCIENV->asKlass(jvmci_type);
   if (holder->is_interface()) {
@@ -400,7 +462,7 @@
   return JVMCIENV->get_jobject(result);
 C2V_END
 
-C2V_VMENTRY(jobject, getImplementor, (JNIEnv* env, jobject, jobject jvmci_type))
+C2V_VMENTRY_NULL(jobject, getImplementor, (JNIEnv* env, jobject, jobject jvmci_type))
   Klass* klass = JVMCIENV->asKlass(jvmci_type);
   if (!klass->is_interface()) {
     THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
@@ -417,12 +479,12 @@
   return JVMCIENV->get_jobject(implementor);
 C2V_END
 
-C2V_VMENTRY(jboolean, methodIsIgnoredBySecurityStackWalk,(JNIEnv* env, jobject, jobject jvmci_method))
+C2V_VMENTRY_0(jboolean, methodIsIgnoredBySecurityStackWalk,(JNIEnv* env, jobject, jobject jvmci_method))
   methodHandle method = JVMCIENV->asMethod(jvmci_method);
   return method->is_ignored_by_security_stack_walk();
 C2V_END
 
-C2V_VMENTRY(jboolean, isCompilable,(JNIEnv* env, jobject, jobject jvmci_method))
+C2V_VMENTRY_0(jboolean, isCompilable,(JNIEnv* env, jobject, jobject jvmci_method))
   methodHandle method = JVMCIENV->asMethod(jvmci_method);
   constantPoolHandle cp = method->constMethod()->constants();
   assert(!cp.is_null(), "npe");
@@ -430,17 +492,17 @@
   return !method->is_not_compilable(CompLevel_full_optimization) && !cp->has_dynamic_constant();
 C2V_END
 
-C2V_VMENTRY(jboolean, hasNeverInlineDirective,(JNIEnv* env, jobject, jobject jvmci_method))
+C2V_VMENTRY_0(jboolean, hasNeverInlineDirective,(JNIEnv* env, jobject, jobject jvmci_method))
   methodHandle method = JVMCIENV->asMethod(jvmci_method);
   return !Inline || CompilerOracle::should_not_inline(method) || method->dont_inline();
 C2V_END
 
-C2V_VMENTRY(jboolean, shouldInlineMethod,(JNIEnv* env, jobject, jobject jvmci_method))
+C2V_VMENTRY_0(jboolean, shouldInlineMethod,(JNIEnv* env, jobject, jobject jvmci_method))
   methodHandle method = JVMCIENV->asMethod(jvmci_method);
   return CompilerOracle::should_inline(method) || method->force_inline();
 C2V_END
 
-C2V_VMENTRY(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, jclass accessing_class, jboolean resolve))
+C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, jclass accessing_class, jboolean resolve))
   JVMCIObject name = JVMCIENV->wrap(jname);
   const char* str = JVMCIENV->as_utf8_string(name);
   TempNewSymbol class_name = SymbolTable::new_symbol(str, CHECK_NULL);
@@ -465,6 +527,9 @@
 
   if (resolve) {
     resolved_klass = SystemDictionary::resolve_or_null(class_name, class_loader, protection_domain, CHECK_0);
+    if (resolved_klass == NULL) {
+      JVMCI_THROW_MSG_NULL(ClassNotFoundException, str);
+    }
   } else {
     if (class_name->char_at(0) == 'L' &&
       class_name->char_at(class_name->utf8_length()-1) == ';') {
@@ -483,7 +548,6 @@
         TempNewSymbol strippedsym = SymbolTable::new_symbol(class_name->as_utf8()+1+fd.dimension(),
                                                             class_name->utf8_length()-2-fd.dimension(),
                                                             CHECK_0);
-        // naked oop "k" is OK here -- we assign back into it
         resolved_klass = SystemDictionary::find(strippedsym,
                                                              class_loader,
                                                              protection_domain,
@@ -502,10 +566,8 @@
   return JVMCIENV->get_jobject(result);
 C2V_END
 
-C2V_VMENTRY(jobject, lookupClass, (JNIEnv* env, jobject, jclass mirror))
-  if (env != JavaThread::current()->jni_environment()) {
-    JVMCI_THROW_MSG_NULL(InternalError, "Only supported when running in HotSpot");
-  }
+C2V_VMENTRY_NULL(jobject, lookupClass, (JNIEnv* env, jobject, jclass mirror))
+  requireInHotSpot("lookupClass", JVMCI_CHECK_NULL);
   if (mirror == NULL) {
     return NULL;
   }
@@ -518,55 +580,56 @@
   return JVMCIENV->get_jobject(result);
 }
 
-C2V_VMENTRY(jobject, resolveConstantInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
+C2V_VMENTRY_NULL(jobject, resolveConstantInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
   constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool);
   oop result = cp->resolve_constant_at(index, CHECK_NULL);
   return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(result));
 C2V_END
 
-C2V_VMENTRY(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
+C2V_VMENTRY_NULL(jobject, resolvePossiblyCachedConstantInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
   constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool);
   oop result = cp->resolve_possibly_cached_constant_at(index, CHECK_NULL);
   return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(result));
 C2V_END
 
-C2V_VMENTRY(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
+C2V_VMENTRY_0(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
   constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool);
   return cp->name_and_type_ref_index_at(index);
 C2V_END
 
-C2V_VMENTRY(jobject, lookupNameInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint which))
+C2V_VMENTRY_NULL(jobject, lookupNameInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint which))
   constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool);
   JVMCIObject sym = JVMCIENV->create_string(cp->name_ref_at(which), JVMCI_CHECK_NULL);
   return JVMCIENV->get_jobject(sym);
 C2V_END
 
-C2V_VMENTRY(jobject, lookupSignatureInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint which))
+C2V_VMENTRY_NULL(jobject, lookupSignatureInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint which))
   constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool);
   JVMCIObject sym = JVMCIENV->create_string(cp->signature_ref_at(which), JVMCI_CHECK_NULL);
   return JVMCIENV->get_jobject(sym);
 C2V_END
 
-C2V_VMENTRY(jint, lookupKlassRefIndexInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
+C2V_VMENTRY_0(jint, lookupKlassRefIndexInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
   constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool);
   return cp->klass_ref_index_at(index);
 C2V_END
 
-C2V_VMENTRY(jobject, resolveTypeInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
+C2V_VMENTRY_NULL(jobject, resolveTypeInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
   constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool);
   Klass* klass = cp->klass_at(index, CHECK_NULL);
   JVMCIKlassHandle resolved_klass(THREAD, klass);
   if (resolved_klass->is_instance_klass()) {
-    bool linked = InstanceKlass::cast(resolved_klass())->link_class_or_fail(CHECK_NULL);
-    if (!linked) {
-      return NULL;
+    InstanceKlass::cast(resolved_klass())->link_class(CHECK_NULL);
+    if (!InstanceKlass::cast(resolved_klass())->is_linked()) {
+      // link_class() should not return here if there is an issue.
+      JVMCI_THROW_MSG_NULL(InternalError, err_msg("Class %s must be linked", resolved_klass()->external_name()));
     }
   }
   JVMCIObject klassObject = JVMCIENV->get_jvmci_type(resolved_klass, JVMCI_CHECK_NULL);
   return JVMCIENV->get_jobject(klassObject);
 C2V_END
 
-C2V_VMENTRY(jobject, lookupKlassInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode))
+C2V_VMENTRY_NULL(jobject, lookupKlassInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode))
   constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool);
   Klass* loading_klass = cp->pool_holder();
   bool is_accessible = false;
@@ -594,13 +657,13 @@
   return JVMCIENV->get_jobject(result);
 C2V_END
 
-C2V_VMENTRY(jobject, lookupAppendixInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
+C2V_VMENTRY_NULL(jobject, lookupAppendixInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
   constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool);
   oop appendix_oop = ConstantPool::appendix_at_if_loaded(cp, index);
   return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(appendix_oop));
 C2V_END
 
-C2V_VMENTRY(jobject, lookupMethodInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode))
+C2V_VMENTRY_NULL(jobject, lookupMethodInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode))
   constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool);
   InstanceKlass* pool_holder = cp->pool_holder();
   Bytecodes::Code bc = (Bytecodes::Code) (((int) opcode) & 0xFF);
@@ -609,12 +672,12 @@
   return JVMCIENV->get_jobject(result);
 C2V_END
 
-C2V_VMENTRY(jint, constantPoolRemapInstructionOperandFromCache, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
+C2V_VMENTRY_0(jint, constantPoolRemapInstructionOperandFromCache, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
   constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool);
   return cp->remap_instruction_operand_from_cache(index);
 C2V_END
 
-C2V_VMENTRY(jobject, resolveFieldInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index, jobject jvmci_method, jbyte opcode, jintArray info_handle))
+C2V_VMENTRY_NULL(jobject, resolveFieldInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index, jobject jvmci_method, jbyte opcode, jintArray info_handle))
   constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool);
   Bytecodes::Code code = (Bytecodes::Code)(((int) opcode) & 0xFF);
   fieldDescriptor fd;
@@ -632,7 +695,7 @@
   return JVMCIENV->get_jobject(field_holder);
 C2V_END
 
-C2V_VMENTRY(jint, getVtableIndexForInterfaceMethod, (JNIEnv* env, jobject, jobject jvmci_type, jobject jvmci_method))
+C2V_VMENTRY_0(jint, getVtableIndexForInterfaceMethod, (JNIEnv* env, jobject, jobject jvmci_type, jobject jvmci_method))
   Klass* klass = JVMCIENV->asKlass(jvmci_type);
   Method* method = JVMCIENV->asMethod(jvmci_method);
   if (klass->is_interface()) {
@@ -650,7 +713,7 @@
   return LinkResolver::vtable_index_of_interface_method(klass, method);
 C2V_END
 
-C2V_VMENTRY(jobject, resolveMethod, (JNIEnv* env, jobject, jobject receiver_jvmci_type, jobject jvmci_method, jobject caller_jvmci_type))
+C2V_VMENTRY_NULL(jobject, resolveMethod, (JNIEnv* env, jobject, jobject receiver_jvmci_type, jobject jvmci_method, jobject caller_jvmci_type))
   Klass* recv_klass = JVMCIENV->asKlass(receiver_jvmci_type);
   Klass* caller_klass = JVMCIENV->asKlass(caller_jvmci_type);
   methodHandle method = JVMCIENV->asMethod(jvmci_method);
@@ -697,13 +760,13 @@
   return JVMCIENV->get_jobject(result);
 C2V_END
 
-C2V_VMENTRY(jboolean, hasFinalizableSubclass,(JNIEnv* env, jobject, jobject jvmci_type))
+C2V_VMENTRY_0(jboolean, hasFinalizableSubclass,(JNIEnv* env, jobject, jobject jvmci_type))
   Klass* klass = JVMCIENV->asKlass(jvmci_type);
   assert(klass != NULL, "method must not be called for primitive types");
   return Dependencies::find_finalizable_subclass(klass) != NULL;
 C2V_END
 
-C2V_VMENTRY(jobject, getClassInitializer, (JNIEnv* env, jobject, jobject jvmci_type))
+C2V_VMENTRY_NULL(jobject, getClassInitializer, (JNIEnv* env, jobject, jobject jvmci_type))
   Klass* klass = JVMCIENV->asKlass(jvmci_type);
   if (!klass->is_instance_klass()) {
     return NULL;
@@ -713,7 +776,7 @@
   return JVMCIENV->get_jobject(result);
 C2V_END
 
-C2V_VMENTRY(jlong, getMaxCallTargetOffset, (JNIEnv* env, jobject, jlong addr))
+C2V_VMENTRY_0(jlong, getMaxCallTargetOffset, (JNIEnv* env, jobject, jlong addr))
   address target_addr = (address) addr;
   if (target_addr != 0x0) {
     int64_t off_low = (int64_t)target_addr - ((int64_t)CodeCache::low_bound() + sizeof(int));
@@ -730,10 +793,10 @@
   method->set_dont_inline(true);
 C2V_END
 
-C2V_VMENTRY(jint, installCode, (JNIEnv *env, jobject, jobject target, jobject compiled_code,
+C2V_VMENTRY_0(jint, installCode, (JNIEnv *env, jobject, jobject target, jobject compiled_code,
             jobject installed_code, jlong failed_speculations_address, jbyteArray speculations_obj))
   HandleMark hm;
-  JNIHandleMark jni_hm;
+  JNIHandleMark jni_hm(thread);
 
   JVMCIObject target_handle = JVMCIENV->wrap(target);
   JVMCIObject compiled_code_handle = JVMCIENV->wrap(compiled_code);
@@ -791,7 +854,7 @@
   return result;
 C2V_END
 
-C2V_VMENTRY(jint, getMetadata, (JNIEnv *env, jobject, jobject target, jobject compiled_code, jobject metadata))
+C2V_VMENTRY_0(jint, getMetadata, (JNIEnv *env, jobject, jobject target, jobject compiled_code, jobject metadata))
 #if INCLUDE_AOT
   HandleMark hm;
   assert(JVMCIENV->is_hotspot(), "AOT code is executed only in HotSpot mode");
@@ -872,7 +935,7 @@
   stats->_osr.reset();
 C2V_END
 
-C2V_VMENTRY(jobject, disassembleCodeBlob, (JNIEnv* env, jobject, jobject installedCode))
+C2V_VMENTRY_NULL(jobject, disassembleCodeBlob, (JNIEnv* env, jobject, jobject installedCode))
   HandleMark hm;
 
   if (installedCode == NULL) {
@@ -909,7 +972,7 @@
   return JVMCIENV->get_jobject(result);
 C2V_END
 
-C2V_VMENTRY(jobject, getStackTraceElement, (JNIEnv* env, jobject, jobject jvmci_method, int bci))
+C2V_VMENTRY_NULL(jobject, getStackTraceElement, (JNIEnv* env, jobject, jobject jvmci_method, int bci))
   HandleMark hm;
 
   methodHandle method = JVMCIENV->asMethod(jvmci_method);
@@ -917,12 +980,10 @@
   return JVMCIENV->get_jobject(element);
 C2V_END
 
-C2V_VMENTRY(jobject, executeHotSpotNmethod, (JNIEnv* env, jobject, jobject args, jobject hs_nmethod))
-  if (env != JavaThread::current()->jni_environment()) {
-    // The incoming arguments array would have to contain JavaConstants instead of regular objects
-    // and the return value would have to be wrapped as a JavaConstant.
-    JVMCI_THROW_MSG_NULL(InternalError, "Wrapping of arguments is currently unsupported");
-  }
+C2V_VMENTRY_NULL(jobject, executeHotSpotNmethod, (JNIEnv* env, jobject, jobject args, jobject hs_nmethod))
+  // The incoming arguments array would have to contain JavaConstants instead of regular objects
+  // and the return value would have to be wrapped as a JavaConstant.
+  requireInHotSpot("executeHotSpotNmethod", JVMCI_CHECK_NULL);
 
   HandleMark hm;
 
@@ -968,7 +1029,7 @@
   }
 C2V_END
 
-C2V_VMENTRY(jlongArray, getLineNumberTable, (JNIEnv* env, jobject, jobject jvmci_method))
+C2V_VMENTRY_NULL(jlongArray, getLineNumberTable, (JNIEnv* env, jobject, jobject jvmci_method))
   Method* method = JVMCIENV->asMethod(jvmci_method);
   if (!method->has_linenumber_table()) {
     return NULL;
@@ -995,7 +1056,7 @@
   return (jlongArray) JVMCIENV->get_jobject(result);
 C2V_END
 
-C2V_VMENTRY(jlong, getLocalVariableTableStart, (JNIEnv* env, jobject, jobject jvmci_method))
+C2V_VMENTRY_0(jlong, getLocalVariableTableStart, (JNIEnv* env, jobject, jobject jvmci_method))
   Method* method = JVMCIENV->asMethod(jvmci_method);
   if (!method->has_localvariable_table()) {
     return 0;
@@ -1003,7 +1064,7 @@
   return (jlong) (address) method->localvariable_table_start();
 C2V_END
 
-C2V_VMENTRY(jint, getLocalVariableTableLength, (JNIEnv* env, jobject, jobject jvmci_method))
+C2V_VMENTRY_0(jint, getLocalVariableTableLength, (JNIEnv* env, jobject, jobject jvmci_method))
   Method* method = JVMCIENV->asMethod(jvmci_method);
   return method->localvariable_table_length();
 C2V_END
@@ -1037,18 +1098,23 @@
   JVMCIENV->invalidate_nmethod_mirror(nmethod_mirror, JVMCI_CHECK);
 C2V_END
 
-C2V_VMENTRY(jobject, readUncompressedOop, (JNIEnv* env, jobject, jlong addr))
+C2V_VMENTRY_NULL(jobject, readUncompressedOop, (JNIEnv* env, jobject, jlong addr))
   oop ret = RawAccess<>::oop_load((oop*)(address)addr);
   return JVMCIENV->get_jobject(JVMCIENV->get_object_constant(ret));
  C2V_END
 
-C2V_VMENTRY(jlongArray, collectCounters, (JNIEnv* env, jobject))
+C2V_VMENTRY_NULL(jlongArray, collectCounters, (JNIEnv* env, jobject))
+  // Returns a zero length array if counters aren't enabled
   JVMCIPrimitiveArray array = JVMCIENV->new_longArray(JVMCICounterSize, JVMCI_CHECK_NULL);
-  JavaThread::collect_counters(JVMCIENV, array);
+  if (JVMCICounterSize > 0) {
+    jlong* temp_array = NEW_RESOURCE_ARRAY(jlong, JVMCICounterSize);
+    JavaThread::collect_counters(temp_array, JVMCICounterSize);
+    JVMCIENV->copy_longs_from(temp_array, array, 0, JVMCICounterSize);
+  }
   return (jlongArray) JVMCIENV->get_jobject(array);
 C2V_END
 
-C2V_VMENTRY(int, allocateCompileId, (JNIEnv* env, jobject, jobject jvmci_method, int entry_bci))
+C2V_VMENTRY_0(int, allocateCompileId, (JNIEnv* env, jobject, jobject jvmci_method, int entry_bci))
   HandleMark hm;
   if (jvmci_method == NULL) {
     JVMCI_THROW_0(NullPointerException);
@@ -1061,17 +1127,17 @@
 C2V_END
 
 
-C2V_VMENTRY(jboolean, isMature, (JNIEnv* env, jobject, jlong metaspace_method_data))
+C2V_VMENTRY_0(jboolean, isMature, (JNIEnv* env, jobject, jlong metaspace_method_data))
   MethodData* mdo = JVMCIENV->asMethodData(metaspace_method_data);
   return mdo != NULL && mdo->is_mature();
 C2V_END
 
-C2V_VMENTRY(jboolean, hasCompiledCodeForOSR, (JNIEnv* env, jobject, jobject jvmci_method, int entry_bci, int comp_level))
+C2V_VMENTRY_0(jboolean, hasCompiledCodeForOSR, (JNIEnv* env, jobject, jobject jvmci_method, int entry_bci, int comp_level))
   Method* method = JVMCIENV->asMethod(jvmci_method);
   return method->lookup_osr_nmethod_for(entry_bci, comp_level, true) != NULL;
 C2V_END
 
-C2V_VMENTRY(jobject, getSymbol, (JNIEnv* env, jobject, jlong symbol))
+C2V_VMENTRY_NULL(jobject, getSymbol, (JNIEnv* env, jobject, jlong symbol))
   JVMCIObject sym = JVMCIENV->create_string((Symbol*)(address)symbol, JVMCI_CHECK_NULL);
   return JVMCIENV->get_jobject(sym);
 C2V_END
@@ -1102,16 +1168,14 @@
   JavaCalls::call(result, method, args, CHECK);
 }
 
-C2V_VMENTRY(jobject, iterateFrames, (JNIEnv* env, jobject compilerToVM, jobjectArray initial_methods, jobjectArray match_methods, jint initialSkip, jobject visitor_handle))
+C2V_VMENTRY_NULL(jobject, iterateFrames, (JNIEnv* env, jobject compilerToVM, jobjectArray initial_methods, jobjectArray match_methods, jint initialSkip, jobject visitor_handle))
 
   if (!thread->has_last_Java_frame()) {
     return NULL;
   }
   Handle visitor(THREAD, JNIHandles::resolve_non_null(visitor_handle));
 
-  if (env != JavaThread::current()->jni_environment()) {
-    JVMCI_THROW_MSG_NULL(InternalError, "getNextStackFrame is only supported for HotSpot stack walking");
-  }
+  requireInHotSpot("iterateFrames", JVMCI_CHECK_NULL);
 
   HotSpotJVMCI::HotSpotStackFrameReference::klass()->initialize(CHECK_NULL);
   Handle frame_reference = HotSpotJVMCI::HotSpotStackFrameReference::klass()->allocate_instance_handle(CHECK_NULL);
@@ -1283,7 +1347,7 @@
   }
 C2V_END
 
-C2V_VMENTRY(jint, isResolvedInvokeHandleInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
+C2V_VMENTRY_0(jint, isResolvedInvokeHandleInPool, (JNIEnv* env, jobject, jobject jvmci_constant_pool, jint index))
   constantPoolHandle cp = JVMCIENV->asConstantPool(jvmci_constant_pool);
   ConstantPoolCacheEntry* cp_cache_entry = cp->cache()->entry_at(cp->decode_cpcache_index(index));
   if (cp_cache_entry->is_resolved(Bytecodes::_invokehandle)) {
@@ -1324,7 +1388,7 @@
 C2V_END
 
 
-C2V_VMENTRY(jobject, getSignaturePolymorphicHolders, (JNIEnv* env, jobject))
+C2V_VMENTRY_NULL(jobject, getSignaturePolymorphicHolders, (JNIEnv* env, jobject))
   JVMCIObjectArray holders = JVMCIENV->new_String_array(2, JVMCI_CHECK_NULL);
   JVMCIObject mh = JVMCIENV->create_string("Ljava/lang/invoke/MethodHandle;", JVMCI_CHECK_NULL);
   JVMCIObject vh = JVMCIENV->create_string("Ljava/lang/invoke/VarHandle;", JVMCI_CHECK_NULL);
@@ -1333,7 +1397,7 @@
   return JVMCIENV->get_jobject(holders);
 C2V_END
 
-C2V_VMENTRY(jboolean, shouldDebugNonSafepoints, (JNIEnv* env, jobject))
+C2V_VMENTRY_0(jboolean, shouldDebugNonSafepoints, (JNIEnv* env, jobject))
   //see compute_recording_non_safepoints in debugInfroRec.cpp
   if (JvmtiExport::should_post_compiled_method_load() && FLAG_IS_DEFAULT(DebugNonSafepoints)) {
     return true;
@@ -1348,9 +1412,7 @@
     JVMCI_THROW_MSG(NullPointerException, "stack frame is null");
   }
 
-  if (env != JavaThread::current()->jni_environment()) {
-    JVMCI_THROW_MSG(InternalError, "getNextStackFrame is only supported for HotSpot stack walking");
-  }
+  requireInHotSpot("materializeVirtualObjects", JVMCI_CHECK);
 
   JVMCIENV->HotSpotStackFrameReference_initialize(JVMCI_CHECK);
 
@@ -1465,20 +1527,76 @@
   HotSpotJVMCI::HotSpotStackFrameReference::set_objectsMaterialized(JVMCIENV, hs_frame, JNI_TRUE);
 C2V_END
 
-C2V_VMENTRY(void, writeDebugOutput, (JNIEnv* env, jobject, jbyteArray bytes, jint offset, jint length))
+// Creates a scope where the current thread is attached and detached
+// from HotSpot if it wasn't already attached when entering the scope.
+extern "C" void jio_printf(const char *fmt, ...);
+class AttachDetach : public StackObj {
+ public:
+  bool _attached;
+  AttachDetach(JNIEnv* env, Thread* current_thread) {
+    if (current_thread == NULL) {
+      extern struct JavaVM_ main_vm;
+      JNIEnv* hotspotEnv;
+      jint res = main_vm.AttachCurrentThread((void**)&hotspotEnv, NULL);
+      _attached = res == JNI_OK;
+      static volatile int report_attach_error = 0;
+      if (res != JNI_OK && report_attach_error == 0 && Atomic::cmpxchg(1, &report_attach_error, 0) == 0) {
+        // Only report an attach error once
+        jio_printf("Warning: attaching current thread to VM failed with %d (future attach errors are suppressed)\n", res);
+      }
+    } else {
+      _attached = false;
+    }
+  }
+  ~AttachDetach() {
+    if (_attached && get_current_thread() != NULL) {
+      extern struct JavaVM_ main_vm;
+      jint res = main_vm.DetachCurrentThread();
+      static volatile int report_detach_error = 0;
+      if (res != JNI_OK && report_detach_error == 0 && Atomic::cmpxchg(1, &report_detach_error, 0) == 0) {
+        // Only report an attach error once
+        jio_printf("Warning: detaching current thread from VM failed with %d (future attach errors are suppressed)\n", res);
+      }
+    }
+  }
+};
+
+C2V_VMENTRY_PREFIX(jint, writeDebugOutput, (JNIEnv* env, jobject, jbyteArray bytes, jint offset, jint length, bool flush, bool can_throw))
+  AttachDetach ad(env, base_thread);
+  bool use_tty = true;
+  if (base_thread == NULL) {
+    if (!ad._attached) {
+      // Can only use tty if the current thread is attached
+      return 0;
+    }
+    base_thread = get_current_thread();
+  }
+  JVMCITraceMark jtm("writeDebugOutput");
+  assert(base_thread->is_Java_thread(), "just checking");
+  JavaThread* thread = (JavaThread*) base_thread;
+  C2V_BLOCK(void, writeDebugOutput, (JNIEnv* env, jobject, jbyteArray bytes, jint offset, jint length))
   if (bytes == NULL) {
-    JVMCI_THROW(NullPointerException);
+    if (can_throw) {
+      JVMCI_THROW_0(NullPointerException);
+    }
+    return -1;
   }
   JVMCIPrimitiveArray array = JVMCIENV->wrap(bytes);
 
   // Check if offset and length are non negative.
   if (offset < 0 || length < 0) {
-    JVMCI_THROW(ArrayIndexOutOfBoundsException);
+    if (can_throw) {
+      JVMCI_THROW_0(ArrayIndexOutOfBoundsException);
+    }
+    return -2;
   }
   // Check if the range is valid.
   int array_length = JVMCIENV->get_length(array);
   if ((((unsigned int) length + (unsigned int) offset) > (unsigned int) array_length)) {
-    JVMCI_THROW(ArrayIndexOutOfBoundsException);
+    if (can_throw) {
+      JVMCI_THROW_0(ArrayIndexOutOfBoundsException);
+    }
+    return -2;
   }
   jbyte buffer[O_BUFLEN];
   while (length > 0) {
@@ -1488,13 +1606,17 @@
     length -= O_BUFLEN;
     offset += O_BUFLEN;
   }
+  if (flush) {
+    tty->flush();
+  }
+  return 0;
 C2V_END
 
 C2V_VMENTRY(void, flushDebugOutput, (JNIEnv* env, jobject))
   tty->flush();
 C2V_END
 
-C2V_VMENTRY(int, methodDataProfileDataSize, (JNIEnv* env, jobject, jlong metaspace_method_data, jint position))
+C2V_VMENTRY_0(int, methodDataProfileDataSize, (JNIEnv* env, jobject, jlong metaspace_method_data, jint position))
   MethodData* mdo = JVMCIENV->asMethodData(metaspace_method_data);
   ProfileData* profile_data = mdo->data_at(position);
   if (mdo->is_valid(profile_data)) {
@@ -1512,7 +1634,7 @@
   JVMCI_THROW_MSG_0(IllegalArgumentException, err_msg("Invalid profile data position %d", position));
 C2V_END
 
-C2V_VMENTRY(jlong, getFingerprint, (JNIEnv* env, jobject, jlong metaspace_klass))
+C2V_VMENTRY_0(jlong, getFingerprint, (JNIEnv* env, jobject, jlong metaspace_klass))
 #if INCLUDE_AOT
   Klass *k = (Klass*) (address) metaspace_klass;
   if (k->is_instance_klass()) {
@@ -1525,7 +1647,7 @@
 #endif
 C2V_END
 
-C2V_VMENTRY(jobject, getHostClass, (JNIEnv* env, jobject, jobject jvmci_type))
+C2V_VMENTRY_NULL(jobject, getHostClass, (JNIEnv* env, jobject, jobject jvmci_type))
   InstanceKlass* k = InstanceKlass::cast(JVMCIENV->asKlass(jvmci_type));
   InstanceKlass* host = k->unsafe_anonymous_host();
   JVMCIKlassHandle handle(THREAD, host);
@@ -1533,7 +1655,7 @@
   return JVMCIENV->get_jobject(result);
 C2V_END
 
-C2V_VMENTRY(jobject, getInterfaces, (JNIEnv* env, jobject, jobject jvmci_type))
+C2V_VMENTRY_NULL(jobject, getInterfaces, (JNIEnv* env, jobject, jobject jvmci_type))
   if (jvmci_type == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1560,7 +1682,7 @@
   return JVMCIENV->get_jobject(interfaces);
 C2V_END
 
-C2V_VMENTRY(jobject, getComponentType, (JNIEnv* env, jobject, jobject jvmci_type))
+C2V_VMENTRY_NULL(jobject, getComponentType, (JNIEnv* env, jobject, jobject jvmci_type))
   if (jvmci_type == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1600,7 +1722,7 @@
   }
 C2V_END
 
-C2V_VMENTRY(int, interpreterFrameSize, (JNIEnv* env, jobject, jobject bytecode_frame_handle))
+C2V_VMENTRY_0(int, interpreterFrameSize, (JNIEnv* env, jobject, jobject bytecode_frame_handle))
   if (bytecode_frame_handle == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1648,12 +1770,12 @@
   }
 C2V_END
 
-C2V_VMENTRY(int, getIdentityHashCode, (JNIEnv* env, jobject, jobject object))
+C2V_VMENTRY_0(int, getIdentityHashCode, (JNIEnv* env, jobject, jobject object))
   Handle obj = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_0);
   return obj->identity_hash();
 C2V_END
 
-C2V_VMENTRY(jboolean, isInternedString, (JNIEnv* env, jobject, jobject object))
+C2V_VMENTRY_0(jboolean, isInternedString, (JNIEnv* env, jobject, jobject object))
   Handle str = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_0);
   if (!java_lang_String::is_instance(str())) {
     return false;
@@ -1664,7 +1786,7 @@
 C2V_END
 
 
-C2V_VMENTRY(jobject, unboxPrimitive, (JNIEnv* env, jobject, jobject object))
+C2V_VMENTRY_NULL(jobject, unboxPrimitive, (JNIEnv* env, jobject, jobject object))
   if (object == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1678,7 +1800,7 @@
   return JVMCIENV->get_jobject(boxResult);
 C2V_END
 
-C2V_VMENTRY(jobject, boxPrimitive, (JNIEnv* env, jobject, jobject object))
+C2V_VMENTRY_NULL(jobject, boxPrimitive, (JNIEnv* env, jobject, jobject object))
   if (object == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1722,7 +1844,7 @@
   return JVMCIENV->get_jobject(result);
 C2V_END
 
-C2V_VMENTRY(jobjectArray, getDeclaredConstructors, (JNIEnv* env, jobject, jobject holder))
+C2V_VMENTRY_NULL(jobjectArray, getDeclaredConstructors, (JNIEnv* env, jobject, jobject holder))
   if (holder == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1751,7 +1873,7 @@
   return JVMCIENV->get_jobjectArray(methods);
 C2V_END
 
-C2V_VMENTRY(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, jobject holder))
+C2V_VMENTRY_NULL(jobjectArray, getDeclaredMethods, (JNIEnv* env, jobject, jobject holder))
   if (holder == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1780,7 +1902,7 @@
   return JVMCIENV->get_jobjectArray(methods);
 C2V_END
 
-C2V_VMENTRY(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object, jobject field, jboolean is_volatile))
+C2V_VMENTRY_NULL(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object, jobject field, jboolean is_volatile))
   if (object == NULL || field == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1848,7 +1970,7 @@
   return JVMCIENV->get_jobject(result);
 C2V_END
 
-C2V_VMENTRY(jboolean, isInstance, (JNIEnv* env, jobject, jobject holder, jobject object))
+C2V_VMENTRY_0(jboolean, isInstance, (JNIEnv* env, jobject, jobject holder, jobject object))
   if (object == NULL || holder == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1857,7 +1979,7 @@
   return obj->is_a(klass);
 C2V_END
 
-C2V_VMENTRY(jboolean, isAssignableFrom, (JNIEnv* env, jobject, jobject holder, jobject otherHolder))
+C2V_VMENTRY_0(jboolean, isAssignableFrom, (JNIEnv* env, jobject, jobject holder, jobject otherHolder))
   if (holder == NULL || otherHolder == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1866,7 +1988,7 @@
   return otherKlass->is_subtype_of(klass);
 C2V_END
 
-C2V_VMENTRY(jboolean, isTrustedForIntrinsics, (JNIEnv* env, jobject, jobject holder))
+C2V_VMENTRY_0(jboolean, isTrustedForIntrinsics, (JNIEnv* env, jobject, jobject holder))
   if (holder == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1877,7 +1999,7 @@
   return false;
 C2V_END
 
-C2V_VMENTRY(jobject, asJavaType, (JNIEnv* env, jobject, jobject object))
+C2V_VMENTRY_NULL(jobject, asJavaType, (JNIEnv* env, jobject, jobject object))
   if (object == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1897,7 +2019,7 @@
 C2V_END
 
 
-C2V_VMENTRY(jobject, asString, (JNIEnv* env, jobject, jobject object))
+C2V_VMENTRY_NULL(jobject, asString, (JNIEnv* env, jobject, jobject object))
   if (object == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1908,14 +2030,14 @@
 C2V_END
 
 
-C2V_VMENTRY(jboolean, equals, (JNIEnv* env, jobject, jobject x, jlong xHandle, jobject y, jlong yHandle))
+C2V_VMENTRY_0(jboolean, equals, (JNIEnv* env, jobject, jobject x, jlong xHandle, jobject y, jlong yHandle))
   if (x == NULL || y == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
   return JVMCIENV->resolve_handle(xHandle) == JVMCIENV->resolve_handle(yHandle);
 C2V_END
 
-C2V_VMENTRY(jobject, getJavaMirror, (JNIEnv* env, jobject, jobject object))
+C2V_VMENTRY_NULL(jobject, getJavaMirror, (JNIEnv* env, jobject, jobject object))
   if (object == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1934,7 +2056,7 @@
 C2V_END
 
 
-C2V_VMENTRY(jint, getArrayLength, (JNIEnv* env, jobject, jobject x))
+C2V_VMENTRY_0(jint, getArrayLength, (JNIEnv* env, jobject, jobject x))
   if (x == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1946,7 +2068,7 @@
  C2V_END
 
 
-C2V_VMENTRY(jobject, readArrayElement, (JNIEnv* env, jobject, jobject x, int index))
+C2V_VMENTRY_NULL(jobject, readArrayElement, (JNIEnv* env, jobject, jobject x, int index))
   if (x == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1986,7 +2108,7 @@
 C2V_END
 
 
-C2V_VMENTRY(jint, arrayBaseOffset, (JNIEnv* env, jobject, jobject kind))
+C2V_VMENTRY_0(jint, arrayBaseOffset, (JNIEnv* env, jobject, jobject kind))
   if (kind == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -1994,7 +2116,7 @@
   return arrayOopDesc::header_size(type) * HeapWordSize;
 C2V_END
 
-C2V_VMENTRY(jint, arrayIndexScale, (JNIEnv* env, jobject, jobject kind))
+C2V_VMENTRY_0(jint, arrayIndexScale, (JNIEnv* env, jobject, jobject kind))
   if (kind == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -2002,7 +2124,7 @@
   return type2aelembytes(type);
 C2V_END
 
-C2V_VMENTRY(jbyte, getByte, (JNIEnv* env, jobject, jobject x, long displacement))
+C2V_VMENTRY_0(jbyte, getByte, (JNIEnv* env, jobject, jobject x, long displacement))
   if (x == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -2010,7 +2132,7 @@
   return xobj->byte_field(displacement);
 }
 
-C2V_VMENTRY(jshort, getShort, (JNIEnv* env, jobject, jobject x, long displacement))
+C2V_VMENTRY_0(jshort, getShort, (JNIEnv* env, jobject, jobject x, long displacement))
   if (x == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -2018,7 +2140,7 @@
   return xobj->short_field(displacement);
 }
 
-C2V_VMENTRY(jint, getInt, (JNIEnv* env, jobject, jobject x, long displacement))
+C2V_VMENTRY_0(jint, getInt, (JNIEnv* env, jobject, jobject x, long displacement))
   if (x == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -2026,7 +2148,7 @@
   return xobj->int_field(displacement);
 }
 
-C2V_VMENTRY(jlong, getLong, (JNIEnv* env, jobject, jobject x, long displacement))
+C2V_VMENTRY_0(jlong, getLong, (JNIEnv* env, jobject, jobject x, long displacement))
   if (x == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -2034,7 +2156,7 @@
   return xobj->long_field(displacement);
 }
 
-C2V_VMENTRY(jobject, getObject, (JNIEnv* env, jobject, jobject x, long displacement))
+C2V_VMENTRY_NULL(jobject, getObject, (JNIEnv* env, jobject, jobject x, long displacement))
   if (x == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
@@ -2052,30 +2174,38 @@
   }
 }
 
-C2V_VMENTRY(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclass mirror))
+static void requireJVMCINativeLibrary(JVMCI_TRAPS) {
   if (!UseJVMCINativeLibrary) {
-    JVMCI_THROW_MSG_0(UnsatisfiedLinkError, "JVMCI shared library is not enabled (requires -XX:+UseJVMCINativeLibrary)");
+    JVMCI_THROW_MSG(UnsupportedOperationException, "JVMCI shared library is not enabled (requires -XX:+UseJVMCINativeLibrary)");
   }
-  if (!JVMCIENV->is_hotspot()) {
-    JVMCI_THROW_MSG_0(UnsatisfiedLinkError, "Cannot call registerNativeMethods from JVMCI shared library");
+}
+
+static JavaVM* requireNativeLibraryJavaVM(const char* caller, JVMCI_TRAPS) {
+  JavaVM* javaVM = JVMCIEnv::get_shared_library_javavm();
+  if (javaVM == NULL) {
+    JVMCI_THROW_MSG_NULL(IllegalStateException, err_msg("Require JVMCI shared library to be initialized in %s", caller));
   }
+  return javaVM;
+}
+
+C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclass mirror))
+  requireJVMCINativeLibrary(JVMCI_CHECK_NULL);
+  requireInHotSpot("registerNativeMethods", JVMCI_CHECK_NULL);
   void* shared_library = JVMCIEnv::get_shared_library_handle();
   if (shared_library == NULL) {
     // Ensure the JVMCI shared library runtime is initialized.
-    JVMCIEnv __peer_jvmci_env__(false, __FILE__, __LINE__);
+    JVMCIEnv __peer_jvmci_env__(thread, false, __FILE__, __LINE__);
     JVMCIEnv* peerEnv = &__peer_jvmci_env__;
     HandleMark hm;
     JVMCIRuntime* runtime = JVMCI::compiler_runtime();
     JVMCIObject receiver = runtime->get_HotSpotJVMCIRuntime(peerEnv);
     if (peerEnv->has_pending_exception()) {
       peerEnv->describe_pending_exception(true);
+    }
+    shared_library = JVMCIEnv::get_shared_library_handle();
+    if (shared_library == NULL) {
       JVMCI_THROW_MSG_0(InternalError, "Error initializing JVMCI runtime");
     }
-    shared_library = JVMCIEnv::get_shared_library_handle();
-  }
-
-  if (shared_library == NULL) {
-    JVMCI_THROW_MSG_0(UnsatisfiedLinkError, "JVMCI shared library is unavailable");
   }
 
   if (mirror == NULL) {
@@ -2113,15 +2243,18 @@
         st.print_raw(pure_name);
         st.print_raw(long_name);
         os::print_jni_name_suffix_on(&st, args_size);
-        jni_name = st.as_string();
-        entry = (address) os::dll_lookup(shared_library, jni_name);
+        char* jni_long_name = st.as_string();
+        entry = (address) os::dll_lookup(shared_library, jni_long_name);
+        if (entry == NULL) {
+          JVMCI_THROW_MSG_0(UnsatisfiedLinkError, err_msg("%s [neither %s nor %s exist in %s]",
+              method->name_and_sig_as_C_string(),
+              jni_name, jni_long_name, JVMCIEnv::get_shared_library_path()));
+        }
       }
-      if (entry == NULL) {
-        JVMCI_THROW_MSG_0(UnsatisfiedLinkError, method->name_and_sig_as_C_string());
-      }
+
       if (method->has_native_function() && entry != method->native_function()) {
-        JVMCI_THROW_MSG_0(UnsatisfiedLinkError, err_msg("Cannot overwrite existing native implementation for %s",
-            method->name_and_sig_as_C_string()));
+        JVMCI_THROW_MSG_0(UnsatisfiedLinkError, err_msg("%s [cannot re-link from " PTR_FORMAT " to " PTR_FORMAT "]",
+            method->name_and_sig_as_C_string(), p2i(method->native_function()), p2i(entry)));
       }
       method->set_native_function(entry, Method::native_bind_event_is_interesting);
       if (PrintJNIResolving) {
@@ -2141,11 +2274,102 @@
   return (jlongArray) JVMCIENV->get_jobject(result);
 }
 
-C2V_VMENTRY(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle))
+C2V_VMENTRY_PREFIX(jboolean, isCurrentThreadAttached, (JNIEnv* env, jobject c2vm))
+  if (base_thread == NULL) {
+    // Called from unattached JVMCI shared library thread
+    return false;
+  }
+  JVMCITraceMark jtm("isCurrentThreadAttached");
+  assert(base_thread->is_Java_thread(), "just checking");
+  JavaThread* thread = (JavaThread*) base_thread;
+  if (thread->jni_environment() == env) {
+    C2V_BLOCK(jboolean, isCurrentThreadAttached, (JNIEnv* env, jobject))
+    requireJVMCINativeLibrary(JVMCI_CHECK_0);
+    JavaVM* javaVM = requireNativeLibraryJavaVM("isCurrentThreadAttached", JVMCI_CHECK_0);
+    JNIEnv* peerEnv;
+    return javaVM->GetEnv((void**)&peerEnv, JNI_VERSION_1_2) == JNI_OK;
+  }
+  return true;
+C2V_END
+
+C2V_VMENTRY_PREFIX(jboolean, attachCurrentThread, (JNIEnv* env, jobject c2vm, jboolean as_daemon))
+  if (base_thread == NULL) {
+    // Called from unattached JVMCI shared library thread
+    extern struct JavaVM_ main_vm;
+    JNIEnv* hotspotEnv;
+    jint res = as_daemon ? main_vm.AttachCurrentThreadAsDaemon((void**)&hotspotEnv, NULL) :
+                           main_vm.AttachCurrentThread((void**)&hotspotEnv, NULL);
+    if (res != JNI_OK) {
+      JNI_THROW_("attachCurrentThread", InternalError, err_msg("Trying to attach thread returned %d", res), false);
+    }
+    return true;
+  }
+  JVMCITraceMark jtm("attachCurrentThread");
+  assert(base_thread->is_Java_thread(), "just checking");\
+  JavaThread* thread = (JavaThread*) base_thread;
+  if (thread->jni_environment() == env) {
+    // Called from HotSpot
+    C2V_BLOCK(jboolean, attachCurrentThread, (JNIEnv* env, jobject, jboolean))
+    requireJVMCINativeLibrary(JVMCI_CHECK_0);
+    JavaVM* javaVM = requireNativeLibraryJavaVM("attachCurrentThread", JVMCI_CHECK_0);
+    JavaVMAttachArgs attach_args;
+    attach_args.version = JNI_VERSION_1_2;
+    attach_args.name = thread->name();
+    attach_args.group = NULL;
+    JNIEnv* peerEnv;
+    if (javaVM->GetEnv((void**)&peerEnv, JNI_VERSION_1_2) == JNI_OK) {
+      return false;
+    }
+    jint res = as_daemon ? javaVM->AttachCurrentThreadAsDaemon((void**)&peerEnv, &attach_args) :
+                           javaVM->AttachCurrentThread((void**)&peerEnv, &attach_args);
+    if (res == JNI_OK) {
+      guarantee(peerEnv != NULL, "must be");
+      return true;
+    }
+    JVMCI_THROW_MSG_0(InternalError, err_msg("Error %d while attaching %s", res, attach_args.name));
+  }
+  // Called from JVMCI shared library
+  return false;
+C2V_END
+
+C2V_VMENTRY_PREFIX(void, detachCurrentThread, (JNIEnv* env, jobject c2vm))
+  if (base_thread == NULL) {
+    // Called from unattached JVMCI shared library thread
+    JNI_THROW("detachCurrentThread", IllegalStateException, err_msg("Cannot detach non-attached thread"));
+  }
+  JVMCITraceMark jtm("detachCurrentThread");
+  assert(base_thread->is_Java_thread(), "just checking");\
+  JavaThread* thread = (JavaThread*) base_thread;
+  if (thread->jni_environment() == env) {
+    // Called from HotSpot
+    C2V_BLOCK(void, detachCurrentThread, (JNIEnv* env, jobject))
+    requireJVMCINativeLibrary(JVMCI_CHECK);
+    requireInHotSpot("detachCurrentThread", JVMCI_CHECK);
+    JavaVM* javaVM = requireNativeLibraryJavaVM("detachCurrentThread", JVMCI_CHECK);
+    JNIEnv* peerEnv;
+    if (javaVM->GetEnv((void**)&peerEnv, JNI_VERSION_1_2) != JNI_OK) {
+      JVMCI_THROW_MSG(IllegalStateException, err_msg("Cannot detach non-attached thread: %s", thread->name()));
+    }
+    jint res = javaVM->DetachCurrentThread();
+    if (res != JNI_OK) {
+      JVMCI_THROW_MSG(InternalError, err_msg("Error %d while attaching %s", res, thread->name()));
+    }
+  } else {
+    // Called from attached JVMCI shared library thread
+    extern struct JavaVM_ main_vm;
+    jint res = main_vm.DetachCurrentThread();
+    if (res != JNI_OK) {
+      JNI_THROW("detachCurrentThread", InternalError, err_msg("Cannot detach non-attached thread"));
+    }
+  }
+C2V_END
+
+C2V_VMENTRY_0(jlong, translate, (JNIEnv* env, jobject, jobject obj_handle))
+  requireJVMCINativeLibrary(JVMCI_CHECK_0);
   if (obj_handle == NULL) {
     return 0L;
   }
-  JVMCIEnv __peer_jvmci_env__(!JVMCIENV->is_hotspot(), __FILE__, __LINE__);
+  JVMCIEnv __peer_jvmci_env__(thread, !JVMCIENV->is_hotspot(), __FILE__, __LINE__);
   JVMCIEnv* peerEnv = &__peer_jvmci_env__;
   JVMCIEnv* thisEnv = JVMCIENV;
 
@@ -2216,7 +2440,8 @@
   return (jlong) peerEnv->make_global(result).as_jobject();
 }
 
-C2V_VMENTRY(jobject, unhand, (JNIEnv* env, jobject, jlong obj_handle))
+C2V_VMENTRY_NULL(jobject, unhand, (JNIEnv* env, jobject, jlong obj_handle))
+  requireJVMCINativeLibrary(JVMCI_CHECK_NULL);
   if (obj_handle == 0L) {
     return NULL;
   }
@@ -2234,7 +2459,7 @@
   JVMCIENV->asNmethod(code);
 }
 
-C2V_VMENTRY(jbyteArray, getCode, (JNIEnv* env, jobject, jobject code_handle))
+C2V_VMENTRY_NULL(jbyteArray, getCode, (JNIEnv* env, jobject, jobject code_handle))
   JVMCIObject code = JVMCIENV->wrap(code_handle);
   CodeBlob* cb = JVMCIENV->asCodeBlob(code);
   if (cb == NULL) {
@@ -2246,10 +2471,8 @@
   return JVMCIENV->get_jbyteArray(result);
 }
 
-C2V_VMENTRY(jobject, asReflectionExecutable, (JNIEnv* env, jobject, jobject jvmci_method))
-  if (env != JavaThread::current()->jni_environment()) {
-    JVMCI_THROW_MSG_NULL(InternalError, "Only supported when running in HotSpot");
-  }
+C2V_VMENTRY_NULL(jobject, asReflectionExecutable, (JNIEnv* env, jobject, jobject jvmci_method))
+  requireInHotSpot("asReflectionExecutable", JVMCI_CHECK_NULL);
   methodHandle m = JVMCIENV->asMethod(jvmci_method);
   oop executable;
   if (m->is_initializer()) {
@@ -2264,10 +2487,8 @@
   return JNIHandles::make_local(THREAD, executable);
 }
 
-C2V_VMENTRY(jobject, asReflectionField, (JNIEnv* env, jobject, jobject jvmci_type, jint index))
-  if (env != JavaThread::current()->jni_environment()) {
-    JVMCI_THROW_MSG_NULL(InternalError, "Only supported when running in HotSpot");
-  }
+C2V_VMENTRY_NULL(jobject, asReflectionField, (JNIEnv* env, jobject, jobject jvmci_type, jint index))
+  requireInHotSpot("asReflectionField", JVMCI_CHECK_NULL);
   Klass* klass = JVMCIENV->asKlass(jvmci_type);
   if (!klass->is_instance_klass()) {
     JVMCI_THROW_MSG_NULL(IllegalArgumentException,
@@ -2284,7 +2505,7 @@
   return JNIHandles::make_local(env, reflected);
 }
 
-C2V_VMENTRY(jobjectArray, getFailedSpeculations, (JNIEnv* env, jobject, jlong failed_speculations_address, jobjectArray current))
+C2V_VMENTRY_NULL(jobjectArray, getFailedSpeculations, (JNIEnv* env, jobject, jlong failed_speculations_address, jobjectArray current))
   FailedSpeculation* head = *((FailedSpeculation**)(address) failed_speculations_address);
   int result_length = 0;
   for (FailedSpeculation* fs = head; fs != NULL; fs = fs->next()) {
@@ -2316,7 +2537,7 @@
   return JVMCIENV->get_jobjectArray(result);
 }
 
-C2V_VMENTRY(jlong, getFailedSpeculationsAddress, (JNIEnv* env, jobject, jobject jvmci_method))
+C2V_VMENTRY_0(jlong, getFailedSpeculationsAddress, (JNIEnv* env, jobject, jobject jvmci_method))
   methodHandle method = JVMCIENV->asMethod(jvmci_method);
   MethodData* method_data = method->method_data();
   if (method_data == NULL) {
@@ -2331,7 +2552,7 @@
   FailedSpeculation::free_failed_speculations((FailedSpeculation**)(address) failed_speculations_address);
 }
 
-C2V_VMENTRY(bool, addFailedSpeculation, (JNIEnv* env, jobject, jlong failed_speculations_address, jbyteArray speculation_obj))
+C2V_VMENTRY_0(bool, addFailedSpeculation, (JNIEnv* env, jobject, jlong failed_speculations_address, jbyteArray speculation_obj))
   JVMCIPrimitiveArray speculation_handle = JVMCIENV->wrap(speculation_obj);
   int speculation_len = JVMCIENV->get_length(speculation_handle);
   char* speculation = NEW_RESOURCE_ARRAY(char, speculation_len);
@@ -2431,7 +2652,7 @@
   {CC "iterateFrames",                                CC "([" RESOLVED_METHOD "[" RESOLVED_METHOD "I" INSPECTED_FRAME_VISITOR ")" OBJECT,   FN_PTR(iterateFrames)},
   {CC "materializeVirtualObjects",                    CC "(" HS_STACK_FRAME_REF "Z)V",                                                      FN_PTR(materializeVirtualObjects)},
   {CC "shouldDebugNonSafepoints",                     CC "()Z",                                                                             FN_PTR(shouldDebugNonSafepoints)},
-  {CC "writeDebugOutput",                             CC "([BII)V",                                                                         FN_PTR(writeDebugOutput)},
+  {CC "writeDebugOutput",                             CC "([BIIZZ)I",                                                                       FN_PTR(writeDebugOutput)},
   {CC "flushDebugOutput",                             CC "()V",                                                                             FN_PTR(flushDebugOutput)},
   {CC "methodDataProfileDataSize",                    CC "(JI)I",                                                                           FN_PTR(methodDataProfileDataSize)},
   {CC "getFingerprint",                               CC "(J)J",                                                                            FN_PTR(getFingerprint)},
@@ -2469,6 +2690,9 @@
   {CC "getObject",                                    CC "(" OBJECTCONSTANT "J)" OBJECTCONSTANT,                                            FN_PTR(getObject)},
   {CC "deleteGlobalHandle",                           CC "(J)V",                                                                            FN_PTR(deleteGlobalHandle)},
   {CC "registerNativeMethods",                        CC "(" CLASS ")[J",                                                                   FN_PTR(registerNativeMethods)},
+  {CC "isCurrentThreadAttached",                      CC "()Z",                                                                             FN_PTR(isCurrentThreadAttached)},
+  {CC "attachCurrentThread",                          CC "(Z)Z",                                                                            FN_PTR(attachCurrentThread)},
+  {CC "detachCurrentThread",                          CC "()V",                                                                             FN_PTR(detachCurrentThread)},
   {CC "translate",                                    CC "(" OBJECT ")J",                                                                   FN_PTR(translate)},
   {CC "unhand",                                       CC "(J)" OBJECT,                                                                      FN_PTR(unhand)},
   {CC "updateHotSpotNmethod",                         CC "(" HS_NMETHOD ")V",                                                               FN_PTR(updateHotSpotNmethod)},
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp	Tue May 07 10:21:04 2019 +0800
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp	Mon May 06 20:05:19 2019 -0700
@@ -160,13 +160,14 @@
 };
 
 class JNIHandleMark : public StackObj {
+  JavaThread* _thread;
   public:
-    JNIHandleMark() { push_jni_handle_block(); }
-    ~JNIHandleMark() { pop_jni_handle_block(); }
+    JNIHandleMark(JavaThread* thread) : _thread(thread) { push_jni_handle_block(thread); }
+    ~JNIHandleMark() { pop_jni_handle_block(_thread); }
 
   private:
-    static void push_jni_handle_block();
-    static void pop_jni_handle_block();
+    static void push_jni_handle_block(JavaThread* thread);
+    static void pop_jni_handle_block(JavaThread* thread);
 };
 
 #endif // SHARE_JVMCI_JVMCICOMPILERTOVM_HPP
--- 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), size_in_bytes);
+    memcpy(dest, HotSpotJVMCI::resolve(src)->byte_at_addr(offset), length);
   } else {
     JNIAccessMark jni(this);
-    jni()->GetByteArrayRegion(src.as_jbyteArray(), offset, size_in_bytes, dest);
+    jni()->GetByteArrayRegion(src.as_jbyteArray(), offset, length, dest);
   }
 }
-void JVMCIEnv::copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, int size_in_bytes) {
-  if (size_in_bytes == 0) {
+void JVMCIEnv::copy_bytes_from(jbyte* 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)->byte_at_addr(offset), src, length);
   } else {
     JNIAccessMark jni(this);
-    jni()->SetByteArrayRegion(dest.as_jbyteArray(), offset, size_in_bytes, src);
+    jni()->SetByteArrayRegion(dest.as_jbyteArray(), offset, length, src);
+  }
+}
+
+void JVMCIEnv::copy_longs_from(jlong* src, JVMCIPrimitiveArray dest, int offset, jsize length) {
+  if (length == 0) {
+    return;
+  }
+  if (is_hotspot()) {
+    memcpy(HotSpotJVMCI::resolve(dest)->long_at_addr(offset), src, length * sizeof(jlong));
+  } else {
+    JNIAccessMark jni(this);
+    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());
   }
 }
 
--- a/src/hotspot/share/jvmci/jvmciEnv.hpp	Tue May 07 10:21:04 2019 +0800
+++ b/src/hotspot/share/jvmci/jvmciEnv.hpp	Mon May 06 20:05:19 2019 -0700
@@ -36,15 +36,6 @@
 class JVMCICompiler;
 class JVMCIRuntime;
 
-// Bring the JVMCI compiler thread into the VM state.
-#define JVMCI_VM_ENTRY_MARK                       \
-  JavaThread* thread = JavaThread::current(); \
-  ThreadInVMfromNative __tiv(thread);       \
-  ResetNoHandleMark rnhm;                   \
-  HandleMarkCleaner __hm(thread);           \
-  Thread* THREAD = thread;                  \
-  debug_only(VMNativeEntryWrapper __vew;)
-
 #define JVMCI_EXCEPTION_CONTEXT \
   JavaThread* thread=JavaThread::current(); \
   Thread* THREAD = thread;
@@ -154,24 +145,25 @@
   static void*   _shared_library_handle; // result of os::dll_load
   static JavaVM* _shared_library_javavm; // result of calling JNI_CreateJavaVM in shared library
 
-  // Attaches the current thread to the JavaVM in the shared library,
-  // initializing the shared library VM first if necessary.
-  // Returns the JNI interface pointer of the current thread.
-  // The _shared_library_* fields are initialized by the first
-  // call to this method.
-  static JNIEnv* attach_shared_library();
+  // Initializes the shared library JavaVM if not already initialized.
+  // Returns the JNI interface pointer for the current thread
+  // if initialization was performed by this call, NULL if
+  // initialization was performed by a previous call.
+  static JNIEnv* init_shared_library(JavaThread* thread);
 
   // Initializes the _env, _mode and _runtime fields.
-  void init_env_mode_runtime(JNIEnv* parent_env);
+  void init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env);
 
-  void init(bool is_hotspot, const char* file, int line);
+  void init(JavaThread* thread, bool is_hotspot, const char* file, int line);
 
-  JNIEnv*                _env;     // JNI env for calling into shared library
-  JVMCIRuntime*          _runtime; // Access to a HotSpotJVMCIRuntime
-  bool             _is_hotspot;    // Which heap is the HotSpotJVMCIRuntime in
-  bool        _throw_to_caller;    // Propagate an exception raised in this env to the caller?
-  const char*            _file;    // The file and ...
-  int                    _line;    // ... line where this JNIEnv was created
+  JNIEnv*                 _env;  // JNI env for calling into shared library
+  bool     _pop_frame_on_close;  // Must pop frame on close?
+  bool        _detach_on_close;  // Must detach on close?
+  JVMCIRuntime*       _runtime;  // Access to a HotSpotJVMCIRuntime
+  bool             _is_hotspot;  // Which heap is the HotSpotJVMCIRuntime in
+  bool        _throw_to_caller;  // Propagate an exception raised in this env to the caller?
+  const char*            _file;  // The file and ...
+  int                    _line;  // ... line where this JNIEnv was created
 
   // Translates an exception on the HotSpot heap to an exception on
   // the shared library heap. The translation includes the stack and
@@ -185,12 +177,12 @@
   // scope closes so that it will be propagated back to Java.
   // The JVMCIEnv destructor translates the exception object for the
   // Java runtime if necessary.
-  JVMCIEnv(JNIEnv* env, const char* file, int line);
+  JVMCIEnv(JavaThread* thread, JNIEnv* env, const char* file, int line);
 
   // Opens a JVMCIEnv scope for a compilation scheduled by the CompileBroker.
   // An exception occurring within the scope must not be propagated back to
   // the CompileBroker.
-  JVMCIEnv(JVMCICompileState* compile_state, const char* file, int line);
+  JVMCIEnv(JavaThread* thread, JVMCICompileState* compile_state, const char* file, int line);
 
   // Opens a JNIEnv scope for a call from within the VM. An exception occurring
   // within the scope must not be propagated back to the caller.
@@ -198,20 +190,20 @@
 
   // Opens a JNIEnv scope for accessing `for_object`. An exception occurring
   // within the scope must not be propagated back to the caller.
-  JVMCIEnv(JVMCIObject for_object, const char* file, int line) {
+  JVMCIEnv(JavaThread* thread, JVMCIObject for_object, const char* file, int line) {
     // A JNI call to access an object in the shared library heap
     // can block or take a long time so do not allow such access
     // on the VM thread.
     assert(for_object.is_hotspot() || !Thread::current()->is_VM_thread(),
         "cannot open JVMCIEnv scope when in the VM thread for accessing a shared library heap object");
-    init(for_object.is_hotspot(), file, line);
+    init(thread, for_object.is_hotspot(), file, line);
   }
 
   // Opens a JNIEnv scope for the HotSpot runtime if `is_hotspot` is true
   // otherwise for the shared library runtime. An exception occurring
   // within the scope must not be propagated back to the caller.
-  JVMCIEnv(bool is_hotspot, const char* file, int line) {
-    init(is_hotspot, file, line);
+  JVMCIEnv(JavaThread* thread, bool is_hotspot, const char* file, int line) {
+    init(thread, is_hotspot, file, line);
   }
 
   ~JVMCIEnv();
@@ -247,8 +239,10 @@
   long get_long_at(JVMCIPrimitiveArray array, int index);
   void put_long_at(JVMCIPrimitiveArray array, int index, jlong value);
 
-  void copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, int size_in_bytes);
-  void copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, int size_in_bytes);
+  void copy_bytes_to(JVMCIPrimitiveArray src, jbyte* dest, int offset, jsize length);
+  void copy_bytes_from(jbyte* src, JVMCIPrimitiveArray dest, int offset, jsize length);
+
+  void copy_longs_from(jlong* src, JVMCIPrimitiveArray dest, int offset, jsize length);
 
   JVMCIObjectArray initialize_intrinsics(JVMCI_TRAPS);
 
@@ -323,6 +317,8 @@
   DO_THROW(IllegalArgumentException)
   DO_THROW(InvalidInstalledCodeException)
   DO_THROW(UnsatisfiedLinkError)
+  DO_THROW(UnsupportedOperationException)
+  DO_THROW(ClassNotFoundException)
 
 #undef DO_THROW
 
--- a/src/hotspot/share/jvmci/jvmciExceptions.hpp	Tue May 07 10:21:04 2019 +0800
+++ b/src/hotspot/share/jvmci/jvmciExceptions.hpp	Mon May 06 20:05:19 2019 -0700
@@ -32,8 +32,8 @@
 #define JVMCIENV __jvmci_env__
 #define JVMCI_TRAPS  JVMCIEnv* JVMCIENV
 
-#define JNI_JVMCIENV(env)                                     \
-  JVMCIEnv __stack_jvmci_env__(env, __FILE__, __LINE__);      \
+#define JNI_JVMCIENV(thread, env)                                     \
+  JVMCIEnv __stack_jvmci_env__(thread, env, __FILE__, __LINE__);      \
   JVMCIEnv* JVMCIENV = &__stack_jvmci_env__
 
 #define THREAD_JVMCIENV(thread)                               \
--- a/src/hotspot/share/jvmci/jvmciJavaClasses.cpp	Tue May 07 10:21:04 2019 +0800
+++ b/src/hotspot/share/jvmci/jvmciJavaClasses.cpp	Mon May 06 20:05:19 2019 -0700
@@ -356,6 +356,43 @@
   jobject  JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c);
 }
 
+// Dumps symbols for public <init>() and <init>(String) methods of
+// non-abstract Throwable subtypes known by the VM. This is to
+// support the use of reflection in jdk.vm.ci.hotspot.TranslatedException.create().
+class ThrowableInitDumper : public SymbolClosure {
+ private:
+  fileStream* _st;
+ public:
+  ThrowableInitDumper(fileStream* st)     { _st = st; }
+  void do_symbol(Symbol** p) {
+    Thread* THREAD = Thread::current();
+    Symbol* name = *p;
+    if (name == NULL) {
+      return;
+    }
+    Klass* k = SystemDictionary::resolve_or_null(name, CHECK_EXIT);
+    if (k != NULL && k->is_instance_klass()) {
+      InstanceKlass* iklass = InstanceKlass::cast(k);
+      if (iklass->is_subclass_of(SystemDictionary::Throwable_klass()) && iklass->is_public() && !iklass->is_abstract()) {
+        const char* class_name = NULL;
+        Array<Method*>* methods = iklass->methods();
+        for (int i = 0; i < methods->length(); i++) {
+          Method* m = methods->at(i);
+          if (m->name() == vmSymbols::object_initializer_name() &&
+              m->is_public() &&
+              (m->signature() == vmSymbols::void_method_signature() || m->signature() == vmSymbols::string_void_signature())) {
+            if (class_name == NULL) {
+              class_name = name->as_C_string();
+              _st->print_cr("class %s", class_name);
+            }
+            _st->print_cr("method %s %s %s", class_name, m->name()->as_C_string(), m->signature()->as_C_string());
+          }
+        }
+      }
+    }
+  }
+};
+
 #define IN_CLASS(fullClassName) current_class_name = vmSymbols::fullClassName()->as_C_string()
 /**
  * Initializes the JNI method and field ids used in JNIJVMCI.
@@ -441,6 +478,8 @@
     fileStream* st = JVMCIGlobals::get_jni_config_file();
 
     DUMP_ALL_NATIVE_METHODS(vmSymbols::jdk_vm_ci_hotspot_CompilerToVM());
+    ThrowableInitDumper dumper(st);
+    vmSymbols::symbols_do(&dumper);
 
     st->flush();
     tty->print_cr("Dumped JVMCI shared library JNI configuration to %s", JVMCILibDumpJNIConfig);
--- a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp	Tue May 07 10:21:04 2019 +0800
+++ b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp	Mon May 06 20:05:19 2019 -0700
@@ -381,12 +381,18 @@
   start_class(InternalError, java_lang_InternalError)                                                         \
     jvmci_constructor(InternalError, "(Ljava/lang/String;)V")                                                 \
   end_class                                                                                                   \
+  start_class(ClassNotFoundException, java_lang_ClassNotFoundException)                                       \
+    jvmci_constructor(ClassNotFoundException, "(Ljava/lang/String;)V")                                        \
+  end_class                                                                                                   \
   start_class(InvalidInstalledCodeException, jdk_vm_ci_code_InvalidInstalledCodeException)                    \
     jvmci_constructor(InvalidInstalledCodeException, "(Ljava/lang/String;)V")                                 \
   end_class                                                                                                   \
   start_class(UnsatisfiedLinkError, java_lang_UnsatisfiedLinkError)                                           \
     jvmci_constructor(UnsatisfiedLinkError, "(Ljava/lang/String;)V")                                          \
   end_class                                                                                                   \
+  start_class(UnsupportedOperationException, java_lang_UnsupportedOperationException)                         \
+    jvmci_constructor(UnsupportedOperationException, "(Ljava/lang/String;)V")                                 \
+  end_class                                                                                                   \
   start_class(StackTraceElement, java_lang_StackTraceElement)                                                 \
     object_field(StackTraceElement, declaringClass, "Ljava/lang/String;")                                     \
     object_field(StackTraceElement, methodName, "Ljava/lang/String;")                                         \
--- a/src/hotspot/share/jvmci/jvmciRuntime.cpp	Tue May 07 10:21:04 2019 +0800
+++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp	Mon May 06 20:05:19 2019 -0700
@@ -655,7 +655,7 @@
 
 // private static JVMCIRuntime JVMCI.initializeRuntime()
 JVM_ENTRY_NO_ENV(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c))
-  JNI_JVMCIENV(env);
+  JNI_JVMCIENV(thread, env);
   if (!EnableJVMCI) {
     JVMCI_THROW_MSG_NULL(InternalError, "JVMCI is not enabled");
   }
@@ -877,7 +877,7 @@
   fatal("check TLAB allocation code for address space conflicts");
 #endif
 
-  JNI_JVMCIENV(env);
+  JNI_JVMCIENV(thread, env);
 
   if (!EnableJVMCI) {
     JVMCI_THROW_MSG(InternalError, "JVMCI is not enabled");
@@ -1353,6 +1353,10 @@
     compile_state->set_failure(true, "No OSR during boostrap");
     return;
   }
+  if (JVMCI::shutdown_called()) {
+    compile_state->set_failure(false, "Avoiding compilation during shutdown");
+    return;
+  }
 
   HandleMark hm;
   JVMCIObject receiver = get_HotSpotJVMCIRuntime(JVMCIENV);
--- a/src/hotspot/share/jvmci/jvmci_globals.cpp	Tue May 07 10:21:04 2019 +0800
+++ b/src/hotspot/share/jvmci/jvmci_globals.cpp	Mon May 06 20:05:19 2019 -0700
@@ -83,7 +83,7 @@
     }
     FLAG_SET_DEFAULT(EnableJVMCI, true);
     if (BootstrapJVMCI && UseJVMCINativeLibrary) {
-      jio_fprintf(defaultStream::error_stream(), "-XX:+BootstrapJVMCI is not compatible with -XX:+UseJVMCINativeLibrary");
+      jio_fprintf(defaultStream::error_stream(), "-XX:+BootstrapJVMCI is not compatible with -XX:+UseJVMCINativeLibrary\n");
       return false;
     }
   }
--- a/src/hotspot/share/jvmci/jvmci_globals.hpp	Tue May 07 10:21:04 2019 +0800
+++ b/src/hotspot/share/jvmci/jvmci_globals.hpp	Mon May 06 20:05:19 2019 -0700
@@ -53,7 +53,10 @@
           "Prints properties used by the JVMCI compiler and exits")         \
                                                                             \
   experimental(bool, BootstrapJVMCI, false,                                 \
-          "Bootstrap JVMCI before running Java main method")                \
+          "Bootstrap JVMCI before running Java main method. This "          \
+          "initializes the compile queue with a small set of methods "      \
+          "and processes the queue until it is empty. Combining this with " \
+          "-XX:-TieredCompilation makes JVMCI compile more of itself.")     \
                                                                             \
   experimental(bool, EagerJVMCI, false,                                     \
           "Force eager JVMCI initialization")                               \
--- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp	Tue May 07 10:21:04 2019 +0800
+++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp	Mon May 06 20:05:19 2019 -0700
@@ -246,6 +246,10 @@
                                                                                                                                      \
   nonstatic_field(ObjArrayKlass,               _element_klass,                                Klass*)                                \
                                                                                                                                      \
+  volatile_nonstatic_field(ObjectMonitor,      _cxq,                                   ObjectWaiter*)                                \
+  volatile_nonstatic_field(ObjectMonitor,      _EntryList,                             ObjectWaiter*)                                \
+  volatile_nonstatic_field(ObjectMonitor,      _succ,                                  Thread*)                                      \
+                                                                                                                                     \
   volatile_nonstatic_field(oopDesc,            _mark,                                         markOop)                               \
   volatile_nonstatic_field(oopDesc,            _metadata._klass,                              Klass*)                                \
                                                                                                                                      \
@@ -347,6 +351,7 @@
   declare_toplevel_type(JVMCIEnv)                                         \
   declare_toplevel_type(LocalVariableTableElement)                        \
   declare_toplevel_type(narrowKlass)                                      \
+  declare_toplevel_type(ObjectWaiter)                                     \
   declare_toplevel_type(Symbol*)                                          \
   declare_toplevel_type(vtableEntry)                                      \
                                                                           \
--- a/src/hotspot/share/runtime/objectMonitor.hpp	Tue May 07 10:21:04 2019 +0800
+++ b/src/hotspot/share/runtime/objectMonitor.hpp	Mon May 06 20:05:19 2019 -0700
@@ -139,6 +139,7 @@
   friend class ObjectSynchronizer;
   friend class ObjectWaiter;
   friend class VMStructs;
+  JVMCI_ONLY(friend class JVMCIVMStructs;)
 
   volatile markOop   _header;       // displaced object header word - mark
   void*     volatile _object;       // backward object pointer - strong root
--- a/src/hotspot/share/runtime/thread.cpp	Tue May 07 10:21:04 2019 +0800
+++ b/src/hotspot/share/runtime/thread.cpp	Mon May 06 20:05:19 2019 -0700
@@ -1575,18 +1575,15 @@
   return !JVMCICountersExcludeCompiler || !thread->is_Compiler_thread();
 }
 
-void JavaThread::collect_counters(JVMCIEnv* jvmci_env, JVMCIPrimitiveArray array) {
-  if (JVMCICounterSize > 0) {
-    JavaThreadIteratorWithHandle jtiwh;
-    int len = jvmci_env->get_length(array);
-    for (int i = 0; i < len; i++) {
-      jvmci_env->put_long_at(array, i, _jvmci_old_thread_counters[i]);
-    }
-    for (; JavaThread *tp = jtiwh.next(); ) {
-      if (jvmci_counters_include(tp)) {
-        for (int i = 0; i < len; i++) {
-          jvmci_env->put_long_at(array, i, jvmci_env->get_long_at(array, i) + tp->_jvmci_counters[i]);
-        }
+void JavaThread::collect_counters(jlong* array, int length) {
+  assert(length == JVMCICounterSize, "wrong value");
+  for (int i = 0; i < length; i++) {
+    array[i] = _jvmci_old_thread_counters[i];
+  }
+  for (JavaThreadIteratorWithHandle jtiwh; JavaThread *tp = jtiwh.next(); ) {
+    if (jvmci_counters_include(tp)) {
+      for (int i = 0; i < length; i++) {
+        array[i] += tp->_jvmci_counters[i];
       }
     }
   }
--- a/src/hotspot/share/runtime/thread.hpp	Tue May 07 10:21:04 2019 +0800
+++ b/src/hotspot/share/runtime/thread.hpp	Mon May 06 20:05:19 2019 -0700
@@ -1152,7 +1152,7 @@
 
  public:
   static jlong* _jvmci_old_thread_counters;
-  static void collect_counters(JVMCIEnv* JVMCIENV, JVMCIPrimitiveArray array);
+  static void collect_counters(jlong* array, int length);
  private:
 #endif // INCLUDE_JVMCI
 
--- a/src/hotspot/share/runtime/vmOperations.cpp	Tue May 07 10:21:04 2019 +0800
+++ b/src/hotspot/share/runtime/vmOperations.cpp	Mon May 06 20:05:19 2019 -0700
@@ -438,14 +438,14 @@
         if (thr->is_Compiler_thread()) {
 #if INCLUDE_JVMCI
           CompilerThread* ct = (CompilerThread*) thr;
-          if (ct->compiler() == NULL || !ct->compiler()->is_jvmci() || !UseJVMCINativeLibrary) {
+          if (ct->compiler() == NULL || !ct->compiler()->is_jvmci()) {
             num_active_compiler_thread++;
           } else {
-            // When using a compiler in a JVMCI shared library, it's possible
-            // for one compiler thread to grab a lock in the shared library,
-            // enter HotSpot and go to sleep on the shutdown safepoint. Another
-            // JVMCI shared library compiler thread can then attempt to grab the
-            // lock and thus never make progress.
+            // A JVMCI compiler thread never accesses VM data structures
+            // while in _thread_in_native state so there's no need to wait
+            // for it and potentially add a 300 millisecond delay to VM
+            // shutdown.
+            num_active--;
           }
 #else
           num_active_compiler_thread++;
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java	Tue May 07 10:21:04 2019 +0800
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java	Mon May 06 20:05:19 2019 -0700
@@ -612,10 +612,15 @@
      * Writes {@code length} bytes from {@code bytes} starting at offset {@code offset} to HotSpot's
      * log stream.
      *
+     * @param flush specifies if the log stream should be flushed after writing
+     * @param canThrow specifies if an error in the {@code bytes}, {@code offset} or {@code length}
+     *            arguments should result in an exception or a negative return value
+     * @return 0 on success, -1 if {@code bytes == null && !canThrow}, -2 if {@code !canThrow} and
+     *         copying would cause access of data outside array bounds
      * @throws NullPointerException if {@code bytes == null}
      * @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds
      */
-    native void writeDebugOutput(byte[] bytes, int offset, int length);
+    native int writeDebugOutput(byte[] bytes, int offset, int length, boolean flush, boolean canThrow);
 
     /**
      * Flush HotSpot's log stream.
@@ -947,4 +952,18 @@
      */
     native boolean addFailedSpeculation(long failedSpeculationsAddress, byte[] speculation);
 
+    /**
+     * @see HotSpotJVMCIRuntime#isCurrentThreadAttached()
+     */
+    native boolean isCurrentThreadAttached();
+
+    /**
+     * @see HotSpotJVMCIRuntime#attachCurrentThread
+     */
+    native boolean attachCurrentThread(boolean asDaemon);
+
+    /**
+     * @see HotSpotJVMCIRuntime#detachCurrentThread()
+     */
+    native void detachCurrentThread();
 }
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java	Tue May 07 10:21:04 2019 +0800
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java	Mon May 06 20:05:19 2019 -0700
@@ -46,7 +46,6 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.ServiceLoader;
-import java.util.TreeMap;
 import java.util.function.Predicate;
 
 import jdk.internal.misc.Unsafe;
@@ -180,8 +179,8 @@
 
                         // Can only do eager initialization of the JVMCI compiler
                         // once the singleton instance is available.
-                        if (instance.config.getFlag("EagerJVMCI", Boolean.class)) {
-                            instance.getCompiler();
+                        if (result.config.getFlag("EagerJVMCI", Boolean.class)) {
+                            result.getCompiler();
                         }
                     }
                     // Ensures JVMCIRuntime::_HotSpotJVMCIRuntime_instance is
@@ -464,7 +463,7 @@
         }
 
         if (Option.PrintConfig.getBoolean()) {
-            printConfig(configStore, compilerToVm);
+            configStore.printConfig();
         }
     }
 
@@ -727,39 +726,21 @@
         }
     }
 
-    @SuppressFBWarnings(value = "DM_DEFAULT_ENCODING", justification = "no localization here please!")
-    private static void printConfigLine(CompilerToVM vm, String format, Object... args) {
-        String line = String.format(format, args);
-        byte[] lineBytes = line.getBytes();
-        vm.writeDebugOutput(lineBytes, 0, lineBytes.length);
-        vm.flushDebugOutput();
-    }
-
-    private static void printConfig(HotSpotVMConfigStore store, CompilerToVM vm) {
-        TreeMap<String, VMField> fields = new TreeMap<>(store.getFields());
-        for (VMField field : fields.values()) {
-            if (!field.isStatic()) {
-                printConfigLine(vm, "[vmconfig:instance field] %s %s {offset=%d[0x%x]}%n", field.type, field.name, field.offset, field.offset);
-            } else {
-                String value = field.value == null ? "null" : field.value instanceof Boolean ? field.value.toString() : String.format("%d[0x%x]", field.value, field.value);
-                printConfigLine(vm, "[vmconfig:static field] %s %s = %s {address=0x%x}%n", field.type, field.name, value, field.address);
-            }
-        }
-        TreeMap<String, VMFlag> flags = new TreeMap<>(store.getFlags());
-        for (VMFlag flag : flags.values()) {
-            printConfigLine(vm, "[vmconfig:flag] %s %s = %s%n", flag.type, flag.name, flag.value);
-        }
-        TreeMap<String, Long> addresses = new TreeMap<>(store.getAddresses());
-        for (Map.Entry<String, Long> e : addresses.entrySet()) {
-            printConfigLine(vm, "[vmconfig:address] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue());
-        }
-        TreeMap<String, Long> constants = new TreeMap<>(store.getConstants());
-        for (Map.Entry<String, Long> e : constants.entrySet()) {
-            printConfigLine(vm, "[vmconfig:constant] %s = %d[0x%x]%n", e.getKey(), e.getValue(), e.getValue());
-        }
-        for (VMIntrinsicMethod e : store.getIntrinsics()) {
-            printConfigLine(vm, "[vmconfig:intrinsic] %d = %s.%s %s%n", e.id, e.declaringClass, e.name, e.descriptor);
-        }
+    /**
+     * Writes {@code length} bytes from {@code bytes} starting at offset {@code offset} to HotSpot's
+     * log stream.
+     *
+     * @param flush specifies if the log stream should be flushed after writing
+     * @param canThrow specifies if an error in the {@code bytes}, {@code offset} or {@code length}
+     *            arguments should result in an exception or a negative return value. If
+     *            {@code false}, this call will not perform any heap allocation
+     * @return 0 on success, -1 if {@code bytes == null && !canThrow}, -2 if {@code !canThrow} and
+     *         copying would cause access of data outside array bounds
+     * @throws NullPointerException if {@code bytes == null}
+     * @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds
+     */
+    public int writeDebugOutput(byte[] bytes, int offset, int length, boolean flush, boolean canThrow) {
+        return compilerToVm.writeDebugOutput(bytes, offset, length, flush, canThrow);
     }
 
     /**
@@ -777,7 +758,7 @@
                 } else if (len == 0) {
                     return;
                 }
-                compilerToVm.writeDebugOutput(b, off, len);
+                compilerToVm.writeDebugOutput(b, off, len, false, true);
             }
 
             @Override
@@ -907,11 +888,13 @@
      *         the Java VM in the JVMCI shared library, and the remaining values are the first 3
      *         pointers in the Invocation API function table (i.e., {@code JNIInvokeInterface})
      * @throws NullPointerException if {@code clazz == null}
-     * @throws IllegalArgumentException if the current execution context is the JVMCI shared library
-     *             or if {@code clazz} is {@link Class#isPrimitive()}
-     * @throws UnsatisfiedLinkError if the JVMCI shared library is not available, a native method in
-     *             {@code clazz} is already linked or the JVMCI shared library does not contain a
-     *             JNI-compatible symbol for a native method in {@code clazz}
+     * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
+     *             {@code -XX:-UseJVMCINativeLibrary})
+     * @throws IllegalStateException if the current execution context is the JVMCI shared library
+     * @throws IllegalArgumentException if {@code clazz} is {@link Class#isPrimitive()}
+     * @throws UnsatisfiedLinkError if there's a problem linking a native method in {@code clazz}
+     *             (no matching JNI symbol or the native method is already linked to a different
+     *             address)
      */
     public long[] registerNativeMethods(Class<?> clazz) {
         return compilerToVm.registerNativeMethods(clazz);
@@ -935,6 +918,8 @@
      *
      * @param obj an object for which an equivalent instance in the peer runtime is requested
      * @return a JNI global reference to the mirror of {@code obj} in the peer runtime
+     * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
+     *             {@code -XX:-UseJVMCINativeLibrary})
      * @throws IllegalArgumentException if {@code obj} is not of a translatable type
      *
      * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references"
@@ -950,7 +935,9 @@
      *
      * @param handle a JNI global reference to an object in the current runtime
      * @return the object referred to by {@code handle}
-     * @throws ClassCastException if the returned object cannot be case to {@code type}
+     * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
+     *             {@code -XX:-UseJVMCINativeLibrary})
+     * @throws ClassCastException if the returned object cannot be cast to {@code type}
      *
      * @see "https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references"
      *
@@ -960,6 +947,44 @@
     }
 
     /**
+     * Determines if the current thread is attached to the peer runtime.
+     *
+     * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
+     *             {@code -XX:-UseJVMCINativeLibrary})
+     * @throws IllegalStateException if the peer runtime has not been initialized
+     */
+    public boolean isCurrentThreadAttached() {
+        return compilerToVm.isCurrentThreadAttached();
+    }
+
+    /**
+     * Ensures the current thread is attached to the peer runtime.
+     *
+     * @param asDaemon if the thread is not yet attached, should it be attached as a daemon
+     * @return {@code true} if this call attached the current thread, {@code false} if the current
+     *         thread was already attached
+     * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
+     *             {@code -XX:-UseJVMCINativeLibrary})
+     * @throws IllegalStateException if the peer runtime has not been initialized or there is an
+     *             error while trying to attach the thread
+     */
+    public boolean attachCurrentThread(boolean asDaemon) {
+        return compilerToVm.attachCurrentThread(asDaemon);
+    }
+
+    /**
+     * Detaches the current thread from the peer runtime.
+     *
+     * @throws UnsupportedOperationException if the JVMCI shared library is not enabled (i.e.
+     *             {@code -XX:-UseJVMCINativeLibrary})
+     * @throws IllegalStateException if the peer runtime has not been initialized or if the current
+     *             thread is not attached or if there is an error while trying to detach the thread
+     */
+    public void detachCurrentThread() {
+        compilerToVm.detachCurrentThread();
+    }
+
+    /**
      * Informs HotSpot that no method whose module is in {@code modules} is to be compiled
      * with {@link #compileMethod}.
      *
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigStore.java	Tue May 07 10:21:04 2019 +0800
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigStore.java	Mon May 06 20:05:19 2019 -0700
@@ -193,8 +193,7 @@
     private static void printConfigLine(CompilerToVM vm, String format, Object... args) {
         String line = String.format(format, args);
         byte[] lineBytes = line.getBytes();
-        vm.writeDebugOutput(lineBytes, 0, lineBytes.length);
-        vm.flushDebugOutput();
+        vm.writeDebugOutput(lineBytes, 0, lineBytes.length, true, true);
     }
 
 }
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java	Tue May 07 10:21:04 2019 +0800
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java	Mon May 06 20:05:19 2019 -0700
@@ -49,16 +49,23 @@
         return this;
     }
 
-    @Override
-    public String toString() {
-        return getMessage();
-    }
+    private static Throwable create(String className, String message) {
+        // Try create with reflection first.
+        try {
+            Class<?> cls = Class.forName(className);
+            if (message == null) {
+                return (Throwable) cls.getConstructor().newInstance();
+            }
+            cls.getDeclaredConstructor(String.class);
+            return (Throwable) cls.getConstructor(String.class).newInstance(message);
+        } catch (Throwable ignore) {
+        }
 
-    private static TranslatedException create(String className, String message) {
         if (className.equals(TranslatedException.class.getName())) {
             // Chop the class name when boxing another TranslatedException
             return new TranslatedException(message);
         }
+
         if (message == null) {
             return new TranslatedException(className);
         }
@@ -147,7 +154,7 @@
                 Throwable throwable = create(exceptionClassName, exceptionMessage);
                 int stackTraceDepth = Integer.parseInt(parts[i++]);
 
-                StackTraceElement[] suffix = parent == null ? new StackTraceElement[0] : getStackTraceSuffix();
+                StackTraceElement[] suffix = getStackTraceSuffix();
                 StackTraceElement[] stackTrace = new StackTraceElement[stackTraceDepth + suffix.length];
                 for (int j = 0; j < stackTraceDepth; j++) {
                     String className = parts[i++];
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java	Tue May 07 10:21:04 2019 +0800
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java	Mon May 06 20:05:19 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -38,13 +38,13 @@
      * @return the simple name
      */
     public static String getSimpleName(Class<?> clazz, boolean withEnclosingClass) {
-        final String simpleName = clazz.getSimpleName();
+        final String simpleName = safeSimpleName(clazz);
         if (simpleName.length() != 0) {
             if (withEnclosingClass) {
                 String prefix = "";
                 Class<?> enclosingClass = clazz;
                 while ((enclosingClass = enclosingClass.getEnclosingClass()) != null) {
-                    prefix = enclosingClass.getSimpleName() + "." + prefix;
+                    prefix = safeSimpleName(enclosingClass) + "." + prefix;
                 }
                 return prefix + simpleName;
             }
@@ -63,6 +63,29 @@
         return name.substring(index + 1);
     }
 
+    private static String safeSimpleName(Class<?> clazz) {
+        try {
+            return clazz.getSimpleName();
+        } catch (InternalError e) {
+            // Scala inner class names do not always start with '$',
+            // causing Class.getSimpleName to throw an InternalError
+            Class<?> enclosingClass = clazz.getEnclosingClass();
+            String fqn = clazz.getName();
+            if (enclosingClass == null) {
+                // Should never happen given logic in
+                // Class.getSimpleName but best be safe
+                return fqn;
+            }
+            String enclosingFQN = enclosingClass.getName();
+            int length = fqn.length();
+            if (enclosingFQN.length() >= length) {
+                // Should also never happen
+                return fqn;
+            }
+            return fqn.substring(enclosingFQN.length());
+        }
+    }
+
     /**
      * Converts a type name in internal form to an external form.
      *
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java	Tue May 07 10:21:04 2019 +0800
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java	Mon May 06 20:05:19 2019 -0700
@@ -283,6 +283,17 @@
     }
 
     /**
+     * A Java {@code char} has a maximal UTF8 length of 3.
+     */
+    private static final int MAX_UNICODE_IN_UTF8_LENGTH = 3;
+
+    /**
+     * {@link DataOutputStream#writeUTF(String)} only supports values whose UTF8 encoding length is
+     * less than 65535.
+     */
+    private static final int MAX_UTF8_PROPERTY_STRING_LENGTH = 65535 / MAX_UNICODE_IN_UTF8_LENGTH;
+
+    /**
      * Serializes the {@linkplain #getSavedProperties() saved system properties} to a byte array for
      * the purpose of {@linkplain #initializeSavedProperties(byte[]) initializing} the initial
      * properties in the JVMCI shared library.
@@ -292,25 +303,48 @@
         if (IS_IN_NATIVE_IMAGE) {
             throw new InternalError("Can only serialize saved properties in HotSpot runtime");
         }
-        Map<String, String> props = Services.getSavedProperties();
+        return serializeProperties(Services.getSavedProperties());
+    }
 
+    private static byte[] serializeProperties(Map<String, String> props) throws IOException {
         // Compute size of output on the assumption that
         // all system properties have ASCII names and values
-        int estimate = 4;
+        int estimate = 4 + 4;
+        int nonUtf8Props = 0;
         for (Map.Entry<String, String> e : props.entrySet()) {
             String name = e.getKey();
             String value = e.getValue();
             estimate += (2 + (name.length())) + (2 + (value.length()));
+            if (name.length() > MAX_UTF8_PROPERTY_STRING_LENGTH || value.length() > MAX_UTF8_PROPERTY_STRING_LENGTH) {
+                nonUtf8Props++;
+            }
         }
 
         ByteArrayOutputStream baos = new ByteArrayOutputStream(estimate);
         DataOutputStream out = new DataOutputStream(baos);
-        out.writeInt(props.size());
+        out.writeInt(props.size() - nonUtf8Props);
+        out.writeInt(nonUtf8Props);
         for (Map.Entry<String, String> e : props.entrySet()) {
             String name = e.getKey();
             String value = e.getValue();
-            out.writeUTF(name);
-            out.writeUTF(value);
+            if (name.length() <= MAX_UTF8_PROPERTY_STRING_LENGTH && value.length() <= MAX_UTF8_PROPERTY_STRING_LENGTH) {
+                out.writeUTF(name);
+                out.writeUTF(value);
+            }
+        }
+        if (nonUtf8Props != 0) {
+            for (Map.Entry<String, String> e : props.entrySet()) {
+                String name = e.getKey();
+                String value = e.getValue();
+                if (name.length() > MAX_UTF8_PROPERTY_STRING_LENGTH || value.length() > MAX_UTF8_PROPERTY_STRING_LENGTH) {
+                    byte[] utf8Name = name.getBytes("UTF-8");
+                    byte[] utf8Value = value.getBytes("UTF-8");
+                    out.writeInt(utf8Name.length);
+                    out.write(utf8Name);
+                    out.writeInt(utf8Value.length);
+                    out.write(utf8Value);
+                }
+            }
         }
         return baos.toByteArray();
     }
@@ -325,13 +359,33 @@
         if (!IS_IN_NATIVE_IMAGE) {
             throw new InternalError("Can only initialize saved properties in JVMCI shared library runtime");
         }
+        savedProperties = Collections.unmodifiableMap(deserializeProperties(serializedProperties));
+    }
+
+    private static Map<String, String> deserializeProperties(byte[] serializedProperties) throws IOException {
         DataInputStream in = new DataInputStream(new ByteArrayInputStream(serializedProperties));
-        Map<String, String> props = new HashMap<>(in.readInt());
+        int utf8Props = in.readInt();
+        int nonUtf8Props = in.readInt();
+        Map<String, String> props = new HashMap<>(utf8Props + nonUtf8Props);
+        int index = 0;
         while (in.available() != 0) {
-            String name = in.readUTF();
-            String value = in.readUTF();
-            props.put(name, value);
+            if (index < utf8Props) {
+                String name = in.readUTF();
+                String value = in.readUTF();
+                props.put(name, value);
+            } else {
+                int nameLen = in.readInt();
+                byte[] nameBytes = new byte[nameLen];
+                in.read(nameBytes);
+                int valueLen = in.readInt();
+                byte[] valueBytes = new byte[valueLen];
+                in.read(valueBytes);
+                String name = new String(nameBytes, "UTF-8");
+                String value = new String(valueBytes, "UTF-8");
+                props.put(name, value);
+            }
+            index++;
         }
-        savedProperties = Collections.unmodifiableMap(props);
+        return props;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/SuppressFBWarnings.java	Mon May 06 20:05:19 2019 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2019, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.vm.ci.services;
+
+/**
+ * Used to suppress <a href="http://findbugs.sourceforge.net">FindBugs</a> warnings.
+ */
+@interface SuppressFBWarnings {
+    /**
+     * The set of FindBugs
+     * <a href="http://findbugs.sourceforge.net/bugDescriptions.html">warnings</a> that are to be
+     * suppressed in annotated element. The value can be a bug category, kind or pattern.
+     */
+    String[] value();
+
+    /**
+     * Reason why the warning is suppressed.
+     */
+    String justification();
+}
--- a/src/jdk.internal.vm.ci/share/classes/module-info.java	Tue May 07 10:21:04 2019 +0800
+++ b/src/jdk.internal.vm.ci/share/classes/module-info.java	Mon May 06 20:05:19 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -30,6 +30,9 @@
     exports jdk.vm.ci.runtime to
         jdk.internal.vm.compiler,
         jdk.internal.vm.compiler.management;
+    exports jdk.vm.ci.meta to jdk.internal.vm.compiler;
+    exports jdk.vm.ci.code to jdk.internal.vm.compiler;
+    exports jdk.vm.ci.hotspot to jdk.internal.vm.compiler;
 
     uses jdk.vm.ci.services.JVMCIServiceLocator;
     uses jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java	Tue May 07 10:21:04 2019 +0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/LoadConstantIndirectlyNode.java	Mon May 06 20:05:19 2019 -0700
@@ -43,6 +43,7 @@
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 
+import jdk.vm.ci.hotspot.HotSpotConstantPoolObject;
 import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
 import jdk.vm.ci.hotspot.HotSpotObjectConstant;
 import jdk.vm.ci.meta.Constant;
@@ -83,7 +84,7 @@
     public void generate(NodeLIRBuilderTool gen) {
         assert constant != null : "Expected the value to fold: " + value;
         Value result;
-        if (constant instanceof HotSpotObjectConstant) {
+        if (constant instanceof HotSpotObjectConstant || constant instanceof HotSpotConstantPoolObject) {
             result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadObjectAddress(constant);
         } else if (constant instanceof HotSpotMetaspaceConstant) {
             result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitLoadMetaspaceAddress(constant, action);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java	Tue May 07 10:21:04 2019 +0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveConstantStubCall.java	Mon May 06 20:05:19 2019 -0700
@@ -45,6 +45,7 @@
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.word.Word;
 
+import jdk.vm.ci.hotspot.HotSpotConstantPoolObject;
 import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
 import jdk.vm.ci.hotspot.HotSpotObjectConstant;
 import jdk.vm.ci.meta.Constant;
@@ -100,7 +101,7 @@
         Value result;
         LIRFrameState fs = gen.state(this);
         assert fs != null : "The stateAfter is null";
-        if (constant instanceof HotSpotObjectConstant) {
+        if (constant instanceof HotSpotObjectConstant || constant instanceof HotSpotConstantPoolObject) {
             result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()).emitObjectConstantRetrieval(constant, stringValue, fs);
         } else if (constant instanceof HotSpotMetaspaceConstant) {
             if (action == HotSpotConstantLoadAction.RESOLVE) {
--- a/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java	Tue May 07 10:21:04 2019 +0800
+++ b/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java	Mon May 06 20:05:19 2019 -0700
@@ -301,7 +301,7 @@
     }
 
     public static void writeDebugOutput(byte[] bytes, int offset, int length) {
-        CTVM.writeDebugOutput(bytes, offset, length);
+        CTVM.writeDebugOutput(bytes, offset, length, true, true);
     }
 
     public static void flushDebugOutput() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotJVMCIRuntime.java	Mon May 06 20:05:19 2019 -0700
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2018, 2019, 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 jdk.vm.ci.hotspot.test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.Predicate;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public class TestHotSpotJVMCIRuntime {
+
+    @Test
+    public void writeDebugOutputTest() {
+        HotSpotJVMCIRuntime runtime = HotSpotJVMCIRuntime.runtime();
+
+        expectWriteDebugOutputFailure(runtime, null, 0, 0, true, true, NullPointerException.class);
+        expectWriteDebugOutputFailure(runtime, null, 0, 0, true, false, -1);
+
+        byte[] emptyOutput = {};
+        byte[] nonEmptyOutput = String.format("non-empty output%n").getBytes();
+
+        for (boolean canThrow : new boolean[]{true, false}) {
+            for (byte[] output : new byte[][]{emptyOutput, nonEmptyOutput}) {
+                for (int offset = 0; offset < output.length; offset++) {
+                    int length = output.length - offset;
+                    runtime.writeDebugOutput(output, offset, length, true, canThrow);
+                }
+
+                Object expect = canThrow ? IndexOutOfBoundsException.class : -2;
+                expectWriteDebugOutputFailure(runtime, output, output.length + 1, 0, true, canThrow, expect);
+                expectWriteDebugOutputFailure(runtime, output, 0, output.length + 1, true, canThrow, expect);
+                expectWriteDebugOutputFailure(runtime, output, -1, 0, true, canThrow, expect);
+                expectWriteDebugOutputFailure(runtime, output, 0, -1, true, canThrow, expect);
+            }
+        }
+    }
+
+    private static void expectWriteDebugOutputFailure(HotSpotJVMCIRuntime runtime, byte[] bytes, int offset, int length, boolean flush, boolean canThrow, Object expect) {
+        try {
+            int result = runtime.writeDebugOutput(bytes, offset, length, flush, canThrow);
+            if (expect instanceof Integer) {
+                Assert.assertEquals((int) expect, result);
+            } else {
+                Assert.fail("expected " + expect + ", got " + result + " for bytes == " + Arrays.toString(bytes));
+            }
+        } catch (Exception e) {
+            if (expect instanceof Integer) {
+                Assert.fail("expected " + expect + ", got " + e + " for bytes == " + Arrays.toString(bytes));
+            } else {
+                Assert.assertTrue(e.toString(), ((Class<?>) expect).isInstance(e));
+            }
+        }
+    }
+
+    @Test
+    public void getIntrinsificationTrustPredicateTest() throws Exception {
+        HotSpotJVMCIRuntime runtime = HotSpotJVMCIRuntime.runtime();
+        MetaAccessProvider metaAccess = runtime.getHostJVMCIBackend().getMetaAccess();
+        Predicate<ResolvedJavaType> predicate = runtime.getIntrinsificationTrustPredicate(HotSpotJVMCIRuntime.class);
+        List<Class<?>> classes = new ArrayList<>(Arrays.asList(
+                        Object.class,
+                        String.class,
+                        Class.class,
+                        HotSpotJVMCIRuntime.class,
+                        VirtualObjectLayoutTest.class,
+                        TestHotSpotJVMCIRuntime.class));
+        try {
+            classes.add(Class.forName("com.sun.crypto.provider.AESCrypt"));
+            classes.add(Class.forName("com.sun.crypto.provider.CipherBlockChaining"));
+        } catch (ClassNotFoundException e) {
+            // Extension classes not available
+        }
+        ClassLoader jvmciLoader = HotSpotJVMCIRuntime.class.getClassLoader();
+        ClassLoader extLoader = getExtensionLoader();
+        for (Class<?> c : classes) {
+            ClassLoader cl = c.getClassLoader();
+            boolean expected = cl == null || cl == jvmciLoader || cl == extLoader;
+            boolean actual = predicate.test(metaAccess.lookupJavaType(c));
+            Assert.assertEquals(c + ": cl=" + cl, expected, actual);
+        }
+    }
+
+    private static ClassLoader getExtensionLoader() throws Exception {
+        Object launcher = Class.forName("sun.misc.Launcher").getMethod("getLauncher").invoke(null);
+        ClassLoader appLoader = (ClassLoader) launcher.getClass().getMethod("getClassLoader").invoke(launcher);
+        ClassLoader extLoader = appLoader.getParent();
+        assert extLoader.getClass().getName().equals("sun.misc.Launcher$ExtClassLoader") : extLoader;
+        return extLoader;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestServices.java	Mon May 06 20:05:19 2019 -0700
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2019, 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 jdk.vm.ci.hotspot.test;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.vm.ci.services.Services;
+
+public class TestServices {
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void serializeSavedPropertiesTest() throws Exception {
+
+        Field f = Services.class.getDeclaredField("MAX_UTF8_PROPERTY_STRING_LENGTH");
+        f.setAccessible(true);
+        int maxUtf8PropertyStringLength = (int) f.get(null);
+
+        Method serializeProperties = Services.class.getDeclaredMethod("serializeProperties", Map.class);
+        Method deserializeProperties = Services.class.getDeclaredMethod("deserializeProperties", byte[].class);
+        serializeProperties.setAccessible(true);
+        deserializeProperties.setAccessible(true);
+
+        Map<String, String> props = new HashMap<>(Services.getSavedProperties());
+        String[] names = {
+                        new String(new char[maxUtf8PropertyStringLength - 100]).replace('\0', 'x'),
+                        new String(new char[maxUtf8PropertyStringLength - 1]).replace('\0', 'x'),
+                        new String(new char[maxUtf8PropertyStringLength]).replace('\0', 'y'),
+                        new String(new char[maxUtf8PropertyStringLength + 1]).replace('\0', 'z'),
+                        new String(new char[maxUtf8PropertyStringLength + 100]).replace('\0', 'z')
+        };
+        String[] values = {
+                        new String(new char[maxUtf8PropertyStringLength - 100]).replace('\0', '1'),
+                        new String(new char[maxUtf8PropertyStringLength - 1]).replace('\0', '1'),
+                        new String(new char[maxUtf8PropertyStringLength]).replace('\0', '2'),
+                        new String(new char[maxUtf8PropertyStringLength + 1]).replace('\0', '1'),
+                        new String(new char[maxUtf8PropertyStringLength + 100]).replace('\0', '3')
+        };
+        for (String name : names) {
+            for (String value : values) {
+                props.put(name, value);
+            }
+        }
+
+        byte[] data = (byte[]) serializeProperties.invoke(null, props);
+
+        Map<String, String> newProps = (Map<String, String>) deserializeProperties.invoke(null, data);
+
+        Assert.assertEquals(props.size(), newProps.size());
+        for (String name : props.keySet()) {
+            String expect = props.get(name);
+            String actual = newProps.get(name);
+            Assert.assertEquals(expect, actual);
+        }
+    }
+}
--- a/test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java	Tue May 07 10:21:04 2019 +0800
+++ b/test/jdk/jdk/modules/etc/JdkQualifiedExportTest.java	Mon May 06 20:05:19 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -71,6 +71,9 @@
     static Set<String> KNOWN_EXCEPTIONS =
         Set.of("jdk.internal.vm.ci/jdk.vm.ci.services",
                "jdk.internal.vm.ci/jdk.vm.ci.runtime",
+               "jdk.internal.vm.ci/jdk.vm.ci.hotspot",
+               "jdk.internal.vm.ci/jdk.vm.ci.meta",
+               "jdk.internal.vm.ci/jdk.vm.ci.code",
                "jdk.jsobject/jdk.internal.netscape.javascript.spi");
 
     static void checkExports(ModuleDescriptor md) {