changeset 54114:a6f04495687e

8219995: Update JVMCI Reviewed-by: never
author kvn
date Mon, 18 Mar 2019 16:54:45 -0700
parents ad1f6009b2f2
children b49b6a0d2a02
files make/autoconf/hotspot.m4 src/hotspot/cpu/sparc/jvmciCodeInstaller_sparc.cpp src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp src/hotspot/share/classfile/classFileParser.cpp src/hotspot/share/code/nmethod.cpp src/hotspot/share/code/nmethod.hpp src/hotspot/share/compiler/compilerDefinitions.cpp src/hotspot/share/compiler/disassembler.cpp src/hotspot/share/jvmci/jvmci.hpp src/hotspot/share/jvmci/jvmciCodeInstaller.cpp src/hotspot/share/jvmci/jvmciCodeInstaller.hpp src/hotspot/share/jvmci/jvmciCompiler.hpp src/hotspot/share/jvmci/jvmciCompilerToVM.cpp src/hotspot/share/jvmci/jvmciEnv.cpp src/hotspot/share/jvmci/jvmciEnv.hpp src/hotspot/share/jvmci/jvmciJavaClasses.cpp src/hotspot/share/jvmci/jvmciJavaClasses.hpp src/hotspot/share/jvmci/jvmciRuntime.cpp src/hotspot/share/jvmci/jvmciRuntime.hpp src/hotspot/share/jvmci/jvmci_globals.cpp src/hotspot/share/jvmci/jvmci_globals.hpp src/hotspot/share/jvmci/vmStructs_jvmci.cpp src/hotspot/share/jvmci/vmSymbols_jvmci.hpp src/hotspot/share/oops/method.cpp src/hotspot/share/oops/methodData.cpp src/hotspot/share/oops/methodData.hpp src/hotspot/share/runtime/deoptimization.cpp src/hotspot/share/runtime/frame.cpp src/hotspot/share/runtime/thread.hpp src/hotspot/share/runtime/vmOperations.cpp src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodePosition.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Cleaner.java 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/DirectHotSpotObjectConstantImpl.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HandleCleaner.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJDKReflection.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIReflection.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/HotSpotMetaAccessProvider.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethodHandle.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationEncoding.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigAccess.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMEntryPoint.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SpeculationLog.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/VMEntryPoint.java src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java test/hotspot/jtreg/compiler/jvmci/errors/CodeInstallerTest.java test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.java test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotSpeculationLog.java test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestSpeculationLog.java
diffstat 64 files changed, 2388 insertions(+), 1082 deletions(-) [+]
line wrap: on
line diff
--- a/make/autoconf/hotspot.m4	Wed Mar 13 21:41:51 2019 -0700
+++ b/make/autoconf/hotspot.m4	Mon Mar 18 16:54:45 2019 -0700
@@ -392,9 +392,8 @@
     JVM_FEATURES_jvmci=""
     INCLUDE_JVMCI="false"
   else
-    # Only enable jvmci on x86_64, sparcv9 and aarch64
+    # Only enable jvmci on x86_64 and aarch64
     if test "x$OPENJDK_TARGET_CPU" = "xx86_64" || \
-       test "x$OPENJDK_TARGET_CPU" = "xsparcv9" || \
        test "x$OPENJDK_TARGET_CPU" = "xaarch64" ; then
       AC_MSG_RESULT([yes])
       JVM_FEATURES_jvmci="jvmci"
--- a/src/hotspot/cpu/sparc/jvmciCodeInstaller_sparc.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/cpu/sparc/jvmciCodeInstaller_sparc.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -46,8 +46,8 @@
 
 void CodeInstaller::pd_patch_OopConstant(int pc_offset, JVMCIObject constant, JVMCI_TRAPS) {
   address pc = _instructions->start() + pc_offset;
-  oop obj = jvmci_env()->asConstant(constant, JVMCI_CHECK);
-  jobject value = JNIHandles::make_local(obj);
+  Handle obj = jvmci_env()->asConstant(constant, JVMCI_CHECK);
+  jobject value = JNIHandles::make_local(obj());
   if (jvmci_env()->get_HotSpotObjectConstantImpl_compressed(constant)) {
     int oop_index = _oop_recorder->find_index(value);
     RelocationHolder rspec = oop_Relocation::spec(oop_index);
--- a/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/cpu/x86/jvmciCodeInstaller_x86.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -66,9 +66,8 @@
 
 void CodeInstaller::pd_patch_OopConstant(int pc_offset, JVMCIObject constant, JVMCI_TRAPS) {
   address pc = _instructions->start() + pc_offset;
-  oop oop = jvmci_env()->asConstant(constant, JVMCI_CHECK);
+  Handle obj = jvmci_env()->asConstant(constant, JVMCI_CHECK);
   Thread* THREAD = Thread::current();
-  Handle obj(THREAD, oop);
   jobject value = JNIHandles::make_local(obj());
   if (jvmci_env()->get_HotSpotObjectConstantImpl_compressed(constant)) {
 #ifdef _LP64
--- a/src/hotspot/share/classfile/classFileParser.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/classfile/classFileParser.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -5632,10 +5632,22 @@
   ClassLoadingService::notify_class_loaded(ik, false /* not shared class */);
 
   if (!is_internal()) {
-    if (log_is_enabled(Info, class, load)) {
+    bool trace_class_loading = log_is_enabled(Info, class, load);
+#if INCLUDE_JVMCI
+    bool trace_loading_cause = TraceClassLoadingCause != NULL &&
+        (strcmp(TraceClassLoadingCause, "*") == 0 ||
+         strstr(ik->external_name(), TraceClassLoadingCause) != NULL);
+    trace_class_loading = trace_class_loading || trace_loading_cause;
+#endif
+    if (trace_class_loading) {
       ResourceMark rm;
       const char* module_name = (module_entry->name() == NULL) ? UNNAMED_MODULE : module_entry->name()->as_C_string();
       ik->print_class_load_logging(_loader_data, module_name, _stream);
+#if INCLUDE_JVMCI
+      if (trace_loading_cause) {
+        JavaThread::current()->print_stack_on(tty);
+      }
+#endif
     }
 
     if (ik->minor_version() == JAVA_PREVIEW_MINOR_VERSION &&
--- a/src/hotspot/share/code/nmethod.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/code/nmethod.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -113,6 +113,10 @@
   int dependencies_size;
   int handler_table_size;
   int nul_chk_table_size;
+#if INCLUDE_JVMCI
+  int speculations_size;
+  int jvmci_data_size;
+#endif
   int oops_size;
   int metadata_size;
 
@@ -130,6 +134,10 @@
     dependencies_size   += nm->dependencies_size();
     handler_table_size  += nm->handler_table_size();
     nul_chk_table_size  += nm->nul_chk_table_size();
+#if INCLUDE_JVMCI
+    speculations_size   += nm->speculations_size();
+    jvmci_data_size     += nm->jvmci_data_size();
+#endif
   }
   void print_nmethod_stats(const char* name) {
     if (nmethod_count == 0)  return;
@@ -147,6 +155,10 @@
     if (dependencies_size != 0)   tty->print_cr(" dependencies   = %d", dependencies_size);
     if (handler_table_size != 0)  tty->print_cr(" handler table  = %d", handler_table_size);
     if (nul_chk_table_size != 0)  tty->print_cr(" nul chk table  = %d", nul_chk_table_size);
+#if INCLUDE_JVMCI
+    if (speculations_size != 0)   tty->print_cr(" speculations   = %d", speculations_size);
+    if (jvmci_data_size != 0)     tty->print_cr(" JVMCI data     = %d", jvmci_data_size);
+#endif
   }
 };
 
@@ -429,9 +441,6 @@
 #if INCLUDE_RTM_OPT
   _rtm_state               = NoRTM;
 #endif
-#if INCLUDE_JVMCI
-  _jvmci_nmethod_data      = NULL;
-#endif
 }
 
 nmethod* nmethod::new_native_nmethod(const methodHandle& method,
@@ -484,7 +493,11 @@
   AbstractCompiler* compiler,
   int comp_level
 #if INCLUDE_JVMCI
- , JVMCINMethodData* jvmci_nmethod_data
+  , char* speculations,
+  int speculations_len,
+  int nmethod_mirror_index,
+  const char* nmethod_mirror_name,
+  FailedSpeculation** failed_speculations
 #endif
 )
 {
@@ -493,12 +506,19 @@
   // create nmethod
   nmethod* nm = NULL;
   { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+#if INCLUDE_JVMCI
+    int jvmci_data_size = JVMCINMethodData::compute_size(nmethod_mirror_name);
+#endif
     int nmethod_size =
       CodeBlob::allocation_size(code_buffer, sizeof(nmethod))
       + adjust_pcs_size(debug_info->pcs_size())
       + align_up((int)dependencies->size_in_bytes(), oopSize)
       + align_up(handler_table->size_in_bytes()    , oopSize)
       + align_up(nul_chk_table->size_in_bytes()    , oopSize)
+#if INCLUDE_JVMCI
+      + align_up(speculations_len                  , oopSize)
+      + align_up(jvmci_data_size                   , oopSize)
+#endif
       + align_up(debug_info->data_size()           , oopSize);
 
     nm = new (nmethod_size, comp_level)
@@ -510,11 +530,17 @@
             compiler,
             comp_level
 #if INCLUDE_JVMCI
-            , jvmci_nmethod_data
+            , speculations,
+            speculations_len,
+            jvmci_data_size
 #endif
             );
 
     if (nm != NULL) {
+#if INCLUDE_JVMCI
+      // Initialize the JVMCINMethodData object inlined into nm
+      nm->jvmci_nmethod_data()->initialize(nmethod_mirror_index, nmethod_mirror_name, failed_speculations);
+#endif
       // To make dependency checking during class loading fast, record
       // the nmethod dependencies in the classes it is dependent on.
       // This allows the dependency checking code to simply walk the
@@ -590,7 +616,13 @@
     _dependencies_offset     = _scopes_pcs_offset;
     _handler_table_offset    = _dependencies_offset;
     _nul_chk_table_offset    = _handler_table_offset;
+#if INCLUDE_JVMCI
+    _speculations_offset     = _nul_chk_table_offset;
+    _jvmci_data_offset       = _speculations_offset;
+    _nmethod_end_offset      = _jvmci_data_offset;
+#else
     _nmethod_end_offset      = _nul_chk_table_offset;
+#endif
     _compile_id              = compile_id;
     _comp_level              = CompLevel_none;
     _entry_point             = code_begin()          + offsets->value(CodeOffsets::Entry);
@@ -666,7 +698,9 @@
   AbstractCompiler* compiler,
   int comp_level
 #if INCLUDE_JVMCI
- , JVMCINMethodData* jvmci_nmethod_data
+  , char* speculations,
+  int speculations_len,
+  int jvmci_data_size
 #endif
   )
   : CompiledMethod(method, "nmethod", type, nmethod_size, sizeof(nmethod), code_buffer, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps, false),
@@ -695,7 +729,6 @@
     set_ctable_begin(header_begin() + _consts_offset);
 
 #if INCLUDE_JVMCI
-    _jvmci_nmethod_data = jvmci_nmethod_data;
     if (compiler->is_jvmci()) {
       // JVMCI might not produce any stub sections
       if (offsets->value(CodeOffsets::Exceptions) != -1) {
@@ -743,7 +776,13 @@
     _dependencies_offset     = _scopes_pcs_offset    + adjust_pcs_size(debug_info->pcs_size());
     _handler_table_offset    = _dependencies_offset  + align_up((int)dependencies->size_in_bytes (), oopSize);
     _nul_chk_table_offset    = _handler_table_offset + align_up(handler_table->size_in_bytes(), oopSize);
+#if INCLUDE_JVMCI
+    _speculations_offset     = _nul_chk_table_offset + align_up(nul_chk_table->size_in_bytes(), oopSize);
+    _jvmci_data_offset       = _speculations_offset  + align_up(speculations_len, oopSize);
+    _nmethod_end_offset      = _jvmci_data_offset    + align_up(jvmci_data_size, oopSize);
+#else
     _nmethod_end_offset      = _nul_chk_table_offset + align_up(nul_chk_table->size_in_bytes(), oopSize);
+#endif
     _entry_point             = code_begin()          + offsets->value(CodeOffsets::Entry);
     _verified_entry_point    = code_begin()          + offsets->value(CodeOffsets::Verified_Entry);
     _osr_entry_point         = code_begin()          + offsets->value(CodeOffsets::OSR_Entry);
@@ -770,6 +809,13 @@
     handler_table->copy_to(this);
     nul_chk_table->copy_to(this);
 
+#if INCLUDE_JVMCI
+    // Copy speculations to nmethod
+    if (speculations_size() != 0) {
+      memcpy(speculations_begin(), speculations, speculations_len);
+    }
+#endif
+
     // we use the information of entry points to find out if a method is
     // static or non static
     assert(compiler->is_c2() || compiler->is_jvmci() ||
@@ -789,10 +835,10 @@
     log->print(" level='%d'", comp_level());
   }
 #if INCLUDE_JVMCI
-  if (_jvmci_nmethod_data != NULL) {
-    const char* jvmci_name = _jvmci_nmethod_data->nmethod_mirror_name();
+  if (jvmci_nmethod_data() != NULL) {
+    const char* jvmci_name = jvmci_nmethod_data()->name();
     if (jvmci_name != NULL) {
-      log->print(" jvmci_nmethod_mirror_name='");
+      log->print(" jvmci_mirror_name='");
       log->text("%s", jvmci_name);
       log->print("'");
     }
@@ -1104,13 +1150,6 @@
   // Log the unloading.
   log_state_change();
 
-#if INCLUDE_JVMCI
-  // The method can only be unloaded after the HotSpotNmethod mirror
-  // are no longer alive. Here we need to clear out the weak
-  // references to the dead objects.
-  maybe_invalidate_jvmci_mirror();
-#endif
-
   // The Method* is gone at this point
   assert(_method == NULL, "Tautology");
 
@@ -1123,6 +1162,15 @@
   // concurrent nmethod unloading. Therefore, there is no need for
   // acquire on the loader side.
   OrderAccess::release_store(&_state, (signed char)unloaded);
+
+#if INCLUDE_JVMCI
+  // Clear the link between this nmethod and a HotSpotNmethod mirror
+  JVMCINMethodData* nmethod_data = jvmci_nmethod_data();
+  if (nmethod_data != NULL) {
+    nmethod_data->invalidate_nmethod_mirror(this);
+    nmethod_data->clear_nmethod_mirror(this);
+  }
+#endif
 }
 
 void nmethod::invalidate_osr_method() {
@@ -1258,6 +1306,14 @@
     unlink_from_method(false /* already owns Patching_lock */);
   } // leave critical region under Patching_lock
 
+#if INCLUDE_JVMCI
+  // Invalidate can't occur while holding the Patching lock
+  JVMCINMethodData* nmethod_data = jvmci_nmethod_data();
+  if (nmethod_data != NULL) {
+    nmethod_data->invalidate_nmethod_mirror(this);
+  }
+#endif
+
 #ifdef ASSERT
   if (is_osr_method() && method() != NULL) {
     // Make sure osr nmethod is invalidated, i.e. not on the list
@@ -1266,9 +1322,6 @@
   }
 #endif
 
-  // Invalidate can't occur while holding the Patching lock
-  JVMCI_ONLY(maybe_invalidate_jvmci_mirror());
-
   // When the nmethod becomes zombie it is no longer alive so the
   // dependencies must be flushed.  nmethods in the not_entrant
   // state will be flushed later when the transition to zombie
@@ -1285,6 +1338,14 @@
       flush_dependencies(/*delete_immediately*/true);
     }
 
+#if INCLUDE_JVMCI
+    // Now that the nmethod has been unregistered, it's
+    // safe to clear the HotSpotNmethod mirror oop.
+    if (nmethod_data != NULL) {
+      nmethod_data->clear_nmethod_mirror(this);
+    }
+#endif
+
     // Clear ICStubs to prevent back patching stubs of zombie or flushed
     // nmethods during the next safepoint (see ICStub::finalize), as well
     // as to free up CompiledICHolder resources.
@@ -1354,10 +1415,6 @@
     CodeCache::drop_scavenge_root_nmethod(this);
   }
 
-#if INCLUDE_JVMCI
-  assert(_jvmci_nmethod_data == NULL, "should have been nulled out when transitioned to zombie");
-#endif
-
   Universe::heap()->flush_nmethod(this);
 
   CodeBlob::flush();
@@ -1651,12 +1708,6 @@
   if (is_unloading()) {
     make_unloaded();
   } else {
-#if INCLUDE_JVMCI
-    if (_jvmci_nmethod_data != NULL) {
-      _jvmci_nmethod_data->update_nmethod_mirror_in_gc(this);
-    }
-#endif
-
     guarantee(unload_nmethod_caches(unloading_occurred),
               "Should not need transition stubs");
   }
@@ -2361,6 +2412,16 @@
                                               p2i(nul_chk_table_begin()),
                                               p2i(nul_chk_table_end()),
                                               nul_chk_table_size());
+#if INCLUDE_JVMCI
+  if (speculations_size () > 0) tty->print_cr(" speculations   [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+                                              p2i(speculations_begin()),
+                                              p2i(speculations_end()),
+                                              speculations_size());
+  if (jvmci_data_size   () > 0) tty->print_cr(" JVMCI data     [" INTPTR_FORMAT "," INTPTR_FORMAT "] = %d",
+                                              p2i(jvmci_data_begin()),
+                                              p2i(jvmci_data_end()),
+                                              jvmci_data_size());
+#endif
 }
 
 #ifndef PRODUCT
@@ -2943,25 +3004,18 @@
 #endif // !PRODUCT
 
 #if INCLUDE_JVMCI
-void nmethod::maybe_invalidate_jvmci_mirror() {
-  if (_jvmci_nmethod_data != NULL) {
-    _jvmci_nmethod_data->invalidate_mirror(this);
-    if (!is_alive()) {
-      JVMCINMethodData::release(_jvmci_nmethod_data);
-      _jvmci_nmethod_data = NULL;
-    }
+void nmethod::update_speculation(JavaThread* thread) {
+  jlong speculation = thread->pending_failed_speculation();
+  if (speculation != 0) {
+    guarantee(jvmci_nmethod_data() != NULL, "failed speculation in nmethod without failed speculation list");
+    jvmci_nmethod_data()->add_failed_speculation(this, speculation);
+    thread->set_pending_failed_speculation(0);
   }
 }
 
-void nmethod::update_speculation(JavaThread* thread) {
-  if (_jvmci_nmethod_data != NULL) {
-    _jvmci_nmethod_data->update_speculation(thread, this);
-  }
-}
-
-const char* nmethod::jvmci_nmethod_mirror_name() {
-  if (_jvmci_nmethod_data != NULL) {
-    return _jvmci_nmethod_data->nmethod_mirror_name();
+const char* nmethod::jvmci_name() {
+  if (jvmci_nmethod_data() != NULL) {
+    return jvmci_nmethod_data()->name();
   }
   return NULL;
 }
--- a/src/hotspot/share/code/nmethod.hpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/code/nmethod.hpp	Mon Mar 18 16:54:45 2019 -0700
@@ -51,8 +51,13 @@
 //  - handler entry point array
 //  [Implicit Null Pointer exception table]
 //  - implicit null table array
+//  [Speculations]
+//  - encoded speculations array
+//  [JVMCINMethodData]
+//  - meta data for JVMCI compiled nmethod
 
 #if INCLUDE_JVMCI
+class FailedSpeculation;
 class JVMCINMethodData;
 #endif
 
@@ -68,10 +73,6 @@
   int       _entry_bci;        // != InvocationEntryBci if this nmethod is an on-stack replacement method
   jmethodID _jmethod_id;       // Cache of method()->jmethod_id()
 
-#if INCLUDE_JVMCI
-  JVMCINMethodData* _jvmci_nmethod_data;
-#endif
-
   // To support simple linked-list chaining of nmethods:
   nmethod*  _osr_link;         // from InstanceKlass::osr_nmethods_head
 
@@ -97,6 +98,10 @@
   int _dependencies_offset;
   int _handler_table_offset;
   int _nul_chk_table_offset;
+#if INCLUDE_JVMCI
+  int _speculations_offset;
+  int _jvmci_data_offset;
+#endif
   int _nmethod_end_offset;
 
   int code_offset() const { return (address) code_begin() - header_begin(); }
@@ -199,7 +204,9 @@
           AbstractCompiler* compiler,
           int comp_level
 #if INCLUDE_JVMCI
-          , JVMCINMethodData* jvmci_nmethod_data
+          , char* speculations,
+          int speculations_len,
+          int jvmci_data_size
 #endif
           );
 
@@ -242,7 +249,11 @@
                               AbstractCompiler* compiler,
                               int comp_level
 #if INCLUDE_JVMCI
-                              , JVMCINMethodData* jvmci_nmethod_data = NULL
+                              , char* speculations = NULL,
+                              int speculations_len = 0,
+                              int nmethod_mirror_index = -1,
+                              const char* nmethod_mirror_name = NULL,
+                              FailedSpeculation** failed_speculations = NULL
 #endif
   );
 
@@ -289,12 +300,24 @@
   address handler_table_begin   () const          { return           header_begin() + _handler_table_offset ; }
   address handler_table_end     () const          { return           header_begin() + _nul_chk_table_offset ; }
   address nul_chk_table_begin   () const          { return           header_begin() + _nul_chk_table_offset ; }
+#if INCLUDE_JVMCI
+  address nul_chk_table_end     () const          { return           header_begin() + _speculations_offset  ; }
+  address speculations_begin    () const          { return           header_begin() + _speculations_offset  ; }
+  address speculations_end      () const          { return           header_begin() + _jvmci_data_offset   ; }
+  address jvmci_data_begin      () const          { return           header_begin() + _jvmci_data_offset    ; }
+  address jvmci_data_end        () const          { return           header_begin() + _nmethod_end_offset   ; }
+#else
   address nul_chk_table_end     () const          { return           header_begin() + _nmethod_end_offset   ; }
+#endif
 
   // Sizes
   int oops_size         () const                  { return (address)  oops_end         () - (address)  oops_begin         (); }
   int metadata_size     () const                  { return (address)  metadata_end     () - (address)  metadata_begin     (); }
   int dependencies_size () const                  { return            dependencies_end () -            dependencies_begin (); }
+#if INCLUDE_JVMCI
+  int speculations_size () const                  { return            speculations_end () -            speculations_begin (); }
+  int jvmci_data_size   () const                  { return            jvmci_data_end   () -            jvmci_data_begin   (); }
+#endif
 
   int     oops_count() const { assert(oops_size() % oopSize == 0, "");  return (oops_size() / oopSize) + 1; }
   int metadata_count() const { assert(metadata_size() % wordSize == 0, ""); return (metadata_size() / wordSize) + 1; }
@@ -454,19 +477,16 @@
   void set_method(Method* method) { _method = method; }
 
 #if INCLUDE_JVMCI
-  // Return the name of the HotSpotNmethod mirror (if any).
-  const char* jvmci_nmethod_mirror_name();
-
-  // Updates the state of the HotSpotNmethod and SpeculationLog
-  // references associated with this nmethod based on the current
-  // value of _state.
-  void maybe_invalidate_jvmci_mirror();
+  // Gets the JVMCI name of this nmethod.
+  const char* jvmci_name();
 
   // Records the pending failed speculation in the
   // JVMCI speculation log associated with this nmethod.
   void update_speculation(JavaThread* thread);
 
-  JVMCINMethodData* jvmci_nmethod_data() { return _jvmci_nmethod_data; }
+  JVMCINMethodData* jvmci_nmethod_data() const {
+    return jvmci_data_size() == 0 ? NULL : (JVMCINMethodData*) jvmci_data_begin();
+  }
 #endif
 
  public:
--- a/src/hotspot/share/compiler/compilerDefinitions.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/compiler/compilerDefinitions.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -253,22 +253,6 @@
     if (FLAG_IS_DEFAULT(TypeProfileWidth)) {
       FLAG_SET_DEFAULT(TypeProfileWidth, 8);
     }
-    if (FLAG_IS_DEFAULT(OnStackReplacePercentage)) {
-      FLAG_SET_DEFAULT(OnStackReplacePercentage, 933);
-    }
-    // JVMCI needs values not less than defaults
-    if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) {
-      FLAG_SET_DEFAULT(ReservedCodeCacheSize, MAX2(64*M, ReservedCodeCacheSize));
-    }
-    if (FLAG_IS_DEFAULT(InitialCodeCacheSize)) {
-      FLAG_SET_DEFAULT(InitialCodeCacheSize, MAX2(16*M, InitialCodeCacheSize));
-    }
-    if (FLAG_IS_DEFAULT(MetaspaceSize)) {
-      FLAG_SET_DEFAULT(MetaspaceSize, MIN2(MAX2(12*M, MetaspaceSize), MaxMetaspaceSize));
-    }
-    if (FLAG_IS_DEFAULT(NewSizeThreadIncrease)) {
-      FLAG_SET_DEFAULT(NewSizeThreadIncrease, MAX2(4*K, NewSizeThreadIncrease));
-    }
     if (TieredStopAtLevel != CompLevel_full_optimization) {
       // Currently JVMCI compiler can only work at the full optimization level
       warning("forcing TieredStopAtLevel to full optimization because JVMCI is enabled");
@@ -278,12 +262,31 @@
       FLAG_SET_DEFAULT(TypeProfileLevel, 0);
     }
 
-    // SVM compiled code requires more stack space
-    if (JVMCIGlobals::java_mode() == JVMCIGlobals::SharedLibrary) {
+    if (UseJVMCINativeLibrary) {
+      // SVM compiled code requires more stack space
       if (FLAG_IS_DEFAULT(CompilerThreadStackSize)) {
         FLAG_SET_DEFAULT(CompilerThreadStackSize, 2*M);
       }
-    }
+    } else {
+      // Adjust the on stack replacement percentage to avoid early
+      // OSR compilations while JVMCI itself is warming up
+      if (FLAG_IS_DEFAULT(OnStackReplacePercentage)) {
+        FLAG_SET_DEFAULT(OnStackReplacePercentage, 933);
+      }
+      // JVMCI needs values not less than defaults
+      if (FLAG_IS_DEFAULT(ReservedCodeCacheSize)) {
+        FLAG_SET_DEFAULT(ReservedCodeCacheSize, MAX2(64*M, ReservedCodeCacheSize));
+      }
+      if (FLAG_IS_DEFAULT(InitialCodeCacheSize)) {
+        FLAG_SET_DEFAULT(InitialCodeCacheSize, MAX2(16*M, InitialCodeCacheSize));
+      }
+      if (FLAG_IS_DEFAULT(MetaspaceSize)) {
+        FLAG_SET_DEFAULT(MetaspaceSize, MIN2(MAX2(12*M, MetaspaceSize), MaxMetaspaceSize));
+      }
+      if (FLAG_IS_DEFAULT(NewSizeThreadIncrease)) {
+        FLAG_SET_DEFAULT(NewSizeThreadIncrease, MAX2(4*K, NewSizeThreadIncrease));
+      }
+    } // !UseJVMCINativeLibrary
   } // UseJVMCICompiler
 }
 #endif // INCLUDE_JVMCI
@@ -401,7 +404,6 @@
   JVMCIGlobals::check_jvmci_supported_gc();
 
   // Do JVMCI specific settings
-  JVMCIGlobals::init_java_mode_from_flags();
   set_jvmci_specific_flags();
 #endif
 
--- a/src/hotspot/share/compiler/disassembler.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/compiler/disassembler.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -672,7 +672,7 @@
   nm->method()->signature()->print_symbol_on(env.output());
 #if INCLUDE_JVMCI
   {
-    const char* jvmciName = nm->jvmci_nmethod_mirror_name();
+    const char* jvmciName = nm->jvmci_name();
     if (jvmciName != NULL) {
       env.output()->print(" (%s)", jvmciName);
     }
--- a/src/hotspot/share/jvmci/jvmci.hpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/jvmci/jvmci.hpp	Mon Mar 18 16:54:45 2019 -0700
@@ -53,7 +53,7 @@
 
   // Access to the HotSpotJVMCIRuntime used by Java code running on the
   // HotSpot heap. It will be the same as _compiler_runtime if
-  // JVMCIGlobals::java_mode() == JVMCIGlobals::HotSpot.
+  // UseJVMCINativeLibrary is false
   static JVMCIRuntime* _java_runtime;
 
  public:
--- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -400,11 +400,11 @@
       }
     } else if (jvmci_env()->isa_HotSpotObjectConstantImpl(value)) {
       if (type == T_OBJECT) {
-        oop obj = jvmci_env()->asConstant(value, JVMCI_CHECK_NULL);
+        Handle obj = jvmci_env()->asConstant(value, JVMCI_CHECK_NULL);
         if (obj == NULL) {
           JVMCI_ERROR_NULL("null value must be in NullConstant");
         }
-        return new ConstantOopWriteValue(JNIHandles::make_local(obj));
+        return new ConstantOopWriteValue(JNIHandles::make_local(obj()));
       } else {
         JVMCI_ERROR_NULL("unexpected object constant, expected %s", basictype_to_str(type));
       }
@@ -585,7 +585,16 @@
 #endif // INCLUDE_AOT
 
 // constructor used to create a method
-JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, JVMCIObject target, JVMCIObject compiled_code, CodeBlob*& cb, JVMCIObject installed_code, JVMCIObject speculation_log, JVMCI_TRAPS) {
+JVMCI::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler,
+    JVMCIObject target,
+    JVMCIObject compiled_code,
+    CodeBlob*& cb,
+    JVMCIObject installed_code,
+    FailedSpeculation** failed_speculations,
+    char* speculations,
+    int speculations_len,
+    JVMCI_TRAPS) {
+
   CodeBuffer buffer("JVMCI Compiler CodeBuffer");
   OopRecorder* recorder = new OopRecorder(&_arena, true);
   initialize_dependencies(compiled_code, recorder, JVMCI_CHECK_OK);
@@ -637,12 +646,13 @@
       JVMCI_THROW_MSG_(IllegalArgumentException, "InstalledCode object must be a HotSpotNmethod when installing a HotSpotCompiledNmethod", JVMCI::ok);
     }
 
-    JVMCIObject nmethod_mirror = installed_code;
+    JVMCIObject mirror = installed_code;
     nmethod* nm = NULL;
     result = runtime()->register_method(jvmci_env(), method, nm, entry_bci, &_offsets, _orig_pc_offset, &buffer,
                                         stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table,
                                         compiler, _debug_recorder, _dependencies, id,
-                                        has_unsafe_access, _has_wide_vector, compiled_code, nmethod_mirror, speculation_log);
+                                        has_unsafe_access, _has_wide_vector, compiled_code, mirror,
+                                        failed_speculations, speculations, speculations_len);
     cb = nm->as_codeblob_or_null();
     if (nm != NULL && compile_state == NULL) {
       DirectiveSet* directive = DirectivesStack::getMatchingDirective(method, compiler);
@@ -831,8 +841,8 @@
         *((void**) dest) = record_metadata_reference(_constants, dest, constant, JVMCI_CHECK_OK);
       }
     } else if (jvmci_env()->isa_HotSpotObjectConstantImpl(constant)) {
-      oop obj = jvmci_env()->asConstant(constant, JVMCI_CHECK_OK);
-      jobject value = JNIHandles::make_local(obj);
+      Handle obj = jvmci_env()->asConstant(constant, JVMCI_CHECK_OK);
+      jobject value = JNIHandles::make_local(obj());
       int oop_index = _oop_recorder->find_index(value);
 
       if (jvmci_env()->get_HotSpotObjectConstantImpl_compressed(constant)) {
@@ -945,13 +955,10 @@
 }
 
 void CodeInstaller::assumption_CallSiteTargetValue(JVMCIObject assumption, JVMCI_TRAPS) {
-  Thread* THREAD = Thread::current();
   JVMCIObject callSiteConstant = jvmci_env()->get_Assumptions_CallSiteTargetValue_callSite(assumption);
-  oop callSiteOop = jvmci_env()->asConstant(callSiteConstant, JVMCI_CHECK);
-  Handle callSite(THREAD, callSiteOop);
+  Handle callSite = jvmci_env()->asConstant(callSiteConstant, JVMCI_CHECK);
   JVMCIObject methodConstant = jvmci_env()->get_Assumptions_CallSiteTargetValue_methodHandle(assumption);
-  oop methodHandleOop = jvmci_env()->asConstant(methodConstant, JVMCI_CHECK);
-  Handle methodHandle(THREAD, methodHandleOop);
+  Handle methodHandle = jvmci_env()->asConstant(methodConstant, JVMCI_CHECK);
   _dependencies->assert_call_site_target_value(callSite(), methodHandle());
 }
 
--- a/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.hpp	Mon Mar 18 16:54:45 2019 -0700
@@ -219,8 +219,15 @@
 #if INCLUDE_AOT
   JVMCI::CodeInstallResult gather_metadata(JVMCIObject target, JVMCIObject compiled_code, CodeMetadata& metadata, JVMCI_TRAPS);
 #endif
-  JVMCI::CodeInstallResult install(JVMCICompiler* compiler, JVMCIObject target, JVMCIObject compiled_code,
-                                   CodeBlob*& cb, JVMCIObject installed_code, JVMCIObject speculation_log, JVMCI_TRAPS);
+  JVMCI::CodeInstallResult install(JVMCICompiler* compiler,
+                                   JVMCIObject target,
+                                   JVMCIObject compiled_code,
+                                   CodeBlob*& cb,
+                                   JVMCIObject installed_code,
+                                   FailedSpeculation** failed_speculations,
+                                   char* speculations,
+                                   int speculations_len,
+                                   JVMCI_TRAPS);
 
   JVMCIEnv* jvmci_env() { return _jvmci_env; }
   JVMCIRuntime* runtime() { return _jvmci_env->runtime(); }
--- a/src/hotspot/share/jvmci/jvmciCompiler.hpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/jvmci/jvmciCompiler.hpp	Mon Mar 18 16:54:45 2019 -0700
@@ -63,7 +63,7 @@
     return _instance;
   }
 
