--- old/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	2020-06-22 18:16:09.000000000 +0200
+++ new/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	2020-06-22 18:16:09.000000000 +0200
@@ -1025,7 +1025,7 @@
   JVMCIObject nmethod_mirror = JVMCIENV->wrap(hs_nmethod);
   nmethodLocker locker;
   nmethod* nm = JVMCIENV->get_nmethod(nmethod_mirror, locker);
-  if (nm == NULL) {
+  if (nm == NULL || !nm->is_in_use()) {
     JVMCI_THROW_NULL(InvalidInstalledCodeException);
   }
   methodHandle mh(THREAD, nm->method());
@@ -1034,7 +1034,7 @@
 
   JavaArgumentUnboxer jap(signature, &jca, (arrayOop) JNIHandles::resolve(args), mh->is_static());
   JavaValue result(jap.return_type());
-  jca.set_alternative_target(nm);
+  jca.set_alternative_target(Handle(THREAD, JNIHandles::resolve(nmethod_mirror.as_jobject())));
   JavaCalls::call(&result, mh, &jca, CHECK_NULL);
 
   if (jap.return_type() == T_VOID) {
--- old/src/hotspot/share/runtime/javaCalls.cpp	2020-06-22 18:16:10.000000000 +0200
+++ new/src/hotspot/share/runtime/javaCalls.cpp	2020-06-22 18:16:10.000000000 +0200
@@ -30,6 +30,9 @@
 #include "compiler/compileBroker.hpp"
 #include "interpreter/interpreter.hpp"
 #include "interpreter/linkResolver.hpp"
+#if INCLUDE_JVMCI
+#include "jvmci/jvmciJavaClasses.hpp"
+#endif
 #include "memory/universe.hpp"
 #include "oops/method.inline.hpp"
 #include "oops/oop.inline.hpp"
@@ -346,27 +349,15 @@
   assert(!SafepointSynchronize::is_at_safepoint(), "call to Java code during VM operation");
   assert(!thread->handle_area()->no_handle_mark_active(), "cannot call out to Java here");
 
-#if INCLUDE_JVMCI
-  // Gets the nmethod (if any) that should be called instead of normal target
-  nmethod* alternative_target = args->alternative_target();
-  if (alternative_target == NULL) {
-#endif
-// Verify the arguments
-
-  if (CheckJNICalls)  {
+  // Verify the arguments
+  if (JVMCI_ONLY(args->alternative_target().is_null() &&) (DEBUG_ONLY(true ||) CheckJNICalls)) {
     args->verify(method, result->get_type());
   }
-  else debug_only(args->verify(method, result->get_type()));
-#if INCLUDE_JVMCI
-  }
-#else
-
   // Ignore call if method is empty
-  if (method->is_empty_method()) {
+  if (JVMCI_ONLY(args->alternative_target().is_null() &&) method->is_empty_method()) {
     assert(result->get_type() == T_VOID, "an empty method must return a void value");
     return;
   }
-#endif
 
 #ifdef ASSERT
   { InstanceKlass* holder = method->method_holder();
@@ -414,17 +405,6 @@
     os::map_stack_shadow_pages(sp);
   }
 
-#if INCLUDE_JVMCI
-  if (alternative_target != NULL) {
-    if (alternative_target->is_alive() && !alternative_target->is_unloading()) {
-      thread->set_jvmci_alternate_call_target(alternative_target->verified_entry_point());
-      entry_point = method->adapter()->get_i2c_entry();
-    } else {
-      THROW(vmSymbols::jdk_vm_ci_code_InvalidInstalledCodeException());
-    }
-  }
-#endif
-
   // do call
   { JavaCallWrapper link(method, receiver, result, CHECK);
     { HandleMark hm(thread);  // HandleMark used by HandleMarkCleaner
@@ -433,7 +413,20 @@
       // the call to call_stub, the optimizer produces wrong code.
       intptr_t* result_val_address = (intptr_t*)(result->get_value_addr());
       intptr_t* parameter_address = args->parameters();
-
+#if INCLUDE_JVMCI
+      // Gets the alternative target (if any) that should be called
+      Handle alternative_target = args->alternative_target();
+      if (!alternative_target.is_null()) {
+        // Must extract verified entry point from HotSpotNmethod after VM to Java
+        // transition in JavaCallWrapper constructor so that it is safe with
+        // respect to nmethod sweeping.
+        address verified_entry_point = (address) HotSpotJVMCI::InstalledCode::entryPoint(NULL, alternative_target());
+        if (verified_entry_point != NULL) {
+          thread->set_jvmci_alternate_call_target(verified_entry_point);
+          entry_point = method->adapter()->get_i2c_entry();
+        }
+      }
+#endif
       StubRoutines::call_stub()(
         (address)&link,
         // (intptr_t*)&(result->_value), // see NOTE above (compiler problem)
--- old/src/hotspot/share/runtime/javaCalls.hpp	2020-06-22 18:16:11.000000000 +0200
+++ new/src/hotspot/share/runtime/javaCalls.hpp	2020-06-22 18:16:11.000000000 +0200
@@ -88,7 +88,10 @@
   int         _size;
   int         _max_size;
   bool        _start_at_zero;      // Support late setting of receiver
-  JVMCI_ONLY(nmethod*    _alternative_target;) // Nmethod that should be called instead of normal target
+#if INCLUDE_JVMCI
+  Handle      _alternative_target; // HotSpotNmethod wrapping an nmethod whose verified entry point
+                                   // should be called instead of the normal target
+#endif
 
   void initialize() {
     // Starts at first element to support set_receiver.
@@ -98,7 +101,6 @@
     _max_size = _default_size;
     _size = 0;
     _start_at_zero = false;
-    JVMCI_ONLY(_alternative_target = NULL;)
   }
 
   // Helper for push_oop and the like.  The value argument is a
@@ -138,18 +140,17 @@
       _max_size = max_size;
       _size = 0;
       _start_at_zero = false;
-      JVMCI_ONLY(_alternative_target = NULL;)
     } else {
       initialize();
     }
   }
 
 #if INCLUDE_JVMCI
-  void set_alternative_target(nmethod* target) {
+  void set_alternative_target(Handle target) {
     _alternative_target = target;
   }
 
-  nmethod* alternative_target() {
+  Handle alternative_target() {
     return _alternative_target;
   }
 #endif
--- old/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java	2020-06-22 18:16:12.000000000 +0200
+++ new/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java	2020-06-22 18:16:11.000000000 +0200
@@ -146,6 +146,18 @@
         return true;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * It's possible for the HotSpot runtime to sweep nmethods at any point in time. As a result,
+     * there is no guarantee that calling this method will execute the wrapped nmethod. Instead, it
+     * may end up executing the bytecode of the associated {@link #getMethod() Java method}. Only if
+     * {@link #isValid()} is {@code true} after returning can the caller be sure that the nmethod
+     * was executed. If {@link #isValid()} is {@code false}, then the only way to determine if the
+     * nmethod was executed is to test for some side-effect specific to the nmethod (e.g., update to
+     * a field) that is not performed by the bytecode of the associated {@link #getMethod() Java
+     * method}.
+     */
     @Override
     public Object executeVarargs(Object... args) throws InvalidInstalledCodeException {
         if (IS_IN_NATIVE_IMAGE) {
