changeset 56459:d880242551d3 fibers

Merge
author rbackman
date Wed, 14 Aug 2019 10:13:51 +0200
parents ca2ad8524915 8b38b9a77f94
children 2be4e800f681
files src/hotspot/share/runtime/continuation.hpp
diffstat 21 files changed, 217 insertions(+), 77 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/cpu/x86/nativeInst_x86.cpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/cpu/x86/nativeInst_x86.cpp	Wed Aug 14 10:13:51 2019 +0200
@@ -676,7 +676,6 @@
      assert(*((address)((intptr_t)instr_addr + i)) == a_byte, "mt safe patching failed");
    }
 #endif
-
 }
 
 
@@ -694,7 +693,7 @@
 }
 
 void NativePostCallNop::patch(jint diff) {
-  assert(diff > 0, "must be");
+  assert(diff != 0, "must be");
   int32_t *code_pos = (int32_t *) addr_at(displacement_offset);
   *((int32_t *)(code_pos)) = (int32_t) diff;
 }
--- a/src/hotspot/share/code/compiledMethod.cpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/code/compiledMethod.cpp	Wed Aug 14 10:13:51 2019 +0200
@@ -37,6 +37,7 @@
 #include "memory/resourceArea.hpp"
 #include "oops/methodData.hpp"
 #include "oops/method.inline.hpp"
+#include "oops/weakHandle.inline.hpp"
 #include "prims/methodHandles.hpp"
 #include "runtime/deoptimization.hpp"
 #include "runtime/jniHandles.inline.hpp"
@@ -51,7 +52,7 @@
     _mark_for_deoptimization_status(not_marked),
     _method(method),
     _gc_data(NULL),
-    _shadow(NULL)
+    _keepalive(NULL)
 {
   init_defaults();
 }
@@ -64,7 +65,7 @@
     _mark_for_deoptimization_status(not_marked),
     _method(method),
     _gc_data(NULL),
-    _shadow(NULL)
+    _keepalive(NULL)
 {
   init_defaults();
 }
@@ -718,6 +719,9 @@
 }
 
 bool CompiledMethod::is_on_continuation_stack() {
-  return JNIHandles::resolve(_shadow) != NULL;
+  if (_keepalive != NULL) {
+    WeakHandle<vm_nmethod_keepalive_data> wh = WeakHandle<vm_nmethod_keepalive_data>::from_raw(_keepalive);
+    return wh.resolve() != NULL;
+  }
+  return false;
 }
-
--- a/src/hotspot/share/code/compiledMethod.hpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/code/compiledMethod.hpp	Wed Aug 14 10:13:51 2019 +0200
@@ -177,7 +177,7 @@
 
   virtual void flush() = 0;
 
-  jweak _shadow;
+  oop* _keepalive; // allocated and maintained by Continuation::weak_storage().
 protected:
   CompiledMethod(Method* method, const char* name, CompilerType type, const CodeBlobLayout& layout, int frame_complete_offset, int frame_size, ImmutableOopMapSet* oop_maps, bool caller_must_gc_arguments, bool compiled);
   CompiledMethod(Method* method, const char* name, CompilerType type, int size, int header_size, CodeBuffer* cb, int frame_complete_offset, int frame_size, OopMapSet* oop_maps, bool caller_must_gc_arguments, bool compiled);
@@ -421,9 +421,9 @@
 
   bool is_on_continuation_stack();
 
-  jweak get_shadow();
-  jweak set_shadow(jweak shadow);
-  bool clear_shadow(jweak old);
+  oop* get_keepalive();
+  oop* set_keepalive(oop* keepalive);
+  bool clear_keepalive(oop* old);
 
 private:
   PcDesc* find_pc_desc(address pc, bool approximate) {
--- a/src/hotspot/share/code/compiledMethod.inline.hpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/code/compiledMethod.inline.hpp	Wed Aug 14 10:13:51 2019 +0200
@@ -59,14 +59,14 @@
   return NULL;
 }
 
-inline jweak CompiledMethod::get_shadow() { return _shadow; }
+inline oop* CompiledMethod::get_keepalive() { return _keepalive; }
 
