8215754: ZGC: nmethod is not unlinked from Method before rendezvous handshake
Reviewed-by: pliden, neliasso
--- 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);