8075805: Crash while trying to release CompiledICHolder
Summary: Removed nmethod transition to zombie outside of sweeper. Added cleaning of ICs of unloaded nmethods.
Reviewed-by: kvn, iveresov
--- a/hotspot/src/share/vm/code/codeCache.cpp Fri Aug 21 09:12:42 2015 +0200
+++ b/hotspot/src/share/vm/code/codeCache.cpp Tue Aug 25 07:49:55 2015 +0200
@@ -746,14 +746,17 @@
void CodeCache::gc_epilogue() {
assert_locked_or_safepoint(CodeCache_lock);
NMethodIterator iter;
- while(iter.next_alive()) {
+ while(iter.next()) {
nmethod* nm = iter.method();
- assert(!nm->is_unloaded(), "Tautology");
- if (needs_cache_clean()) {
- nm->cleanup_inline_caches();
+ if (!nm->is_zombie()) {
+ if (needs_cache_clean()) {
+ // 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);
prune_scavenge_root_nmethods();
@@ -993,29 +996,6 @@
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() {
assert_locked_or_safepoint(CodeCache_lock);
NMethodIterator iter;
@@ -1072,7 +1052,7 @@
// Deoptimize all activations depending on marked nmethods
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();
}
}
@@ -1102,7 +1082,7 @@
// Deoptimize all activations depending on marked nmethods
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();
}
}
--- a/hotspot/src/share/vm/code/codeCache.hpp Fri Aug 21 09:12:42 2015 +0200
+++ b/hotspot/src/share/vm/code/codeCache.hpp Tue Aug 25 07:49:55 2015 +0200
@@ -225,7 +225,6 @@
public:
static void mark_all_nmethods_for_deoptimization();
static int mark_for_deoptimization(Method* dependee);
- static void make_marked_nmethods_zombies();
static void make_marked_nmethods_not_entrant();
// Flushing and deoptimization
--- a/hotspot/src/share/vm/code/compiledIC.cpp Fri Aug 21 09:12:42 2015 +0200
+++ b/hotspot/src/share/vm/code/compiledIC.cpp Tue Aug 25 07:49:55 2015 +0200
@@ -343,8 +343,8 @@
// Kill any leftover stub we might have too
clear_ic_stub();
if (is_optimized()) {
- set_ic_destination(entry);
- } else {
+ set_ic_destination(entry);
+ } else {
set_ic_destination_and_value(entry, (void*)NULL);
}
} else {
--- a/hotspot/src/share/vm/code/compiledIC.hpp Fri Aug 21 09:12:42 2015 +0200
+++ b/hotspot/src/share/vm/code/compiledIC.hpp Tue Aug 25 07:49:55 2015 +0200
@@ -214,7 +214,7 @@
//
// 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 clear_ic_stub();
--- a/hotspot/src/share/vm/code/nmethod.cpp Fri Aug 21 09:12:42 2015 +0200
+++ b/hotspot/src/share/vm/code/nmethod.cpp Tue Aug 25 07:49:55 2015 +0200
@@ -1021,7 +1021,6 @@
void nmethod::cleanup_inline_caches() {
-
assert_locked_or_safepoint(CompiledIC_lock);
// If the method is not entrant or zombie then a JMP is plastered over the
@@ -1037,7 +1036,8 @@
// 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;
RelocIterator iter(this, low_boundary);
while(iter.next()) {
@@ -1049,7 +1049,7 @@
CodeBlob *cb = CodeCache::find_blob_unsafe(ic->ic_destination());
if( cb != NULL && cb->is_nmethod() ) {
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();
}
break;
@@ -1059,7 +1059,7 @@
CodeBlob *cb = CodeCache::find_blob_unsafe(csc->destination());
if( cb != NULL && cb->is_nmethod() ) {
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();
}
break;
@@ -2529,7 +2529,7 @@
// Hmm. OSR methods can be deopted but not marked as zombie or not_entrant
// seems odd.
- if( is_zombie() || is_not_entrant() )
+ if (is_zombie() || is_not_entrant() || is_unloaded())
return;
// Make sure all the entry points are correctly aligned for patching.
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Aug 21 09:12:42 2015 +0200
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Tue Aug 25 07:49:55 2015 +0200
@@ -3771,7 +3771,7 @@
// Deoptimize all activations depending on marked nmethods
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();
// From now on we know that the dependency information is complete
--- a/hotspot/src/share/vm/runtime/sweeper.cpp Fri Aug 21 09:12:42 2015 +0200
+++ b/hotspot/src/share/vm/runtime/sweeper.cpp Tue Aug 25 07:49:55 2015 +0200
@@ -618,19 +618,14 @@
MutexLocker cl(CompiledIC_lock);
nm->clear_ic_stubs();
}
- // Acquiring the CompiledIC_lock may block for a safepoint and set the
- // nmethod to zombie (see 'CodeCache::make_marked_nmethods_zombies').
- // 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;
+ 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;
assert(nm->is_zombie(), "nmethod must be zombie");
} else {
// Still alive, clean up its inline caches
--- a/hotspot/src/share/vm/runtime/vm_operations.cpp Fri Aug 21 09:12:42 2015 +0200
+++ b/hotspot/src/share/vm/runtime/vm_operations.cpp Tue Aug 25 07:49:55 2015 +0200
@@ -109,8 +109,8 @@
// Deoptimize all activations depending on marked nmethods
Deoptimization::deoptimize_dependents();
- // Make the dependent methods zombies
- CodeCache::make_marked_nmethods_zombies();
+ // Make the dependent methods not entrant
+ CodeCache::make_marked_nmethods_not_entrant();
}
void VM_MarkActiveNMethods::doit() {