-  virtual const char* name() { return "JVMCI"; }
+  virtual const char* name() { return UseJVMCINativeLibrary ? "JVMCI-native" : "JVMCI"; }
 
   virtual bool supports_native()                 { return true; }
   virtual bool supports_osr   ()                 { return true; }
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -32,6 +32,7 @@
 #include "oops/cpCache.inline.hpp"
 #include "oops/generateOopMap.hpp"
 #include "oops/method.inline.hpp"
+#include "oops/methodData.hpp"
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/typeArrayOop.inline.hpp"
 #include "compiler/compileBroker.hpp"
@@ -307,7 +308,7 @@
   if (base_object.is_null()) {
     method = *((Method**)(offset));
   } else if (JVMCIENV->isa_HotSpotObjectConstantImpl(base_object)) {
-    oop obj = JVMCIENV->asConstant(base_object, JVMCI_CHECK_NULL);
+    Handle obj = JVMCIENV->asConstant(base_object, JVMCI_CHECK_NULL);
     if (obj->is_a(SystemDictionary::ResolvedMethodName_klass())) {
       method = (Method*) (intptr_t) obj->long_field(offset);
     } else {
@@ -351,7 +352,7 @@
   if (base_object.is_non_null() && offset == oopDesc::klass_offset_in_bytes()) {
     // klass = JVMCIENV->unhandle(base_object)->klass();
     if (JVMCIENV->isa_HotSpotObjectConstantImpl(base_object)) {
-      oop base_oop = JVMCIENV->asConstant(base_object, JVMCI_CHECK_NULL);
+      Handle base_oop = JVMCIENV->asConstant(base_object, JVMCI_CHECK_NULL);
       klass = base_oop->klass();
     } else {
       assert(false, "What types are we actually expecting here?");
@@ -365,9 +366,9 @@
       } else if (JVMCIENV->isa_HotSpotResolvedObjectTypeImpl(base_object)) {
         base_address = (intptr_t) JVMCIENV->asKlass(base_object);
       } else if (JVMCIENV->isa_HotSpotObjectConstantImpl(base_object)) {
-        oop base_oop = JVMCIENV->asConstant(base_object, JVMCI_CHECK_NULL);
+        Handle base_oop = JVMCIENV->asConstant(base_object, JVMCI_CHECK_NULL);
         if (base_oop->is_a(SystemDictionary::Class_klass())) {
-          base_address = (jlong) (address) base_oop;
+          base_address = (jlong) (address) base_oop();
         }
       }
       if (base_address == 0) {
@@ -730,7 +731,8 @@
   method->set_dont_inline(true);
 C2V_END
 
-C2V_VMENTRY(jint, installCode, (JNIEnv *env, jobject, jobject target, jobject compiled_code, jobject installed_code, jobject speculation_log))
+C2V_VMENTRY(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;
 
@@ -738,16 +740,27 @@
   JVMCIObject compiled_code_handle = JVMCIENV->wrap(compiled_code);
   CodeBlob* cb = NULL;
   JVMCIObject installed_code_handle = JVMCIENV->wrap(installed_code);
-  JVMCIObject speculation_log_handle = JVMCIENV->wrap(speculation_log);
+  JVMCIPrimitiveArray speculations_handle = JVMCIENV->wrap(speculations_obj);
+
+  int speculations_len = JVMCIENV->get_length(speculations_handle);
+  char* speculations = NEW_RESOURCE_ARRAY(char, speculations_len);
+  JVMCIENV->copy_bytes_to(speculations_handle, (jbyte*) speculations, 0, speculations_len);
 
   JVMCICompiler* compiler = JVMCICompiler::instance(true, CHECK_JNI_ERR);
 
   TraceTime install_time("installCode", JVMCICompiler::codeInstallTimer());
   bool is_immutable_PIC = JVMCIENV->get_HotSpotCompiledCode_isImmutablePIC(compiled_code_handle) > 0;
-  JVMCINMethodData::cleanup();
 
   CodeInstaller installer(JVMCIENV, is_immutable_PIC);
-  JVMCI::CodeInstallResult result = installer.install(compiler, target_handle, compiled_code_handle, cb, installed_code_handle, speculation_log_handle, JVMCI_CHECK_0);
+  JVMCI::CodeInstallResult result = installer.install(compiler,
+      target_handle,
+      compiled_code_handle,
+      cb,
+      installed_code_handle,
+      (FailedSpeculation**)(address) failed_speculations_address,
+      speculations,
+      speculations_len,
+      JVMCI_CHECK_0);
 
   if (PrintCodeCacheOnCompilation) {
     stringStream s;
@@ -789,7 +802,6 @@
   JVMCIObject metadata_handle = JVMCIENV->wrap(metadata);
 
   CodeMetadata code_metadata;
-  JVMCINMethodData::cleanup();
 
   CodeInstaller installer(JVMCIENV, true /* immutable PIC compilation */);
   JVMCI::CodeInstallResult result = installer.gather_metadata(target_handle, compiled_code_handle, code_metadata, JVMCI_CHECK_0);
@@ -907,12 +919,7 @@
 C2V_END
 
 C2V_VMENTRY(jobject, executeHotSpotNmethod, (JNIEnv* env, jobject, jobject args, jobject hs_nmethod))
-  bool wrap_objects = false;
   if (env != JavaThread::current()->jni_environment()) {
-    wrap_objects = true;
-  }
-
-  if (wrap_objects) {
     // 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");
@@ -1631,8 +1638,7 @@
 C2V_END
 
 C2V_VMENTRY(void, compileToBytecode, (JNIEnv* env, jobject, jobject lambda_form_handle))
-  oop lambda_form_oop = JVMCIENV->asConstant(JVMCIENV->wrap(lambda_form_handle), JVMCI_CHECK);
-  Handle lambda_form(THREAD, lambda_form_oop);
+  Handle lambda_form = JVMCIENV->asConstant(JVMCIENV->wrap(lambda_form_handle), JVMCI_CHECK);
   if (lambda_form->is_a(SystemDictionary::LambdaForm_klass())) {
     TempNewSymbol compileToBytecode = SymbolTable::new_symbol("compileToBytecode", CHECK);
     JavaValue result(T_VOID);
@@ -1644,17 +1650,17 @@
 C2V_END
 
 C2V_VMENTRY(int, getIdentityHashCode, (JNIEnv* env, jobject, jobject object))
-  oop obj = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_0);
+  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))
-  oop str = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_0);
-  if (!java_lang_String::is_instance(str)) {
+  Handle str = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_0);
+  if (!java_lang_String::is_instance(str())) {
     return false;
   }
   int len;
-  jchar* name = java_lang_String::as_unicode_string(str, len, CHECK_0);
+  jchar* name = java_lang_String::as_unicode_string(str(), len, CHECK_0);
   return (StringTable::lookup(name, len) != NULL);
 C2V_END
 
@@ -1663,10 +1669,12 @@
   if (object == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
-  oop box = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_NULL);
-  BasicType type = java_lang_boxing_object::basic_type(box);
+  Handle box = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_NULL);
+  BasicType type = java_lang_boxing_object::basic_type(box());
   jvalue result;
-  java_lang_boxing_object::get_value(box, &result);
+  if (java_lang_boxing_object::get_value(box(), &result) == T_ILLEGAL) {
+    return NULL;
+  }
   JVMCIObject boxResult = JVMCIENV->create_box(type, &result, JVMCI_CHECK_NULL);
   return JVMCIENV->get_jobject(boxResult);
 C2V_END
@@ -1677,6 +1685,9 @@
   }
   JVMCIObject box = JVMCIENV->wrap(object);
   BasicType type = JVMCIENV->get_box_type(box);
+  if (type == T_ILLEGAL) {
+    return NULL;
+  }
   jvalue value = JVMCIENV->get_boxed_value(type, box);
   JavaValue box_result(T_OBJECT);
   JavaCallArguments jargs;
@@ -1794,17 +1805,16 @@
     JVMCI_THROW_MSG_0(InternalError, err_msg("Can't find field with displacement %d", displacement));
   }
   JVMCIObject base = JVMCIENV->wrap(object);
-  oop obj_oop;
+  Handle obj;
   if (JVMCIENV->isa_HotSpotObjectConstantImpl(base)) {
-    obj_oop = JVMCIENV->asConstant(base, JVMCI_CHECK_NULL);
+    obj = JVMCIENV->asConstant(base, JVMCI_CHECK_NULL);
   } else if (JVMCIENV->isa_HotSpotResolvedObjectTypeImpl(base)) {
     Klass* klass = JVMCIENV->asKlass(base);
-    obj_oop = klass->java_mirror();
+    obj = Handle(THREAD, klass->java_mirror());
   } else {
     JVMCI_THROW_MSG_NULL(IllegalArgumentException,
                          err_msg("Unexpected type: %s", JVMCIENV->klass_name(base)));
   }
-  Handle obj(THREAD, obj_oop);
   jlong value = 0;
   JVMCIObject kind;
   switch (constant_type) {
@@ -1843,8 +1853,7 @@
   if (object == NULL || holder == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
-  oop obj_oop = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_0);
-  Handle obj(THREAD, obj_oop);
+  Handle obj = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_0);
   Klass* klass = JVMCIENV->asKlass(JVMCIENV->wrap(holder));
   return obj->is_a(klass);
 C2V_END
@@ -1873,8 +1882,7 @@
   if (object == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
-  oop obj_oop = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_NULL);
-  Handle obj(THREAD, obj_oop);
+  Handle obj = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_NULL);
   if (java_lang_Class::is_instance(obj())) {
     if (java_lang_Class::is_primitive(obj())) {
       JVMCIObject type = JVMCIENV->get_jvmci_primitive_type(java_lang_Class::primitive_type(obj()));
@@ -1894,8 +1902,8 @@
   if (object == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
-  oop obj = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_NULL);
-  const char* str = java_lang_String::as_utf8_string(obj);
+  Handle obj = JVMCIENV->asConstant(JVMCIENV->wrap(object), JVMCI_CHECK_NULL);
+  const char* str = java_lang_String::as_utf8_string(obj());
   JVMCIObject result = JVMCIENV->create_string(str, JVMCI_CHECK_NULL);
   return JVMCIENV->get_jobject(result);
 C2V_END
@@ -1913,16 +1921,16 @@
     JVMCI_THROW_0(NullPointerException);
   }
   JVMCIObject base_object = JVMCIENV->wrap(object);
-  oop mirror;
+  Handle mirror;
   if (JVMCIENV->isa_HotSpotResolvedObjectTypeImpl(base_object)) {
-    mirror = JVMCIENV->asKlass(base_object)->java_mirror();
+    mirror = Handle(THREAD, JVMCIENV->asKlass(base_object)->java_mirror());
   } else if (JVMCIENV->isa_HotSpotResolvedPrimitiveType(base_object)) {
     mirror = JVMCIENV->asConstant(JVMCIENV->get_HotSpotResolvedPrimitiveType_mirror(base_object), JVMCI_CHECK_NULL);
   } else {
     JVMCI_THROW_MSG_NULL(IllegalArgumentException,
                          err_msg("Unexpected type: %s", JVMCIENV->klass_name(base_object)));
  }
-  JVMCIObject result = JVMCIENV->get_object_constant(mirror);
+  JVMCIObject result = JVMCIENV->get_object_constant(mirror());
   return JVMCIENV->get_jobject(result);
 C2V_END
 
@@ -1931,9 +1939,9 @@
   if (x == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
-  oop xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
+  Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
   if (xobj->klass()->is_array_klass()) {
-    return arrayOop(xobj)->length();
+    return arrayOop(xobj())->length();
   }
   return -1;
  C2V_END
@@ -1943,8 +1951,7 @@
   if (x == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
-  oop xobj_oop = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_NULL);
-  Handle xobj(THREAD, xobj_oop);
+  Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_NULL);
   if (xobj->klass()->is_array_klass()) {
     arrayOop array = arrayOop(xobj());
     BasicType element_type = ArrayKlass::cast(array->klass())->element_type();
@@ -2000,7 +2007,7 @@
   if (x == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
-  oop xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
+  Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
   return xobj->byte_field(displacement);
 }
 
@@ -2008,7 +2015,7 @@
   if (x == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
-  oop xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
+  Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
   return xobj->short_field(displacement);
 }
 
@@ -2016,7 +2023,7 @@
   if (x == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
-  oop xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
+  Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
   return xobj->int_field(displacement);
 }
 
@@ -2024,7 +2031,7 @@
   if (x == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
-  oop xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
+  Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
   return xobj->long_field(displacement);
 }
 
@@ -2032,7 +2039,7 @@
   if (x == NULL) {
     JVMCI_THROW_0(NullPointerException);
   }
-  oop xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
+  Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0);
   oop res = xobj->obj_field(displacement);
   JVMCIObject result = JVMCIENV->get_object_constant(res);
   return JVMCIENV->get_jobject(result);
@@ -2136,19 +2143,19 @@
     result = peerEnv->get_jvmci_primitive_type(type);
   } else if (thisEnv->isa_IndirectHotSpotObjectConstantImpl(obj) ||
              thisEnv->isa_DirectHotSpotObjectConstantImpl(obj)) {
-    oop constant = thisEnv->asConstant(obj, JVMCI_CHECK_0);
-    result = peerEnv->get_object_constant(constant);
+    Handle constant = thisEnv->asConstant(obj, JVMCI_CHECK_0);
+    result = peerEnv->get_object_constant(constant());
   } else if (thisEnv->isa_HotSpotNmethod(obj)) {
     nmethod* nm = thisEnv->asNmethod(obj);
     if (nm != NULL) {
       JVMCINMethodData* data = nm->jvmci_nmethod_data();
       if (data != NULL) {
-        // First check if an InstalledCode instance already exists in the appropriate runtime
-        JVMCIObject peer_installed_code = data->get_nmethod_mirror();
-        if (!peer_installed_code.is_null() && peer_installed_code.is_hotspot() != obj.is_hotspot()) {
-          nmethod* peer_nm = peerEnv->asNmethod(peer_installed_code);
-          if (peer_nm == nm) {
-            result = peer_installed_code;
+        if (peerEnv->is_hotspot()) {
+          // Only the mirror in the HotSpot heap is accessible
+          // through JVMCINMethodData
+          oop nmethod_mirror = data->get_nmethod_mirror(nm);
+          if (nmethod_mirror != NULL) {
+            result = HotSpotJVMCI::wrap(nmethod_mirror);
           }
         }
       }
@@ -2157,17 +2164,29 @@
       JVMCIObject methodObject = thisEnv->get_HotSpotNmethod_method(obj);
       methodHandle mh = thisEnv->asMethod(methodObject);
       jboolean isDefault = thisEnv->get_HotSpotNmethod_isDefault(obj);
+      jlong compileIdSnapshot = thisEnv->get_HotSpotNmethod_compileIdSnapshot(obj);
       JVMCIObject name_string = thisEnv->get_InstalledCode_name(obj);
       const char* cstring = name_string.is_null() ? NULL : thisEnv->as_utf8_string(name_string);
       // Create a new HotSpotNmethod instance in the peer runtime
-      result = peerEnv->new_HotSpotNmethod(mh(), cstring, isDefault, JVMCI_CHECK_0);
+      result = peerEnv->new_HotSpotNmethod(mh(), cstring, isDefault, compileIdSnapshot, JVMCI_CHECK_0);
       if (nm == NULL) {
         // nmethod must have been unloaded
       } else {
         // Link the new HotSpotNmethod to the nmethod
         peerEnv->initialize_installed_code(result, nm, JVMCI_CHECK_0);
-        JVMCINMethodData* data = nm->jvmci_nmethod_data();
-        data->add_nmethod_mirror(peerEnv, result, JVMCI_CHECK_0);
+        // Only HotSpotNmethod instances are tracked directly by the runtime.
+        // HotSpotNMethodHandle instances are updated cooperatively.
+        if (peerEnv->is_hotspot()) {
+          JVMCINMethodData* data = nm->jvmci_nmethod_data();
+          if (data == NULL) {
+            JVMCI_THROW_MSG_0(IllegalArgumentException, "Cannot set HotSpotNmethod mirror for default nmethod");
+          }
+          if (data->get_nmethod_mirror(nm) != NULL) {
+            JVMCI_THROW_MSG_0(IllegalArgumentException, "Cannot overwrite existing HotSpotNmethod mirror for nmethod");
+          }
+          oop nmethod_mirror = HotSpotJVMCI::resolve(result);
+          data->set_nmethod_mirror(nm, nmethod_mirror);
+        }
       }
     }
   } else {
@@ -2189,7 +2208,7 @@
   return result;
 }
 
-C2V_VMENTRY(void, updateHotSpotNmethodHandle, (JNIEnv* env, jobject, jobject code_handle))
+C2V_VMENTRY(void, updateHotSpotNmethod, (JNIEnv* env, jobject, jobject code_handle))
   JVMCIObject code = JVMCIENV->wrap(code_handle);
   // Execute this operation for the side effect of updating the InstalledCode state
   JVMCIENV->asNmethod(code);
@@ -2245,6 +2264,61 @@
   return JNIHandles::make_local(env, reflected);
 }
 
+C2V_VMENTRY(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()) {
+    result_length++;
+  }
+  int current_length = 0;
+  JVMCIObjectArray current_array = NULL;
+  if (current != NULL) {
+    current_array = JVMCIENV->wrap(current);
+    current_length = JVMCIENV->get_length(current_array);
+    if (current_length == result_length) {
+      // No new failures
+      return current;
+    }
+  }
+  JVMCIObjectArray result = JVMCIENV->new_byte_array_array(result_length, JVMCI_CHECK_NULL);
+  int result_index = 0;
+  for (FailedSpeculation* fs = head; result_index < result_length; fs = fs->next()) {
+    assert(fs != NULL, "npe");
+    JVMCIPrimitiveArray entry;
+    if (result_index < current_length) {
+      entry = (JVMCIPrimitiveArray) JVMCIENV->get_object_at(current_array, result_index);
+    } else {
+      entry = JVMCIENV->new_byteArray(fs->data_len(), JVMCI_CHECK_NULL);
+      JVMCIENV->copy_bytes_from((jbyte*) fs->data(), entry, 0, fs->data_len());
+    }
+    JVMCIENV->put_object_at(result, result_index++, entry);
+  }
+  return JVMCIENV->get_jobjectArray(result);
+}
+
+C2V_VMENTRY(jlong, getFailedSpeculationsAddress, (JNIEnv* env, jobject, jobject jvmci_method))
+  methodHandle method = JVMCIENV->asMethod(jvmci_method);
+  MethodData* method_data = method->method_data();
+  if (method_data == NULL) {
+    ClassLoaderData* loader_data = method->method_holder()->class_loader_data();
+    method_data = MethodData::allocate(loader_data, method, CHECK_0);
+    method->set_method_data(method_data);
+  }
+  return (jlong) method_data->get_failed_speculations_address();
+}
+
+C2V_VMENTRY(void, releaseFailedSpeculations, (JNIEnv* env, jobject, jlong failed_speculations_address))
+  FailedSpeculation::free_failed_speculations((FailedSpeculation**)(address) failed_speculations_address);
+}
+
+C2V_VMENTRY(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);
+  JVMCIENV->copy_bytes_to(speculation_handle, (jbyte*) speculation, 0, speculation_len);
+  return FailedSpeculation::add_failed_speculation(NULL, (FailedSpeculation**)(address) failed_speculations_address, (address) speculation, speculation_len);
+}
+
 #define CC (char*)  /*cast a literal from (const char*)*/
 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f))
 
@@ -2267,7 +2341,6 @@
 #define HS_RESOLVED_FIELD       "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaField;"
 #define HS_INSTALLED_CODE       "Ljdk/vm/ci/hotspot/HotSpotInstalledCode;"
 #define HS_NMETHOD              "Ljdk/vm/ci/hotspot/HotSpotNmethod;"
-#define HS_NMETHOD_HANDLE       "Ljdk/vm/ci/hotspot/HotSpotNmethodHandle;"
 #define HS_CONSTANT_POOL        "Ljdk/vm/ci/hotspot/HotSpotConstantPool;"
 #define HS_COMPILED_CODE        "Ljdk/vm/ci/hotspot/HotSpotCompiledCode;"
 #define HS_CONFIG               "Ljdk/vm/ci/hotspot/HotSpotVMConfig;"
@@ -2319,7 +2392,7 @@
   {CC "getConstantPool",                              CC "(" METASPACE_OBJECT ")" HS_CONSTANT_POOL,                                         FN_PTR(getConstantPool)},
   {CC "getResolvedJavaType0",                         CC "(Ljava/lang/Object;JZ)" HS_RESOLVED_KLASS,                                        FN_PTR(getResolvedJavaType0)},
   {CC "readConfiguration",                            CC "()[" OBJECT,                                                                      FN_PTR(readConfiguration)},
-  {CC "installCode",                                  CC "(" TARGET_DESCRIPTION HS_COMPILED_CODE INSTALLED_CODE HS_SPECULATION_LOG ")I",    FN_PTR(installCode)},
+  {CC "installCode",                                  CC "(" TARGET_DESCRIPTION HS_COMPILED_CODE INSTALLED_CODE "J[B)I",                    FN_PTR(installCode)},
   {CC "getMetadata",                                  CC "(" TARGET_DESCRIPTION HS_COMPILED_CODE HS_METADATA ")I",                          FN_PTR(getMetadata)},
   {CC "resetCompilationStatistics",                   CC "()V",                                                                             FN_PTR(resetCompilationStatistics)},
   {CC "disassembleCodeBlob",                          CC "(" INSTALLED_CODE ")" STRING,                                                     FN_PTR(disassembleCodeBlob)},
@@ -2378,10 +2451,14 @@
   {CC "registerNativeMethods",                        CC "(" CLASS ")[J",                                                                   FN_PTR(registerNativeMethods)},
   {CC "translate",                                    CC "(" OBJECT ")J",                                                                   FN_PTR(translate)},
   {CC "unhand",                                       CC "(J)" OBJECT,                                                                      FN_PTR(unhand)},
-  {CC "updateHotSpotNmethodHandle",                   CC "(" HS_NMETHOD_HANDLE ")V",                                                        FN_PTR(updateHotSpotNmethodHandle)},
+  {CC "updateHotSpotNmethod",                         CC "(" HS_NMETHOD ")V",                                                               FN_PTR(updateHotSpotNmethod)},
   {CC "getCode",                                      CC "(" HS_INSTALLED_CODE ")[B",                                                       FN_PTR(getCode)},
   {CC "asReflectionExecutable",                       CC "(" HS_RESOLVED_METHOD ")" REFLECTION_EXECUTABLE,                                  FN_PTR(asReflectionExecutable)},
   {CC "asReflectionField",                            CC "(" HS_RESOLVED_KLASS "I)" REFLECTION_FIELD,                                       FN_PTR(asReflectionField)},
