8226705: [REDO] Deoptimize with handshakes

Reviewed-by: eosterlund, dcubed, dlong, pchilanomate
This commit is contained in:
Robbin Ehn 2019-09-19 10:52:22 +02:00
parent 336b741b1c
commit 35a9f6864a
33 changed files with 398 additions and 326 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"
@ -476,7 +477,6 @@ nmethod* nmethod::new_native_nmethod(const methodHandle& method,
debug_only(nm->verify();) // might block
nm->log_new_nmethod();
nm->make_in_use();
}
return nm;
}
@ -1138,6 +1138,11 @@ void nmethod::inc_decompile_count() {
bool nmethod::try_transition(int new_state_int) {
signed char new_state = new_state_int;
#ifdef DEBUG
if (new_state != unloaded) {
assert_lock_strong(CompiledMethod_lock);
}
#endif
for (;;) {
signed char old_state = Atomic::load(&_state);
if (old_state >= new_state) {
@ -1193,11 +1198,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
@ -1281,16 +1282,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(this);
}
}
@ -1317,24 +1311,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 ml(CompiledMethod_lock->owned_by_self() ? NULL : CompiledMethod_lock, Mutex::_no_safepoint_check_flag);
if (Atomic::load(&_state) >= state) {
// another thread already performed this transition so nothing
@ -1389,8 +1383,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