8215754: ZGC: nmethod is not unlinked from Method before rendezvous handshake
authoreosterlund
Fri, 11 Jan 2019 13:15:37 +0100
changeset 53282 cb7fff9105a8
parent 53281 672b629e1f72
child 53283 f7491df4fd3a
8215754: ZGC: nmethod is not unlinked from Method before rendezvous handshake Reviewed-by: pliden, neliasso
src/hotspot/share/code/nmethod.cpp
src/hotspot/share/code/nmethod.hpp
src/hotspot/share/gc/z/zBarrierSetNMethod.cpp
src/hotspot/share/gc/z/zNMethodTable.cpp
--- a/src/hotspot/share/code/nmethod.cpp	Fri Jan 11 11:02:00 2019 +0100
+++ b/src/hotspot/share/code/nmethod.cpp	Fri Jan 11 13:15:37 2019 +0100
@@ -1159,6 +1159,19 @@
   }
 }
 
+void nmethod::unlink_from_method(bool acquire_lock) {
+  // We need to check if both the _code and _from_compiled_code_entry_point
+  // refer to this nmethod because there is a race in setting these two fields
+  // in Method* as seen in bugid 4947125.
+  // If the vep() points to the zombie nmethod, the memory for the nmethod
+  // could be flushed and the compiler and vtable stubs could still call
+  // through it.
+  if (method() != NULL && (method()->code() == this ||
+                           method()->from_compiled_entry() == verified_entry_point())) {
+    method()->clear_code(acquire_lock);
+  }
+}
+
 /**
  * Common functionality for both make_not_entrant and make_zombie
  */
@@ -1246,17 +1259,7 @@
     JVMCI_ONLY(maybe_invalidate_installed_code());
 
     // Remove nmethod from method.
-    // We need to check if both the _code and _from_compiled_code_entry_point
-    // refer to this nmethod because there is a race in setting these two fields
-    // in Method* as seen in bugid 4947125.
-    // If the vep() points to the zombie nmethod, the memory for the nmethod
-    // could be flushed and the compiler and vtable stubs could still call
-    // through it.
-    if (method() != NULL && (method()->code() == this ||
-                             method()->from_compiled_entry() == verified_entry_point())) {
-      HandleMark hm;
-      method()->clear_code(false /* already owns Patching_lock */);
-    }
+    unlink_from_method(false /* already owns Patching_lock */);
   } // leave critical region under Patching_lock
 
 #ifdef ASSERT
--- a/src/hotspot/share/code/nmethod.hpp	Fri Jan 11 11:02:00 2019 +0100
+++ b/src/hotspot/share/code/nmethod.hpp	Fri Jan 11 13:15:37 2019 +0100
@@ -376,6 +376,8 @@
 
   int   comp_level() const                        { return _comp_level; }
 
+  void unlink_from_method(bool acquire_lock);
+
   // Support for oops in scopes and relocs:
   // Note: index 0 is reserved for null.
   oop   oop_at(int index) const;
--- a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp	Fri Jan 11 11:02:00 2019 +0100
+++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp	Fri Jan 11 13:15:37 2019 +0100
@@ -42,6 +42,11 @@
   }
 
   if (nm->is_unloading()) {
+    // We don't need to take the lock when unlinking nmethods from
+    // the Method, because it is only concurrently unlinked by
+    // the entry barrier, which acquires the per nmethod lock.
+    nm->unlink_from_method(false /* acquire_lock */);
+
     // We can end up calling nmethods that are unloading
     // since we clear compiled ICs lazily. Returning false
     // will re-resovle the call and update the compiled IC.
--- a/src/hotspot/share/gc/z/zNMethodTable.cpp	Fri Jan 11 11:02:00 2019 +0100
+++ b/src/hotspot/share/gc/z/zNMethodTable.cpp	Fri Jan 11 13:15:37 2019 +0100
@@ -611,15 +611,20 @@
       return;
     }
 
+    ZLocker<ZReentrantLock> locker(ZNMethodTable::lock_for_nmethod(nm));
+
     if (nm->is_unloading()) {
       // Unlinking of the dependencies must happen before the
       // handshake separating unlink and purge.
       nm->flush_dependencies(false /* delete_immediately */);
+
+      // We don't need to take the lock when unlinking nmethods from
+      // the Method, because it is only concurrently unlinked by
+      // the entry barrier, which acquires the per nmethod lock.
+      nm->unlink_from_method(false /* acquire_lock */);
       return;
     }
 
-    ZLocker<ZReentrantLock> locker(ZNMethodTable::lock_for_nmethod(nm));
-
     // Heal oops and disarm
     ZNMethodOopClosure cl;
     ZNMethodTable::entry_oops_do(entry, &cl);