-inline jweak CompiledMethod::set_shadow(jweak obj) {
-  return Atomic::cmpxchg(obj, &_shadow, (jweak) NULL);
+inline oop* CompiledMethod::set_keepalive(oop* obj) {
+  return Atomic::cmpxchg(obj, &_keepalive, (oop*) NULL);
 }
 
-inline bool CompiledMethod::clear_shadow(jweak old) {
-  return Atomic::cmpxchg((jweak) NULL, &_shadow, (jweak) old) == old;
+inline bool CompiledMethod::clear_keepalive(oop* old) {
+  return Atomic::cmpxchg((oop*) NULL, &_keepalive, (oop*) old) == old;
 }
 
 // class ExceptionCache methods
--- a/src/hotspot/share/code/nmethod.cpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/code/nmethod.cpp	Wed Aug 14 10:13:51 2019 +0200
@@ -49,6 +49,7 @@
 #include "oops/method.inline.hpp"
 #include "oops/methodData.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/weakHandle.inline.hpp"
 #include "prims/jvmtiImpl.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/flags/flagSetting.hpp"
@@ -1826,10 +1827,19 @@
   }
 }
 
-void nmethod::oops_do(OopClosure* f, bool allow_dead, bool allow_null) {
+void nmethod::oops_do(OopClosure* f, bool allow_dead, bool allow_null, bool keepalive_is_strong) {
   // make sure the oops ready to receive visitors
   assert(allow_dead || is_alive(), "should not call follow on dead nmethod");
 
+  if (keepalive_is_strong) {
+    if (_keepalive != NULL) {
+      WeakHandle<vm_nmethod_keepalive_data> wh = WeakHandle<vm_nmethod_keepalive_data>::from_raw(_keepalive);
+      if (wh.resolve() != NULL) {
+        f->do_oop(_keepalive);
+      }
+    }
+  }
+
   // Prevent extra code cache walk for platforms that don't have immediate oops.
   if (relocInfo::mustIterateImmediateOopsInCode()) {
     RelocIterator iter(this, oops_reloc_begin());
--- a/src/hotspot/share/code/nmethod.hpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/code/nmethod.hpp	Wed Aug 14 10:13:51 2019 +0200
@@ -483,8 +483,9 @@
 #endif
 
  public:
-  void oops_do(OopClosure* f) { oops_do(f, false); }
-  void oops_do(OopClosure* f, bool allow_dead, bool allow_null = false);
+  void oops_do_keepalive(OopClosure* f, bool keepalive) { oops_do(f, false, false, keepalive); }
+  void oops_do(OopClosure* f) { oops_do(f, false, false); }
+  void oops_do(OopClosure* f, bool allow_dead, bool allow_null = false, bool shadow_is_strong = false);
 
   bool test_set_oops_do_mark();
   static void oops_do_marking_prologue();
--- a/src/hotspot/share/gc/g1/g1CodeBlobClosure.cpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1CodeBlobClosure.cpp	Wed Aug 14 10:13:51 2019 +0200
@@ -57,7 +57,7 @@
   if (nm != NULL) {
     if (!nm->test_set_oops_do_mark()) {
       _oc.set_nm(nm);
-      nm->oops_do(&_oc);
+      nm->oops_do_keepalive(&_oc, _keepalive_is_strong);
       nm->fix_oop_relocations();
     }
   }
--- a/src/hotspot/share/gc/g1/g1CodeBlobClosure.hpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1CodeBlobClosure.hpp	Wed Aug 14 10:13:51 2019 +0200
@@ -51,8 +51,9 @@
   };
 
   HeapRegionGatheringOopClosure _oc;
+  bool _keepalive_is_strong;
 public:
-  G1CodeBlobClosure(OopClosure* oc) : _oc(oc) {}
+  G1CodeBlobClosure(OopClosure* oc, bool keepalive_is_strong) : _oc(oc), _keepalive_is_strong(keepalive_is_strong) {}
 
   void do_code_blob(CodeBlob* cb);
 };
--- a/src/hotspot/share/gc/g1/g1RootClosures.cpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1RootClosures.cpp	Wed Aug 14 10:13:51 2019 +0200
@@ -44,8 +44,8 @@
   CLDClosure* strong_clds()           { return &_closures._clds; }
   CLDClosure* second_pass_weak_clds() { return NULL; }
 
-  CodeBlobClosure* strong_codeblobs()      { return &_closures._codeblobs; }
-  CodeBlobClosure* weak_codeblobs()        { return &_closures._codeblobs; }
+  CodeBlobClosure* strong_codeblobs()      { return &_closures._strong_codeblobs; }
+  CodeBlobClosure* weak_codeblobs()        { return &_closures._weak_codeblobs; }
 
   OopClosure* raw_strong_oops() { return &_closures._oops; }
 
@@ -87,8 +87,8 @@
   // return a NULL closure for the following specialized versions in that case.
   CLDClosure* second_pass_weak_clds() { return null_if<G1MarkFromRoot>(&_weak._clds); }
 
-  CodeBlobClosure* strong_codeblobs()      { return &_strong._codeblobs; }
-  CodeBlobClosure* weak_codeblobs()        { return &_weak._codeblobs; }
+  CodeBlobClosure* strong_codeblobs()      { return &_strong._strong_codeblobs; }
+  CodeBlobClosure* weak_codeblobs()        { return &_weak._weak_codeblobs; }
 
   OopClosure* raw_strong_oops() { return &_strong._oops; }
 
--- a/src/hotspot/share/gc/g1/g1SharedClosures.hpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/gc/g1/g1SharedClosures.hpp	Wed Aug 14 10:13:51 2019 +0200
@@ -37,11 +37,12 @@
   G1ParCopyClosure<G1BarrierCLD,  Mark> _oops_in_cld;
 
   G1CLDScanClosure                _clds;
-  G1CodeBlobClosure               _codeblobs;
+  G1CodeBlobClosure               _strong_codeblobs;
+  G1CodeBlobClosure               _weak_codeblobs;
 
   G1SharedClosures(G1CollectedHeap* g1h, G1ParScanThreadState* pss, bool process_only_dirty, int cld_claim) :
     _oops(g1h, pss),
     _oops_in_cld(g1h, pss),
     _clds(&_oops_in_cld, process_only_dirty, cld_claim),
-    _codeblobs(&_oops) {}
+    _strong_codeblobs(&_oops, true), _weak_codeblobs(&_oops, false) {}
 };
