mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8226705: [REDO] Deoptimize with handshakes
Reviewed-by: eosterlund, dcubed, dlong, pchilanomate
This commit is contained in:
parent
336b741b1c
commit
35a9f6864a
33 changed files with 398 additions and 326 deletions
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue