8215754: ZGC: nmethod is not unlinked from Method before rendezvous handshake
Reviewed-by: pliden, neliasso
This commit is contained in:
parent
804d51618f
commit
c03e894387
@ -1159,6 +1159,19 @@ void nmethod::log_state_change() const {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ bool nmethod::make_not_entrant_or_zombie(int state) {
|
||||
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
|
||||
|
@ -376,6 +376,8 @@ class nmethod : public CompiledMethod {
|
||||
|
||||
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;
|
||||
|
@ -42,6 +42,11 @@ bool ZBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) {
|
||||
}
|
||||
|
||||
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.
|
||||
|
@ -611,15 +611,20 @@ public:
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user