--- a/src/hotspot/share/gc/shared/weakProcessorPhases.cpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/gc/shared/weakProcessorPhases.cpp	Wed Aug 14 10:13:51 2019 +0200
@@ -27,6 +27,7 @@
 #include "classfile/systemDictionary.hpp"
 #include "gc/shared/weakProcessorPhases.hpp"
 #include "prims/resolvedMethodTable.hpp"
+#include "runtime/continuation.hpp"
 #include "runtime/jniHandles.hpp"
 #include "utilities/debug.hpp"
 #include "utilities/macros.hpp"
@@ -83,6 +84,7 @@
   case stringtable: return "StringTable weak processing";
   case resolved_method_table: return "ResolvedMethodTable weak processing";
   case vm: return "VM weak processing";
+  case nmethod_keepalive: return "NMethod keepalive (continuations)";
   default:
     ShouldNotReachHere();
     return "Invalid weak processing phase";
@@ -105,6 +107,7 @@
   case stringtable: return StringTable::weak_storage();
   case resolved_method_table: return ResolvedMethodTable::weak_storage();
   case vm: return SystemDictionary::vm_weak_oop_storage();
+  case nmethod_keepalive: return Continuation::weak_storage();
   default:
     ShouldNotReachHere();
     return NULL;
--- a/src/hotspot/share/gc/shared/weakProcessorPhases.hpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/gc/shared/weakProcessorPhases.hpp	Wed Aug 14 10:13:51 2019 +0200
@@ -46,6 +46,7 @@
     jni,
     stringtable,
     resolved_method_table,
+    nmethod_keepalive,
     vm
   };
 
--- a/src/hotspot/share/oops/weakHandle.cpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/oops/weakHandle.cpp	Wed Aug 14 10:13:51 2019 +0200
@@ -30,6 +30,7 @@
 #include "oops/oop.hpp"
 #include "oops/weakHandle.inline.hpp"
 #include "prims/resolvedMethodTable.hpp"
+#include "runtime/continuation.hpp"
 #include "utilities/debug.hpp"
 #include "utilities/ostream.hpp"
 
@@ -45,6 +46,10 @@
   return ResolvedMethodTable::weak_storage();
 }
 
+template <> OopStorage* WeakHandle<vm_nmethod_keepalive_data>::get_storage() {
+  return Continuation::weak_storage();
+}
+
 template <WeakHandleType T>
 WeakHandle<T> WeakHandle<T>::create(Handle obj) {
   assert(obj() != NULL, "no need to create weak null oop");
@@ -58,6 +63,12 @@
 }
 
 template <WeakHandleType T>
+WeakHandle<T> WeakHandle<T>::from_raw(oop* raw) {
+  assert(raw != NULL, "can't create from raw with NULL value");
+  return WeakHandle(raw);
+}
+
+template <WeakHandleType T>
 void WeakHandle<T>::release() const {
   // Only release if the pointer to the object has been created.
   if (_obj != NULL) {
@@ -80,3 +91,4 @@
 template class WeakHandle<vm_class_loader_data>;
 template class WeakHandle<vm_string_table_data>;
 template class WeakHandle<vm_resolved_method_table_data>;
+template class WeakHandle<vm_nmethod_keepalive_data>;
--- a/src/hotspot/share/oops/weakHandle.hpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/oops/weakHandle.hpp	Wed Aug 14 10:13:51 2019 +0200
@@ -39,7 +39,7 @@
 // This is the vm version of jweak but has different GC lifetimes and policies,
 // depending on the type.
 
-enum WeakHandleType { vm_class_loader_data, vm_string_table_data, vm_resolved_method_table_data };
+enum WeakHandleType { vm_class_loader_data, vm_string_table_data, vm_resolved_method_table_data, vm_nmethod_keepalive_data };
 
 template <WeakHandleType T>
 class WeakHandle {
@@ -53,12 +53,14 @@
   WeakHandle() : _obj(NULL) {} // needed for init
 
   static WeakHandle create(Handle obj);
+  static WeakHandle from_raw(oop* raw);
   inline oop resolve() const;
   inline oop peek() const;
   void release() const;
   bool is_null() const { return _obj == NULL; }
 
   void replace(oop with_obj);
+  oop* raw() { return _obj; }
 
   void print() const;
   void print_on(outputStream* st) const;
--- a/src/hotspot/share/runtime/continuation.cpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/runtime/continuation.cpp	Wed Aug 14 10:13:51 2019 +0200
@@ -33,6 +33,7 @@
 #include "compiler/oopMap.inline.hpp"
 #include "jfr/jfrEvents.hpp"
 #include "gc/shared/memAllocator.hpp"
+#include "gc/shared/oopStorage.hpp"
 #include "gc/shared/threadLocalAllocBuffer.inline.hpp"
 #include "interpreter/interpreter.hpp"
 #include "interpreter/linkResolver.hpp"
@@ -42,6 +43,8 @@
 #include "metaprogramming/conditional.hpp"
 #include "oops/access.inline.hpp"
 #include "oops/objArrayOop.inline.hpp"
+#include "oops/weakHandle.hpp"
+#include "oops/weakHandle.inline.hpp"
 #include "prims/jvmtiThreadState.hpp"
 #include "runtime/continuation.hpp"
 #include "runtime/deoptimization.hpp"
@@ -103,6 +106,8 @@
 
 int Continuations::_flags = 0;
 
+OopStorage* Continuation::_weak_handles = NULL;
+
 PERFTEST_ONLY(static int PERFTEST_LEVEL = ContPerfTest;)
 // Freeze:
 // 5 - no call into C
@@ -511,7 +516,7 @@
   static void copy_primitive_array(typeArrayOop old_array, int old_start, typeArrayOop new_array, int new_start, int count);
   template <typename ConfigT> bool allocate_ref_stack(int nr_oops);
   template <typename ConfigT> objArrayOop  allocate_refstack_array(size_t nr_oops);
-  template <typename ConfigT> objArrayOop  allocate_shadow_array(size_t nr_oops);
+  template <typename ConfigT> objArrayOop  allocate_keepalive_array(size_t nr_oops);
   template <typename ConfigT> bool grow_ref_stack(int nr_oops);
   template <typename ConfigT> void copy_ref_array(objArrayOop old_array, int old_start, objArrayOop new_array, int new_start, int count);
   template <typename ConfigT> void zero_ref_array(objArrayOop new_array, int new_length, int min_length);
@@ -1439,48 +1444,74 @@
   }
 };
 
+/*
+ * This class is mainly responsible for the work that is required to make sure that nmethods that
+ * are referenced from a Continuation stack are kept alive.
+ *
+ * While freezing, for each nmethod a keepalive array is allocated. It contains elements for all the
+ * oops that are either immediates or in the oop section in the nmethod (basically all that would be
+ * published to the closure while running nm->oops_do().).
+ *
+ * The keepalive array is than strongly linked from the oop array in the Continuation, a weak reference
+ * is kept in the nmethod -> the keepalive array.
+ *
+ * Some GCs (currently only G1) have code that considers the weak reference to the keepalive array a
+ * strong reference while this nmethod is on the stack. This is true while we are freezing, it helps
+ * performance because we don't need to allocate and keep oops to this objects in a Handle for such GCs.
+ * As soon as they are linked into the nmethod we know the object will stay alive.
+ */
 template <typename ConfigT>
 class CompiledMethodKeepalive {
 private:
   typedef typename ConfigT::OopT OopT;
   typedef CompiledMethodKeepalive<ConfigT> SelfT;
-
-  Handle _shadowHolder;
+  typedef typename ConfigT::KeepaliveObjectT KeepaliveObjectT;
+
+  typename KeepaliveObjectT::TypeT _keepalive;
   CompiledMethod* _method;
   SelfT* _parent;
+  JavaThread* _thread;
   int _nr_oops;
   bool _required;
 
+  void store_keepalive(JavaThread* thread, oop* keepalive) { _keepalive = KeepaliveObjectT::make_keepalive(thread, keepalive); }
+  oop read_keepalive() { return KeepaliveObjectT::read_keepalive(_keepalive); }
+
 public:
-  CompiledMethodKeepalive(CompiledMethod* cm, SelfT* parent, JavaThread* thread) : _method(cm), _parent(NULL), _nr_oops(0), _required(false) {
-    jweak shadow = cm->get_shadow();
-    oop resolved = JNIHandles::resolve(shadow);
-    if (resolved != NULL) {
-      _shadowHolder = Handle(thread, resolved);
-      return;
-    }
-
-    if (shadow != NULL) {
-      //log_info(jvmcont)("trying to clear stale shadow for %p", _method);
-      if (cm->clear_shadow(shadow)) {
-        //log_info(jvmcont)("shadow cleared for %p", _method);
-        thread->keepalive_cleanup()->append(shadow);
+  CompiledMethodKeepalive(CompiledMethod* cm, SelfT* parent, JavaThread* thread) : _method(cm), _parent(NULL), _thread(thread), _nr_oops(0), _required(false) {
+    oop* keepalive = cm->get_keepalive();
+    if (keepalive != NULL) {
+   //   log_info(jvmcont)("keepalive is %p (%p) for nm %p", keepalive, (void *) *keepalive, cm);
+      WeakHandle<vm_nmethod_keepalive_data> wh = WeakHandle<vm_nmethod_keepalive_data>::from_raw(keepalive);
+      oop resolved = wh.resolve();
+      if (resolved != NULL) {
+        //log_info(jvmcont)("found keepalive %p (%p)", keepalive, (void *) resolved);
+        store_keepalive(thread, keepalive);
+        return;
+      }
+
+      //log_info(jvmcont)("trying to clear stale keepalive for %p", _method);
+      if (cm->clear_keepalive(keepalive)) {
+        //log_info(jvmcont)("keepalive cleared for %p", _method);
+        thread->keepalive_cleanup()->append(wh);
         // put on a list for cleanup in a safepoint
       }
     }
+  //  log_info(jvmcont)("keepalive is %p for nm %p", keepalive, cm);
 
     nmethod* nm = cm->as_nmethod_or_null();
     if (nm != NULL) {
       _nr_oops = nm->nr_oops();
-      //log_info(jvmcont)("need shadow for %d oops", _nr_oops);
+      //log_info(jvmcont)("need keepalive for %d oops", _nr_oops);
       _required = true;
       _parent = parent;
     }
   }
 
   void write_at(ContMirror& mirror, int index) {
+    assert(_keepalive != NULL, "");
     //log_develop_info(jvmcont)("writing mirror at %d\n", index);
-    mirror.add_oop<ConfigT>(_shadowHolder(), index);
+    mirror.add_oop<ConfigT>(read_keepalive(), index);
     //*(hsp + index)
   }
 
@@ -1492,26 +1523,32 @@
 
     nmethod* nm = _method->as_nmethod_or_null();
     if (nm != NULL) {
-      PersistOops<OopT> persist(_nr_oops, (objArrayOop) _shadowHolder());
+      assert(_keepalive != NULL && read_keepalive() != NULL, "");
+      PersistOops<OopT> persist(_nr_oops, (objArrayOop) read_keepalive());
       nm->oops_do(&persist);
       //log_info(jvmcont)("oops persisted");
     }
   }
 
-  void set_handle(Handle shadow) {
-    _shadowHolder = shadow;
-    jobject obj = JNIHandles::make_weak_global(shadow);
-    jobject result = _method->set_shadow(obj);
+  void set_handle(Handle keepalive) {
+    WeakHandle<vm_nmethod_keepalive_data> wh = WeakHandle<vm_nmethod_keepalive_data>::create(keepalive);
+    oop* result = _method->set_keepalive(wh.raw());
+
     if (result != NULL) {
+      store_keepalive(_thread, result);
       // someone else managed to do it before us, destroy the weak
       _required = false;
-      JNIHandles::destroy_weak_global(obj);
+      wh.release();
+    } else {
+      store_keepalive(_thread, wh.raw());
+      //log_info(jvmcont)("Winning cas for %p (%p -> %p (%p))", _method, result, wh.raw(), (void *) wh.resolve());
     }
   }
 
   SelfT* parent() { return _parent; }
   bool required() const { return _required; }
   int nr_oops() const { return _nr_oops; }
+
 };
 
 template <typename FKind>
@@ -3821,11 +3858,12 @@
   if (oops == 0) {
     oops = 1;
   }
-  Handle shadow = Handle(_thread, allocate_shadow_array<ConfigT>(oops));
+  oop keepalive_obj = allocate_keepalive_array<ConfigT>(oops);
 
   uint64_t counter = SafepointSynchronize::safepoint_counter();
   // check gc cycle
-  keepalive->set_handle(shadow);
+  Handle keepaliveHandle = Handle(_thread, keepalive_obj);
+  keepalive->set_handle(keepaliveHandle);
   // check gc cycle and maybe reload
   //if (!SafepointSynchronize::is_same_safepoint(counter)) {
     post_safepoint(conth);
@@ -4063,10 +4101,10 @@
 }
 
 template <typename ConfigT>
-objArrayOop ContMirror::allocate_shadow_array(size_t nr_oops) {
+objArrayOop ContMirror::allocate_keepalive_array(size_t nr_oops) {
   //assert(nr_oops > 0, "");
   bool zero = true; // !BarrierSet::barrier_set()->is_a(BarrierSet::ModRef);
-  log_develop_trace(jvmcont)("allocate_shadow_array nr_oops: %lu zero: %d", nr_oops, zero);
+  log_develop_trace(jvmcont)("allocate_keepalive_array nr_oops: %lu zero: %d", nr_oops, zero);
 
   ArrayKlass* klass = ArrayKlass::cast(Universe::objectArrayKlassObj());
   size_t size_in_words = objArrayOopDesc::object_size((int)nr_oops);
@@ -4243,12 +4281,41 @@
 }
 #endif
 
-template <bool compressed_oops, bool post_barrier, bool gen_stubs>
+/* This is hopefully only temporary, currently only G1 has support for making the weak
+ * keepalive OOPs strong while their nmethods are on the stack. */
+class HandleKeepalive {
+public:
+  typedef Handle TypeT;
+
+  static Handle make_keepalive(JavaThread* thread, oop* keepalive) {
+    return Handle(thread, WeakHandle<vm_nmethod_keepalive_data>::from_raw(keepalive).resolve());
+  }
+
+  static oop read_keepalive(Handle obj) {
+    return obj();
+  }
+};
+
+class NoKeepalive {
+public:
+  typedef oop* TypeT;
+
+  static oop* make_keepalive(JavaThread* thread, oop* keepalive) {
+    return keepalive;
+  }
+
+  static oop read_keepalive(oop* keepalive) {
+    return WeakHandle<vm_nmethod_keepalive_data>::from_raw(keepalive).resolve();
+  }
+};
+
+template <bool compressed_oops, bool post_barrier, bool gen_stubs, bool g1gc>
 class Config {
 public:
-  typedef Config<compressed_oops, post_barrier, gen_stubs> SelfT;
+  typedef Config<compressed_oops, post_barrier, gen_stubs, g1gc> SelfT;
   typedef typename Conditional<compressed_oops, narrowOop, oop>::type OopT;
   typedef typename Conditional<post_barrier, RawOopWriter<SelfT>, NormalOopWriter<SelfT> >::type OopWriterT;
+  typedef typename Conditional<g1gc, NoKeepalive, HandleKeepalive>::type KeepaliveObjectT;
 
   static const bool _compressed_oops = compressed_oops;
   static const bool _post_barrier = post_barrier;
@@ -4283,27 +4350,42 @@
 
   template <bool use_compressed, bool is_modref>
   static void resolve_gencode() {
-    LoomGenCode ? resolve<use_compressed, is_modref, true>()
-                : resolve<use_compressed, is_modref, false>();
+    LoomGenCode 
+      ? resolve_g1<use_compressed, is_modref, true>()
+      : resolve_g1<use_compressed, is_modref, false>();
   } 
 
-  template <bool use_compressed, bool is_modref, bool gen_code>
+  template <bool use_compressed, bool is_modref, bool gencode>
+  static void resolve_g1() {
+    UseG1GC && UseContinuationStrong
+      ? resolve<use_compressed, is_modref, gencode, true>()
+      : resolve<use_compressed, is_modref, gencode, false>();
+  }
+
+  template <bool use_compressed, bool is_modref, bool gencode, bool g1gc>
   static void resolve() {
     // tty->print_cr(">>> ConfigResolve::resolve use_compressed: %d is_modref: %d gen_code:%d", use_compressed, is_modref, gen_code);
 
-    cont_freeze_fast    = Config<use_compressed, is_modref, gen_code>::template freeze<mode_fast>;
-    cont_freeze_slow    = Config<use_compressed, is_modref, gen_code>::template freeze<mode_slow>;
-    cont_freeze_preempt = Config<use_compressed, is_modref, gen_code>::template freeze<mode_preempt>;
-
-    cont_thaw_fast    = Config<use_compressed, is_modref, gen_code>::template thaw<mode_fast>;
-    cont_thaw_slow    = Config<use_compressed, is_modref, gen_code>::template thaw<mode_slow>;
-    cont_thaw_preempt = Config<use_compressed, is_modref, gen_code>::template thaw<mode_preempt>;
+    cont_freeze_fast    = Config<use_compressed, is_modref, gencode, g1gc>::template freeze<mode_fast>;
+    cont_freeze_slow    = Config<use_compressed, is_modref, gencode, g1gc>::template freeze<mode_slow>;
+    cont_freeze_preempt = Config<use_compressed, is_modref, gencode, g1gc>::template freeze<mode_preempt>;
+
+    cont_thaw_fast    = Config<use_compressed, is_modref, gencode, g1gc>::template thaw<mode_fast>;
+    cont_thaw_slow    = Config<use_compressed, is_modref, gencode, g1gc>::template thaw<mode_slow>;
+    cont_thaw_preempt = Config<use_compressed, is_modref, gencode, g1gc>::template thaw<mode_preempt>;
   }
 };
 
 void Continuations::init() {
   ConfigResolve::resolve();
   OopMapStubGenerator::init();
+  Continuation::init();
+}
+
+void Continuation::init() {
+  _weak_handles = new OopStorage("Continuation NMethodKeepalive weak",
+      NMethodKeepaliveAlloc_lock,
+      NMethodKeepaliveActive_lock);
 }
 
 class KeepaliveCleanupClosure : public ThreadClosure {
@@ -4316,12 +4398,12 @@
 
   virtual void do_thread(Thread* thread) {
     JavaThread* jthread = (JavaThread*) thread;
-    GrowableArray<jweak>* cleanup_list = jthread->keepalive_cleanup();
+    GrowableArray<WeakHandle<vm_nmethod_keepalive_data> >* cleanup_list = jthread->keepalive_cleanup();
     int len = cleanup_list->length();
     _count += len;
     for (int i = 0; i < len; ++i) {
-      jweak ref = cleanup_list->at(i);
-      JNIHandles::destroy_weak_global(ref);
+      WeakHandle<vm_nmethod_keepalive_data> ref = cleanup_list->at(i);
+      ref.release();
     }
 
     cleanup_list->clear();
@@ -4377,9 +4459,16 @@
 #endif
 
 void Continuation::nmethod_patched(nmethod* nm) {
-  log_info(jvmcont)("nmethod patched %p", nm);
-  jweak shadow = nm->get_shadow();
-  oop resolved = JNIHandles::resolve(shadow);
+  //log_info(jvmcont)("nmethod patched %p", nm);
+  oop* keepalive = nm->get_keepalive();
+  if (keepalive == NULL) {
+    return;
+  }
+  WeakHandle<vm_nmethod_keepalive_data> wh = WeakHandle<vm_nmethod_keepalive_data>::from_raw(keepalive);
+  oop resolved = wh.resolve();
+#ifdef DEBUG
+  Universe::heap()->is_in_or_null(resolved);
+#endif
 
 #ifndef PRODUCT
   CountOops count;
--- a/src/hotspot/share/runtime/continuation.hpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/runtime/continuation.hpp	Wed Aug 14 10:13:51 2019 +0200
@@ -67,9 +67,16 @@
 
 class javaVFrame;
 class JavaThread;
+class OopStorage;
 
 class Continuation : AllStatic {
+private:
+  static OopStorage* _weak_handles;
 public:
+  static void init();
+
+  static OopStorage* weak_storage() { return _weak_handles; }
+
   static int freeze(JavaThread* thread, FrameInfo* fi, bool from_interpreter);
   static int prepare_thaw(FrameInfo* fi, bool return_barrier);
   static address thaw_leaf(FrameInfo* fi, bool return_barrier, bool exception);
--- a/src/hotspot/share/runtime/globals.hpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/runtime/globals.hpp	Wed Aug 14 10:13:51 2019 +0200
@@ -2439,6 +2439,9 @@
   product(bool, UseContinuationLazyCopy, true,                              \
       "Use lazy-copy in continuations")                                     \
                                                                             \
+  product(bool, UseContinuationStrong, true,                                \
+      "The weak keepalive is considered strong on stack")                   \
+                                                                            \
   product(bool, UseContinuationFastPath, true,                              \
       "Use fast-path frame walking in continuations")                       \
                                                                             \
--- a/src/hotspot/share/runtime/mutexLocker.cpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/runtime/mutexLocker.cpp	Wed Aug 14 10:13:51 2019 +0200
@@ -59,6 +59,8 @@
 Mutex*   VMWeakActive_lock            = NULL;
 Mutex*   ResolvedMethodTableWeakAlloc_lock  = NULL;
 Mutex*   ResolvedMethodTableWeakActive_lock = NULL;
+Mutex*   NMethodKeepaliveAlloc_lock   = NULL;
+Mutex*   NMethodKeepaliveActive_lock  = NULL;
 Mutex*   JmethodIdCreation_lock       = NULL;
 Mutex*   JfieldIdCreation_lock        = NULL;
 Monitor* JNICritical_lock             = NULL;
@@ -228,6 +230,9 @@
   def(ResolvedMethodTableWeakAlloc_lock    , PaddedMutex  , oopstorage,   true,  Monitor::_safepoint_check_never);
   def(ResolvedMethodTableWeakActive_lock   , PaddedMutex  , oopstorage-1, true,  Monitor::_safepoint_check_never);
 
+  def(NMethodKeepaliveAlloc_lock   , PaddedMutex  , oopstorage,   true,  Monitor::_safepoint_check_never);
+  def(NMethodKeepaliveActive_lock  , PaddedMutex  , oopstorage-1, true,  Monitor::_safepoint_check_never);
+
   def(FullGCCount_lock             , PaddedMonitor, leaf,        true,  Monitor::_safepoint_check_never);      // in support of ExplicitGCInvokesConcurrent
   if (UseG1GC) {
     def(DirtyCardQ_CBL_mon         , PaddedMonitor, access,      true,  Monitor::_safepoint_check_never);
--- a/src/hotspot/share/runtime/mutexLocker.hpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/runtime/mutexLocker.hpp	Wed Aug 14 10:13:51 2019 +0200
@@ -52,6 +52,8 @@
 extern Mutex*   VMWeakActive_lock;               // VM Weak Handles storage active list lock
 extern Mutex*   ResolvedMethodTableWeakAlloc_lock;  // ResolvedMethodTable weak storage allocate list
 extern Mutex*   ResolvedMethodTableWeakActive_lock; // ResolvedMethodTable weak storage active list
+extern Mutex*   NMethodKeepaliveAlloc_lock;      // Continuation weak storage allocate list
+extern Mutex*   NMethodKeepaliveActive_lock;     // Continuation weak storage active list
 extern Mutex*   JmethodIdCreation_lock;          // a lock on creating JNI method identifiers
 extern Mutex*   JfieldIdCreation_lock;           // a lock on creating JNI static field identifiers
 extern Monitor* JNICritical_lock;                // a lock used while entering and exiting JNI critical regions, allows GC to sometimes get in
--- a/src/hotspot/share/runtime/thread.cpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/runtime/thread.cpp	Wed Aug 14 10:13:51 2019 +0200
@@ -1681,7 +1681,7 @@
   set_vframe_array_head(NULL);
   set_vframe_array_last(NULL);
   set_deferred_locals(NULL);
-  set_keepalive_cleanup(new (ResourceObj::C_HEAP, mtInternal) GrowableArray<jweak>(16, true));
+  set_keepalive_cleanup(new (ResourceObj::C_HEAP, mtInternal) GrowableArray<WeakHandle<vm_nmethod_keepalive_data> >(16, true));
   set_deopt_mark(NULL);
   set_deopt_compiled_method(NULL);
   clear_must_deopt_id();
--- a/src/hotspot/share/runtime/thread.hpp	Mon Aug 12 09:24:33 2019 +0100
+++ b/src/hotspot/share/runtime/thread.hpp	Wed Aug 14 10:13:51 2019 +0200
@@ -1025,7 +1025,7 @@
   // This holds the pointer to array (yeah like there might be more than one) of
   // description of compiled vframes that have locals that need to be updated.
   GrowableArray<jvmtiDeferredLocalVariableSet*>* _deferred_locals_updates;
-  GrowableArray<jweak>* _keepalive_cleanup;
+  GrowableArray<WeakHandle<vm_nmethod_keepalive_data> >* _keepalive_cleanup;
 
   // Handshake value for fixing 6243940. We need a place for the i2c
   // adapter to store the callee Method*. This value is NEVER live
@@ -1519,8 +1519,8 @@
   GrowableArray<jvmtiDeferredLocalVariableSet*>* deferred_locals() const { return _deferred_locals_updates; }
   void set_deferred_locals(GrowableArray<jvmtiDeferredLocalVariableSet *>* vf) { _deferred_locals_updates = vf; }
 
-  void set_keepalive_cleanup(GrowableArray<jweak>* lst) { _keepalive_cleanup = lst; }
-  GrowableArray<jweak>* keepalive_cleanup() const { return _keepalive_cleanup; }
+  void set_keepalive_cleanup(GrowableArray<WeakHandle<vm_nmethod_keepalive_data> >* lst) { _keepalive_cleanup = lst; }
+  GrowableArray<WeakHandle<vm_nmethod_keepalive_data> >* keepalive_cleanup() const { return _keepalive_cleanup; }
 
   // These only really exist to make debugging deopt problems simpler