< prev index next >

src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp

Print this page
rev 59811 : 8247670: Shenandoah: deadlock during class unloading OOME

@@ -218,10 +218,11 @@
 
 class ShenandoahNMethodUnlinkClosure : public NMethodClosure {
 private:
   bool                      _unloading_occurred;
   volatile bool             _failed;
+  bool                      _refill_icBuffer;
   ShenandoahHeap* const     _heap;
   BarrierSetNMethod* const  _bs;
 
   void set_failed() {
     Atomic::store(&_failed, true);

@@ -245,10 +246,11 @@
    }
 public:
   ShenandoahNMethodUnlinkClosure(bool unloading_occurred) :
       _unloading_occurred(unloading_occurred),
       _failed(false),
+      _refill_icBuffer(false),
       _heap(ShenandoahHeap::heap()),
       _bs(ShenandoahBarrierSet::barrier_set()->barrier_set_nmethod()) {}
 
   virtual void do_nmethod(nmethod* nm) {
     assert(_heap->is_concurrent_weak_root_in_progress(), "Only this phase");

@@ -262,29 +264,42 @@
     if (!nm->is_alive()) {
       return;
     }
 
     if (nm->is_unloading()) {
-      ShenandoahReentrantLocker locker(nm_data->lock());
+      ShenandoahAbortableNMethodLocker locker(nm_data->lock());
+      if (locker.aborted()) {
+        set_failed();
+      } else {
       unlink(nm);
+      }
       return;
     }
 
-    ShenandoahReentrantLocker locker(nm_data->lock());
+    ShenandoahAbortableNMethodLocker locker(nm_data->lock());
+    if (locker.aborted()) {
+      set_failed();
+      return;
+    }
 
     // Heal oops and disarm
     if (_bs->is_armed(nm)) {
       ShenandoahNMethod::heal_nmethod_metadata(nm_data);
       _bs->disarm(nm);
     }
 
     // Clear compiled ICs and exception caches
     if (!nm->unload_nmethod_caches(_unloading_occurred)) {
+      _refill_icBuffer = true;
       set_failed();
     }
   }
 
+  bool need_refill_icBuffer() const {
+    return _refill_icBuffer;
+  }
+
   bool failed() const {
     return Atomic::load(&_failed);
   }
 };
 

@@ -316,33 +331,41 @@
   }
 
   bool success() const {
     return !_cl.failed();
   }
+
+  bool need_refill_icBuffer() const {
+    return _cl.need_refill_icBuffer();
+  }
 };
 
 void ShenandoahCodeRoots::unlink(WorkGang* workers, bool unloading_occurred) {
   assert(ShenandoahConcurrentRoots::should_do_concurrent_class_unloading(),
          "Only when running concurrent class unloading");
 
   for (;;) {
     ICRefillVerifier verifier;
+    bool need_refill_icBuffer = false;
 
     {
       ShenandoahUnlinkTask task(unloading_occurred, &verifier);
       workers->run_task(&task);
       if (task.success()) {
         return;
       }
+      need_refill_icBuffer = task.need_refill_icBuffer();
     }
 
+    if (need_refill_icBuffer) {
     // Cleaning failed because we ran out of transitional IC stubs,
     // so we have to refill and try again. Refilling requires taking
     // a safepoint, so we temporarily leave the suspendible thread set.
     SuspendibleThreadSetLeaver sts;
     InlineCacheBuffer::refill_ic_stubs();
   }
+  }
 }
 
 class ShenandoahNMethodPurgeClosure : public NMethodClosure {
 public:
   virtual void do_nmethod(nmethod* nm) {
< prev index next >