# HG changeset patch # User eosterlund # Date 1547208937 -3600 # Node ID cb7fff9105a8819d73773b290d88b36227f7d11d # Parent 672b629e1f7208062ab65ed0d8f8950bac465d43 8215754: ZGC: nmethod is not unlinked from Method before rendezvous handshake Reviewed-by: pliden, neliasso diff -r 672b629e1f72 -r cb7fff9105a8 src/hotspot/share/code/nmethod.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 diff -r 672b629e1f72 -r cb7fff9105a8 src/hotspot/share/code/nmethod.hpp --- 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; diff -r 672b629e1f72 -r cb7fff9105a8 src/hotspot/share/gc/z/zBarrierSetNMethod.cpp --- 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. diff -r 672b629e1f72 -r cb7fff9105a8 src/hotspot/share/gc/z/zNMethodTable.cpp --- 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 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 locker(ZNMethodTable::lock_for_nmethod(nm)); - // Heal oops and disarm ZNMethodOopClosure cl; ZNMethodTable::entry_oops_do(entry, &cl);