8075805: Crash while trying to release CompiledICHolder
Removed nmethod transition to zombie outside of sweeper. Added cleaning of ICs of unloaded nmethods. Reviewed-by: kvn, iveresov
This commit is contained in:
parent
a9e232a8ef
commit
72e8f28d56
@ -746,14 +746,17 @@ void CodeCache::gc_prologue() {
|
|||||||
void CodeCache::gc_epilogue() {
|
void CodeCache::gc_epilogue() {
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
NMethodIterator iter;
|
NMethodIterator iter;
|
||||||
while(iter.next_alive()) {
|
while(iter.next()) {
|
||||||
nmethod* nm = iter.method();
|
nmethod* nm = iter.method();
|
||||||
assert(!nm->is_unloaded(), "Tautology");
|
if (!nm->is_zombie()) {
|
||||||
if (needs_cache_clean()) {
|
if (needs_cache_clean()) {
|
||||||
nm->cleanup_inline_caches();
|
// Clean ICs of unloaded nmethods as well because they may reference other
|
||||||
|
// unloaded nmethods that may be flushed earlier in the sweeper cycle.
|
||||||
|
nm->cleanup_inline_caches();
|
||||||
|
}
|
||||||
|
DEBUG_ONLY(nm->verify());
|
||||||
|
DEBUG_ONLY(nm->verify_oop_relocations());
|
||||||
}
|
}
|
||||||
DEBUG_ONLY(nm->verify());
|
|
||||||
DEBUG_ONLY(nm->verify_oop_relocations());
|
|
||||||
}
|
}
|
||||||
set_needs_cache_clean(false);
|
set_needs_cache_clean(false);
|
||||||
prune_scavenge_root_nmethods();
|
prune_scavenge_root_nmethods();
|
||||||
@ -993,29 +996,6 @@ int CodeCache::mark_for_deoptimization(Method* dependee) {
|
|||||||
return number_of_marked_CodeBlobs;
|
return number_of_marked_CodeBlobs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeCache::make_marked_nmethods_zombies() {
|
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
|
|
||||||
NMethodIterator iter;
|
|
||||||
while(iter.next_alive()) {
|
|
||||||
nmethod* nm = iter.method();
|
|
||||||
if (nm->is_marked_for_deoptimization()) {
|
|
||||||
|
|
||||||
// If the nmethod has already been made non-entrant and it can be converted
|
|
||||||
// then zombie it now. Otherwise make it non-entrant and it will eventually
|
|
||||||
// be zombied when it is no longer seen on the stack. Note that the nmethod
|
|
||||||
// might be "entrant" and not on the stack and so could be zombied immediately
|
|
||||||
// but we can't tell because we don't track it on stack until it becomes
|
|
||||||
// non-entrant.
|
|
||||||
|
|
||||||
if (nm->is_not_entrant() && nm->can_not_entrant_be_converted()) {
|
|
||||||
nm->make_zombie();
|
|
||||||
} else {
|
|
||||||
nm->make_not_entrant();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeCache::make_marked_nmethods_not_entrant() {
|
void CodeCache::make_marked_nmethods_not_entrant() {
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
NMethodIterator iter;
|
NMethodIterator iter;
|
||||||
@ -1072,7 +1052,7 @@ void CodeCache::flush_evol_dependents_on(instanceKlassHandle ev_k_h) {
|
|||||||
// Deoptimize all activations depending on marked nmethods
|
// Deoptimize all activations depending on marked nmethods
|
||||||
Deoptimization::deoptimize_dependents();
|
Deoptimization::deoptimize_dependents();
|
||||||
|
|
||||||
// Make the dependent methods not entrant (in VM_Deoptimize they are made zombies)
|
// Make the dependent methods not entrant
|
||||||
make_marked_nmethods_not_entrant();
|
make_marked_nmethods_not_entrant();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1102,7 +1082,7 @@ void CodeCache::flush_dependents_on_method(methodHandle m_h) {
|
|||||||
// Deoptimize all activations depending on marked nmethods
|
// Deoptimize all activations depending on marked nmethods
|
||||||
Deoptimization::deoptimize_dependents();
|
Deoptimization::deoptimize_dependents();
|
||||||
|
|
||||||
// Make the dependent methods not entrant (in VM_Deoptimize they are made zombies)
|
// Make the dependent methods not entrant
|
||||||
make_marked_nmethods_not_entrant();
|
make_marked_nmethods_not_entrant();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,7 +225,6 @@ class CodeCache : AllStatic {
|
|||||||
public:
|
public:
|
||||||
static void mark_all_nmethods_for_deoptimization();
|
static void mark_all_nmethods_for_deoptimization();
|
||||||
static int mark_for_deoptimization(Method* dependee);
|
static int mark_for_deoptimization(Method* dependee);
|
||||||
static void make_marked_nmethods_zombies();
|
|
||||||
static void make_marked_nmethods_not_entrant();
|
static void make_marked_nmethods_not_entrant();
|
||||||
|
|
||||||
// Flushing and deoptimization
|
// Flushing and deoptimization
|
||||||
|
@ -343,8 +343,8 @@ void CompiledIC::set_to_clean() {
|
|||||||
// Kill any leftover stub we might have too
|
// Kill any leftover stub we might have too
|
||||||
clear_ic_stub();
|
clear_ic_stub();
|
||||||
if (is_optimized()) {
|
if (is_optimized()) {
|
||||||
set_ic_destination(entry);
|
set_ic_destination(entry);
|
||||||
} else {
|
} else {
|
||||||
set_ic_destination_and_value(entry, (void*)NULL);
|
set_ic_destination_and_value(entry, (void*)NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -214,7 +214,7 @@ class CompiledIC: public ResourceObj {
|
|||||||
//
|
//
|
||||||
// They all takes a TRAP argument, since they can cause a GC if the inline-cache buffer is full.
|
// They all takes a TRAP argument, since they can cause a GC if the inline-cache buffer is full.
|
||||||
//
|
//
|
||||||
void set_to_clean(); // Can only be called during a safepoint operation
|
void set_to_clean();
|
||||||
void set_to_monomorphic(CompiledICInfo& info);
|
void set_to_monomorphic(CompiledICInfo& info);
|
||||||
void clear_ic_stub();
|
void clear_ic_stub();
|
||||||
|
|
||||||
|
@ -1021,7 +1021,6 @@ void nmethod::clear_ic_stubs() {
|
|||||||
|
|
||||||
|
|
||||||
void nmethod::cleanup_inline_caches() {
|
void nmethod::cleanup_inline_caches() {
|
||||||
|
|
||||||
assert_locked_or_safepoint(CompiledIC_lock);
|
assert_locked_or_safepoint(CompiledIC_lock);
|
||||||
|
|
||||||
// If the method is not entrant or zombie then a JMP is plastered over the
|
// If the method is not entrant or zombie then a JMP is plastered over the
|
||||||
@ -1037,7 +1036,8 @@ void nmethod::cleanup_inline_caches() {
|
|||||||
// In fact, why are we bothering to look at oops in a non-entrant method??
|
// In fact, why are we bothering to look at oops in a non-entrant method??
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find all calls in an nmethod, and clear the ones that points to zombie methods
|
// Find all calls in an nmethod and clear the ones that point to non-entrant,
|
||||||
|
// zombie and unloaded nmethods.
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
RelocIterator iter(this, low_boundary);
|
RelocIterator iter(this, low_boundary);
|
||||||
while(iter.next()) {
|
while(iter.next()) {
|
||||||
@ -1049,7 +1049,7 @@ void nmethod::cleanup_inline_caches() {
|
|||||||
CodeBlob *cb = CodeCache::find_blob_unsafe(ic->ic_destination());
|
CodeBlob *cb = CodeCache::find_blob_unsafe(ic->ic_destination());
|
||||||
if( cb != NULL && cb->is_nmethod() ) {
|
if( cb != NULL && cb->is_nmethod() ) {
|
||||||
nmethod* nm = (nmethod*)cb;
|
nmethod* nm = (nmethod*)cb;
|
||||||
// Clean inline caches pointing to both zombie and not_entrant methods
|
// Clean inline caches pointing to zombie, non-entrant and unloaded methods
|
||||||
if (!nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean();
|
if (!nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1059,7 +1059,7 @@ void nmethod::cleanup_inline_caches() {
|
|||||||
CodeBlob *cb = CodeCache::find_blob_unsafe(csc->destination());
|
CodeBlob *cb = CodeCache::find_blob_unsafe(csc->destination());
|
||||||
if( cb != NULL && cb->is_nmethod() ) {
|
if( cb != NULL && cb->is_nmethod() ) {
|
||||||
nmethod* nm = (nmethod*)cb;
|
nmethod* nm = (nmethod*)cb;
|
||||||
// Clean inline caches pointing to both zombie and not_entrant methods
|
// Clean inline caches pointing to zombie, non-entrant and unloaded methods
|
||||||
if (!nm->is_in_use() || (nm->method()->code() != nm)) csc->set_to_clean();
|
if (!nm->is_in_use() || (nm->method()->code() != nm)) csc->set_to_clean();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2529,7 +2529,7 @@ void nmethod::verify() {
|
|||||||
// Hmm. OSR methods can be deopted but not marked as zombie or not_entrant
|
// Hmm. OSR methods can be deopted but not marked as zombie or not_entrant
|
||||||
// seems odd.
|
// seems odd.
|
||||||
|
|
||||||
if( is_zombie() || is_not_entrant() )
|
if (is_zombie() || is_not_entrant() || is_unloaded())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Make sure all the entry points are correctly aligned for patching.
|
// Make sure all the entry points are correctly aligned for patching.
|
||||||
|
@ -3771,7 +3771,7 @@ void VM_RedefineClasses::flush_dependent_code(instanceKlassHandle k_h, TRAPS) {
|
|||||||
// Deoptimize all activations depending on marked nmethods
|
// Deoptimize all activations depending on marked nmethods
|
||||||
Deoptimization::deoptimize_dependents();
|
Deoptimization::deoptimize_dependents();
|
||||||
|
|
||||||
// Make the dependent methods not entrant (in VM_Deoptimize they are made zombies)
|
// Make the dependent methods not entrant
|
||||||
CodeCache::make_marked_nmethods_not_entrant();
|
CodeCache::make_marked_nmethods_not_entrant();
|
||||||
|
|
||||||
// From now on we know that the dependency information is complete
|
// From now on we know that the dependency information is complete
|
||||||
|
@ -618,19 +618,14 @@ NMethodSweeper::MethodStateChange NMethodSweeper::process_nmethod(nmethod* nm) {
|
|||||||
MutexLocker cl(CompiledIC_lock);
|
MutexLocker cl(CompiledIC_lock);
|
||||||
nm->clear_ic_stubs();
|
nm->clear_ic_stubs();
|
||||||
}
|
}
|
||||||
// Acquiring the CompiledIC_lock may block for a safepoint and set the
|
if (PrintMethodFlushing && Verbose) {
|
||||||
// nmethod to zombie (see 'CodeCache::make_marked_nmethods_zombies').
|
tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm);
|
||||||
// Check if nmethod is still non-entrant at this point.
|
|
||||||
if (nm->is_not_entrant()) {
|
|
||||||
if (PrintMethodFlushing && Verbose) {
|
|
||||||
tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm);
|
|
||||||
}
|
|
||||||
// Code cache state change is tracked in make_zombie()
|
|
||||||
nm->make_zombie();
|
|
||||||
SWEEP(nm);
|
|
||||||
assert(result == None, "sanity");
|
|
||||||
result = MadeZombie;
|
|
||||||
}
|
}
|
||||||
|
// Code cache state change is tracked in make_zombie()
|
||||||
|
nm->make_zombie();
|
||||||
|
SWEEP(nm);
|
||||||
|
assert(result == None, "sanity");
|
||||||
|
result = MadeZombie;
|
||||||
assert(nm->is_zombie(), "nmethod must be zombie");
|
assert(nm->is_zombie(), "nmethod must be zombie");
|
||||||
} else {
|
} else {
|
||||||
// Still alive, clean up its inline caches
|
// Still alive, clean up its inline caches
|
||||||
|
@ -109,8 +109,8 @@ void VM_Deoptimize::doit() {
|
|||||||
// Deoptimize all activations depending on marked nmethods
|
// Deoptimize all activations depending on marked nmethods
|
||||||
Deoptimization::deoptimize_dependents();
|
Deoptimization::deoptimize_dependents();
|
||||||
|
|
||||||
// Make the dependent methods zombies
|
// Make the dependent methods not entrant
|
||||||
CodeCache::make_marked_nmethods_zombies();
|
CodeCache::make_marked_nmethods_not_entrant();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VM_MarkActiveNMethods::doit() {
|
void VM_MarkActiveNMethods::doit() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user