8221734: Deoptimize with handshakes

Reviewed-by: dcubed, dholmes, pchilanomate, dlong, coleenp
This commit is contained in:
Robbin Ehn 2019-05-23 10:13:29 +02:00
parent 4ea77d3e78
commit 9baafa55a6
28 changed files with 274 additions and 175 deletions

View file

@ -50,6 +50,7 @@
#include "oops/oop.inline.hpp"
#include "prims/jvmtiImpl.hpp"
#include "runtime/atomic.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/flags/flagSetting.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
@ -1176,11 +1177,7 @@ void nmethod::make_unloaded() {
// have the Method* live here, in case we unload the nmethod because
// it is pointing to some oop (other than the Method*) being unloaded.
if (_method != NULL) {
// OSR methods point to the Method*, but the Method* does not
// point back!
if (_method->code() == this) {
_method->clear_code(); // Break a cycle
}
_method->unlink_code(this);
}
// Make the class unloaded - i.e., change state and notify sweeper
@ -1262,16 +1259,9 @@ 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);
void nmethod::unlink_from_method() {
if (method() != NULL) {
method()->unlink_code();
}
}
@ -1298,24 +1288,24 @@ bool nmethod::make_not_entrant_or_zombie(int state) {
// during patching, depending on the nmethod state we must notify the GC that
// code has been unloaded, unregistering it. We cannot do this right while
// holding the Patching_lock because we need to use the CodeCache_lock. This
// holding the CompiledMethod_lock because we need to use the CodeCache_lock. This
// would be prone to deadlocks.
// This flag is used to remember whether we need to later lock and unregister.
bool nmethod_needs_unregister = false;
{
// invalidate osr nmethod before acquiring the patching lock since
// they both acquire leaf locks and we don't want a deadlock.
// This logic is equivalent to the logic below for patching the
// verified entry point of regular methods. We check that the
// nmethod is in use to ensure that it is invalidated only once.
if (is_osr_method() && is_in_use()) {
// this effectively makes the osr nmethod not entrant
invalidate_osr_method();
}
// invalidate osr nmethod before acquiring the patching lock since
// they both acquire leaf locks and we don't want a deadlock.
// This logic is equivalent to the logic below for patching the
// verified entry point of regular methods. We check that the
// nmethod is in use to ensure that it is invalidated only once.
if (is_osr_method() && is_in_use()) {
// this effectively makes the osr nmethod not entrant
invalidate_osr_method();
}
{
// Enter critical section. Does not block for safepoint.
MutexLocker pl(Patching_lock, Mutex::_no_safepoint_check_flag);
MutexLocker pl(CompiledMethod_lock, Mutex::_no_safepoint_check_flag);
if (_state == state) {
// another thread already performed this transition so nothing
@ -1359,8 +1349,9 @@ bool nmethod::make_not_entrant_or_zombie(int state) {
log_state_change();
// Remove nmethod from method.
unlink_from_method(false /* already owns Patching_lock */);
} // leave critical region under Patching_lock
unlink_from_method();
} // leave critical region under CompiledMethod_lock
#if INCLUDE_JVMCI
// Invalidate can't occur while holding the Patching lock