+  {CC "getFailedSpeculations",                        CC "(J[[B)[[B",                                                                       FN_PTR(getFailedSpeculations)},
+  {CC "getFailedSpeculationsAddress",                 CC "(" HS_RESOLVED_METHOD ")J",                                                       FN_PTR(getFailedSpeculationsAddress)},
+  {CC "releaseFailedSpeculations",                    CC "(J)V",                                                                            FN_PTR(releaseFailedSpeculations)},
+  {CC "addFailedSpeculation",                         CC "(J[B)Z",                                                                          FN_PTR(addFailedSpeculation)},
 };
 
 int CompilerToVM::methods_count() {
--- a/src/hotspot/share/jvmci/jvmciEnv.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/jvmci/jvmciEnv.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -92,58 +92,69 @@
 void* JVMCIEnv::_shared_library_handle = NULL;
 char* JVMCIEnv::_shared_library_path = NULL;
 
-static void init_shared_library_options(JavaVMInitArgs& vm_args) {
-  int n_options = 0;
-  int args_len = 0;
-  const size_t len = JVMCILibArgs != NULL ? strlen(JVMCILibArgs) : 0;
-  char sep = JVMCILibArgsSep[0];
-  const char* p = JVMCILibArgs;
-  const char* end = JVMCILibArgs + len;
-  while (p < end) {
-    if (*p != sep) {
-      args_len++;
-      if (p == JVMCILibArgs || *(p - 1) == sep) {
-        n_options++;
-      }
+void JVMCIEnv::copy_saved_properties() {
+  assert(!is_hotspot(), "can only copy saved properties from HotSpot to native image");
+
+  JavaThread* THREAD = JavaThread::current();
+
+  Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::jdk_vm_ci_services_Services(), Handle(), Handle(), true, THREAD);
+  if (HAS_PENDING_EXCEPTION) {
+    JVMCIRuntime::exit_on_pending_exception(NULL, "Error initializing jdk.vm.ci.services.Services");
+  }
+  InstanceKlass* ik = InstanceKlass::cast(k);
+  if (ik->should_be_initialized()) {
+    ik->initialize(THREAD);
+    if (HAS_PENDING_EXCEPTION) {
+      JVMCIRuntime::exit_on_pending_exception(NULL, "Error initializing jdk.vm.ci.services.Services");
     }
-    p++;
   }
 
-  JavaVMOption* options = NEW_RESOURCE_ARRAY(JavaVMOption, n_options);
-  int option_index = 0;
+  // Get the serialized saved properties from HotSpot
+  TempNewSymbol serializeSavedProperties = SymbolTable::new_symbol("serializeSavedProperties", CHECK_EXIT);
+  JavaValue result(T_OBJECT);
+  JavaCallArguments args;
+  JavaCalls::call_static(&result, ik, serializeSavedProperties, vmSymbols::serializePropertiesToByteArray_signature(), &args, THREAD);
+  if (HAS_PENDING_EXCEPTION) {
+    JVMCIRuntime::exit_on_pending_exception(NULL, "Error calling jdk.vm.ci.services.Services.serializeSavedProperties");
+  }
+  oop res = (oop) result.get_jobject();
+  assert(res->is_typeArray(), "must be");
+  assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "must be");
+  typeArrayOop ba = typeArrayOop(res);
+  int serialized_properties_len = ba->length();
 
-  if (args_len != 0) {
-    int i = 0;
-    char* args = NEW_RESOURCE_ARRAY(char, args_len);
-    char* a = args;
-    int args_index = 0;
-    p = JVMCILibArgs;
-    while (p < end) {
-      // Skip separator chars
-      while (*p == sep) {
-        p++;
-      }
+  // Copy serialized saved properties from HotSpot object into native buffer
+  jbyte* serialized_properties = NEW_RESOURCE_ARRAY(jbyte, serialized_properties_len);
+  memcpy(serialized_properties, ba->byte_at_addr(0), serialized_properties_len);
 
-      char* arg = a;
-      while (*p != sep && *p != '\0') {
-        *a++ = *p++;
-      }
-      p++;
-      if (arg != a) {
-        *a++ = '\0';
-        options[option_index++].optionString = arg;
-      }
-    }
+  // Copy native buffer into shared library object
+  JVMCIPrimitiveArray buf = new_byteArray(serialized_properties_len, this);
+  if (has_pending_exception()) {
+    describe_pending_exception(true);
+    fatal("Error in copy_saved_properties");
   }
-  assert(option_index == n_options, "must be");
-  vm_args.options = options;
-  vm_args.nOptions = n_options;
+  copy_bytes_from(serialized_properties, buf, 0, serialized_properties_len);
+  if (has_pending_exception()) {
+    describe_pending_exception(true);
+    fatal("Error in copy_saved_properties");
+  }
+
+  // Initialize saved properties in shared library
+  jclass servicesClass = JNIJVMCI::Services::clazz();
+  jmethodID initializeSavedProperties = JNIJVMCI::Services::initializeSavedProperties_method();
+  JNIAccessMark jni(this);
+  jni()->CallStaticVoidMethod(servicesClass, initializeSavedProperties, buf.as_jobject());
+  if (jni()->ExceptionCheck()) {
+    jni()->ExceptionDescribe();
+    fatal("Error calling jdk.vm.ci.services.Services.initializeSavedProperties");
+  }
 }
 
 JNIEnv* JVMCIEnv::attach_shared_library() {
   if (_shared_library_javavm == NULL) {
     MutexLocker locker(JVMCI_lock);
     if (_shared_library_javavm == NULL) {
+
       char path[JVM_MAXPATHLEN];
       char ebuf[1024];
       if (JVMCILibPath != NULL) {
@@ -175,7 +186,8 @@
       JavaVMInitArgs vm_args;
       vm_args.version = JNI_VERSION_1_2;
       vm_args.ignoreUnrecognized = JNI_TRUE;
-      init_shared_library_options(vm_args);
+      vm_args.options = NULL;
+      vm_args.nOptions = 0;
 
       JavaVM* the_javavm = NULL;
       int result = (*JNI_CreateJavaVM)(&the_javavm, (void**) &env, &vm_args);
@@ -200,9 +212,9 @@
 void JVMCIEnv::init_env_mode_runtime(JNIEnv* parent_env) {
   // By default there is only one runtime which is the compiler runtime.
   _runtime = JVMCI::compiler_runtime();
-  if (JVMCIGlobals::java_mode() == JVMCIGlobals::HotSpot) {
+  if (!UseJVMCINativeLibrary) {
     // In HotSpot mode, JNI isn't used at all.
-    _mode = JVMCIGlobals::HotSpot;
+    _is_hotspot = true;
     _env = NULL;
     return;
   }
@@ -214,14 +226,14 @@
     if (thread->jni_environment() == parent_env) {
       // Select the Java runtime
       _runtime = JVMCI::java_runtime();
-      _mode = JVMCIGlobals::HotSpot;
+      _is_hotspot = true;
       _env = NULL;
       return;
     }
   }
 
   // Running in JVMCI shared library mode so get a shared library JNIEnv
-  _mode = JVMCIGlobals::SharedLibrary;
+  _is_hotspot = false;
   _env = attach_shared_library();
   assert(parent_env == NULL || _env == parent_env, "must be");
 
@@ -263,7 +275,7 @@
   _line = line;
   if (is_hotspot) {
     _env = NULL;
-    _mode = JVMCIGlobals::HotSpot;
+    _is_hotspot = true;
     _runtime = JVMCI::java_runtime();
   } else {
     init_env_mode_runtime(NULL);
@@ -643,20 +655,33 @@
   }
 }
 
-JVMCIObject JVMCIEnv::new_HotSpotNmethod(methodHandle method, const char* name, jboolean isDefault, JVMCI_TRAPS) {
+JVMCIObject JVMCIEnv::new_HotSpotNmethod(methodHandle method, const char* name, jboolean isDefault, jlong compileId, JVMCI_TRAPS) {
   JavaThread* THREAD = JavaThread::current();
 
   JVMCIObject methodObject = get_jvmci_method(method(), JVMCI_CHECK_(JVMCIObject()));
 
   if (is_hotspot()) {
-    HotSpotJVMCI::HotSpotNmethod::klass()->initialize(CHECK_(JVMCIObject()));
-    oop obj = HotSpotJVMCI::HotSpotNmethod::klass()->allocate_instance(CHECK_(JVMCIObject()));
+    InstanceKlass* ik = InstanceKlass::cast(HotSpotJVMCI::HotSpotNmethod::klass());
+    if (ik->should_be_initialized()) {
+      ik->initialize(CHECK_(JVMCIObject()));
+    }
+    oop obj = ik->allocate_instance(CHECK_(JVMCIObject()));
+    Handle obj_h(THREAD, obj);
+    Handle nameStr = java_lang_String::create_from_str(name, CHECK_(JVMCIObject()));
 
-    Handle nameStr = java_lang_String::create_from_str(name, CHECK_(JVMCIObject()));
-    HotSpotJVMCI::InstalledCode::set_name(this, obj, nameStr());
-    HotSpotJVMCI::HotSpotNmethod::set_isDefault(this, obj, isDefault);
-    HotSpotJVMCI::HotSpotNmethod::set_method(this, obj, HotSpotJVMCI::resolve(methodObject));
-    return wrap(obj);
+    // Call constructor
+    JavaCallArguments jargs;
+    jargs.push_oop(obj_h);
+    jargs.push_oop(Handle(THREAD, HotSpotJVMCI::resolve(methodObject)));
+    jargs.push_oop(nameStr);
+    jargs.push_int(isDefault);
+    jargs.push_long(compileId);
+    JavaValue result(T_VOID);
+    JavaCalls::call_special(&result, ik,
+                            vmSymbols::object_initializer_name(),
+                            vmSymbols::method_string_bool_long_signature(),
+                            &jargs, CHECK_(JVMCIObject()));
+    return wrap(obj_h());
   } else {
     JNIAccessMark jni(this);
     jobject nameStr = name == NULL ? NULL : jni()->NewStringUTF(name);
@@ -664,8 +689,8 @@
       return JVMCIObject();
     }
 
-    jobject result = jni()->NewObject(JNIJVMCI::HotSpotNmethodHandle::clazz(),
-                                      JNIJVMCI::HotSpotNmethodHandle::constructor(),
+    jobject result = jni()->NewObject(JNIJVMCI::HotSpotNmethod::clazz(),
+                                      JNIJVMCI::HotSpotNmethod::constructor(),
                                       methodObject.as_jobject(), nameStr, isDefault);
     return wrap(result);
   }
@@ -901,6 +926,19 @@
   }
 }
 
+JVMCIObjectArray JVMCIEnv::new_byte_array_array(int length, JVMCI_TRAPS) {
+  if (is_hotspot()) {
+    JavaThread* THREAD = JavaThread::current();
+    Klass* byteArrayArrayKlass = TypeArrayKlass::cast(Universe::byteArrayKlassObj  ())->array_klass(CHECK_(JVMCIObject()));
+    objArrayOop result = ObjArrayKlass::cast(byteArrayArrayKlass) ->allocate(length, CHECK_(JVMCIObject()));
+    return wrap(result);
+  } else {
+    JNIAccessMark jni(this);
+    jobjectArray result = jni()->NewObjectArray(length, JNIJVMCI::byte_array(), NULL);
+    return wrap(result);
+  }
+}
+
 JVMCIPrimitiveArray JVMCIEnv::new_intArray(int length, JVMCI_TRAPS) {
   if (is_hotspot()) {
     JavaThread* THREAD = JavaThread::current();
@@ -1029,21 +1067,23 @@
 }
 
 
-oop JVMCIEnv::asConstant(JVMCIObject constant, JVMCI_TRAPS) {
+Handle JVMCIEnv::asConstant(JVMCIObject constant, JVMCI_TRAPS) {
   if (constant.is_null()) {
-    return NULL;
+    return Handle();
   }
+  JavaThread* THREAD = JavaThread::current();
   if (is_hotspot()) {
     assert(HotSpotJVMCI::DirectHotSpotObjectConstantImpl::is_instance(this, constant), "wrong type");
-    return HotSpotJVMCI::DirectHotSpotObjectConstantImpl::object(this, HotSpotJVMCI::resolve(constant));
+    oop obj = HotSpotJVMCI::DirectHotSpotObjectConstantImpl::object(this, HotSpotJVMCI::resolve(constant));
+    return Handle(THREAD, obj);
   } else {
     assert(isa_IndirectHotSpotObjectConstantImpl(constant), "wrong type");
     jlong object_handle = get_IndirectHotSpotObjectConstantImpl_objectHandle(constant);
     oop result = resolve_handle(object_handle);
     if (result == NULL) {
-      JVMCI_THROW_MSG_NULL(InternalError, "Constant was unexpectedly NULL");
+      JVMCI_THROW_MSG_(InternalError, "Constant was unexpectedly NULL", Handle());
     }
-    return result;
+    return Handle(THREAD, result);
   }
 }
 
@@ -1131,9 +1171,6 @@
     if (nm->is_in_use()) {
       set_InstalledCode_entryPoint(installed_code, (jlong) nm->verified_entry_point());
     }
-    if (isa_HotSpotNmethodHandle(installed_code)) {
-      set_HotSpotNmethodHandle_compileId(installed_code, nm->compile_id());
-    }
   } else {
     set_InstalledCode_entryPoint(installed_code, (jlong) cb->code_begin());
   }
@@ -1144,20 +1181,20 @@
 }
 
 
-void JVMCIEnv::invalidate_nmethod_mirror(JVMCIObject nmethod_mirror, JVMCI_TRAPS) {
-  if (nmethod_mirror.is_null()) {
+void JVMCIEnv::invalidate_nmethod_mirror(JVMCIObject mirror, JVMCI_TRAPS) {
+  if (mirror.is_null()) {
     JVMCI_THROW(NullPointerException);
   }
 
-  jlong nativeMethod = get_InstalledCode_address(nmethod_mirror);
-  nmethod* nm = (nmethod*)nativeMethod;
+  jlong nativeMethod = get_InstalledCode_address(mirror);
+  nmethod* nm = JVMCIENV->asNmethod(mirror);
   if (nm == NULL) {
     // Nothing to do
     return;
   }
 
   Thread* THREAD = Thread::current();
-  if (!nmethod_mirror.is_hotspot() && !THREAD->is_Java_thread()) {
+  if (!mirror.is_hotspot() && !THREAD->is_Java_thread()) {
     // Calling back into native might cause the execution to block, so only allow this when calling
     // from a JavaThread, which is the normal case anyway.
     JVMCI_THROW_MSG(IllegalArgumentException,
@@ -1175,7 +1212,7 @@
 
   // A HotSpotNmethod instance can only reference a single nmethod
   // during its lifetime so simply clear it here.
-  set_InstalledCode_address(nmethod_mirror, 0);
+  set_InstalledCode_address(mirror, 0);
 }
 
 Klass* JVMCIEnv::asKlass(JVMCIObject obj) {
@@ -1198,33 +1235,35 @@
   if (code == NULL) {
     return NULL;
   }
-  if (isa_HotSpotNmethodHandle(obj)) {
-    // The state of HotSpotNMethodHandles are updated cooperatively so
-    // safely find the original nmethod* and then update the fields
-    // based on its state.
-    CodeBlob* cb = CodeCache::find_blob_unsafe(code);
-    if (cb == (CodeBlob*) code) {
-      // Found a live CodeBlob with the same address, make sure it's the same nmethod
-      nmethod* nm = cb->as_nmethod_or_null();
-      long compile_id = get_HotSpotNmethodHandle_compileId(obj);
-      if (nm != NULL && nm->compile_id() == compile_id) {
-        if (!nm->is_alive()) {
-          // Break the link to the nmethod so that the instance is no
-          // longer alive.
-          set_InstalledCode_address(obj, 0);
-          set_InstalledCode_entryPoint(obj, 0);
-        } else if (nm->is_not_entrant()) {
-          // Zero the entry point so that it appears invalid but keep
-          // the address so that it still is alive.
-          set_InstalledCode_entryPoint(obj, 0);
+  if (isa_HotSpotNmethod(obj)) {
+    jlong compile_id_snapshot = get_HotSpotNmethod_compileIdSnapshot(obj);
+    if (compile_id_snapshot != 0L) {
+      // A HotSpotNMethod not in an nmethod's oops table so look up
+      // the nmethod and then update the fields based on its state.
+      CodeBlob* cb = CodeCache::find_blob_unsafe(code);
+      if (cb == (CodeBlob*) code) {
+        // Found a live CodeBlob with the same address, make sure it's the same nmethod
+        nmethod* nm = cb->as_nmethod_or_null();
+        if (nm != NULL && nm->compile_id() == compile_id_snapshot) {
+          if (!nm->is_alive()) {
+            // Break the links from the mirror to the nmethod
+            set_InstalledCode_address(obj, 0);
+            set_InstalledCode_entryPoint(obj, 0);
+          } else if (nm->is_not_entrant()) {
+            // Zero the entry point so that the nmethod
+            // cannot be invoked by the mirror but can
+            // still be deoptimized.
+            set_InstalledCode_entryPoint(obj, 0);
+          }
+          return cb;
         }
-        return cb;
       }
+      // Clear the InstalledCode fields of this HotSpotNmethod
+      // that no longer refers to an nmethod in the code cache.
+      set_InstalledCode_address(obj, 0);
+      set_InstalledCode_entryPoint(obj, 0);
+      return NULL;
     }
-    // Clear the InstalledCode fields of this HotSpotNmethodHandle
-    set_InstalledCode_address(obj, 0);
-    set_InstalledCode_entryPoint(obj, 0);
-    return NULL;
   }
   return (CodeBlob*) code;
 }
--- a/src/hotspot/share/jvmci/jvmciEnv.hpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/jvmci/jvmciEnv.hpp	Mon Mar 18 16:54:45 2019 -0700
@@ -32,6 +32,7 @@
 #include "compiler/oopMap.hpp"
 #include "jvmci/jvmciJavaClasses.hpp"
 #include "jvmci/jvmciExceptions.hpp"
+#include "oops/typeArrayOop.inline.hpp"
 #include "runtime/interfaceSupport.inline.hpp"
 #include "runtime/thread.hpp"
 #include "memory/oopFactory.hpp"
@@ -142,7 +143,7 @@
 
   JNIEnv*                _env;     // JNI env for calling into shared library
   JVMCIRuntime*          _runtime; // Access to a HotSpotJVMCIRuntime
-  JVMCIGlobals::JavaMode _mode;    // Which heap is the HotSpotJVMCIRuntime in
+  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
@@ -194,6 +195,10 @@
     return _runtime;
   }
 
+  // Initializes Services.savedProperties in the shared library by copying
+  // the values from the same field in the HotSpot heap.
+  void copy_saved_properties();
+
   jboolean has_pending_exception() {
     if (!is_hotspot()) {
       JNIAccessMark jni(this);
@@ -204,7 +209,15 @@
     }
   }
 
-  jboolean clear_pending_exception();
+  void clear_pending_exception() {
+    if (!is_hotspot()) {
+      JNIAccessMark jni(this);
+      jni()->ExceptionClear();
+    } else {
+      Thread* THREAD = Thread::current();
+      CLEAR_PENDING_EXCEPTION;
+    }
+  }
 
   // Prints an exception and stack trace of a pending exception.
   void describe_pending_exception(bool clear);
@@ -347,10 +360,14 @@
     }
   }
 
+  // Get the primitive value from a Java boxing object.  It's hard error to
+  // pass a non-primitive BasicType.
   jvalue get_boxed_value(BasicType type, JVMCIObject object) {
     jvalue result;
     if (is_hotspot()) {
-      java_lang_boxing_object::get_value(HotSpotJVMCI::resolve(object), &result);
+      if (java_lang_boxing_object::get_value(HotSpotJVMCI::resolve(object), &result) == T_ILLEGAL) {
+        ShouldNotReachHere();
+      }
     } else {
       JNIAccessMark jni(this);
       jfieldID field = JNIJVMCI::box_field(type);
@@ -370,6 +387,7 @@
     return result;
   }
 
+  // Return the BasicType of the object if it's a boxing object, otherwise return T_ILLEGAL.
   BasicType get_box_type(JVMCIObject object) {
     if (is_hotspot()) {
       return java_lang_boxing_object::basic_type(HotSpotJVMCI::resolve(object));
@@ -384,12 +402,25 @@
       if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_LONG))) return T_LONG;
       if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_FLOAT))) return T_FLOAT;
       if (jni()->IsSameObject(clazz, JNIJVMCI::box_class(T_DOUBLE))) return T_DOUBLE;
-      ShouldNotReachHere();
-      return T_CONFLICT;
+      return T_ILLEGAL;
     }
   }
 
+  // Create a boxing object of the appropriate primitive type.
   JVMCIObject create_box(BasicType type, jvalue* value, JVMCI_TRAPS) {
+    switch (type) {
+      case T_BOOLEAN:
+      case T_BYTE:
+      case T_CHAR:
+      case T_SHORT:
+      case T_INT:
+      case T_LONG:
+      case T_FLOAT:
+      case T_DOUBLE:
+        break;
+      default:
+        JVMCI_THROW_MSG_(IllegalArgumentException, "Only boxes for primitive values can be created", JVMCIObject());
+    }
     if (is_hotspot()) {
       JavaThread* THREAD = JavaThread::current();
       oop box = java_lang_boxing_object::create(type, value, CHECK_(JVMCIObject()));
@@ -446,7 +477,7 @@
   JVMCIObjectArray    wrap(jobjectArray obj)  { return (JVMCIObjectArray)    wrap((jobject) obj); }
   JVMCIPrimitiveArray wrap(jintArray obj)     { return (JVMCIPrimitiveArray) wrap((jobject) obj); }
   JVMCIPrimitiveArray wrap(jbooleanArray obj) { return (JVMCIPrimitiveArray) wrap((jobject) obj); }
-  JVMCIPrimitiveArray wrap(jbyteArray obj) { return (JVMCIPrimitiveArray) wrap((jobject) obj); }
+  JVMCIPrimitiveArray wrap(jbyteArray obj)    { return (JVMCIPrimitiveArray) wrap((jobject) obj); }
   JVMCIPrimitiveArray wrap(jlongArray obj)    { return (JVMCIPrimitiveArray) wrap((jobject) obj); }
 
  private:
@@ -554,7 +585,7 @@
   JVMCIObject get_jvmci_constant_pool(constantPoolHandle cp, JVMCI_TRAPS);
   JVMCIObject get_jvmci_primitive_type(BasicType type);
 
-  oop asConstant(JVMCIObject object, JVMCI_TRAPS);
+  Handle asConstant(JVMCIObject object, JVMCI_TRAPS);
   JVMCIObject get_object_constant(oop objOop, bool compressed = false, bool dont_register = false);
 
   JVMCIPrimitiveArray new_booleanArray(int length, JVMCI_TRAPS);
@@ -562,8 +593,10 @@
   JVMCIPrimitiveArray new_intArray(int length, JVMCI_TRAPS);
   JVMCIPrimitiveArray new_longArray(int length, JVMCI_TRAPS);
 
+  JVMCIObjectArray new_byte_array_array(int length, JVMCI_TRAPS);
+
   JVMCIObject new_StackTraceElement(methodHandle method, int bci, JVMCI_TRAPS);
-  JVMCIObject new_HotSpotNmethod(methodHandle method, const char* name, jboolean isDefault, JVMCI_TRAPS);
+  JVMCIObject new_HotSpotNmethod(methodHandle method, const char* name, jboolean isDefault, jlong compileId, JVMCI_TRAPS);
   JVMCIObject new_VMField(JVMCIObject name, JVMCIObject type, jlong offset, jlong address, JVMCIObject value, JVMCI_TRAPS);
   JVMCIObject new_VMFlag(JVMCIObject name, JVMCIObject type, JVMCIObject value, JVMCI_TRAPS);
   JVMCIObject new_VMIntrinsicMethod(JVMCIObject declaringClass, JVMCIObject name, JVMCIObject descriptor, int id, JVMCI_TRAPS);
@@ -581,9 +614,9 @@
   void destroy_global(JVMCIObject object);
   void destroy_weak(JVMCIObject object);
 
-  // Deoptimizes the nmethod (if any) in the address field of a given
-  // HotSpotNmethod object. The address field is also zeroed.
-  void invalidate_nmethod_mirror(JVMCIObject nmethod_mirror, JVMCI_TRAPS);
+  // Deoptimizes the nmethod (if any) in the HotSpotNmethod.address
+  // field of mirror. The field is subsequently zeroed.
+  void invalidate_nmethod_mirror(JVMCIObject mirror, JVMCI_TRAPS);
 
   void initialize_installed_code(JVMCIObject installed_code, CodeBlob* cb, JVMCI_TRAPS);
 
@@ -597,9 +630,7 @@
 
   // Determines if this is for the JVMCI runtime in the HotSpot
   // heap (true) or the shared library heap (false).
-  bool is_hotspot() { return _mode == JVMCIGlobals::HotSpot; }
-
-  JVMCIGlobals::JavaMode mode()              { return _mode; }
+  bool is_hotspot() { return _is_hotspot; }
 
   JVMCICompileState* compile_state() { return _compile_state; }
   void set_compile_state(JVMCICompileState* compile_state) {
--- a/src/hotspot/share/jvmci/jvmciJavaClasses.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/jvmci/jvmciJavaClasses.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -23,6 +23,7 @@
 
 #include "precompiled.hpp"
 #include "classfile/symbolTable.hpp"
+#include "interpreter/linkResolver.hpp"
 #include "jvmci/jvmciEnv.hpp"
 #include "jvmci/jvmciJavaClasses.hpp"
 #include "jvmci/jvmciRuntime.hpp"
@@ -30,19 +31,7 @@
 #include "oops/oop.inline.hpp"
 #include "runtime/jniHandles.inline.hpp"
 #include "runtime/fieldDescriptor.inline.hpp"
-/*
-#include "classfile/systemDictionary.hpp"
-#include "oops/instanceMirrorKlass.hpp"
-#include "utilities/exceptions.hpp"
-#include "jvmci/jvmciEnv.hpp"
-#include "jvmci/jvmciJavaClasses.hpp"
-#include "jvmci/jvmciRuntime.hpp"
-#include "compiler/compileBroker.hpp"
-#include "runtime/jniHandles.hpp"
-#include "runtime/javaCalls.hpp"
-#include "classfile/symbolTable.hpp"
-#include "memory/oopFactory.hpp"
-*/
+
 // ------------------------------------------------------------------
 
 /**
@@ -76,8 +65,27 @@
   }
 }
 
+#ifndef PRODUCT
+static void check_resolve_method(const char* call_type, Klass* resolved_klass, Symbol* method_name, Symbol* method_signature, TRAPS) {
+  methodHandle method;
+  LinkInfo link_info(resolved_klass, method_name, method_signature, NULL, LinkInfo::skip_access_check);
+  if (strcmp(call_type, "call_static") == 0) {
+    method = LinkResolver::resolve_static_call_or_null(link_info);
+  } else if (strcmp(call_type, "call_virtual") == 0) {
+    method = LinkResolver::resolve_virtual_call_or_null(resolved_klass, link_info);
+  } else if (strcmp(call_type, "call_special") == 0) {
+    method = LinkResolver::resolve_special_call_or_null(link_info);
+  } else {
+    fatal("Unknown or unsupported call type: %s", call_type);
+  }
+  if (method.is_null()) {
+    fatal("Could not resolve %s.%s%s", resolved_klass->external_name(), method_name->as_C_string(), method_signature->as_C_string());
+  }
+}
+#endif
 
 jclass JNIJVMCI::_box_classes[T_CONFLICT+1];
+jclass JNIJVMCI::_byte_array;
 jfieldID JNIJVMCI::_box_fields[T_CONFLICT+1];
 jmethodID JNIJVMCI::_box_constructors[T_CONFLICT+1];
 jmethodID JNIJVMCI::_Class_getName_method;
@@ -104,9 +112,17 @@
 #define STATIC_OBJECT_FIELD(className, name, signature) FIELD(className, name, signature, true)
 #define STATIC_INT_FIELD(className, name) FIELD(className, name, "I", true)
 #define STATIC_BOOLEAN_FIELD(className, name) FIELD(className, name, "Z", true)
+#ifdef PRODUCT
 #define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args)
 #define CONSTRUCTOR(className, signature)
-
+#else
+#define METHOD(jniCallType, jniGetMethod, hsCallType, returnType, className, methodName, signatureSymbolName, args) \
+  check_resolve_method(#hsCallType, k, vmSymbols::methodName##_name(), vmSymbols::signatureSymbolName(), CHECK);
+#define CONSTRUCTOR(className, signature) { \
+  TempNewSymbol sig = SymbolTable::new_symbol(signature, CHECK); \
+  check_resolve_method("call_special", k, vmSymbols::object_initializer_name(), sig, CHECK); \
+  }
+#endif
 /**
  * Computes and initializes the offsets used by HotSpotJVMCI.
  */
@@ -377,6 +393,16 @@
 
   BOX_CLASSES(DO_BOX_CLASS);
 
+  if (JVMCILibDumpJNIConfig == NULL) {
+    _byte_array = env->FindClass("[B");
+    JVMCI_EXCEPTION_CHECK(env, "FindClass([B)");
+    _byte_array = (jclass) env->NewGlobalRef(_byte_array);
+    assert(_byte_array != NULL, "uninitialized");
+  } else {
+    fileStream* st = JVMCIGlobals::get_jni_config_file();
+    st->print_cr("class [B");
+  }
+
 #define DUMP_ALL_NATIVE_METHODS(class_symbol) do {                                                                  \
   current_class_name = class_symbol->as_C_string();                                                                 \
   Klass* k = SystemDictionary::resolve_or_fail(class_symbol, true, CHECK_EXIT);                                     \
--- a/src/hotspot/share/jvmci/jvmciJavaClasses.hpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/jvmci/jvmciJavaClasses.hpp	Mon Mar 18 16:54:45 2019 -0700
@@ -39,8 +39,25 @@
  * Java code executing in the JVMCI shared library.
  */
 
-#define JVMCI_CLASSES_DO(start_class, end_class, char_field, int_field, boolean_field, long_field, float_field, object_field, \
-                         primarray_field, objectarray_field, static_object_field, static_objectarray_field, static_int_field, static_boolean_field, jvmci_method, jvmci_constructor) \
+#define JVMCI_CLASSES_DO(start_class, \
+                         end_class, \
+                         char_field, \
+                         int_field, \
+                         boolean_field, \
+                         long_field, \
+                         float_field, \
+                         object_field, \
+                         primarray_field, \
+                         objectarray_field, \
+                         static_object_field, \
+                         static_objectarray_field, \
+                         static_int_field, \
+                         static_boolean_field, \
+                         jvmci_method, \
+                         jvmci_constructor) \
+  start_class(Services, jdk_vm_ci_services_Services)                                                          \
+    jvmci_method(CallStaticVoidMethod, GetStaticMethodID, call_static, void, Services, initializeSavedProperties, byte_array_void_signature, (JVMCIObject serializedProperties)) \
+  end_class                                                                                                   \
   start_class(Architecture, jdk_vm_ci_code_Architecture)                                                      \
     object_field(Architecture, wordKind, "Ljdk/vm/ci/meta/PlatformKind;")                                     \
   end_class                                                                                                   \
@@ -53,7 +70,7 @@
   start_class(HotSpotResolvedPrimitiveType, jdk_vm_ci_hotspot_HotSpotResolvedPrimitiveType)                   \
     object_field(HotSpotResolvedPrimitiveType, mirror, "Ljdk/vm/ci/hotspot/HotSpotObjectConstantImpl;")       \
   object_field(HotSpotResolvedPrimitiveType, kind, "Ljdk/vm/ci/meta/JavaKind;")                               \
-    static_objectarray_field(HotSpotResolvedPrimitiveType, primitives, "[Ljdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType;")        \
+    static_objectarray_field(HotSpotResolvedPrimitiveType, primitives, "[Ljdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType;") \
   end_class                                                                                                   \
   start_class(HotSpotResolvedJavaFieldImpl, jdk_vm_ci_hotspot_HotSpotResolvedJavaFieldImpl)                   \
     object_field(HotSpotResolvedJavaFieldImpl, type, "Ljdk/vm/ci/meta/JavaType;")                             \
@@ -77,12 +94,9 @@
   end_class                                                                                                   \
   start_class(HotSpotNmethod, jdk_vm_ci_hotspot_HotSpotNmethod)                                               \
     boolean_field(HotSpotNmethod, isDefault)                                                                  \
+    long_field(HotSpotNmethod, compileIdSnapshot)                                                             \
     object_field(HotSpotNmethod, method, "Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl;")                 \
-    jvmci_constructor(HotSpotNmethod, "(Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl;Ljava/lang/String;Z)V")              \
-  end_class                                                                                                   \
-  start_class(HotSpotNmethodHandle, jdk_vm_ci_hotspot_HotSpotNmethodHandle)                                   \
-    long_field(HotSpotNmethodHandle, compileId)                                                               \
-    jvmci_constructor(HotSpotNmethodHandle, "(Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl;Ljava/lang/String;Z)V") \
+    jvmci_constructor(HotSpotNmethod, "(Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl;Ljava/lang/String;ZJ)V") \
   end_class                                                                                                   \
   start_class(HotSpotCompiledCode, jdk_vm_ci_hotspot_HotSpotCompiledCode)                                     \
     object_field(HotSpotCompiledCode, name, "Ljava/lang/String;")                                             \
@@ -302,9 +316,6 @@
     object_field(StackLockValue, slot, "Ljdk/vm/ci/meta/AllocatableValue;")                                   \
     boolean_field(StackLockValue, eliminated)                                                                 \
   end_class                                                                                                   \
-  start_class(HotSpotSpeculationLog, jdk_vm_ci_hotspot_HotSpotSpeculationLog)                                 \
-    long_field(HotSpotSpeculationLog, lastFailed)                                                             \
-  end_class                                                                                                   \
   start_class(HotSpotStackFrameReference, jdk_vm_ci_hotspot_HotSpotStackFrameReference)                       \
     object_field(HotSpotStackFrameReference, compilerToVM, "Ljdk/vm/ci/hotspot/CompilerToVM;")                \
     boolean_field(HotSpotStackFrameReference, objectsMaterialized)                                            \
@@ -329,8 +340,8 @@
   start_class(HotSpotJVMCIRuntime, jdk_vm_ci_hotspot_HotSpotJVMCIRuntime)                                     \
     int_field(HotSpotJVMCIRuntime, compilationLevelAdjustment)                                                \
     jvmci_method(CallNonvirtualObjectMethod, GetMethodID, call_special, JVMCIObject, HotSpotJVMCIRuntime, compileMethod, compileMethod_signature, (JVMCIObject runtime, JVMCIObject method, int entry_bci, jlong env, int id)) \
-    jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, void, HotSpotJVMCIRuntime, encodeThrowable, encodeThrowable_signature, (JVMCIObject throwable)) \
-    jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, void, HotSpotJVMCIRuntime, decodeThrowable, decodeThrowable_signature, (JVMCIObject encodedThrowable)) \
+    jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, encodeThrowable, encodeThrowable_signature, (JVMCIObject throwable)) \
+    jvmci_method(CallStaticObjectMethod, GetStaticMethodID, call_static, JVMCIObject, HotSpotJVMCIRuntime, decodeThrowable, decodeThrowable_signature, (JVMCIObject encodedThrowable)) \
     jvmci_method(CallNonvirtualIntMethod, GetMethodID, call_special, int, HotSpotJVMCIRuntime, adjustCompilationLevel, adjustCompilationLevel_signature, (JVMCIObject runtime, JVMCIObject declaringClass, JVMCIObject name, JVMCIObject signature, bool is_osr, int level)) \
     jvmci_method(CallNonvirtualVoidMethod, GetMethodID, call_special, void, HotSpotJVMCIRuntime, bootstrapFinished, void_method_signature, (JVMCIObject runtime, JVMCI_TRAPS)) \
     jvmci_method(CallNonvirtualVoidMethod, GetMethodID, call_special, void, HotSpotJVMCIRuntime, shutdown, void_method_signature, (JVMCIObject runtime)) \
@@ -561,7 +572,7 @@
   static typeArrayOop resolve(JVMCIPrimitiveArray obj) { return (typeArrayOop) JNIHandles::resolve(obj.as_jobject()); }
 
   static JVMCIObject wrap(jobject obj) { return JVMCIObject(obj, true); }
-  static JVMCIObject wrap(oop obj) { return JVMCIObject(JNIHandles::make_local(obj), true); }
+  static JVMCIObject wrap(oop obj) { assert(Thread::current()->is_Java_thread(), "must be"); return JVMCIObject(JNIHandles::make_local(obj), true); }
 
   static inline Method* asMethod(JVMCIEnv* env, oop jvmci_method) {
     return *(Method**) HotSpotResolvedJavaMethodImpl::metadataHandle(env, jvmci_method);
@@ -656,6 +667,7 @@
 class JNIJVMCI {
   friend class JVMCIEnv;
 
+  static jclass _byte_array;
   static jclass _box_classes[T_CONFLICT+1];
   static jfieldID _box_fields[T_CONFLICT+1];
   static jmethodID _box_constructors[T_CONFLICT+1];
@@ -669,6 +681,8 @@
  public:
   static jmethodID Class_getName_method() { return _Class_getName_method; }
 
+  static jclass    byte_array()           { assert(_byte_array != NULL, "uninit");      return _byte_array; }
+
   static jclass    box_class(BasicType type)       { assert(_box_classes[type]!= NULL, "uninit");      return _box_classes[type]; }
   static jfieldID  box_field(BasicType type)       { assert(_box_fields[type]!= NULL, "uninit");       return _box_fields[type]; }
   static jmethodID box_constructor(BasicType type) { assert(_box_constructors[type]!= NULL, "uninit"); return _box_constructors[type]; }
--- a/src/hotspot/share/jvmci/jvmciRuntime.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -963,199 +963,97 @@
   JVMCIENV->call_HotSpotJVMCIRuntime_getCompiler(jvmciRuntime, JVMCI_CHECK);
 }
 
-JVMCINMethodData* volatile JVMCINMethodData::_for_release = NULL;
-
-JVMCINMethodData::JVMCINMethodData(JVMCIEnv* jvmciEnv, JVMCIObject nmethod_mirror, JVMCIObject speculation_log, bool triggers_invalidation) {
-  _next = NULL;
-  _triggers_invalidation = triggers_invalidation;
-  _speculation_log = jvmciEnv->make_weak(speculation_log);
-  if (jvmciEnv->is_hotspot()) {
-    _nmethod_mirror = jvmciEnv->make_weak(nmethod_mirror);
+void JVMCINMethodData::initialize(
+  int nmethod_mirror_index,
+  const char* name,
+  FailedSpeculation** failed_speculations)
+{
+  _failed_speculations = failed_speculations;
+  _nmethod_mirror_index = nmethod_mirror_index;
+  if (name != NULL) {
+    _has_name = true;
+    char* dest = (char*) this->name();
+    strcpy(dest, name);
   } else {
-    _nmethod_mirror = JVMCIObject();
-  }
-  _nmethod_mirror_name = NULL;
-
-  if (jvmciEnv->isa_InstalledCode(nmethod_mirror)) {
-    JVMCIObject nmethod_mirror_name = jvmciEnv->get_InstalledCode_name(nmethod_mirror);
-    if (!nmethod_mirror_name.is_null()) {
-      const char* name = jvmciEnv->as_utf8_string(nmethod_mirror_name);
-      char* name_copy = NEW_C_HEAP_ARRAY(char, strlen(name) + 1, mtCompiler);
-      strcpy(name_copy, name);
-      _nmethod_mirror_name = name_copy;
-    }
+    _has_name = false;
   }
 }
 
-JVMCINMethodData::~JVMCINMethodData() {
-  clear_nmethod_mirror();
-  guarantee(_nmethod_mirror.is_null(), "must be clear now");
-  clear_speculation_log(true);
-  guarantee(_speculation_log.is_null(), "must be clear now");
-  if (_nmethod_mirror_name != NULL) {
-    FREE_C_HEAP_ARRAY(char, _nmethod_mirror_name);
-    _nmethod_mirror_name = NULL;
+void JVMCINMethodData::add_failed_speculation(nmethod* nm, jlong speculation) {
+  uint index = (speculation >> 32) & 0xFFFFFFFF;
+  int length = (int) speculation;
+  if (index + length > (uint) nm->speculations_size()) {
+    fatal(INTPTR_FORMAT "[index: %d, length: %d] out of bounds wrt encoded speculations of length %u", speculation, index, length, nm->speculations_size());
+  }
+  address data = nm->speculations_begin() + index;
+  FailedSpeculation::add_failed_speculation(nm, _failed_speculations, data, length);
+}
+
+oop JVMCINMethodData::get_nmethod_mirror(nmethod* nm) {
+  if (_nmethod_mirror_index == -1) {
+    return NULL;
+  }
+  return nm->oop_at(_nmethod_mirror_index);
+}
+
+void JVMCINMethodData::set_nmethod_mirror(nmethod* nm, oop new_mirror) {
+  assert(_nmethod_mirror_index != -1, "cannot set JVMCI mirror for nmethod");
+  oop* addr = nm->oop_addr_at(_nmethod_mirror_index);
+  assert(new_mirror != NULL, "use clear_nmethod_mirror to clear the mirror");
+  assert(*addr == NULL, "cannot overwrite non-null mirror");
+
+  // Patching in an oop so make sure nm is on the scavenge list.
+  if (ScavengeRootsInCode && Universe::heap()->is_scavengable(new_mirror)) {
+    MutexLockerEx ml_code (CodeCache_lock, Mutex::_no_safepoint_check_flag);
+    if (!nm->on_scavenge_root_list()) {
+      CodeCache::add_scavenge_root_nmethod(nm);
+    }
+
+    // Since we've patched some oops in the nmethod,
+    // (re)register it with the heap.
+    Universe::heap()->register_nmethod(nm);
+  }
+
+  *addr = new_mirror;
+}
+
+void JVMCINMethodData::clear_nmethod_mirror(nmethod* nm) {
+  if (_nmethod_mirror_index != -1) {
+    oop* addr = nm->oop_addr_at(_nmethod_mirror_index);
+    *addr = NULL;
   }
 }
 
-void JVMCINMethodData::release(JVMCINMethodData* data) {
-  if (data->_speculation_log.is_null() || data->_speculation_log.is_hotspot()) {
-    delete data;
-  } else {
-    // Queue the data for release.  Reuse the patching lock since we need a non-safepoint locking
-    // and the JVMCI_lock must permit safepoint.
-    MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag);
-    data->_next = _for_release;
-    _for_release = data;
-  }
-}
-
-void JVMCINMethodData::cleanup() {
-  if (_for_release == NULL) {
-    return;
-  }
-  JVMCINMethodData* current = NULL;
-  {
-    MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag);
-    current = _for_release;
-    _for_release = NULL;
-  }
-  while (current != NULL) {
-    JVMCINMethodData* next = current->_next;
-    delete current;
-    current = next;
-  }
-}
-
-JVMCIObject JVMCINMethodData::get_nmethod_mirror() {
-  return _nmethod_mirror;
-}
-
-void JVMCINMethodData::add_nmethod_mirror(JVMCIEnv* jvmciEnv, JVMCIObject nmethod_mirror, JVMCI_TRAPS) {
-  // Only HotSpotNmethod instances are tracking directly by the runtime.  HotSpotNMethodHandle
-  // instances are updated cooperatively.
-  if (!jvmciEnv->is_hotspot()) {
+void JVMCINMethodData::invalidate_nmethod_mirror(nmethod* nm) {
+  oop nmethod_mirror = get_nmethod_mirror(nm);
+  if (nmethod_mirror == NULL) {
     return;
   }
 
-  if (_nmethod_mirror.is_non_null()) {
-    JVMCI_THROW_MSG(IllegalArgumentException, "Cannot overwrite existing HotSpotNmethod object for nmethod");
-  }
-  _nmethod_mirror = jvmciEnv->make_weak(nmethod_mirror);
-}
-
-void JVMCINMethodData::update_nmethod_mirror_in_gc(nmethod* nm) {
-  if (_nmethod_mirror.is_null()) {
-    return;
-  }
-  oop mirror_obj = HotSpotJVMCI::resolve(_nmethod_mirror);
-  if (mirror_obj == NULL) {
-    clear_nmethod_mirror();
-  }
-  if (_triggers_invalidation) {
-    if (_nmethod_mirror.is_null()) {
-      // The references to the mirror have been dropped so invalidate
-      // the nmethod and allow the sweeper to reclaim it.
-      nm->make_not_entrant();
+  // Update the values in the mirror if it still refers to nm.
+  // We cannot use JVMCIObject to wrap the mirror as this is called
+  // during GC, forbidding the creation of JNIHandles.
+  JVMCIEnv* jvmciEnv = NULL;
+  nmethod* current = (nmethod*) HotSpotJVMCI::InstalledCode::address(jvmciEnv, nmethod_mirror);
+  if (nm == current) {
+    if (!nm->is_alive()) {
+      // Break the link from the mirror to nm such that
+      // future invocations via the mirror will result in
+      // an InvalidInstalledCodeException.
+      HotSpotJVMCI::InstalledCode::set_address(jvmciEnv, nmethod_mirror, 0);
+      HotSpotJVMCI::InstalledCode::set_entryPoint(jvmciEnv, nmethod_mirror, 0);
+    } else if (nm->is_not_entrant()) {
+      // Zero the entry point so any new invocation will fail but keep
+      // the address link around that so that existing activations can
+      // be deoptimized via the mirror (i.e. JVMCIEnv::invalidate_installed_code).
+      HotSpotJVMCI::InstalledCode::set_entryPoint(jvmciEnv, nmethod_mirror, 0);
     }
   }
 }
 
-void JVMCINMethodData::invalidate_mirror(nmethod* nm) {
-  if (_nmethod_mirror.is_null()) {
-    return;
-  }
-  assert(_nmethod_mirror.is_hotspot(), "only HotSpot reference is supported");
-  JVMCIEnv jvmciEnv(_nmethod_mirror, __FILE__, __LINE__);
-  if (!_nmethod_mirror.is_null()) {
-    // Check weak reference for null
-    if (jvmciEnv.equals(_nmethod_mirror, JVMCIObject())) {
-      // The referent is null so delete weak reference
-      jvmciEnv.destroy_weak(_nmethod_mirror);
-      _nmethod_mirror = JVMCIObject();
-      return;
-    }
-
-    // Update the values in the HotSpotNmethod object if it still refers to this nmethod
-    nmethod* current = (nmethod*) jvmciEnv.get_InstalledCode_address(_nmethod_mirror);
-    if (nm == current) {
-      if (!nm->is_alive()) {
-        // Break the link from HotSpotNmethod to nmethod such that
-        // future invocations via the HotSpotNmethod will result in
-        // an InvalidInstalledCodeException.
-        jvmciEnv.set_InstalledCode_address(_nmethod_mirror, 0);
-        jvmciEnv.set_InstalledCode_entryPoint(_nmethod_mirror, 0);
-      } else if (nm->is_not_entrant()) {
-        // Zero the entry point so any new invocation will fail but keep
-        // the address link around that so that existing activations can
-        // be invalidated (i.e. JVMCIEnv::invalidate_installed_code).
-        jvmciEnv.set_InstalledCode_entryPoint(_nmethod_mirror, 0);
-      }
-    }
-  }
-  if (!nm->is_alive()) {
-    // Clear these out after the nmethod is dead and all
-    // relevant fields in the HotSpotNmethod have been zeroed.
-    clear_nmethod_mirror();
-  }
-  if (!nm->is_alive()) {
-    clear_speculation_log();
-  }
-}
-
-void JVMCINMethodData::update_speculation(JavaThread* thread, nmethod* nm) {
-  long speculation = thread->pending_failed_speculation();
-  if (speculation != 0) {
-    if (!_speculation_log.is_null()) {
-      JVMCIEnv jvmciEnv(_speculation_log, __FILE__, __LINE__);
-      if (jvmciEnv.equals(_speculation_log, JVMCIObject())) {
-        // The weak reference has been cleared
-        jvmciEnv.destroy_weak(_speculation_log);
-        _speculation_log = JVMCIObject();
-        return;
-      }
-      if (TraceDeoptimization || TraceUncollectedSpeculations) {
-        if (jvmciEnv.get_HotSpotSpeculationLog_lastFailed(_speculation_log) != 0) {
-          tty->print_cr("A speculation that was not collected by the compiler is being overwritten");
-        }
-      }
-      if (TraceDeoptimization) {
-        tty->print_cr("Saving speculation to speculation log");
-      }
-      jvmciEnv.set_HotSpotSpeculationLog_lastFailed(_speculation_log, speculation);
-    } else {
-      if (TraceDeoptimization) {
-        tty->print_cr("Speculation present but no speculation log");
-      }
-    }
-    thread->set_pending_failed_speculation(0);
-  }
-}
-
-void JVMCINMethodData::clear_nmethod_mirror() {
-  if (!_nmethod_mirror.is_null()) {
-    JVMCIEnv jvmciEnv(_nmethod_mirror, __FILE__, __LINE__);
-    jvmciEnv.destroy_weak(_nmethod_mirror);
-    _nmethod_mirror = JVMCIObject();
-  }
-}
-
-void JVMCINMethodData::clear_speculation_log(bool force) {
-  if (!_speculation_log.is_null()) {
-    // Non HotSpot speculations have to be cleaned up more carefully so
-    // they shouldn't be done by default.
-    if (!force && !_speculation_log.is_hotspot()) {
-      return;
-    }
-    JVMCIEnv jvmciEnv(_speculation_log, __FILE__, __LINE__);
-    jvmciEnv.destroy_weak(_speculation_log);
-    _speculation_log = JVMCIObject();
-  }
-}
-
 void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(JVMCI_TRAPS) {
   if (!_HotSpotJVMCIRuntime_instance.is_null()) {
-    if (JVMCIENV->is_hotspot() && JVMCIGlobals::java_mode() == JVMCIGlobals::SharedLibrary) {
+    if (JVMCIENV->is_hotspot() && UseJVMCINativeLibrary) {
       JVMCI_THROW_MSG(InternalError, "JVMCI has already been enabled in the JVMCI shared library");
     }
   }
@@ -1197,7 +1095,7 @@
 void JVMCI::initialize_globals() {
   _object_handles = JNIHandleBlock::allocate_block();
   _metadata_handles = MetadataHandleBlock::allocate_block();
-  if (JVMCIGlobals::java_mode() == JVMCIGlobals::SharedLibrary) {
+  if (UseJVMCINativeLibrary) {
     // There are two runtimes.
     _compiler_runtime = new JVMCIRuntime();
     _java_runtime = new JVMCIRuntime();
@@ -1236,7 +1134,7 @@
     HandleMark hm;
     ResourceMark rm;
     JavaThread* THREAD = JavaThread::current();
-    if (JVMCIENV->mode() == JVMCIGlobals::HotSpot) {
+    if (JVMCIENV->is_hotspot()) {
       HotSpotJVMCI::compute_offsets(CHECK_EXIT);
     } else {
       JNIAccessMark jni(JVMCIENV);
@@ -1256,7 +1154,12 @@
     create_jvmci_primitive_type(T_FLOAT, JVMCI_CHECK_EXIT_((void)0));
     create_jvmci_primitive_type(T_DOUBLE, JVMCI_CHECK_EXIT_((void)0));
     create_jvmci_primitive_type(T_VOID, JVMCI_CHECK_EXIT_((void)0));
+
+    if (!JVMCIENV->is_hotspot()) {
+      JVMCIENV->copy_saved_properties();
+    }
   }
+
   _initialized = true;
   _being_initialized = false;
   JVMCI_lock->notify_all();
@@ -1292,7 +1195,6 @@
     initialize(JVMCI_CHECK);
     JVMCIENV->call_JVMCI_getRuntime(JVMCI_CHECK);
   }
-  assert(_HotSpotJVMCIRuntime_instance.is_non_null(), "what?");
 }
 
 JVMCIObject JVMCIRuntime::get_HotSpotJVMCIRuntime(JVMCI_TRAPS) {
@@ -1456,26 +1358,30 @@
   ResourceMark rm;
   HandleMark hm;
 
-#define CHECK_RETURN JVMCIENV); \
-  if (HAS_PENDING_EXCEPTION) { \
-    Handle exception(THREAD, PENDING_EXCEPTION); \
-    CLEAR_PENDING_EXCEPTION; \
-  \
-    if (exception->is_a(SystemDictionary::ThreadDeath_klass())) { \
-      /* In the special case of ThreadDeath, we need to reset the */ \
-      /* pending async exception so that it is propagated.         */ \
-      thread->set_pending_async_exception(exception()); \
-      return level; \
-    } \
-    tty->print("Uncaught exception while adjusting compilation level: "); \
-    java_lang_Throwable::print(exception(), tty); \
-    tty->cr(); \
-    java_lang_Throwable::print_stack_trace(exception, tty); \
-    if (HAS_PENDING_EXCEPTION) { \
-      CLEAR_PENDING_EXCEPTION; \
-    } \
-    return level; \
-  } \
+#define CHECK_RETURN JVMCIENV);                                         \
+  if (JVMCIENV->has_pending_exception()) {                              \
+    if (JVMCIENV->is_hotspot()) {                                       \
+      Handle exception(THREAD, PENDING_EXCEPTION);                      \
+      CLEAR_PENDING_EXCEPTION;                                          \
+                                                                        \
+      if (exception->is_a(SystemDictionary::ThreadDeath_klass())) {     \
+        /* In the special case of ThreadDeath, we need to reset the */  \
+        /* pending async exception so that it is propagated.         */ \
+        thread->set_pending_async_exception(exception());               \
+        return level;                                                   \
+      }                                                                 \
+      tty->print("Uncaught exception while adjusting compilation level: "); \
+      java_lang_Throwable::print(exception(), tty);                     \
+      tty->cr();                                                        \
+      java_lang_Throwable::print_stack_trace(exception, tty);           \
+      if (HAS_PENDING_EXCEPTION) {                                      \
+        CLEAR_PENDING_EXCEPTION;                                        \
+      }                                                                 \
+    } else {                                                            \
+      JVMCIENV->clear_pending_exception();                              \
+    }                                                                   \
+    return level;                                                       \
+  }                                                                     \
   (void)(0
 
 
@@ -1488,7 +1394,7 @@
     sig = JVMCIENV->create_string(method->signature(), CHECK_RETURN);
   }
 
-  int comp_level = JVMCIENV->call_HotSpotJVMCIRuntime_adjustCompilationLevel(receiver, method->method_holder(), name, sig, is_osr, level, JVMCI_CHECK_EXIT_(level));
+  int comp_level = JVMCIENV->call_HotSpotJVMCIRuntime_adjustCompilationLevel(receiver, method->method_holder(), name, sig, is_osr, level, CHECK_RETURN);
   if (comp_level < CompLevel_none || comp_level > CompLevel_full_optimization) {
     assert(false, "compilation level out of bounds");
     return level;
@@ -1543,15 +1449,6 @@
   vm_exit(-1);
 }
 
-Klass* JVMCIRuntime::resolve_or_null(Symbol* name, TRAPS) {
-  return SystemDictionary::resolve_or_null(name, CHECK_NULL);
-}
-
-Klass* JVMCIRuntime::resolve_or_fail(Symbol* name, TRAPS) {
-  return SystemDictionary::resolve_or_fail(name, true, CHECK_NULL);
-}
-
-
 // ------------------------------------------------------------------
 // Note: the logic of this method should mirror the logic of
 // constantPoolOopDesc::verify_constant_pool_resolve.
@@ -1935,8 +1832,19 @@
   }
 
   HandleMark hm;
-  JVMCIObject receiver = get_HotSpotJVMCIRuntime(JVMCI_CHECK_EXIT);
-  JVMCIObject jvmci_method = JVMCIENV->get_jvmci_method(method, JVMCI_CHECK);
+  JVMCIObject receiver = get_HotSpotJVMCIRuntime(JVMCIENV);
+  if (JVMCIENV->has_pending_exception()) {
+    JVMCIENV->describe_pending_exception(true);
+    compile_state->set_failure(false, "exception getting HotSpotJVMCIRuntime object");
+    return;
+  }
+  JVMCIObject jvmci_method = JVMCIENV->get_jvmci_method(method, JVMCIENV);
+  if (JVMCIENV->has_pending_exception()) {
+    JVMCIENV->describe_pending_exception(true);
+    compile_state->set_failure(false, "exception getting JVMCI wrapper method");
+    return;
+  }
+
   JVMCIObject result_object = JVMCIENV->call_HotSpotJVMCIRuntime_compileMethod(receiver, jvmci_method, entry_bci,
                                                                      (jlong) compile_state, compile_state->task()->compile_id());
   if (!JVMCIENV->has_pending_exception()) {
@@ -1992,17 +1900,27 @@
                                 bool has_wide_vector,
                                 JVMCIObject compiled_code,
                                 JVMCIObject nmethod_mirror,
-                                JVMCIObject speculation_log) {
+                                FailedSpeculation** failed_speculations,
+                                char* speculations,
+                                int speculations_len) {
   JVMCI_EXCEPTION_CONTEXT;
   nm = NULL;
   int comp_level = CompLevel_full_optimization;
   char* failure_detail = NULL;
 
+  bool install_default = JVMCIENV->get_HotSpotNmethod_isDefault(nmethod_mirror) != 0;
   assert(JVMCIENV->isa_HotSpotNmethod(nmethod_mirror), "must be");
-  bool install_default = JVMCIENV->get_HotSpotNmethod_isDefault(nmethod_mirror) != 0;
-  bool triggers_invalidation = !install_default;
-
-  JVMCINMethodData* data = new JVMCINMethodData(JVMCIENV, nmethod_mirror, speculation_log, triggers_invalidation);
+  JVMCIObject name = JVMCIENV->get_InstalledCode_name(nmethod_mirror);
+  const char* nmethod_mirror_name = name.is_null() ? NULL : JVMCIENV->as_utf8_string(name);
+  int nmethod_mirror_index;
+  if (!install_default) {
+    // Reserve or initialize mirror slot in the oops table.
+    OopRecorder* oop_recorder = debug_info->oop_recorder();
+    nmethod_mirror_index = oop_recorder->allocate_oop_index(nmethod_mirror.is_hotspot() ? nmethod_mirror.as_jobject() : NULL);
+  } else {
+    // A HotSpotNmethod mirror whose compileIdSnapshot is non-zero is not tracked by the nmethod
+    nmethod_mirror_index = -1;
+  }
 
   JVMCI::CodeInstallResult result;
   {
@@ -2053,10 +1971,11 @@
                                  frame_words, oop_map_set,
                                  handler_table, &implicit_tbl,
                                  compiler, comp_level,
-                                 data);
+                                 speculations, speculations_len,
+                                 nmethod_mirror_index, nmethod_mirror_name, failed_speculations);
+
 
       // Free codeBlobs
-      //code_buffer->free_blob();
       if (nm == NULL) {
         // The CodeCache is full.  Print out warning and disable compilation.
         {
@@ -2074,7 +1993,9 @@
           JVMCIENV->compile_state()->task()->set_code(nm);
         }
 
+        JVMCINMethodData* data = nm->jvmci_nmethod_data();
         if (install_default) {
+          assert(!nmethod_mirror.is_hotspot() || data->get_nmethod_mirror(nm) == NULL, "must be");
           if (entry_bci == InvocationEntryBci) {
             if (TieredCompilation) {
               // If there is an old version we're done with it
@@ -2110,6 +2031,8 @@
             }
             InstanceKlass::cast(method->method_holder())->add_osr_nmethod(nm);
           }
+        } else {
+          assert(!nmethod_mirror.is_hotspot() || data->get_nmethod_mirror(nm) == HotSpotJVMCI::resolve(nmethod_mirror), "must be");
         }
         nm->make_in_use();
       }
@@ -2117,11 +2040,6 @@
     }
   }
 
-  if (result != JVMCI::ok) {
-    delete data;
-    data = NULL;
-  }
-
   // String creation must be done outside lock
   if (failure_detail != NULL) {
     // A failure to allocate the string is silently ignored.
--- a/src/hotspot/share/jvmci/jvmciRuntime.hpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp	Mon Mar 18 16:54:45 2019 -0700
@@ -34,84 +34,56 @@
 class JVMCIEnv;
 class JVMCICompileState;
 
-// Encapsulates the JVMCI metadata associated with an nmethod.
-class JVMCINMethodData: public CHeapObj<mtCompiler> {
-  // Weak reference to the SpeculationLog mirror in either
-  // the HotSpot or JVMCI shared library heap.
-  JVMCIObject _speculation_log;
+// Encapsulates the JVMCI metadata for an nmethod.
+// JVMCINMethodData objects are inlined into nmethods
+// at nmethod::_jvmci_data_offset.
+class JVMCINMethodData {
+  // Index for the HotSpotNmethod mirror in the nmethod's oops table.
+  // This is -1 if there is no mirror in the oops table.
+  int _nmethod_mirror_index;
 
-  // Value of HotSpotNmethod.name converted to a C string.
-  const char* _nmethod_mirror_name;
+  // Is HotSpotNmethod.name non-null? If so, the value is
+  // embedded in the end of this object.
+  bool _has_name;
 
-  // Weak reference to the HotSpotNmethod mirror in the HotSpot heap.
-  JVMCIObject _nmethod_mirror;
+  // Address of the failed speculations list to which a speculation
+  // is appended when it causes a deoptimization.
+  FailedSpeculation** _failed_speculations;
 
-  // Determines whether the associated nmethod is invalidated when the
-  // referent in _nmethod_mirror is cleared.  This will be false if
-  // the referent is initialized to a HotSpotNmethod object whose
-  // isDefault field is true.  That is, a mirror other than a
-  // "default" HotSpotNmethod causes nmethod invalidation.  See
-  // HotSpotNmethod.isDefault for more detail.
-  bool _triggers_invalidation;
+public:
+  // Computes the size of a JVMCINMethodData object
+  static int compute_size(const char* nmethod_mirror_name) {
+    int size = sizeof(JVMCINMethodData);
+    if (nmethod_mirror_name != NULL) {
+      size += (int) strlen(nmethod_mirror_name) + 1;
+    }
+    return size;
+  }
 
-  // Used to maintain the linked list held by the _for_release field
-  JVMCINMethodData* _next;
+  void initialize(int nmethod_mirror_index,
+             const char* name,
+             FailedSpeculation** failed_speculations);
 
-  // Maintains a list of JVMCINMethodDatas that require cleanup on the
-  // next call to installCode. This field must be updated under
-  // the JVMCI_lock.
-  static JVMCINMethodData* volatile _for_release;
+  // Adds `speculation` to the failed speculations list.
+  void add_failed_speculation(nmethod* nm, jlong speculation);
 
- public:
-  JVMCINMethodData(JVMCIEnv* jvmciEnv, JVMCIObject nmethod_mirror, JVMCIObject speculation_log, bool triggers_invalidation);
+  // Gets the JVMCI name of the nmethod (which may be NULL).
+  const char* name() { return _has_name ? (char*)(((address) this) + sizeof(JVMCINMethodData)) : NULL; }
 
-  // Releases all resources held by this object.
-  ~JVMCINMethodData();
+  // Clears the HotSpotNmethod.address field in the  mirror. If nm
+  // is dead, the HotSpotNmethod.entryPoint field is also cleared.
+  void invalidate_nmethod_mirror(nmethod* nm);
 
-  // Release the data object or queue it for lazy cleanup.
-  // If the data object contains non-null references to objects
-  // in the shared library heap, cleanup is deferred since
-  // processing these references can block on the ThreadToNativeFromVM
-  // transition calling into the shared library.
-  static void release(JVMCINMethodData* data);
+  // Gets the mirror from nm's oops table.
+  oop get_nmethod_mirror(nmethod* nm);
 
-  // Release any instances which require lazy cleanup.
-  static void cleanup();
+  // Sets the mirror in nm's oops table.
+  void set_nmethod_mirror(nmethod* nm, oop mirror);
 
-  // Gets the value of HotSpotNmethod.name converted to a C string (which may be NULL).
-  const char* nmethod_mirror_name() { return _nmethod_mirror_name; }
-
-  // Clears the `address` field in the HotSpotNmethod mirror. If the nmethod
-  // is no longer alive, the `entryPoint` field is also cleared, the weak
-  // reference to the mirror is released (e.g., JNI DeleteWeakGlobalRef)
-  // and the speculation log is cleared.
-  void invalidate_mirror(nmethod* nm);
-
-  // Process the HotSpotNmethod mirror during the nmethod unloading
-  // phase of a HotSpot GC. If the weak reference to the mirror is
-  // null and _triggers_invalidation is true, then the nmethod is made non-entrant.
-  void update_nmethod_mirror_in_gc(nmethod* nm);
-
-  // Records the pending failed speculation (if any) in the
-  // speculation log (if it exists).
-  void update_speculation(JavaThread* thread, nmethod* nm);
-
-  // Gets the HotSpotNmethod mirror in the HotSpot heap
-  JVMCIObject get_nmethod_mirror();
-
-  // Adds a HotSpotNmethod mirror.
-  void add_nmethod_mirror(JVMCIEnv* jvmciEnv, JVMCIObject mirror, JVMCI_TRAPS);
-
-  // Deletes the weak reference (if any) to the HotSpotNmethod object
-  // associated with this nmethod.
-  void clear_nmethod_mirror();
-
-  // Deletes the weak reference (if any) to the SpeculationLog object
-  // associated with this nmethod.
-  void clear_speculation_log(bool force = false);
+  // Clears the mirror in nm's oops table.
+  void clear_nmethod_mirror(nmethod* nm);
 };
 
-
 // A top level class that represents an initialized JVMCI runtime.
 // There is one instance of this class per HotSpotJVMCIRuntime object.
 class JVMCIRuntime: public CHeapObj<mtCompiler> {
@@ -274,9 +246,11 @@
                        int                       compile_id,
                        bool                      has_unsafe_access,
                        bool                      has_wide_vector,
-                       JVMCIObject              compiled_code,
-                       JVMCIObject              nmethod_mirror,
-                       JVMCIObject              speculation_log);
+                       JVMCIObject               compiled_code,
+                       JVMCIObject               nmethod_mirror,
+                       FailedSpeculation**       failed_speculations,
+                       char*                     speculations,
+                       int                       speculations_len);
 
   /**
    * Exits the VM due to an unexpected exception.
@@ -321,16 +295,6 @@
   } \
   (void)(0
 
-  /**
-   * Same as SystemDictionary::resolve_or_null but uses the JVMCI loader.
-   */
-  static Klass* resolve_or_null(Symbol* name, TRAPS);
-
-  /**
-   * Same as SystemDictionary::resolve_or_fail but uses the JVMCI loader.
-   */
-  static Klass* resolve_or_fail(Symbol* name, TRAPS);
-
   static BasicType kindToBasicType(Handle kind, TRAPS);
 
   static void new_instance_common(JavaThread* thread, Klass* klass, bool null_on_fail);
--- a/src/hotspot/share/jvmci/jvmci_globals.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/jvmci/jvmci_globals.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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,7 +30,6 @@
 #include "utilities/ostream.hpp"
 #include "runtime/globals_extension.hpp"
 
-JVMCIGlobals::JavaMode JVMCIGlobals::_java_mode = HotSpot;
 fileStream* JVMCIGlobals::_jni_config_file = NULL;
 
 JVMCI_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \
@@ -83,6 +82,10 @@
       return false;
     }
     FLAG_SET_DEFAULT(EnableJVMCI, true);
+    if (BootstrapJVMCI && UseJVMCINativeLibrary) {
+      jio_fprintf(defaultStream::error_stream(), "-XX:+BootstrapJVMCI is not compatible with -XX:+UseJVMCINativeLibrary");
+      return false;
+    }
   }
 
   if (!EnableJVMCI) {
@@ -92,6 +95,7 @@
       FLAG_SET_DEFAULT(EagerJVMCI, false);
     }
   }
+  JVMCI_FLAG_CHECKED(TraceClassLoadingCause)
   JVMCI_FLAG_CHECKED(EagerJVMCI)
 
   CHECK_NOT_SET(JVMCITraceLevel,              EnableJVMCI)
@@ -101,11 +105,8 @@
   CHECK_NOT_SET(JVMCINMethodSizeLimit,        EnableJVMCI)
   CHECK_NOT_SET(MethodProfileWidth,           EnableJVMCI)
   CHECK_NOT_SET(JVMCIPrintProperties,         EnableJVMCI)
-  CHECK_NOT_SET(TraceUncollectedSpeculations, EnableJVMCI)
   CHECK_NOT_SET(UseJVMCINativeLibrary,        EnableJVMCI)
   CHECK_NOT_SET(JVMCILibPath,                 EnableJVMCI)
-  CHECK_NOT_SET(JVMCILibArgs,                 EnableJVMCI)
-  CHECK_NOT_SET(JVMCILibArgsSep,              EnableJVMCI)
   CHECK_NOT_SET(JVMCILibDumpJNIConfig,        EnableJVMCI)
 
 #ifndef PRODUCT
@@ -131,12 +132,6 @@
     }
   }
 
-  if (strlen(JVMCILibArgsSep) != 1) {
-    jio_fprintf(defaultStream::error_stream(),
-        "Length of -XX:JVMCILibArgsSep value must be 1: \"%s\"\n", JVMCILibArgsSep);
-    return false;
-  }
-
   return true;
 }
 
@@ -150,18 +145,3 @@
     }
   }
 }
-
-void JVMCIGlobals::init_java_mode_from_flags() {
-  if (EnableJVMCI) {
-    if (!UseJVMCINativeLibrary) {
-      _java_mode = HotSpot;
-    } else {
-      _java_mode = SharedLibrary;
-
-      // Make JVMCI initialization eager if loaded from a shared library
-      if (FLAG_IS_DEFAULT(EagerJVMCI)) {
-        FLAG_SET_DEFAULT(EagerJVMCI, true);
-      }
-    }
-  }
-}
--- a/src/hotspot/share/jvmci/jvmci_globals.hpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/jvmci/jvmci_globals.hpp	Mon Mar 18 16:54:45 2019 -0700
@@ -100,16 +100,6 @@
   experimental(intx, MethodProfileWidth, 0,                                 \
           "Number of methods to record in call profile")                    \
                                                                             \
-  develop(bool, TraceUncollectedSpeculations, false,                        \
-          "Print message when a failed speculation was not collected")      \
-                                                                            \
-  product(ccstr, JVMCILibArgs, NULL,                                        \
-          "Arguments for JVMCI shared library VM separated by a space (use "\
-          "JVMCILibArgsSep for an alternative separator)")                  \
-                                                                            \
-  experimental(ccstr, JVMCILibArgsSep, " ",                                 \
-          "Single character separator between JVMCILibArgs")                \
-                                                                            \
   experimental(ccstr, JVMCILibPath, NULL,                                   \
           "LD path for loading the JVMCI shared library")                   \
                                                                             \
@@ -122,6 +112,10 @@
           "instead of loading it from class files and executing it "        \
           "on the HotSpot heap")                                            \
                                                                             \
+  experimental(ccstr, TraceClassLoadingCause, NULL,                         \
+          "Print Java stack trace when loading a class whose fully"         \
+          "qualified name contains this string (\"*\" matches any class).") \
+                                                                            \
   NOT_COMPILER2(diagnostic(bool, UseMultiplyToLenIntrinsic, false,          \
           "Enables intrinsification of BigInteger.multiplyToLen()"))        \
                                                                             \
@@ -156,18 +150,9 @@
 #define JVMCI_SHARED_LIBRARY_NAME "jvmcicompiler"
 
 class JVMCIGlobals {
- public:
-  // Specifies where the JVMCI Java code is (i.e., jars or shared library)
-  enum JavaMode {
-    HotSpot,      // HotSpot heap, raw VM internal access
-    SharedLibrary // Shared library, JNI access
-  };
  private:
-  static JavaMode _java_mode;
   static fileStream* _jni_config_file;
  public:
-  // Initializes the Java mode from the UseJVMCINativeLibrary flag.
-  static void init_java_mode_from_flags();
 
   // Returns true if jvmci flags are consistent. If not consistent,
   // an error message describing the inconsistency is printed before
@@ -177,7 +162,6 @@
   // Check and exit VM with error if selected GC is not supported by JVMCI.
   static void check_jvmci_supported_gc();
 
-  static JavaMode java_mode() { return _java_mode; }
   static fileStream* get_jni_config_file() { return _jni_config_file; }
 };
 #endif // SHARE_JVMCI_JVMCI_GLOBALS_HPP
--- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -180,7 +180,7 @@
   volatile_nonstatic_field(JavaThread,         _is_method_handle_return,                      int)                                   \
   nonstatic_field(JavaThread,                  _osthread,                                     OSThread*)                             \
   nonstatic_field(JavaThread,                  _pending_deoptimization,                       int)                                   \
-  nonstatic_field(JavaThread,                  _pending_failed_speculation,                   long)                                  \
+  nonstatic_field(JavaThread,                  _pending_failed_speculation,                   jlong)                                 \
   nonstatic_field(JavaThread,                  _pending_transfer_to_interpreter,              bool)                                  \
   nonstatic_field(JavaThread,                  _jvmci_counters,                               jlong*)                                \
   nonstatic_field(JavaThread,                  _should_post_on_exceptions_flag,               int)                                   \
@@ -354,6 +354,7 @@
   declare_toplevel_type(JVMFlag)                                          \
   declare_toplevel_type(JVMFlag*)                                         \
   declare_toplevel_type(InvocationCounter)                                \
+  declare_toplevel_type(JVMCICompileState)                                \
   declare_toplevel_type(JVMCIEnv)                                         \
   declare_toplevel_type(LocalVariableTableElement)                        \
   declare_toplevel_type(narrowKlass)                                      \
--- a/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/jvmci/vmSymbols_jvmci.hpp	Mon Mar 18 16:54:45 2019 -0700
@@ -29,6 +29,7 @@
 #define JVMCI_VM_SYMBOLS_DO(template, do_alias)
 #else
 #define JVMCI_VM_SYMBOLS_DO(template, do_alias)                                                                                           \
+  template(jdk_vm_ci_services_Services,                           "jdk/vm/ci/services/Services")                                          \
   template(jdk_vm_ci_runtime_JVMCI,                               "jdk/vm/ci/runtime/JVMCI")                                              \
   template(jdk_vm_ci_hotspot_HotSpotCompiledCode,                 "jdk/vm/ci/hotspot/HotSpotCompiledCode")                                \
   template(jdk_vm_ci_hotspot_HotSpotCompiledCode_Comment,         "jdk/vm/ci/hotspot/HotSpotCompiledCode$Comment")                        \
@@ -38,7 +39,6 @@
   template(jdk_vm_ci_hotspot_CompilerToVM,                        "jdk/vm/ci/hotspot/CompilerToVM")                                       \
   template(jdk_vm_ci_hotspot_HotSpotInstalledCode,                "jdk/vm/ci/hotspot/HotSpotInstalledCode")                               \
   template(jdk_vm_ci_hotspot_HotSpotNmethod,                      "jdk/vm/ci/hotspot/HotSpotNmethod")                                     \
-  template(jdk_vm_ci_hotspot_HotSpotNmethodHandle,                "jdk/vm/ci/hotspot/HotSpotNmethodHandle")                               \
   template(jdk_vm_ci_hotspot_HotSpotResolvedJavaMethodImpl,       "jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl")                      \
   template(jdk_vm_ci_hotspot_HotSpotResolvedObjectTypeImpl,       "jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl")                      \
   template(jdk_vm_ci_hotspot_HotSpotResolvedPrimitiveType,        "jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType")                       \
@@ -104,33 +104,35 @@
   template(adjustCompilationLevel_signature,                      "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;ZI)I")          \
   template(compileMethod_name,                                    "compileMethod")                                                        \
   template(compileMethod_signature,                               "(Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;IJI)Ljdk/vm/ci/hotspot/HotSpotCompilationRequestResult;") \
-  template(encodeThrowable_name,                                  "encodeThrowable")                                                                                       \
-  template(encodeThrowable_signature,                             "(Ljava/lang/Throwable;)Ljava/lang/String;")                                                             \
-  template(decodeThrowable_name,                                  "decodeThrowable")                                                                                       \
-  template(decodeThrowable_signature,                             "(Ljava/lang/String;)Ljava/lang/Throwable;")                                                             \
-  template(fromMetaspace_name,                                    "fromMetaspace")                                                                                         \
-  template(method_fromMetaspace_signature,                        "(J)Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;")                                                      \
-  template(constantPool_fromMetaspace_signature,                  "(J)Ljdk/vm/ci/hotspot/HotSpotConstantPool;")                                                            \
-  template(klass_fromMetaspace_signature,                         "(JLjava/lang/String;)Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl;")                                \
-  template(primitive_fromMetaspace_signature,                     "(Ljdk/vm/ci/hotspot/HotSpotObjectConstantImpl;C)Ljdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType;")      \
-  template(getRuntime_name,                                       "getRuntime")                                                                                            \
-  template(getRuntime_signature,                                  "()Ljdk/vm/ci/runtime/JVMCIRuntime;")                                                                    \
-  template(initializeRuntime_name,                                "initializeRuntime")                                                                                     \
-  do_alias(initializeRuntime_signature, getRuntime_signature)                                                                                                              \
-  template(runtime_name,                                          "runtime")                                                                                               \
-  template(runtime_signature,                                     "()Ljdk/vm/ci/hotspot/HotSpotJVMCIRuntime;")                                                             \
-  template(getCompiler_name,                                      "getCompiler")                                                                                           \
-  template(getCompiler_signature,                                 "()Ljdk/vm/ci/runtime/JVMCICompiler;")                                                                   \
-  template(callToString_name,                                     "callToString")                                                                                          \
-  template(callToString_signature,                                "(Ljava/lang/Object;)Ljava/lang/String;")                                                                \
-  template(getName_name,                                          "getName")                                                                                               \
-  template(bootstrapFinished_name,                                "bootstrapFinished")                                                                                     \
-  template(forTypeChar_name,                                      "forTypeChar")                                                                                           \
-  template(forTypeChar_signature,                                 "(CJ)Ljdk/vm/ci/meta/PrimitiveConstant;")                                                                \
-  template(forFloat_name,                                         "forFloat")                                                                                              \
-  template(forFloat_signature,                                    "(F)Ljdk/vm/ci/meta/PrimitiveConstant;")                                                                 \
-  template(forDouble_name,                                        "forDouble")                                                                                             \
-  template(forDouble_signature,                                   "(D)Ljdk/vm/ci/meta/PrimitiveConstant;")                                                                 \
+  template(encodeThrowable_name,                                  "encodeThrowable")                                                      \
+  template(encodeThrowable_signature,                             "(Ljava/lang/Throwable;)Ljava/lang/String;")                            \
+  template(decodeThrowable_name,                                  "decodeThrowable")                                                      \
+  template(decodeThrowable_signature,                             "(Ljava/lang/String;)Ljava/lang/Throwable;")                            \
+  template(fromMetaspace_name,                                    "fromMetaspace")                                                        \
+  template(method_fromMetaspace_signature,                        "(J)Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethod;")                     \
+  template(constantPool_fromMetaspace_signature,                  "(J)Ljdk/vm/ci/hotspot/HotSpotConstantPool;")                           \
+  template(klass_fromMetaspace_signature,                         "(JLjava/lang/String;)Ljdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl;") \
+  template(primitive_fromMetaspace_signature,                     "(Ljdk/vm/ci/hotspot/HotSpotObjectConstantImpl;C)Ljdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType;") \
+  template(getRuntime_name,                                       "getRuntime")                                                           \
+  template(getRuntime_signature,                                  "()Ljdk/vm/ci/runtime/JVMCIRuntime;")                                   \
+  template(initializeRuntime_name,                                "initializeRuntime")                                                    \
+  do_alias(initializeRuntime_signature, getRuntime_signature)                                                                             \
+  template(runtime_name,                                          "runtime")                                                              \
+  template(runtime_signature,                                     "()Ljdk/vm/ci/hotspot/HotSpotJVMCIRuntime;")                            \
+  template(getCompiler_name,                                      "getCompiler")                                                          \
+  template(getCompiler_signature,                                 "()Ljdk/vm/ci/runtime/JVMCICompiler;")                                  \
+  template(callToString_name,                                     "callToString")                                                         \
+  template(callToString_signature,                                "(Ljava/lang/Object;)Ljava/lang/String;")                               \
+  template(getName_name,                                          "getName")                                                              \
+  template(bootstrapFinished_name,                                "bootstrapFinished")                                                    \
+  template(forTypeChar_name,                                      "forTypeChar")                                                          \
+  template(forTypeChar_signature,                                 "(CJ)Ljdk/vm/ci/meta/PrimitiveConstant;")                               \
+  template(forFloat_name,                                         "forFloat")                                                             \
+  template(forFloat_signature,                                    "(F)Ljdk/vm/ci/meta/PrimitiveConstant;")                                \
+  template(forDouble_name,                                        "forDouble")                                                            \
+  template(forDouble_signature,                                   "(D)Ljdk/vm/ci/meta/PrimitiveConstant;")                                \
+  template(method_string_bool_long_signature,                     "(Ljdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl;Ljava/lang/String;ZJ)V") \
+  template(initializeSavedProperties_name,                        "initializeSavedProperties")                                            \
 
 #endif
 
--- a/src/hotspot/share/oops/method.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/oops/method.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -116,6 +116,11 @@
 void Method::deallocate_contents(ClassLoaderData* loader_data) {
   MetadataFactory::free_metadata(loader_data, constMethod());
   set_constMethod(NULL);
+#if INCLUDE_JVMCI
+  if (method_data()) {
+    FailedSpeculation::free_failed_speculations(method_data()->get_failed_speculations_address());
+  }
+#endif
   MetadataFactory::free_metadata(loader_data, method_data());
   set_method_data(NULL);
   MetadataFactory::free_metadata(loader_data, method_counters());
--- a/src/hotspot/share/oops/methodData.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/oops/methodData.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -846,6 +846,86 @@
   return false;
 }
 
+#if INCLUDE_JVMCI
+
+void* FailedSpeculation::operator new(size_t size, size_t fs_size) throw() {
+  return CHeapObj<mtCompiler>::operator new(fs_size, std::nothrow);
+}
+
+FailedSpeculation::FailedSpeculation(address speculation, int speculation_len) : _data_len(speculation_len), _next(NULL) {
+  memcpy(data(), speculation, speculation_len);
+}
+
+// A heuristic check to detect nmethods that outlive a failed speculations list.
+static void guarantee_failed_speculations_alive(nmethod* nm, FailedSpeculation** failed_speculations_address) {
+  jlong head = (jlong)(address) *failed_speculations_address;
+  if ((head & 0x1) == 0x1) {
+    stringStream st;
+    if (nm != NULL) {
+      st.print("%d", nm->compile_id());
+      Method* method = nm->method();
+      st.print_raw("{");
+      if (method != NULL) {
+        method->print_name(&st);
+      } else {
+        const char* jvmci_name = nm->jvmci_name();
+        if (jvmci_name != NULL) {
+          st.print_raw(jvmci_name);
+        }
+      }
+      st.print_raw("}");
+    } else {
+      st.print("<unknown>");
+    }
+    fatal("Adding to failed speculations list that appears to have been freed. Source: %s", st.as_string());
+  }
+}
+
+bool FailedSpeculation::add_failed_speculation(nmethod* nm, FailedSpeculation** failed_speculations_address, address speculation, int speculation_len) {
+  assert(failed_speculations_address != NULL, "must be");
+  size_t fs_size = sizeof(FailedSpeculation) + speculation_len;
+  FailedSpeculation* fs = new (fs_size) FailedSpeculation(speculation, speculation_len);
+  if (fs == NULL) {
+    // no memory -> ignore failed speculation
+    return false;
+  }
+
+  guarantee(is_aligned(fs, sizeof(FailedSpeculation*)), "FailedSpeculation objects must be pointer aligned");
+  guarantee_failed_speculations_alive(nm, failed_speculations_address);
+
+  FailedSpeculation** cursor = failed_speculations_address;
+  do {
+    if (*cursor == NULL) {
+      FailedSpeculation* old_fs = Atomic::cmpxchg(fs, cursor, (FailedSpeculation*) NULL);
+      if (old_fs == NULL) {
+        // Successfully appended fs to end of the list
+        return true;
+      }
+      cursor = old_fs->next_adr();
+    } else {
+      cursor = (*cursor)->next_adr();
+    }
+  } while (true);
+}
+
+void FailedSpeculation::free_failed_speculations(FailedSpeculation** failed_speculations_address) {
+  assert(failed_speculations_address != NULL, "must be");
+  FailedSpeculation* fs = *failed_speculations_address;
+  while (fs != NULL) {
+    FailedSpeculation* next = fs->next();
+    delete fs;
+    fs = next;
+  }
+
+  // Write an unaligned value to failed_speculations_address to denote
+  // that it is no longer a valid pointer. This is allows for the check
+  // in add_failed_speculation against adding to a freed failed
+  // speculations list.
+  long* head = (long*) failed_speculations_address;
+  (*head) = (*head) | 0x1;
+}
+#endif // INCLUDE_JVMCI
+
 int MethodData::compute_extra_data_count(int data_size, int empty_bc_count, bool needs_speculative_traps) {
 #if INCLUDE_JVMCI
   if (ProfileTraps) {
@@ -1227,6 +1307,7 @@
 
 #if INCLUDE_JVMCI
   _jvmci_ir_size = 0;
+  _failed_speculations = NULL;
 #endif
 
 #if INCLUDE_RTM_OPT
--- a/src/hotspot/share/oops/methodData.hpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/oops/methodData.hpp	Mon Mar 18 16:54:45 2019 -0700
@@ -1949,6 +1949,42 @@
 };
 
 
+#if INCLUDE_JVMCI
+// Encapsulates an encoded speculation reason. These are linked together in
+// a list that is atomically appended to during deoptimization. Entries are
+// never removed from the list.
+// @see jdk.vm.ci.hotspot.HotSpotSpeculationLog.HotSpotSpeculationEncoding
+class FailedSpeculation: public CHeapObj<mtCompiler> {
+ private:
+  // The length of HotSpotSpeculationEncoding.toByteArray(). The data itself
+  // is an array embedded at the end of this object.
+  int   _data_len;
+
+  // Next entry in a linked list.
+  FailedSpeculation* _next;
+
+  FailedSpeculation(address data, int data_len);
+
+  FailedSpeculation** next_adr() { return &_next; }
+
+  // Placement new operator for inlining the speculation data into
+  // the FailedSpeculation object.
+  void* operator new(size_t size, size_t fs_size) throw();
+
+ public:
+  char* data()         { return (char*)(((address) this) + sizeof(FailedSpeculation)); }
+  int data_len() const { return _data_len; }
+  FailedSpeculation* next() const { return _next; }
+
+  // Atomically appends a speculation from nm to the list whose head is at (*failed_speculations_address).
+  // Returns false if the FailedSpeculation object could not be allocated.
+  static bool add_failed_speculation(nmethod* nm, FailedSpeculation** failed_speculations_address, address speculation, int speculation_len);
+
+  // Frees all entries in the linked list whose head is at (*failed_speculations_address).
+  static void free_failed_speculations(FailedSpeculation** failed_speculations_address);
+};
+#endif
+
 class MethodData : public Metadata {
   friend class VMStructs;
   friend class JVMCIVMStructs;
@@ -2030,7 +2066,8 @@
 
 #if INCLUDE_JVMCI
   // Support for HotSpotMethodData.setCompiledIRSize(int)
-  int               _jvmci_ir_size;
+  int                _jvmci_ir_size;
+  FailedSpeculation* _failed_speculations;
 #endif
 
   // Size of _data array in bytes.  (Excludes header and extra_data fields.)
@@ -2191,6 +2228,12 @@
   InvocationCounter* invocation_counter()     { return &_invocation_counter; }
   InvocationCounter* backedge_counter()       { return &_backedge_counter;   }
 
+#if INCLUDE_JVMCI
+  FailedSpeculation** get_failed_speculations_address() {
+    return &_failed_speculations;
+  }
+#endif
+
 #if INCLUDE_RTM_OPT
   int rtm_state() const {
     return _rtm_state;
--- a/src/hotspot/share/runtime/deoptimization.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/runtime/deoptimization.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -1520,7 +1520,7 @@
     methodHandle    trap_method = trap_scope->method();
     int             trap_bci    = trap_scope->bci();
 #if INCLUDE_JVMCI
-    long            speculation = thread->pending_failed_speculation();
+    jlong           speculation = thread->pending_failed_speculation();
     if (nm->is_compiled_by_jvmci() && nm->is_nmethod()) { // Exclude AOTed methods
       nm->as_nmethod()->update_speculation(thread);
     } else {
@@ -1575,7 +1575,7 @@
                          format_trap_request(buf, sizeof(buf), trap_request));
 #if INCLUDE_JVMCI
         if (speculation != 0) {
-          xtty->print(" speculation='" JLONG_FORMAT "'", (jlong)speculation);
+          xtty->print(" speculation='" JLONG_FORMAT "'", speculation);
         }
 #endif
         nm->log_identity(xtty);
@@ -1623,7 +1623,7 @@
         tty->print(" compiler=%s compile_id=%d", nm->compiler_name(), nm->compile_id());
 #if INCLUDE_JVMCI
         if (nm->is_nmethod()) {
-          const char* installed_code_name = nm->as_nmethod()->jvmci_nmethod_mirror_name();
+          const char* installed_code_name = nm->as_nmethod()->jvmci_name();
           if (installed_code_name != NULL) {
             tty->print(" (JVMCI: installed code name=%s) ", installed_code_name);
           }
--- a/src/hotspot/share/runtime/frame.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/runtime/frame.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -681,7 +681,7 @@
 #if INCLUDE_JVMCI
         if (cm->is_nmethod()) {
           nmethod* nm = cm->as_nmethod();
-          const char* jvmciName = nm->jvmci_nmethod_mirror_name();
+          const char* jvmciName = nm->jvmci_name();
           if (jvmciName != NULL) {
             st->print(" (%s)", jvmciName);
           }
--- a/src/hotspot/share/runtime/thread.hpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/runtime/thread.hpp	Mon Mar 18 16:54:45 2019 -0700
@@ -1140,7 +1140,7 @@
 
   // An id of a speculation that JVMCI compiled code can use to further describe and
   // uniquely identify the  speculative optimization guarded by the uncommon trap
-  long       _pending_failed_speculation;
+  jlong     _pending_failed_speculation;
 
   // These fields are mutually exclusive in terms of live ranges.
   union {
@@ -1537,13 +1537,13 @@
 
 #if INCLUDE_JVMCI
   int  pending_deoptimization() const             { return _pending_deoptimization; }
-  long pending_failed_speculation() const         { return _pending_failed_speculation; }
+  jlong pending_failed_speculation() const        { return _pending_failed_speculation; }
   bool adjusting_comp_level() const               { return _adjusting_comp_level; }
   void set_adjusting_comp_level(bool b)           { _adjusting_comp_level = b; }
   bool has_pending_monitorenter() const           { return _pending_monitorenter; }
   void set_pending_monitorenter(bool b)           { _pending_monitorenter = b; }
   void set_pending_deoptimization(int reason)     { _pending_deoptimization = reason; }
-  void set_pending_failed_speculation(long failed_speculation) { _pending_failed_speculation = failed_speculation; }
+  void set_pending_failed_speculation(jlong failed_speculation) { _pending_failed_speculation = failed_speculation; }
   void set_pending_transfer_to_interpreter(bool b) { _pending_transfer_to_interpreter = b; }
   void set_jvmci_alternate_call_target(address a) { assert(_jvmci._alternate_call_target == NULL, "must be"); _jvmci._alternate_call_target = a; }
   void set_jvmci_implicit_exception_pc(address a) { assert(_jvmci._implicit_exception_pc == NULL, "must be"); _jvmci._implicit_exception_pc = a; }
--- a/src/hotspot/share/runtime/vmOperations.cpp	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/hotspot/share/runtime/vmOperations.cpp	Mon Mar 18 16:54:45 2019 -0700
@@ -435,7 +435,16 @@
       if (thr!=thr_cur && thr->thread_state() == _thread_in_native) {
         num_active++;
         if (thr->is_Compiler_thread()) {
-          num_active_compiler_thread++;
+          CompilerThread* ct = (CompilerThread*) thr;
+          if (ct->compiler() == NULL || !ct->compiler()->is_jvmci()) {
+            num_active_compiler_thread++;
+          } else {
+            // When using a Java based JVMCI compiler, it's possible
+            // for one compiler thread to grab a Java lock, enter
+            // HotSpot and go to sleep on the shutdown safepoint.
+            // Another JVMCI compiler thread can then attempt grab
+            // the lock and thus never make progress.
+          }
         }
       }
     }
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodePosition.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodePosition.java	Mon Mar 18 16:54:45 2019 -0700
@@ -87,7 +87,11 @@
 
     @Override
     public int hashCode() {
-        return getBCI();
+        int hc = method.hashCode() * 31 + bci;
+        if (caller != null) {
+            hc = (hc * 31) + caller.hashCode();
+        }
+        return hc;
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Cleaner.java	Mon Mar 18 16:54:45 2019 -0700
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2018, 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;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+
+import jdk.vm.ci.common.NativeImageReinitialize;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * A cleaner tracks a referent object and includes some {@linkplain #doCleanup() cleanup code} that
+ * is run some time after the referent object has become weakly-reachable.
+ *
+ * This is like {@link sun.misc.Cleaner} but with weak semantics instead of phantom. Objects
+ * referenced by this might be referenced by {@link ResolvedJavaType} which is kept alive by a
+ * {@link WeakReference} so we need equivalent reference strength.
+ */
+abstract class Cleaner extends WeakReference<Object> {
+
+    /**
+     * Head of linked list of cleaners.
+     */
+    @NativeImageReinitialize private static Cleaner first;
+
+    /**
+     * Linked list pointers.
+     */
+    private Cleaner next = null;
+    private Cleaner prev = null;
+
+    Cleaner(Object referent) {
+        super(referent, queue);
+        add(this);
+    }
+
+    private static synchronized Cleaner add(Cleaner cl) {
+        if (first != null) {
+            clean();
+        }
+        if (first != null) {
+            cl.next = first;
+            first.prev = cl;
+        }
+        first = cl;
+        return cl;
+    }
+
+    /**
+     * Removes {@code cl} from the linked list of cleaners.
+     */
+    private static synchronized void remove(Cleaner cl) {
+        // If already removed, do nothing
+        if (cl.next == cl) {
+            return;
+        }
+
+        // Update list
+        if (first == cl) {
+            if (cl.next != null) {
+                first = cl.next;
+            } else {
+                first = cl.prev;
+            }
+        }
+        if (cl.next != null) {
+            cl.next.prev = cl.prev;
+        }
+        if (cl.prev != null) {
+            cl.prev.next = cl.next;
+        }
+
+        // Indicate removal by pointing the cleaner to itself
+        cl.next = cl;
+        cl.prev = cl;
+    }
+
+    /**
+     * Performs the cleanup action now that this object's referent has become weakly reachable.
+     */
+    abstract void doCleanup();
+
+    /**
+     * Remove the cleaners whose referents have become weakly reachable.
+     */
+    static void clean() {
+        Cleaner c = (Cleaner) queue.poll();
+        while (c != null) {
+            remove(c);
+            c.doCleanup();
+            c = (Cleaner) queue.poll();
+        }
+    }
+
+    /**
+     * The {@link ReferenceQueue} to which {@link Cleaner}s are enqueued once their referents'
+     * become unreachable.
+     */
+    private static final ReferenceQueue<Object> queue = new ReferenceQueue<>();
+}
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java	Mon Mar 18 16:54:45 2019 -0700
@@ -385,7 +385,7 @@
      * @throws JVMCIError if there is something wrong with the compiled code or the associated
      *             metadata.
      */
-    native int installCode(TargetDescription target, HotSpotCompiledCode compiledCode, InstalledCode code, HotSpotSpeculationLog speculationLog);
+    native int installCode(TargetDescription target, HotSpotCompiledCode compiledCode, InstalledCode code, long failedSpeculationsAddress, byte[] speculations);
 
     /**
      * Generates the VM metadata for some compiled code and copies them into {@code metaData}. This
@@ -883,10 +883,11 @@
     native Object unhand(long handle);
 
     /**
-     * Updates the internal fields of the nmethodHandle based on the current state of the
-     * corresponding nmethod.
+     * Updates {@code address} and {@code entryPoint} fields of {@code nmethodMirror} based on the
+     * current state of the {@code nmethod} identified by {@code address} and
+     * {@code nmethodMirror.compileId} in the code cache.
      */
-    native void updateHotSpotNmethodHandle(HotSpotNmethodHandle nmethodHandle);
+    native void updateHotSpotNmethod(HotSpotNmethod nmethodMirror);
 
     /**
      * @see InstalledCode#getCode()
@@ -916,4 +917,34 @@
      * {@code DeleteGlobalRef} JNI function.
      */
     native void deleteGlobalHandle(long handle);
+
+    /**
+     * Gets the failed speculations pointed to by {@code *failedSpeculationsAddress}.
+     *
+     * @param currentFailures the known failures at {@code failedSpeculationsAddress}
+     * @return the list of failed speculations with each entry being a single speculation in the
+     *         format emitted by {@link HotSpotSpeculationEncoding#toByteArray()}
+     */
+    native byte[][] getFailedSpeculations(long failedSpeculationsAddress, byte[][] currentFailures);
+
+    /**
+     * Gets the address of the {@code MethodData::_failed_speculations} field in the
+     * {@code MethodData} associated with {@code method}. This will create and install the
+     * {@code MethodData} if it didn't already exist.
+     */
+    native long getFailedSpeculationsAddress(HotSpotResolvedJavaMethodImpl method);
+
+    /**
+     * Frees the failed speculations pointed to by {@code *failedSpeculationsAddress}.
+     */
+    native void releaseFailedSpeculations(long failedSpeculationsAddress);
+
+    /**
+     * Adds a speculation to the failed speculations pointed to by
+     * {@code *failedSpeculationsAddress}.
+     *
+     * @return {@code false} if the speculation could not be appended to the list
+     */
+    native boolean addFailedSpeculation(long failedSpeculationsAddress, byte[] speculation);
+
 }
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java	Mon Mar 18 16:54:45 2019 -0700
@@ -60,4 +60,9 @@
         assert compressed;
         return new DirectHotSpotObjectConstantImpl(object, false);
     }
+
+    @Override
+    public int getIdentityHashCode() {
+        return System.identityHashCode(object);
+    }
 }
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HandleCleaner.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HandleCleaner.java	Mon Mar 18 16:54:45 2019 -0700
@@ -24,12 +24,6 @@
 
 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
 
-import java.lang.ref.ReferenceQueue;
-import java.lang.ref.WeakReference;
-
-import jdk.vm.ci.common.NativeImageReinitialize;
-import jdk.vm.ci.meta.ResolvedJavaType;
-
 /**
  * This class manages a set of {@code jobject} and {@code jmetadata} handles whose lifetimes are
  * dependent on associated {@link IndirectHotSpotObjectConstantImpl} and
@@ -40,23 +34,8 @@
  * or metadata reference alive through the use of handles. Once the call completes the wrapper
  * object is registered here and will be scanned during metadata scanning. The weakness of the
  * reference to the wrapper object allows the handles to be reclaimed when they are no longer used.
- *
- * This is like {@link sun.misc.Cleaner} but with weak semantics instead of phantom. Objects
- * referenced by this might be referenced by {@link ResolvedJavaType} which is kept alive by a
- * {@link WeakReference} so we need equivalent reference strength.
  */
-final class HandleCleaner extends WeakReference<Object> {
-
-    /**
-     * Head of linked list of cleaners.
-     */
-    @NativeImageReinitialize private static HandleCleaner first = null;
-
-    /**
-     * Linked list pointers.
-     */
-    private HandleCleaner next = null;
-    private HandleCleaner prev = null;
+final class HandleCleaner extends Cleaner {
 
     /**
      * A {@code jmetadata} or {@code jobject} handle.
@@ -68,47 +47,8 @@
      */
     private final boolean isJObject;
 
-    private static synchronized HandleCleaner add(HandleCleaner cl) {
-        if (first != null) {
-            cl.next = first;
-            first.prev = cl;
-        }
-        first = cl;
-        return cl;
-    }
-
-    /**
-     * Removes {@code cl} from the linked list of cleaners.
-     */
-    private static synchronized boolean remove(HandleCleaner cl) {
-        // If already removed, do nothing
-        if (cl.next == cl) {
-            return false;
-        }
-
-        // Update list
-        if (first == cl) {
-            if (cl.next != null) {
-                first = cl.next;
-            } else {
-                first = cl.prev;
-            }
-        }
-        if (cl.next != null) {
-            cl.next.prev = cl.prev;
-        }
-        if (cl.prev != null) {
-            cl.prev.next = cl.next;
-        }
-
-        // Indicate removal by pointing the cleaner to itself
-        cl.next = cl;
-        cl.prev = cl;
-        return true;
-    }
-
     private HandleCleaner(Object wrapper, long handle, boolean isJObject) {
-        super(wrapper, queue);
+        super(wrapper);
         this.handle = handle;
         this.isJObject = isJObject;
     }
@@ -116,8 +56,8 @@
     /**
      * Releases the resource associated with {@code this.handle}.
      */
-    private void deleteHandle() {
-        remove(this);
+    @Override
+    void doCleanup() {
         if (isJObject) {
             // The sentinel value used to denote a free handle is
             // an object on the HotSpot heap so we call into the
@@ -133,29 +73,12 @@
     }
 
     /**
-     * Cleans the handles who wrappers have been garbage collected.
-     */
-    private static void clean() {
-        HandleCleaner ref = (HandleCleaner) queue.poll();
-        while (ref != null) {
-            ref.deleteHandle();
-            ref = (HandleCleaner) queue.poll();
-        }
-    }
-
-    /**
-     * The {@link ReferenceQueue} to which handle wrappers are enqueued once they become
-     * unreachable.
-     */
-    private static final ReferenceQueue<Object> queue = new ReferenceQueue<>();
-
-    /**
      * Registers a cleaner for {@code handle}. The cleaner will release the handle some time after
      * {@code wrapper} is detected as unreachable by the garbage collector.
      */
+    @SuppressWarnings("unused")
     static void create(Object wrapper, long handle) {
-        clean();
         assert wrapper instanceof IndirectHotSpotObjectConstantImpl || wrapper instanceof MetaspaceHandleObject;
-        add(new HandleCleaner(wrapper, handle, wrapper instanceof IndirectHotSpotObjectConstantImpl));
+        new HandleCleaner(wrapper, handle, wrapper instanceof IndirectHotSpotObjectConstantImpl);
     }
 }
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java	Mon Mar 18 16:54:45 2019 -0700
@@ -106,21 +106,39 @@
         if (installedCode != null) {
             throw new IllegalArgumentException("InstalledCode argument must be null");
         }
+        HotSpotCompiledCode hsCompiledCode = (HotSpotCompiledCode) compiledCode;
+        String name = hsCompiledCode.getName();
+        HotSpotCompiledNmethod hsCompiledNmethod = null;
         if (method == null) {
             // Must be a stub
-            resultInstalledCode = new HotSpotRuntimeStub(((HotSpotCompiledCode) compiledCode).getName());
+            resultInstalledCode = new HotSpotRuntimeStub(name);
         } else {
-            resultInstalledCode = new HotSpotNmethod((HotSpotResolvedJavaMethodImpl) method, ((HotSpotCompiledCode) compiledCode).getName(), isDefault);
+            hsCompiledNmethod = (HotSpotCompiledNmethod) hsCompiledCode;
+            HotSpotResolvedJavaMethodImpl hsMethod = (HotSpotResolvedJavaMethodImpl) method;
+            resultInstalledCode = new HotSpotNmethod(hsMethod, name, isDefault, hsCompiledNmethod.id);
         }
 
-        HotSpotSpeculationLog speculationLog = (log != null && log.hasSpeculations()) ? (HotSpotSpeculationLog) log : null;
+        HotSpotSpeculationLog speculationLog = null;
+        if (log != null) {
+            if (log.hasSpeculations()) {
+                speculationLog = (HotSpotSpeculationLog) log;
+            }
+        }
 
-        int result = runtime.getCompilerToVM().installCode(target, (HotSpotCompiledCode) compiledCode, resultInstalledCode, speculationLog);
+        byte[] speculations;
+        long failedSpeculationsAddress;
+        if (speculationLog != null) {
+            speculations = speculationLog.getFlattenedSpeculations(true);
+            failedSpeculationsAddress = speculationLog.getFailedSpeculationsAddress();
+        } else {
+            speculations = new byte[0];
+            failedSpeculationsAddress = 0L;
+        }
+        int result = runtime.getCompilerToVM().installCode(target, (HotSpotCompiledCode) compiledCode, resultInstalledCode, failedSpeculationsAddress, speculations);
         if (result != config.codeInstallResultOk) {
             String resultDesc = config.getCodeInstallResultDescription(result);
-            if (compiledCode instanceof HotSpotCompiledNmethod) {
-                HotSpotCompiledNmethod compiledNmethod = (HotSpotCompiledNmethod) compiledCode;
-                String msg = compiledNmethod.getInstallationFailureMessage();
+            if (hsCompiledNmethod != null) {
+                String msg = hsCompiledNmethod.getInstallationFailureMessage();
                 if (msg != null) {
                     msg = String.format("Code installation failed: %s%n%s", resultDesc, msg);
                 } else {
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJDKReflection.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJDKReflection.java	Mon Mar 18 16:54:45 2019 -0700
@@ -33,7 +33,6 @@
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
 import java.util.HashMap;
-import java.util.Map;
 
 import jdk.vm.ci.common.JVMCIError;
 import jdk.vm.ci.meta.JavaConstant;
@@ -42,7 +41,6 @@
 import jdk.vm.ci.meta.ResolvedJavaField;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.meta.SpeculationLog;
 
 /**
  * Implementation of {@link HotSpotJVMCIReflection} in terms of standard JDK reflection API. This is
@@ -120,29 +118,6 @@
         return readFieldValue(field, value, isVolatile);
     }
 
-    /**
-     * The {@link SpeculationLog} for methods compiled by JVMCI hang off this per-declaring-type
-     * {@link ClassValue}. The raw Method* value is safe to use as a key in the map as a) it is
-     * never moves and b) we never read from it.
-     * <p>
-     * One implication is that we will preserve {@link SpeculationLog}s for methods that have been
-     * redefined via class redefinition. It's tempting to periodically flush such logs but we cannot
-     * read the JVM_ACC_IS_OBSOLETE bit (or anything else) via the raw pointer as obsoleted methods
-     * are subject to clean up and deletion (see InstanceKlass::purge_previous_versions_internal).
-     */
-    private static final ClassValue<Map<Long, SpeculationLog>> SpeculationLogs = new ClassValue<Map<Long, SpeculationLog>>() {
-        @Override
-        protected Map<Long, SpeculationLog> computeValue(java.lang.Class<?> type) {
-            return new HashMap<>(4);
-        }
-    };
-
-    @Override
-    Map<Long, SpeculationLog> getSpeculationLogs(HotSpotResolvedObjectTypeImpl holder) {
-        Class<?> javaMirror = getMirror(holder);
-        return SpeculationLogs.get(javaMirror);
-    }
-
     @Override
     boolean equals(HotSpotObjectConstantImpl a, HotSpotObjectConstantImpl b) {
         return resolveObject(a) == resolveObject(b) && a.isCompressed() == b.isCompressed();
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java	Mon Mar 18 16:54:45 2019 -0700
@@ -27,10 +27,10 @@
 
 import jdk.vm.ci.code.CompilationRequest;
 import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.common.NativeImageReinitialize;
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option;
 import jdk.vm.ci.runtime.JVMCICompiler;
 import jdk.vm.ci.runtime.JVMCICompilerFactory;
-import jdk.vm.ci.common.NativeImageReinitialize;
 import jdk.vm.ci.runtime.JVMCIRuntime;
 import jdk.vm.ci.services.JVMCIPermission;
 import jdk.vm.ci.services.JVMCIServiceLocator;
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIReflection.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIReflection.java	Mon Mar 18 16:54:45 2019 -0700
@@ -24,13 +24,11 @@
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Type;
-import java.util.Map;
 
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.meta.SpeculationLog;
 
 /**
  * Reflection interface for reflecting on the internals of HotSpot JVMCI types and objects.
@@ -57,8 +55,6 @@
 
     abstract JavaConstant readFieldValue(HotSpotObjectConstantImpl object, HotSpotResolvedJavaField field, boolean isVolatile);
 
-    abstract Map<Long, SpeculationLog> getSpeculationLogs(HotSpotResolvedObjectTypeImpl holder);
-
     abstract boolean equals(HotSpotObjectConstantImpl hotSpotResolvedJavaType, HotSpotObjectConstantImpl that);
 
     abstract JavaConstant getJavaMirror(HotSpotResolvedPrimitiveType hotSpotResolvedJavaType);
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java	Mon Mar 18 16:54:45 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, 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
@@ -48,7 +48,6 @@
 import java.util.TreeMap;
 import java.util.function.Predicate;
 
-import jdk.internal.misc.VM;
 import jdk.internal.misc.Unsafe;
 
 import jdk.vm.ci.code.Architecture;
@@ -256,7 +255,7 @@
         @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "sentinel must be String since it's a static final in an enum")
         private Object getValue() {
             if (value == UNINITIALIZED) {
-                String propertyValue = VM.getSavedProperty(getPropertyName());
+                String propertyValue = Services.getSavedProperties().get(getPropertyName());
                 if (propertyValue == null) {
                     this.value = defaultValue;
                     this.isDefault = true;
@@ -739,6 +738,10 @@
      */
     @VMEntryPoint
     private void shutdown() throws Exception {
+        // Cleaners are normally only processed when a new Cleaner is
+        // instantiated so process all remaining cleaners now.
+        Cleaner.clean();
+
         for (HotSpotVMEventListener vmEventListener : getVmEventListeners()) {
             vmEventListener.notifyShutdown();
         }
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java	Mon Mar 18 16:54:45 2019 -0700
@@ -22,8 +22,6 @@
  */
 package jdk.vm.ci.hotspot;
 
-import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
-
 import java.lang.reflect.Executable;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
@@ -89,19 +87,17 @@
 
         HotSpotResolvedJavaType holder = runtime.fromClass(fieldHolder);
         assert holder != null : fieldHolder;
+        ResolvedJavaField[] fields;
         if (Modifier.isStatic(reflectionField.getModifiers())) {
-            final long offset = UNSAFE.staticFieldOffset(reflectionField);
-            for (ResolvedJavaField field : holder.getStaticFields()) {
-                if (offset == field.getOffset()) {
-                    return field;
-                }
-            }
+            fields = holder.getStaticFields();
         } else {
-            final long offset = UNSAFE.objectFieldOffset(reflectionField);
-            for (ResolvedJavaField field : holder.getInstanceFields(false)) {
-                if (offset == field.getOffset()) {
-                    return field;
-                }
+            fields = holder.getInstanceFields(false);
+        }
+        ResolvedJavaType fieldType = lookupJavaType(reflectionField.getType());
+        for (ResolvedJavaField field : fields) {
+            if (reflectionField.getName().equals(field.getName()) && field.getType().equals(fieldType)) {
+                assert Modifier.isStatic(reflectionField.getModifiers()) == field.isStatic();
+                return field;
             }
         }
 
@@ -160,7 +156,9 @@
         if (constant.equals(JavaConstant.LONG_0)) {
             return SpeculationLog.NO_SPECULATION;
         }
-        assert speculationLog != null : "Must have a speculation log";
+        if (speculationLog == null) {
+            throw new IllegalArgumentException("A speculation log is required to decode the speculation denoted by " + constant);
+        }
         return speculationLog.lookupSpeculation(constant);
     }
 
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java	Mon Mar 18 16:54:45 2019 -0700
@@ -23,6 +23,7 @@
 package jdk.vm.ci.hotspot;
 
 import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM;
+import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
 
 import jdk.vm.ci.code.InstalledCode;
 import jdk.vm.ci.code.InvalidInstalledCodeException;
@@ -34,14 +35,6 @@
  * Implementation of {@link InstalledCode} for code installed as an {@code nmethod}. The address of
  * the {@code nmethod} is stored in {@link InstalledCode#address} and the value of
  * {@code nmethod::verified_entry_point()} is in {@link InstalledCode#entryPoint}.
- * <p>
- * When a {@link HotSpotNmethod} dies, it triggers invalidation of the {@code nmethod} unless
- * {@link #isDefault() == true}.
- * <p>
- * The diagram below shows the relationship between an {@code nmethod} and its
- * {@link HotSpotNmethod} mirrors:
- * <p>
- * <img src="doc-files/HotSpotNmethod Mirrors.jpg">
  */
 public class HotSpotNmethod extends HotSpotInstalledCode {
 
@@ -53,29 +46,61 @@
 
     /**
      * Specifies whether the {@code nmethod} associated with this object is the code executed by
-     * default HotSpot linkage when a normal Java call to {@link #method} is made. This true when
-     * {@code this.method.metadataHandle->_code == this.address}. If not, then the {@code nmethod}
-     * can only be invoked via a non-default mechanism based on a strong reference to this object
-     * (e.g., https://goo.gl/LX88rZ). As such, HotSpot will invalidate the {@code nmethod} once this
-     * object dies if {@code isDefault == false}.
+     * default HotSpot linkage when a normal Java call to {@link #method} is made. That is, does
+     * {@code this.method.metadataHandle->_code} == {@code this.address}. If not, then the
+     * {@code nmethod} can only be invoked via a reference to this object. An example of this is the
+     * trampoline mechanism used by Truffle: https://goo.gl/LX88rZ.
      */
     private final boolean isDefault;
 
-    HotSpotNmethod(HotSpotResolvedJavaMethodImpl method, String name, boolean isDefault) {
+    /**
+     * Determines whether this object is in the oops table of the nmethod.
+     * <p>
+     * If this object is in the oops table, the VM uses the oops table entry to update this object's
+     * {@link #address} and {@link #entryPoint} fields when the state of the nmethod changes. The
+     * nmethod will be unloadable when this object dies.
+     * <p>
+     * Otherwise, the nmethod's unloadability is not changed when this object dies.
+     */
+    boolean inOopsTable() {
+        return compileIdSnapshot != 0;
+    }
+
+    /**
+     * If this field is 0, this object is in the oops table of the nmethod. Otherwise, the value of
+     * the field records the nmethod's compile identifier. This value is used to confirm an entry in
+     * the code cache retrieved by {@link #address} is indeed the nmethod represented by this
+     * object.
+     *
+     * @see #inOopsTable
+     */
+    private final long compileIdSnapshot;
+
+    HotSpotNmethod(HotSpotResolvedJavaMethodImpl method, String name, boolean isDefault, long compileId) {
         super(name);
         this.method = method;
         this.isDefault = isDefault;
+        boolean inOopsTable = !IS_IN_NATIVE_IMAGE && !isDefault;
+        this.compileIdSnapshot = inOopsTable ? 0L : compileId;
+        assert inOopsTable || compileId != 0L : this;
     }
 
     /**
      * Determines if the nmethod associated with this object is the compiled entry point for
-     * {@link #getMethod()}. If {@code false}, then the nmethod is unloaded when the VM determines
-     * this object has died.
+     * {@link #getMethod()}.
      */
     public boolean isDefault() {
         return isDefault;
     }
 
+    @Override
+    public boolean isValid() {
+        if (compileIdSnapshot != 0L) {
+            compilerToVM().updateHotSpotNmethod(this);
+        }
+        return super.isValid();
+    }
+
     public ResolvedJavaMethod getMethod() {
         return method;
     }
@@ -86,8 +111,25 @@
     }
 
     @Override
+    public long getAddress() {
+        if (compileIdSnapshot != 0L) {
+            compilerToVM().updateHotSpotNmethod(this);
+        }
+        return super.getAddress();
+    }
+
+    @Override
+    public long getEntryPoint() {
+        if (compileIdSnapshot != 0L) {
+            return 0;
+        }
+        return super.getEntryPoint();
+    }
+
+    @Override
     public String toString() {
-        return String.format("HotSpotNmethod[method=%s, codeBlob=0x%x, isDefault=%b, name=%s]", method, getAddress(), isDefault, name);
+        return String.format("HotSpotNmethod[method=%s, codeBlob=0x%x, isDefault=%b, name=%s, inOopsTable=%s]",
+                        method, getAddress(), isDefault, name, inOopsTable());
     }
 
     private boolean checkArgs(Object... args) {
@@ -106,6 +148,9 @@
 
     @Override
     public Object executeVarargs(Object... args) throws InvalidInstalledCodeException {
+        if (IS_IN_NATIVE_IMAGE) {
+            throw new HotSpotJVMCIUnsupportedOperationError("Cannot execute nmethod via mirror in native image");
+        }
         assert checkArgs(args);
         return compilerToVM().executeHotSpotNmethod(args, this);
     }
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethodHandle.java	Wed Mar 13 21:41:51 2019 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2018, 2018, 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;
-
-import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM;
-
-/**
- * A subclass of {@link HotSpotNmethod} with cooperative update semantics. It cannot be used for
- * invocation but will properly answer all other queries. It doesn't support the
- * {@link HotSpotNmethod#isDefault} semantics of triggering unloading of the corresponding nmethod
- * when the instance is reclaimed.
- */
-class HotSpotNmethodHandle extends HotSpotNmethod {
-    @SuppressFBWarnings(value = "UWF_UNWRITTEN_FIELD", justification = "field is set by the native part") private long compileId;
-
-    HotSpotNmethodHandle(HotSpotResolvedJavaMethodImpl method, String name, boolean isDefault) {
-        super(method, name, isDefault);
-    }
-
-    @Override
-    public Object executeVarargs(Object... args) {
-        throw new HotSpotJVMCIUnsupportedOperationError("unsupported from native image");
-    }
-
-    @Override
-    public boolean isValid() {
-        compilerToVM().updateHotSpotNmethodHandle(this);
-        return super.isValid();
-    }
-
-    @Override
-    public boolean isAlive() {
-        compilerToVM().updateHotSpotNmethodHandle(this);
-        return super.isAlive();
-    }
-
-    @Override
-    public long getAddress() {
-        compilerToVM().updateHotSpotNmethodHandle(this);
-        return super.getAddress();
-    }
-
-    @Override
-    public long getEntryPoint() {
-        return 0;
-    }
-}
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java	Mon Mar 18 16:54:45 2019 -0700
@@ -63,9 +63,7 @@
     }
 
     @Override
-    public int getIdentityHashCode() {
-        return runtime().compilerToVm.getIdentityHashCode(this);
-    }
+    public abstract int getIdentityHashCode();
 
     @Override
     public JavaConstant getCallSiteTarget(Assumptions assumptions) {
@@ -151,7 +149,7 @@
 
     @Override
     public int hashCode() {
-        return runtime().reflection.hashCode();
+        return getIdentityHashCode();
     }
 
     @Override
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java	Mon Mar 18 16:54:45 2019 -0700
@@ -35,7 +35,6 @@
 import java.lang.reflect.Executable;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
-import java.util.Map;
 
 import jdk.vm.ci.common.JVMCIError;
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option;
@@ -704,15 +703,8 @@
 
     @Override
     public SpeculationLog getSpeculationLog() {
-        Map<Long, SpeculationLog> map = holder.getSpeculationLogs();
-        synchronized (map) {
-            SpeculationLog log = map.get(getMetaspaceMethod());
-            if (log == null) {
-                log = new HotSpotSpeculationLog();
-                map.put(getMetaspaceMethod(), log);
-            }
-            return log;
-        }
+        long address = compilerToVM().getFailedSpeculationsAddress(this);
+        return new HotSpotSpeculationLog(address);
     }
 
     @Override
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java	Mon Mar 18 16:54:45 2019 -0700
@@ -35,7 +35,6 @@
 import java.lang.reflect.Modifier;
 import java.nio.ByteOrder;
 import java.util.HashMap;
-import java.util.Map;
 
 import jdk.vm.ci.common.JVMCIError;
 import jdk.vm.ci.meta.Assumptions.AssumptionResult;
@@ -50,7 +49,6 @@
 import jdk.vm.ci.meta.ResolvedJavaField;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.meta.SpeculationLog;
 import jdk.vm.ci.meta.UnresolvedJavaField;
 import jdk.vm.ci.meta.UnresolvedJavaType;
 
@@ -597,10 +595,6 @@
         runtime().compilerToVm.ensureInitialized(this);
     }
 
-    public Map<Long, SpeculationLog> getSpeculationLogs() {
-        return runtime().reflection.getSpeculationLogs(this);
-    }
-
     @Override
     public boolean equals(Object obj) {
         if (obj == this) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationEncoding.java	Mon Mar 18 16:54:45 2019 -0700
@@ -0,0 +1,197 @@
+/*
+ * 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;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.SpeculationLog.SpeculationReasonEncoding;
+
+/**
+ * Implements a {@link SpeculationReasonEncoding} that {@linkplain #getByteArray() produces} a byte
+ * array. Data is added via a {@link DataOutputStream}. When producing the final byte array, if the
+ * total length of data exceeds the length of a SHA-1 digest, then a SHA-1 digest of the data is
+ * produced instead.
+ */
+final class HotSpotSpeculationEncoding extends ByteArrayOutputStream implements SpeculationReasonEncoding {
+
+    private DataOutputStream dos = new DataOutputStream(this);
+    private byte[] result;
+
+    HotSpotSpeculationEncoding() {
+        super(SHA1_LENGTH);
+    }
+
+    private void checkOpen() {
+        if (result != null) {
+            throw new IllegalArgumentException("Cannot update closed speculation encoding");
+        }
+    }
+
+    private static final int NULL_METHOD = -1;
+    private static final int NULL_TYPE = -2;
+    private static final int NULL_STRING = -3;
+
+    @Override
+    public void addByte(int value) {
+        checkOpen();
+        try {
+            dos.writeByte(value);
+        } catch (IOException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    @Override
+    public void addShort(int value) {
+        checkOpen();
+        try {
+            dos.writeShort(value);
+        } catch (IOException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    @Override
+    public void addMethod(ResolvedJavaMethod method) {
+        if (!addNull(method, NULL_METHOD)) {
+            checkOpen();
+            if (method instanceof HotSpotResolvedJavaMethodImpl) {
+                try {
+                    dos.writeLong(((HotSpotResolvedJavaMethodImpl) method).getMetaspaceMethod());
+                } catch (IOException e) {
+                    throw new InternalError(e);
+                }
+            } else {
+                throw new IllegalArgumentException("Cannot encode unsupported type " + method.getClass().getName() + ": " + method.format("%H.%n(%p)"));
+            }
+        }
+    }
+
+    @Override
+    public void addType(ResolvedJavaType type) {
+        if (!addNull(type, NULL_TYPE)) {
+            checkOpen();
+            if (type instanceof HotSpotResolvedObjectTypeImpl) {
+                try {
+                    dos.writeLong(((HotSpotResolvedObjectTypeImpl) type).getMetaspaceKlass());
+                } catch (IOException e) {
+                    throw new InternalError(e);
+                }
+            } else {
+                throw new IllegalArgumentException("Cannot encode unsupported type " + type.getClass().getName() + ": " + type.toClassName());
+            }
+        }
+    }
+
+    @Override
+    public void addString(String value) {
+        if (!addNull(value, NULL_STRING)) {
+            checkOpen();
+            try {
+                dos.writeChars(value);
+            } catch (IOException e) {
+                throw new InternalError(e);
+            }
+        }
+    }
+
+    @Override
+    public void addInt(int value) {
+        checkOpen();
+        try {
+            dos.writeInt(value);
+        } catch (IOException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    @Override
+    public void addLong(long value) {
+        checkOpen();
+        try {
+            dos.writeLong(value);
+        } catch (IOException e) {
+            throw new InternalError(e);
+        }
+    }
+
+    private boolean addNull(Object o, int nullValue) {
+        if (o == null) {
+            addInt(nullValue);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Prototype SHA1 digest that is cloned before use.
+     */
+    private static final MessageDigest SHA1 = getSHA1();
+    private static final int SHA1_LENGTH = SHA1.getDigestLength();
+
+    private static MessageDigest getSHA1() {
+        try {
+            MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
+            sha1.clone();
+            return sha1;
+        } catch (CloneNotSupportedException | NoSuchAlgorithmException e) {
+            // Should never happen given that SHA-1 is mandated in a
+            // compliant Java platform implementation.
+            throw new JVMCIError("Expect a cloneable implementation of a SHA-1 message digest to be available", e);
+        }
+    }
+
+    /**
+     * Gets the final encoded byte array and closes this encoding such that any further attempts to
+     * update it result in an {@link IllegalArgumentException}.
+     */
+    byte[] getByteArray() {
+        if (result == null) {
+            if (count > SHA1_LENGTH) {
+                try {
+                    MessageDigest md = (MessageDigest) SHA1.clone();
+                    md.update(buf, 0, count);
+                    result = md.digest();
+                } catch (CloneNotSupportedException e) {
+                    throw new InternalError(e);
+                }
+            } else {
+                if (buf.length == count) {
+                    // No need to copy the byte array
+                    return buf;
+                }
+                result = Arrays.copyOf(buf, count);
+            }
+            dos = null;
+        }
+        return result;
+    }
+}
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java	Mon Mar 18 16:54:45 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -22,98 +22,340 @@
  */
 package jdk.vm.ci.hotspot;
 
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Formatter;
+import java.util.List;
+
+import jdk.vm.ci.code.BailoutException;
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.SpeculationLog;
 
+/**
+ * Implements a {@link SpeculationLog} that can be used to:
+ * <ul>
+ * <li>Query failed speculations recorded in a native linked list of {@code FailedSpeculation}s (see
+ * methodData.hpp).</li>
+ * <li>Make speculations during compilation and record them in compiled code. This must only be done
+ * on compilation-local {@link HotSpotSpeculationLog} objects.</li>
+ * </ul>
+ *
+ * The choice of constructor determines whether the native failed speculations list is
+ * {@linkplain #managesFailedSpeculations() managed} by a {@link HotSpotSpeculationLog} object.
+ */
 public class HotSpotSpeculationLog implements SpeculationLog {
+
+    private static final byte[] NO_FLATTENED_SPECULATIONS = {};
+
+    /**
+     * Creates a speculation log that manages a failed speculation list. That is, when this object
+     * dies, the native resources of the list are freed.
+     *
+     * @see #managesFailedSpeculations()
+     * @see #getFailedSpeculationsAddress()
+     */
+    public HotSpotSpeculationLog() {
+        managesFailedSpeculations = true;
+    }
+
+    /**
+     * Creates a speculation log that reads from an externally managed failed speculation list. That
+     * is, the lifetime of the list is independent of this object.
+     *
+     * @param failedSpeculationsAddress an address in native memory at which the pointer to the
+     *            externally managed sailed speculation list resides
+     */
+    public HotSpotSpeculationLog(long failedSpeculationsAddress) {
+        if (failedSpeculationsAddress == 0) {
+            throw new IllegalArgumentException("failedSpeculationsAddress cannot be 0");
+        }
+        this.failedSpeculationsAddress = failedSpeculationsAddress;
+        managesFailedSpeculations = false;
+    }
+
+    /**
+     * Gets the address of the pointer to the native failed speculations list.
+     *
+     * @see #managesFailedSpeculations()
+     */
+    public long getFailedSpeculationsAddress() {
+        if (managesFailedSpeculations) {
+            synchronized (this) {
+                if (failedSpeculationsAddress == 0L) {
+                    failedSpeculationsAddress = UnsafeAccess.UNSAFE.allocateMemory(HotSpotJVMCIRuntime.getHostWordKind().getByteCount());
+                    UnsafeAccess.UNSAFE.putAddress(failedSpeculationsAddress, 0L);
+                    LogCleaner c = new LogCleaner(this, failedSpeculationsAddress);
+                    assert c.address == failedSpeculationsAddress;
+                }
+            }
+        }
+        return failedSpeculationsAddress;
+    }
+
+    /**
+     * Adds {@code speculation} to the native list of failed speculations. To update this object's
+     * view of the failed speculations, {@link #collectFailedSpeculations()} must be called after
+     * this method returns.
+     *
+     * This method exists primarily for testing purposes. Speculations are normally only added to
+     * the list by HotSpot during deoptimization.
+     *
+     * @return {@code false} if the speculation could not be appended to the list
+     */
+    public boolean addFailedSpeculation(Speculation speculation) {
+        return compilerToVM().addFailedSpeculation(getFailedSpeculationsAddress(), ((HotSpotSpeculation) speculation).encoding);
+    }
+
+    /**
+     * Returns {@code true} if the value returned by {@link #getFailedSpeculationsAddress()} is only
+     * valid only as long as this object is alive, {@code false} otherwise.
+     */
+    public boolean managesFailedSpeculations() {
+        return managesFailedSpeculations;
+    }
+
     public static final class HotSpotSpeculation extends Speculation {
-        private JavaConstant encoding;
 
-        HotSpotSpeculation(SpeculationReason reason, JavaConstant encoding) {
+        /**
+         * A speculation id is a long encoding an offset (high 32 bits) and a length (low 32 bts).
+         * Combined, the index and length denote where the {@linkplain #encoding encoded
+         * speculation} is in a {@linkplain HotSpotSpeculationLog#getFlattenedSpeculations
+         * flattened} speculations array.
+         */
+        private final JavaConstant id;
+
+        private final byte[] encoding;
+
+        HotSpotSpeculation(SpeculationReason reason, JavaConstant id, byte[] encoding) {
             super(reason);
+            this.id = id;
             this.encoding = encoding;
         }
 
         public JavaConstant getEncoding() {
-            return encoding;
+            return id;
+        }
+
+        @Override
+        public String toString() {
+            long indexAndLength = id.asLong();
+            int index = decodeIndex(indexAndLength);
+            int length = decodeLength(indexAndLength);
+            return String.format("{0x%016x[index: %d, len: %d, hash: 0x%x]: %s}", indexAndLength, index, length, Arrays.hashCode(encoding), getReason());
         }
     }
 
-    /** Written by the C++ code that performs deoptimization. */
-    private volatile long lastFailed;
+    /**
+     * Address of a pointer to a set of failed speculations. The address is recorded in the nmethod
+     * compiled with this speculation log such that when it fails a speculation, the speculation is
+     * added to the list.
+     */
+    private long failedSpeculationsAddress;
 
-    /** All speculations that have caused a deoptimization. */
-    private Set<SpeculationReason> failedSpeculations;
+    private final boolean managesFailedSpeculations;
 
-    /** Strong references to all reasons embedded in the current nmethod. */
-    private HashMap<SpeculationReason, JavaConstant> speculations;
+    /**
+     * The list of failed speculations read from native memory via
+     * {@link CompilerToVM#getFailedSpeculations}.
+     */
+    private byte[][] failedSpeculations;
 
-    private long currentSpeculationID;
+    /**
+     * Speculations made during the compilation associated with this log.
+     */
+    private List<byte[]> speculations;
+    private List<SpeculationReason> speculationReasons;
 
     @Override
-    public synchronized void collectFailedSpeculations() {
-        if (lastFailed != 0) {
-            if (failedSpeculations == null) {
-                failedSpeculations = new HashSet<>(2);
-            }
-            if (speculations != null) {
-                SpeculationReason lastFailedSpeculation = lookupSpeculation(this.lastFailed);
-                if (lastFailedSpeculation != null) {
-                    failedSpeculations.add(lastFailedSpeculation);
-                }
-                lastFailed = 0;
-                speculations = null;
-            }
+    public void collectFailedSpeculations() {
+        if (failedSpeculationsAddress != 0 && UnsafeAccess.UNSAFE.getLong(failedSpeculationsAddress) != 0) {
+            failedSpeculations = compilerToVM().getFailedSpeculations(failedSpeculationsAddress, failedSpeculations);
+            assert failedSpeculations.getClass() == byte[][].class;
         }
     }
 
-    private SpeculationReason lookupSpeculation(long value) {
-        for (Map.Entry<SpeculationReason, JavaConstant> entry : speculations.entrySet()) {
-            if (value == entry.getValue().asLong()) {
-                return entry.getKey();
+    byte[] getFlattenedSpeculations(boolean validate) {
+        if (speculations == null) {
+            return NO_FLATTENED_SPECULATIONS;
+        }
+        if (validate) {
+            int newFailuresStart = failedSpeculations == null ? 0 : failedSpeculations.length;
+            collectFailedSpeculations();
+            if (failedSpeculations != null && failedSpeculations.length != newFailuresStart) {
+                for (SpeculationReason reason : speculationReasons) {
+                    byte[] encoding = encode(reason);
+                    // Only check against new failures
+                    if (contains(failedSpeculations, newFailuresStart, encoding)) {
+                        throw new BailoutException(false, "Speculation failed: " + reason);
+                    }
+                }
             }
         }
-        return null;
+        int size = 0;
+        for (byte[] s : speculations) {
+            size += s.length;
+        }
+        byte[] result = new byte[size];
+        size = 0;
+        for (byte[] s : speculations) {
+            System.arraycopy(s, 0, result, size, s.length);
+            size += s.length;
+        }
+        return result;
     }
 
     @Override
-    public synchronized boolean maySpeculate(SpeculationReason reason) {
-        if (failedSpeculations != null && failedSpeculations.contains(reason)) {
-            return false;
+    public boolean maySpeculate(SpeculationReason reason) {
+        if (failedSpeculations == null) {
+            collectFailedSpeculations();
+        }
+        if (failedSpeculations != null && failedSpeculations.length != 0) {
+            byte[] encoding = encode(reason);
+            return !contains(failedSpeculations, 0, encoding);
         }
         return true;
     }
 
-    @Override
-    public synchronized Speculation speculate(SpeculationReason reason) {
-        if (speculations == null) {
-            speculations = new HashMap<>();
+    /**
+     * @return {@code true} if {@code needle} is in {@code haystack[fromIndex..haystack.length-1]}
+     */
+    private static boolean contains(byte[][] haystack, int fromIndex, byte[] needle) {
+        for (int i = fromIndex; i < haystack.length; i++) {
+            byte[] fs = haystack[i];
+
+            if (Arrays.equals(fs, needle)) {
+                return true;
+            }
         }
-        JavaConstant id = speculations.get(reason);
-        if (id == null) {
-            id = JavaConstant.forLong(++currentSpeculationID);
-            speculations.put(reason, id);
-        }
-        return new HotSpotSpeculation(reason, id);
+        return false;
+    }
+
+    private static long encodeIndexAndLength(int index, int length) {
+        return ((long) index) << 32 | length;
+    }
+
+    private static int decodeIndex(long indexAndLength) {
+        return (int) (indexAndLength >>> 32);
+    }
+
+    private static int decodeLength(long indexAndLength) {
+        return (int) indexAndLength & 0xFFFFFFFF;
     }
 
     @Override
-    public synchronized boolean hasSpeculations() {
-        return speculations != null && !speculations.isEmpty();
+    public Speculation speculate(SpeculationReason reason) {
+        byte[] encoding = encode(reason);
+        JavaConstant id;
+        if (speculations == null) {
+            speculations = new ArrayList<>();
+            speculationReasons = new ArrayList<>();
+            id = JavaConstant.forLong(encodeIndexAndLength(0, encoding.length));
+            speculations.add(encoding);
+            speculationReasons.add(reason);
+        } else {
+            id = null;
+            int flattenedIndex = 0;
+            for (byte[] fs : speculations) {
+                if (Arrays.equals(fs, encoding)) {
+                    id = JavaConstant.forLong(encodeIndexAndLength(flattenedIndex, fs.length));
+                    break;
+                }
+                flattenedIndex += fs.length;
+            }
+            if (id == null) {
+                id = JavaConstant.forLong(encodeIndexAndLength(flattenedIndex, encoding.length));
+                speculations.add(encoding);
+                speculationReasons.add(reason);
+            }
+        }
+
+        return new HotSpotSpeculation(reason, id, encoding);
+    }
+
+    private static byte[] encode(SpeculationReason reason) {
+        HotSpotSpeculationEncoding encoding = (HotSpotSpeculationEncoding) reason.encode(HotSpotSpeculationEncoding::new);
+        byte[] result = encoding == null ? null : encoding.getByteArray();
+        if (result == null) {
+            throw new IllegalArgumentException(HotSpotSpeculationLog.class.getName() + " expects " + reason.getClass().getName() + ".encode() to return a non-empty encoding");
+        }
+        return result;
     }
 
     @Override
-    public synchronized Speculation lookupSpeculation(JavaConstant constant) {
+    public boolean hasSpeculations() {
+        return speculations != null;
+    }
+
+    @Override
+    public Speculation lookupSpeculation(JavaConstant constant) {
         if (constant.isDefaultForKind()) {
             return NO_SPECULATION;
         }
-        SpeculationReason reason = lookupSpeculation(constant.asLong());
-        assert reason != null : "Speculation should have been registered";
-        return new HotSpotSpeculation(reason, constant);
+        int flattenedIndex = decodeIndex(constant.asLong());
+        int index = 0;
+        for (byte[] s : speculations) {
+            if (flattenedIndex == 0) {
+                SpeculationReason reason = speculationReasons.get(index);
+                return new HotSpotSpeculation(reason, constant, s);
+            }
+            index++;
+            flattenedIndex -= s.length;
+        }
+        throw new IllegalArgumentException("Unknown encoded speculation: " + constant);
+    }
+
+    @Override
+    public String toString() {
+        Formatter buf = new Formatter();
+        buf.format("{managed:%s, failedSpeculationsAddress:0x%x, failedSpeculations:[", managesFailedSpeculations, failedSpeculationsAddress);
+
+        String sep = "";
+        if (failedSpeculations != null) {
+            for (int i = 0; i < failedSpeculations.length; i++) {
+                buf.format("%s{len:%d, hash:0x%x}", sep, failedSpeculations[i].length, Arrays.hashCode(failedSpeculations[i]));
+                sep = ", ";
+            }
+        }
+
+        buf.format("], speculations:[");
+
+        int size = 0;
+        if (speculations != null) {
+            sep = "";
+            for (int i = 0; i < speculations.size(); i++) {
+                byte[] s = speculations.get(i);
+                size += s.length;
+                buf.format("%s{len:%d, hash:0x%x, reason:{%s}}", sep, s.length, Arrays.hashCode(s), speculationReasons.get(i));
+                sep = ", ";
+            }
+        }
+        buf.format("], len:%d, hash:0x%x}", size, Arrays.hashCode(getFlattenedSpeculations(false)));
+        return buf.toString();
+    }
+
+    /**
+     * Frees the native memory resources associated with {@link HotSpotSpeculationLog}s once they
+     * become reclaimable.
+     */
+    private static final class LogCleaner extends Cleaner {
+
+        LogCleaner(HotSpotSpeculationLog referent, long address) {
+            super(referent);
+            this.address = address;
+        }
+
+        @Override
+        void doCleanup() {
+            long pointer = UnsafeAccess.UNSAFE.getAddress(address);
+            if (pointer != 0) {
+                compilerToVM().releaseFailedSpeculations(address);
+            }
+            UnsafeAccess.UNSAFE.freeMemory(address);
+        }
+
+        final long address;
     }
 }
+
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java	Mon Mar 18 16:54:45 2019 -0700
@@ -25,6 +25,7 @@
 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
 
+import jdk.vm.ci.services.Services;
 import jdk.internal.misc.Unsafe;
 
 /**
@@ -52,7 +53,7 @@
      * {@linkplain HotSpotJVMCIBackendFactory backend}.
      */
     String getHostArchitectureName() {
-        String arch = System.getProperty("os.arch");
+        String arch = Services.getSavedProperties().get("os.arch");
         switch (arch) {
             case "x86_64":
                 return "amd64";
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigAccess.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigAccess.java	Mon Mar 18 16:54:45 2019 -0700
@@ -22,6 +22,9 @@
  */
 package jdk.vm.ci.hotspot;
 
+import java.util.Set;
+import java.util.stream.Collectors;
+
 import jdk.vm.ci.common.JVMCIError;
 
 /**
@@ -50,8 +53,8 @@
             if (notPresent != null) {
                 return notPresent;
             }
-            store.printConfig();
-            throw new JVMCIError("expected VM symbol not found in " + store + ": " + name);
+            throw missingEntry("address", name, store.vmFlags.keySet());
+
         }
         return entry;
     }
@@ -82,8 +85,7 @@
             if (notPresent != null) {
                 return notPresent;
             }
-            store.printConfig();
-            throw new JVMCIError("expected VM constant not found in " + store + ": " + name);
+            throw missingEntry("constant", name, store.vmConstants.keySet());
         }
         return type.cast(convertValue(name, type, c, null));
     }
@@ -112,15 +114,23 @@
      * @throws JVMCIError if the field is static or not present and {@code notPresent} is null
      */
     public <T> T getFieldOffset(String name, Class<T> type, String cppType, T notPresent) {
-        assert type == Integer.class || type == Long.class;
-        VMField entry = getField(name, cppType, notPresent == null);
-        if (entry == null) {
-            return notPresent;
-        }
-        if (entry.address != 0) {
-            throw new JVMCIError("cannot get offset of static field " + name);
-        }
-        return type.cast(convertValue(name, type, entry.offset, cppType));
+        return getFieldOffset0(name, type, notPresent, cppType, null);
+    }
+
+    /**
+     * Gets the offset of a non-static C++ field.
+     *
+     * @param name fully qualified name of the field
+     * @param type the boxed type to which the offset value will be converted (must be
+     *            {@link Integer} or {@link Long})
+     * @param notPresent if non-null and the field is not present then this value is returned
+     * @param outCppType if non-null, the C++ type of the field (e.g., {@code "HeapWord*"}) is
+     *            returned in element 0 of this array
+     * @return the offset in bytes of the requested field
+     * @throws JVMCIError if the field is static or not present and {@code notPresent} is null
+     */
+    public <T> T getFieldOffset(String name, Class<T> type, T notPresent, String[] outCppType) {
+        return getFieldOffset0(name, type, notPresent, null, outCppType);
     }
 
     /**
@@ -134,7 +144,7 @@
      * @throws JVMCIError if the field is static or not present
      */
     public <T> T getFieldOffset(String name, Class<T> type, String cppType) {
-        return getFieldOffset(name, type, cppType, null);
+        return getFieldOffset0(name, type, null, cppType, null);
     }
 
     /**
@@ -147,7 +157,22 @@
      * @throws JVMCIError if the field is static or not present
      */
     public <T> T getFieldOffset(String name, Class<T> type) {
-        return getFieldOffset(name, type, null, null);
+        return getFieldOffset0(name, type, null, null, null);
+    }
+
+    private <T> T getFieldOffset0(String name, Class<T> type, T notPresent, String inCppType, String[] outCppType) {
+        assert type == Integer.class || type == Long.class;
+        VMField entry = getField(name, inCppType, notPresent == null);
+        if (entry == null) {
+            return notPresent;
+        }
+        if (entry.address != 0) {
+            throw new JVMCIError("cannot get offset of static field " + name);
+        }
+        if (outCppType != null) {
+            outCppType[0] = entry.type;
+        }
+        return type.cast(convertValue(name, type, entry.offset, inCppType));
     }
 
     /**
@@ -160,14 +185,21 @@
      * @throws JVMCIError if the field is not static or not present and {@code notPresent} is null
      */
     public long getFieldAddress(String name, String cppType, Long notPresent) {
-        VMField entry = getField(name, cppType, notPresent == null);
-        if (entry == null) {
-            return notPresent;
-        }
-        if (entry.address == 0) {
-            throw new JVMCIError(name + " is not a static field");
-        }
-        return entry.address;
+        return getFieldAddress0(name, notPresent, cppType, null);
+    }
+
+    /**
+     * Gets the address of a static C++ field.
+     *
+     * @param name fully qualified name of the field
+     * @param notPresent if non-null and the field is not present then this value is returned
+     * @param outCppType if non-null, the C++ type of the field (e.g., {@code "HeapWord*"}) is
+     *            returned in element 0 of this array
+     * @return the address of the requested field
+     * @throws JVMCIError if the field is not static or not present and {@code notPresent} is null
+     */
+    public long getFieldAddress(String name, Long notPresent, String[] outCppType) {
+        return getFieldAddress0(name, notPresent, null, outCppType);
     }
 
     /**
@@ -179,7 +211,21 @@
      * @throws JVMCIError if the field is not static or not present
      */
     public long getFieldAddress(String name, String cppType) {
-        return getFieldAddress(name, cppType, null);
+        return getFieldAddress0(name, null, cppType, null);
+    }
+
+    private long getFieldAddress0(String name, Long notPresent, String inCppType, String[] outCppType) {
+        VMField entry = getField(name, inCppType, notPresent == null);
+        if (entry == null) {
+            return notPresent;
+        }
+        if (entry.address == 0) {
+            throw new JVMCIError(name + " is not a static field");
+        }
+        if (outCppType != null) {
+            outCppType[0] = entry.type;
+        }
+        return entry.address;
     }
 
     /**
@@ -193,14 +239,7 @@
      * @throws JVMCIError if the field is not static or not present and {@code notPresent} is null
      */
     public <T> T getFieldValue(String name, Class<T> type, String cppType, T notPresent) {
-        VMField entry = getField(name, cppType, notPresent == null);
-        if (entry == null) {
-            return notPresent;
-        }
-        if (entry.value == null) {
-            throw new JVMCIError(name + " is not a static field ");
-        }
-        return type.cast(convertValue(name, type, entry.value, cppType));
+        return getFieldValue0(name, type, notPresent, cppType, null);
     }
 
     /**
@@ -213,7 +252,22 @@
      * @throws JVMCIError if the field is not static or not present
      */
     public <T> T getFieldValue(String name, Class<T> type, String cppType) {
-        return getFieldValue(name, type, cppType, null);
+        return getFieldValue0(name, type, null, cppType, null);
+    }
+
+    /**
+     * Gets the value of a static C++ field.
+     *
+     * @param name fully qualified name of the field
+     * @param type the boxed type to which the constant value will be converted
+     * @param notPresent if non-null and the field is not present then this value is returned
+     * @param outCppType if non-null, the C++ type of the field (e.g., {@code "HeapWord*"}) is
+     *            returned in element 0 of this array
+     * @return the value of the requested field
+     * @throws JVMCIError if the field is not static or not present and {@code notPresent} is null
+     */
+    public <T> T getFieldValue(String name, Class<T> type, T notPresent, String[] outCppType) {
+        return getFieldValue0(name, type, notPresent, null, outCppType);
     }
 
     /**
@@ -225,7 +279,21 @@
      * @throws JVMCIError if the field is not static or not present
      */
     public <T> T getFieldValue(String name, Class<T> type) {
-        return getFieldValue(name, type, null, null);
+        return getFieldValue0(name, type, null, null, null);
+    }
+
+    private <T> T getFieldValue0(String name, Class<T> type, T notPresent, String inCppType, String[] outCppType) {
+        VMField entry = getField(name, inCppType, notPresent == null);
+        if (entry == null) {
+            return notPresent;
+        }
+        if (entry.value == null) {
+            throw new JVMCIError(name + " is not a static field ");
+        }
+        if (outCppType != null) {
+            outCppType[0] = entry.type;
+        }
+        return type.cast(convertValue(name, type, entry.value, inCppType));
     }
 
     /**
@@ -243,8 +311,7 @@
             if (!required) {
                 return null;
             }
-            store.printConfig();
-            throw new JVMCIError("expected VM field not found in " + store + ": " + name);
+            throw missingEntry("field", name, store.vmFields.keySet());
         }
 
         // Make sure the native type is still the type we expect.
@@ -288,8 +355,7 @@
                 if (notPresent != null) {
                     return notPresent;
                 }
-                store.printConfig();
-                throw new JVMCIError("expected VM flag not found in " + store + ": " + name);
+                throw missingEntry("flag", name, store.vmFlags.keySet());
             } else {
                 cppType = null;
             }
@@ -300,6 +366,11 @@
         return type.cast(convertValue(name, type, value, cppType));
     }
 
+    private JVMCIError missingEntry(String category, String name, Set<String> keys) {
+        throw new JVMCIError("expected VM %s not found in %s: %s%nAvailable values:%n    %s", category, store, name,
+                        keys.stream().sorted().collect(Collectors.joining(System.lineSeparator() + "    ")));
+    }
+
     private static <T> Object convertValue(String name, Class<T> toType, Object value, String cppType) throws JVMCIError {
         if (toType == Boolean.class) {
             if (value instanceof String) {
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java	Mon Mar 18 16:54:45 2019 -0700
@@ -22,6 +22,8 @@
  */
 package jdk.vm.ci.hotspot;
 
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
+
 import jdk.vm.ci.meta.JavaConstant;
 
 final class IndirectHotSpotObjectConstantImpl extends HotSpotObjectConstantImpl {
@@ -29,6 +31,7 @@
      * An object handle in {@code JVMCI::_jvmci_handles}.
      */
     final long objectHandle;
+    private int hashCode;
 
     final IndirectHotSpotObjectConstantImpl base;
 
@@ -64,4 +67,17 @@
         assert compressed;
         return new IndirectHotSpotObjectConstantImpl(this, false);
     }
+
+    @Override
+    public int getIdentityHashCode() {
+        int hash = hashCode;
+        if (hash == 0) {
+            hash = runtime().compilerToVm.getIdentityHashCode(this);
+            if (hash == 0) {
+                hash = 31;
+            }
+            hashCode = hash;
+        }
+        return hash;
+    }
 }
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java	Mon Mar 18 16:54:45 2019 -0700
@@ -27,15 +27,11 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Array;
 import java.lang.reflect.Type;
-import java.util.HashMap;
-import java.util.Map;
 
-import jdk.vm.ci.common.NativeImageReinitialize;
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.meta.SpeculationLog;
 
 /**
  * Implementation of {@link HotSpotJVMCIReflection} when running in a JVMCI shared library.
@@ -99,20 +95,6 @@
         return javaConstant;
     }
 
-    @NativeImageReinitialize private static HashMap<Long, HashMap<Long, SpeculationLog>> speculationLogs;
-
-    @Override
-    synchronized Map<Long, SpeculationLog> getSpeculationLogs(HotSpotResolvedObjectTypeImpl holder) {
-        if (speculationLogs == null) {
-            speculationLogs = new HashMap<>();
-        }
-        Map<Long, SpeculationLog> log = speculationLogs.get(holder.getMetaspaceKlass());
-        if (log == null) {
-            log = new HashMap<>(4);
-        }
-        return log;
-    }
-
     @Override
     boolean equals(HotSpotObjectConstantImpl x, HotSpotObjectConstantImpl y) {
         if (x == y) {
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMEntryPoint.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMEntryPoint.java	Mon Mar 18 16:54:45 2019 -0700
@@ -25,7 +25,7 @@
 /**
  * Marker interface for methods which are called from the JVM.
  */
-public @interface VMEntryPoint {
+@interface VMEntryPoint {
     /**
      * An optional comment describing the caller.
      */
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java	Mon Mar 18 16:54:45 2019 -0700
@@ -102,14 +102,25 @@
      */
     JavaConstant encodeDeoptActionAndReason(DeoptimizationAction action, DeoptimizationReason reason, int debugId);
 
+    /**
+     * Gets a constant that denotes {@code speculation}. The constant can passed to the
+     * deoptimization handler (e.g., through a thread local) to indicate a failed speculation.
+     */
     JavaConstant encodeSpeculation(Speculation speculation);
 
+    /**
+     * Decodes {@code constant} back to a {@link Speculation} object.
+     *
+     * @throws IllegalArgumentException if {@code constant} can only be decoded through a
+     *             {@link SpeculationLog} and {@code speculationLog} does not contain the
+     *             speculation denoted by {@code constant}
+     */
+    Speculation decodeSpeculation(JavaConstant constant, SpeculationLog speculationLog);
+
     DeoptimizationReason decodeDeoptReason(JavaConstant constant);
 
     DeoptimizationAction decodeDeoptAction(JavaConstant constant);
 
-    Speculation decodeSpeculation(JavaConstant constant, SpeculationLog speculationLog);
-
     int decodeDebugId(JavaConstant constant);
 
     int getArrayBaseOffset(JavaKind elementKind);
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java	Mon Mar 18 16:54:45 2019 -0700
@@ -38,7 +38,8 @@
     /**
      * Returns the bytecode of this method, if the method has code. The returned byte array does not
      * contain breakpoints or non-Java bytecodes. This may return null if the
-     * {@link #getDeclaringClass() holder} is not {@link ResolvedJavaType#isLinked() linked}.
+     * {@linkplain #getDeclaringClass() declaring class} is not
+     * {@linkplain ResolvedJavaType#isLinked() linked}.
      *
      * The contained constant pool indices may not be the ones found in the original class file but
      * they can be used with the JVMCI API (e.g. methods in {@link ConstantPool}).
@@ -438,13 +439,15 @@
     }
 
     /**
-     * Checks whether the method has bytecodes associated with it. Methods without bytecodes are
-     * either abstract or native methods.
+     * Checks whether the method has bytecodes associated with it. Note that even if this method
+     * returns {@code true}, {@link #getCode} can return {@code null} if
+     * {@linkplain #getDeclaringClass() declaring class} is not
+     * {@linkplain ResolvedJavaType#isLinked() linked}.
      *
-     * @return whether the definition of this method is Java bytecodes
+     * @return {@code this.getCodeSize() != 0}
      */
     default boolean hasBytecodes() {
-        return isConcrete() && !isNative();
+        return getCodeSize() != 0;
     }
 
     /**
@@ -463,5 +466,11 @@
         return getDeclaringClass().isJavaLangObject() && getName().equals("<init>");
     }
 
+    /**
+     * Gets a speculation log that can be used when compiling this method to make new speculations
+     * and query previously failed speculations. The implementation may return a new
+     * {@link SpeculationLog} object each time this method is called so its the caller's
+     * responsibility to ensure the same speculation log is used throughout a compilation.
+     */
     SpeculationLog getSpeculationLog();
 }
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SpeculationLog.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SpeculationLog.java	Mon Mar 18 16:54:45 2019 -0700
@@ -22,19 +22,72 @@
  */
 package jdk.vm.ci.meta;
 
+import java.util.Map;
+import java.util.function.Supplier;
+
 /**
- * Manages unique deoptimization reasons. Reasons are embedded in compiled code and can be
- * invalidated at run time. Subsequent compilations then should not speculate again on such
- * invalidated reasons to avoid repeated deoptimization.
- *
- * All methods of this interface are called by the compiler. There is no need for API to register
- * failed speculations during deoptimization, since every VM has different needs there.
+ * Manages unique {@link SpeculationReason} objects that denote why a deoptimization occurred.
+ * Reasons are embedded in compiled code for a method. If the compiled code deoptimizes at a
+ * position associated with a {@link SpeculationReason}, the reason is added to a set of failed
+ * speculations associated with the method. A subsequent compilation of the method can query the
+ * failed speculations via a {@link SpeculationLog} to avoid making a speculation based on
+ * invalidated reasons. This avoids repeated deoptimizations.
  */
 public interface SpeculationLog {
     /**
-     * Marker interface for speculation objects that can be added to the speculation log.
+     * The specific attributes of a speculation that a compiler uses to denote a speculation in a
+     * compiled method. Typical attributes of a speculation are a bytecode position, type
+     * information about a variable being speculated on and an enum denoting the type of operation
+     * to which the speculation applies. A {@link SpeculationReason} is used as a key in a
+     * {@link Map} and so it must implement {@link Object#equals(Object)} and
+     * {@link Object#hashCode()} in terms of its attributes.
+     *
+     * A JVMCI implementation may serialize speculations for storage off heap (e.g. in native memory
+     * associated with an nmethod). For this reason, the attributes of a {@link SpeculationReason}
+     * are restricted to those supported by the {@code add...} methods of
+     * {@link SpeculationReasonEncoding}.
      */
     public interface SpeculationReason {
+
+        /**
+         * Encodes the attributes of this reason using a {@link SpeculationReasonEncoding}. For
+         * efficiency, a {@link SpeculationReason} implementation should cache the returned value
+         * and return it for all subsequent calls to this method. This also underlines the
+         * requirement that the encoding for a specific reason instance should be stable.
+         *
+         * @param encodingSupplier source of a {@link SpeculationReasonEncoding}
+         * @return a {@link SpeculationReasonEncoding} that encodes all the attributes that uniquely
+         *         identify this reason
+         */
+        default SpeculationReasonEncoding encode(Supplier<SpeculationReasonEncoding> encodingSupplier) {
+            return null;
+        }
+    }
+
+    /**
+     * Provides a facility for encoding the attributes of a {@link SpeculationReason}. The encoding
+     * format is determined by the implementation of this interface.
+     */
+    public interface SpeculationReasonEncoding {
+        void addByte(int value);
+
+        void addShort(int value);
+
+        void addInt(int value);
+
+        void addLong(long value);
+
+        void addMethod(ResolvedJavaMethod method);
+
+        void addType(ResolvedJavaType type);
+
+        void addString(String value);
+
+        default void addField(ResolvedJavaField field) {
+            addType(field.getDeclaringClass());
+            addInt(field.getModifiers());
+            addInt(field.getOffset());
+        }
     }
 
     /**
@@ -44,7 +97,7 @@
     }
 
     class Speculation {
-        private SpeculationReason reason;
+        private final SpeculationReason reason;
 
         public Speculation(SpeculationReason reason) {
             this.reason = reason;
@@ -77,7 +130,8 @@
     Speculation NO_SPECULATION = new Speculation(new NoSpeculationReason());
 
     /**
-     * Must be called before compilation, i.e., before a compiler calls {@link #maySpeculate}.
+     * Updates the set of failed speculations recorded in this log. This must be called before
+     * compilation.
      */
     void collectFailedSpeculations();
 
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java	Mon Mar 18 16:54:45 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -22,7 +22,11 @@
  */
 package jdk.vm.ci.services;
 
-import java.lang.reflect.Method;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Formatter;
@@ -69,8 +73,8 @@
     private Services() {
     }
 
-    static final Map<String, String> SAVED_PROPERTIES = VM.getSavedProperties();
-    static final boolean JVMCI_ENABLED = Boolean.parseBoolean(SAVED_PROPERTIES.get("jdk.internal.vm.ci.enabled"));
+    private static volatile Map<String, String> savedProperties = VM.getSavedProperties();
+    static final boolean JVMCI_ENABLED = Boolean.parseBoolean(savedProperties.get("jdk.internal.vm.ci.enabled"));
 
     /**
      * Checks that JVMCI is enabled in the VM and throws an error if it isn't.
@@ -90,7 +94,7 @@
         if (sm != null) {
             sm.checkPermission(new JVMCIPermission());
         }
-        return SAVED_PROPERTIES;
+        return savedProperties;
     }
 
     /**
@@ -236,8 +240,9 @@
             singleProvider = provider;
         }
         if (singleProvider == null && required) {
-            String javaHome = System.getProperty("java.home");
-            String vmName = System.getProperty("java.vm.name");
+            Map<String, String> savedProps = getSavedProperties();
+            String javaHome = savedProps.get("java.home");
+            String vmName = savedProps.get("java.vm.name");
             Formatter errorMessage = new Formatter();
             errorMessage.format("The VM does not expose required service %s.%n", service.getName());
             errorMessage.format("Currently used Java home directory is %s.%n", javaHome);
@@ -264,4 +269,56 @@
         return ClassLoader.getSystemClassLoader();
     }
 
+    /**
+     * 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.
+     */
+    @VMEntryPoint
+    private static byte[] serializeSavedProperties() throws IOException {
+        if (IS_IN_NATIVE_IMAGE) {
+            throw new InternalError("Can only serialize saved properties in HotSpot runtime");
+        }
+        Map<String, String> props = Services.getSavedProperties();
+
+        // Compute size of output on the assumption that
+        // all system properties have ASCII names and values
+        int estimate = 4;
+        for (Map.Entry<String, String> e : props.entrySet()) {
+            String name = e.getKey();
+            String value = e.getValue();
+            estimate += (2 + (name.length())) + (2 + (value.length()));
+        }
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(estimate);
+        DataOutputStream out = new DataOutputStream(baos);
+        out.writeInt(props.size());
+        for (Map.Entry<String, String> e : props.entrySet()) {
+            String name = e.getKey();
+            String value = e.getValue();
+            out.writeUTF(name);
+            out.writeUTF(value);
+        }
+        return baos.toByteArray();
+    }
+
+    /**
+     * Initialized the {@linkplain #getSavedProperties() saved system properties} in the JVMCI
+     * shared library from the {@linkplain #serializeSavedProperties() serialized saved properties}
+     * in the HotSpot runtime.
+     */
+    @VMEntryPoint
+    private static void initializeSavedProperties(byte[] serializedProperties) throws IOException {
+        if (!IS_IN_NATIVE_IMAGE) {
+            throw new InternalError("Can only initialize saved properties in JVMCI shared library runtime");
+        }
+        DataInputStream in = new DataInputStream(new ByteArrayInputStream(serializedProperties));
+        Map<String, String> props = new HashMap<>(in.readInt());
+        while (in.available() != 0) {
+            String name = in.readUTF();
+            String value = in.readUTF();
+            props.put(name, value);
+        }
+        savedProperties = Collections.unmodifiableMap(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/VMEntryPoint.java	Mon Mar 18 16:54:45 2019 -0700
@@ -0,0 +1,33 @@
+/*
+ * 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.services;
+
+/**
+ * Marker interface for methods which are called from the JVM.
+ */
+@interface VMEntryPoint {
+    /**
+     * An optional comment describing the caller.
+     */
+    String value() default "";
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java	Mon Mar 18 16:54:45 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -34,8 +34,16 @@
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
 
+import org.graalvm.compiler.serviceprovider.SpeculationReasonGroup.SpeculationContextObject;
+
+import jdk.vm.ci.code.BytecodePosition;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.meta.SpeculationLog.SpeculationReason;
+import jdk.vm.ci.meta.SpeculationLog.SpeculationReasonEncoding;
 import jdk.vm.ci.runtime.JVMCI;
 import jdk.vm.ci.services.JVMCIPermission;
 import jdk.vm.ci.services.Services;
@@ -179,6 +187,7 @@
         final int groupId;
         final String groupName;
         final Object[] context;
+        private SpeculationReasonEncoding encoding;
 
         DirectSpeculationReason(int groupId, String groupName, Object[] context) {
             this.groupId = groupId;
@@ -204,6 +213,123 @@
         public String toString() {
             return String.format("%s@%d%s", groupName, groupId, Arrays.toString(context));
         }
+
+        @Override
+        public SpeculationReasonEncoding encode(Supplier<SpeculationReasonEncoding> encodingSupplier) {
+            if (encoding == null) {
+                encoding = encodingSupplier.get();
+                encoding.addInt(groupId);
+                for (Object o : context) {
+                    if (o == null) {
+                        encoding.addInt(0);
+                    } else {
+                        addNonNullObject(encoding, o);
+                    }
+                }
+            }
+            return encoding;
+        }
+
+        static void addNonNullObject(SpeculationReasonEncoding encoding, Object o) {
+            Class<? extends Object> c = o.getClass();
+            if (c == String.class) {
+                encoding.addString((String) o);
+            } else if (c == Byte.class) {
+                encoding.addByte((Byte) o);
+            } else if (c == Short.class) {
+                encoding.addShort((Short) o);
+            } else if (c == Character.class) {
+                encoding.addShort((Character) o);
+            } else if (c == Integer.class) {
+                encoding.addInt((Integer) o);
+            } else if (c == Long.class) {
+                encoding.addLong((Long) o);
+            } else if (c == Float.class) {
+                encoding.addInt(Float.floatToRawIntBits((Float) o));
+            } else if (c == Double.class) {
+                encoding.addLong(Double.doubleToRawLongBits((Double) o));
+            } else if (o instanceof Enum) {
+                encoding.addInt(((Enum<?>) o).ordinal());
+            } else if (o instanceof ResolvedJavaMethod) {
+                encoding.addMethod((ResolvedJavaMethod) o);
+            } else if (o instanceof ResolvedJavaType) {
+                encoding.addType((ResolvedJavaType) o);
+            } else if (o instanceof ResolvedJavaField) {
+                encoding.addField((ResolvedJavaField) o);
+            } else if (o instanceof SpeculationContextObject) {
+                SpeculationContextObject sco = (SpeculationContextObject) o;
+                // These are compiler objects which all have the same class
+                // loader so the class name uniquely identifies the class.
+                encoding.addString(o.getClass().getName());
+                sco.accept(new EncodingAdapter(encoding));
+            } else if (o.getClass() == BytecodePosition.class) {
+                BytecodePosition p = (BytecodePosition) o;
+                while (p != null) {
+                    encoding.addInt(p.getBCI());
+                    encoding.addMethod(p.getMethod());
+                    p = p.getCaller();
+                }
+            } else {
+                throw new IllegalArgumentException("Unsupported type for encoding: " + c.getName());
+            }
+        }
+    }
+
+    static class EncodingAdapter implements SpeculationContextObject.Visitor {
+        private final SpeculationReasonEncoding encoding;
+
+        EncodingAdapter(SpeculationReasonEncoding encoding) {
+            this.encoding = encoding;
+        }
+
+        @Override
+        public void visitBoolean(boolean v) {
+            encoding.addByte(v ? 1 : 0);
+        }
+
+        @Override
+        public void visitByte(byte v) {
+            encoding.addByte(v);
+        }
+
+        @Override
+        public void visitChar(char v) {
+            encoding.addShort(v);
+        }
+
+        @Override
+        public void visitShort(short v) {
+            encoding.addInt(v);
+        }
+
+        @Override
+        public void visitInt(int v) {
+            encoding.addInt(v);
+        }
+
+        @Override
+        public void visitLong(long v) {
+            encoding.addLong(v);
+        }
+
+        @Override
+        public void visitFloat(float v) {
+            encoding.addInt(Float.floatToRawIntBits(v));
+        }
+
+        @Override
+        public void visitDouble(double v) {
+            encoding.addLong(Double.doubleToRawLongBits(v));
+        }
+
+        @Override
+        public void visitObject(Object v) {
+            if (v == null) {
+                encoding.addInt(0);
+            } else {
+                DirectSpeculationReason.addNonNullObject(encoding, v);
+            }
+        }
     }
 
     static SpeculationReason createSpeculationReason(int groupId, String groupName, Object... context) {
--- a/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/test/hotspot/jtreg/compiler/jvmci/common/patches/jdk.internal.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java	Mon Mar 18 16:54:45 2019 -0700
@@ -168,7 +168,16 @@
 
     public static int installCode(TargetDescription target,
             HotSpotCompiledCode compiledCode, InstalledCode code, HotSpotSpeculationLog speculationLog) {
-        return CTVM.installCode(target, compiledCode, code, speculationLog);
+        byte[] speculations;
+        long failedSpeculationsAddress;
+        if (speculationLog != null) {
+            speculations = speculationLog.getFlattenedSpeculations(true);
+            failedSpeculationsAddress = speculationLog.getFailedSpeculationsAddress();
+        } else {
+            speculations = new byte[0];
+            failedSpeculationsAddress = 0L;
+        }
+        return CTVM.installCode(target, compiledCode, code, failedSpeculationsAddress, speculations);
     }
 
     public static int getMetadata(TargetDescription target,
--- a/test/hotspot/jtreg/compiler/jvmci/errors/CodeInstallerTest.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/test/hotspot/jtreg/compiler/jvmci/errors/CodeInstallerTest.java	Mon Mar 18 16:54:45 2019 -0700
@@ -32,7 +32,9 @@
 import jdk.vm.ci.code.site.Site;
 import jdk.vm.ci.hotspot.HotSpotCompiledCode;
 import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment;
+import jdk.vm.ci.hotspot.HotSpotCompiledNmethod;
 import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
 import jdk.vm.ci.meta.Assumptions.Assumption;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.PlatformKind;
@@ -50,7 +52,7 @@
     protected final MetaAccessProvider metaAccess;
     protected final HotSpotConstantReflectionProvider constantReflection;
 
-    protected final ResolvedJavaMethod dummyMethod;
+    protected final HotSpotResolvedJavaMethod dummyMethod;
 
     public static void dummyMethod() {
     }
@@ -69,12 +71,13 @@
             Assert.fail();
         }
 
-        dummyMethod = metaAccess.lookupJavaMethod(method);
+        dummyMethod = (HotSpotResolvedJavaMethod) metaAccess.lookupJavaMethod(method);
     }
 
     protected void installEmptyCode(Site[] sites, Assumption[] assumptions, Comment[] comments, int dataSectionAlignment, DataPatch[] dataSectionPatches, StackSlot deoptRescueSlot) {
-        HotSpotCompiledCode code = new HotSpotCompiledCode("dummyMethod", new byte[0], 0, sites, assumptions, new ResolvedJavaMethod[]{dummyMethod}, comments, new byte[8], dataSectionAlignment,
-                        dataSectionPatches, false, 0, deoptRescueSlot);
+        HotSpotCompiledCode code = new HotSpotCompiledNmethod("dummyMethod", new byte[0], 0, sites, assumptions, new ResolvedJavaMethod[]{dummyMethod}, comments, new byte[8], dataSectionAlignment,
+                        dataSectionPatches, false, 0, deoptRescueSlot,
+                        dummyMethod, 0, 1, 0L, false);
         codeCache.addCode(dummyMethod, code, null, null);
     }
 
--- a/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/test/hotspot/jtreg/compiler/jvmci/events/JvmciNotifyInstallEventTest.java	Mon Mar 18 16:54:45 2019 -0700
@@ -74,6 +74,7 @@
 import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
 import jdk.vm.ci.hotspot.HotSpotCompiledCode;
 import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment;
+import jdk.vm.ci.hotspot.HotSpotCompiledNmethod;
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
 import jdk.vm.ci.hotspot.HotSpotVMEventListener;
@@ -118,10 +119,11 @@
         }
         HotSpotResolvedJavaMethod method = CTVMUtilities
                 .getResolvedMethod(SimpleClass.class, testMethod);
-        HotSpotCompiledCode compiledCode = new HotSpotCompiledCode(METHOD_NAME,
+        HotSpotCompiledCode compiledCode = new HotSpotCompiledNmethod(METHOD_NAME,
                 new byte[0], 0, new Site[0], new Assumption[0],
                 new ResolvedJavaMethod[]{method}, new Comment[0], new byte[0],
-                16, new DataPatch[0], false, 0, null);
+                16, new DataPatch[0], false, 0, null,
+                method, 0, 1, 0L, false);
         codeCache.installCode(method, compiledCode, /* installedCode = */ null,
                 /* speculationLog = */ null, /* isDefault = */ false);
         Asserts.assertEQ(gotInstallNotification, 1,
--- /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/TestHotSpotSpeculationLog.java	Mon Mar 18 16:54:45 2019 -0700
@@ -0,0 +1,101 @@
+/*
+ * 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.function.Supplier;
+
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+import jdk.vm.ci.hotspot.HotSpotSpeculationLog;
+import jdk.vm.ci.meta.SpeculationLog;
+import jdk.vm.ci.meta.SpeculationLog.SpeculationReasonEncoding;
+
+public class TestHotSpotSpeculationLog {
+
+    static final class DummyReason implements SpeculationLog.SpeculationReason {
+
+        final String name;
+        private SpeculationReasonEncoding cachedEncoding;
+
+        DummyReason(String name) {
+            this.name = name;
+        }
+
+        @Override
+        public SpeculationReasonEncoding encode(Supplier<SpeculationReasonEncoding> encodingSupplier) {
+            SpeculationReasonEncoding encoding = cachedEncoding;
+            if (encoding == null) {
+                encoding = encodingSupplier.get();
+                encoding.addString(name);
+            }
+            cachedEncoding = encoding;
+            return encoding;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof DummyReason) {
+                DummyReason that = (DummyReason) obj;
+                return this.name.equals(that.name);
+            }
+            return super.equals(obj);
+        }
+
+        @Override
+        public int hashCode() {
+            return name.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+
+    @Test
+    public synchronized void testFailedSpeculations() {
+        HotSpotSpeculationLog log = new HotSpotSpeculationLog();
+        DummyReason reason1 = new DummyReason("dummy1");
+        DummyReason reason2 = new DummyReason("dummy2");
+        Assert.assertTrue(log.maySpeculate(reason1));
+        Assert.assertTrue(log.maySpeculate(reason2));
+
+        SpeculationLog.Speculation s1 = log.speculate(reason1);
+        SpeculationLog.Speculation s2 = log.speculate(reason2);
+
+        boolean added = log.addFailedSpeculation(s1);
+        Assume.assumeTrue(added);
+        log.collectFailedSpeculations();
+        Assert.assertFalse(log.maySpeculate(reason1));
+        Assert.assertTrue(log.maySpeculate(reason2));
+
+        added = log.addFailedSpeculation(s2);
+        Assume.assumeTrue(added);
+        log.collectFailedSpeculations();
+        Assume.assumeTrue(added);
+        Assert.assertFalse(log.maySpeculate(reason1));
+        Assert.assertFalse(log.toString(), log.maySpeculate(reason2));
+    }
+}
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestSpeculationLog.java	Wed Mar 13 21:41:51 2019 -0700
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestSpeculationLog.java	Mon Mar 18 16:54:45 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -24,24 +24,107 @@
  */
 package jdk.vm.ci.runtime.test;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.function.Supplier;
+
 import org.junit.Assert;
 import org.junit.Test;
 
+import jdk.vm.ci.code.CodeCacheProvider;
 import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.meta.SpeculationLog;
+import jdk.vm.ci.meta.SpeculationLog.SpeculationReasonEncoding;
+import jdk.vm.ci.runtime.JVMCI;
 
 public class TestSpeculationLog extends MethodUniverse {
 
-    static class Dummy implements SpeculationLog.SpeculationReason {
+    static final class Dummy implements SpeculationLog.SpeculationReason {
 
+        final int[] ints = {Integer.MIN_VALUE, -42, -1, 0, 1, 42, Integer.MAX_VALUE};
+        final long[] longs = {Long.MIN_VALUE, -42, -1, 0, 1, 42, Long.MAX_VALUE};
+        final String[] strings = {null, "non-empty string", ""};
+        final Collection<ResolvedJavaMethod> methods = new ArrayList<>(MethodUniverse.methods.values()).subList(0, 10);
+        final Collection<ResolvedJavaMethod> constructors = new ArrayList<>(MethodUniverse.constructors.values()).subList(0, 10);
+        final Collection<ResolvedJavaType> types = new ArrayList<>(TypeUniverse.javaTypes).subList(0, 10);
+
+        private final boolean useCache;
+        private SpeculationReasonEncoding cachedEncoding;
+
+        Dummy(boolean useCache) {
+            this.useCache = useCache;
+        }
+
+        @Override
+        public SpeculationReasonEncoding encode(Supplier<SpeculationReasonEncoding> encodingSupplier) {
+            SpeculationReasonEncoding encoding = cachedEncoding;
+            if (encoding == null) {
+                encoding = encodingSupplier.get();
+                for (int i : ints) {
+                    encoding.addInt(i);
+                }
+                for (long l : longs) {
+                    encoding.addLong(l);
+                }
+                for (String s : strings) {
+                    encoding.addString(s);
+                }
+                for (ResolvedJavaMethod m : methods) {
+                    encoding.addMethod(m);
+                }
+                for (ResolvedJavaMethod c : constructors) {
+                    encoding.addMethod(c);
+                }
+                for (ResolvedJavaType t : types) {
+                    encoding.addType(t);
+                }
+                encoding.addMethod(null);
+                encoding.addType(null);
+            }
+            if (useCache) {
+                cachedEncoding = encoding;
+            }
+            return encoding;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof Dummy) {
+                Dummy that = (Dummy) obj;
+                return Arrays.equals(this.ints, that.ints) &&
+                                Arrays.equals(this.longs, that.longs) &&
+                                Arrays.equals(this.strings, that.strings) &&
+                                this.methods.equals(that.methods) &&
+                                this.constructors.equals(that.constructors) &&
+                                this.types.equals(that.types);
+            }
+            return super.equals(obj);
+        }
+
+        @Override
+        public int hashCode() {
+            return 31 * Arrays.hashCode(ints) ^
+                            Arrays.hashCode(longs) ^
+                            Arrays.hashCode(strings) ^
+                            methods.hashCode() ^
+                            constructors.hashCode() ^
+                            types.hashCode();
+        }
     }
 
     @Test
-    public void testSpeculationIdentity() {
-        Dummy spec = new Dummy();
-        SpeculationLog log = methods.entrySet().iterator().next().getValue().getSpeculationLog();
-        SpeculationLog.Speculation s1 = log.speculate(spec);
-        SpeculationLog.Speculation s2 = log.speculate(spec);
+    public synchronized void testSpeculationIdentity() {
+        CodeCacheProvider codeCache = JVMCI.getRuntime().getHostJVMCIBackend().getCodeCache();
+        SpeculationLog log = codeCache.createSpeculationLog();
+        Dummy spec1 = new Dummy(true);
+        Dummy spec2 = new Dummy(false);
+        Assert.assertTrue(log.maySpeculate(spec1));
+        Assert.assertTrue(log.maySpeculate(spec2));
+        SpeculationLog.Speculation s1 = log.speculate(spec1);
+        SpeculationLog.Speculation s2 = log.speculate(spec2);
         Assert.assertTrue("Speculation should maintain identity", s1.equals(s2));
         JavaConstant e1 = metaAccess.encodeSpeculation(s1);
         JavaConstant e2 = metaAccess.encodeSpeculation(s2);