diff --git a/src/share/vm/code/codeCache.cpp b/src/share/vm/code/codeCache.cpp index d6629967227cbfc10d5acd10838bf0f2122e3b8c..c9059d73c67f0e5962ff49a6fb6ac58f3bcc06b0 100644 --- a/src/share/vm/code/codeCache.cpp +++ b/src/share/vm/code/codeCache.cpp @@ -521,13 +521,12 @@ void CodeCache::gc_prologue() { void CodeCache::gc_epilogue() { assert_locked_or_safepoint(CodeCache_lock); - FOR_ALL_ALIVE_BLOBS(cb) { - if (cb->is_nmethod()) { - nmethod *nm = (nmethod*)cb; - 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. + NOT_DEBUG(if (needs_cache_clean())) { + FOR_ALL_ALIVE_BLOBS(cb) { + if (cb->is_nmethod()) { + nmethod *nm = (nmethod*)cb; + assert(!nm->is_unloaded(), "Tautology"); + DEBUG_ONLY(if (needs_cache_clean())) { nm->cleanup_inline_caches(); } DEBUG_ONLY(nm->verify()); diff --git a/src/share/vm/code/compiledIC.cpp b/src/share/vm/code/compiledIC.cpp index 45f25274eeb2a90d81fa8534a8591ae69373e364..478a6cf58d0c0707aeaefe292c737d0124802470 100644 --- a/src/share/vm/code/compiledIC.cpp +++ b/src/share/vm/code/compiledIC.cpp @@ -287,6 +287,7 @@ bool CompiledIC::is_call_to_compiled() const { assert( is_c1_method || !is_monomorphic || is_optimized() || + !caller->is_alive() || (cached_metadata() != NULL && cached_metadata()->is_klass()), "sanity check"); #endif // ASSERT return is_monomorphic; @@ -321,7 +322,7 @@ bool CompiledIC::is_call_to_interpreted() const { } -void CompiledIC::set_to_clean() { +void CompiledIC::set_to_clean(bool in_use) { assert(SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->is_locked() , "MT-unsafe call"); if (TraceInlineCacheClearing || TraceICs) { tty->print_cr("IC@" INTPTR_FORMAT ": set to clean", p2i(instruction_address())); @@ -337,7 +338,7 @@ void CompiledIC::set_to_clean() { // A zombie transition will always be safe, since the metadata has already been set to NULL, so // we only need to patch the destination - bool safe_transition = is_optimized() || SafepointSynchronize::is_at_safepoint(); + bool safe_transition = !in_use || is_optimized() || SafepointSynchronize::is_at_safepoint(); if (safe_transition) { // Kill any leftover stub we might have too diff --git a/src/share/vm/code/compiledIC.hpp b/src/share/vm/code/compiledIC.hpp index a24bf315e435bbc53b768c2ccbe105797cded258..b797329ac727066be32533b3344009315d62dd0c 100644 --- a/src/share/vm/code/compiledIC.hpp +++ b/src/share/vm/code/compiledIC.hpp @@ -228,7 +228,7 @@ class CompiledIC: public ResourceObj { // // They all takes a TRAP argument, since they can cause a GC if the inline-cache buffer is full. // - void set_to_clean(); + void set_to_clean(bool in_use = true); void set_to_monomorphic(CompiledICInfo& info); void clear_ic_stub(); diff --git a/src/share/vm/code/nmethod.cpp b/src/share/vm/code/nmethod.cpp index f8be257ecde65333a9c34510340ae82de008a909..94f49629be297b039f8fde2684492bbd632294e8 100644 --- a/src/share/vm/code/nmethod.cpp +++ b/src/share/vm/code/nmethod.cpp @@ -1191,7 +1191,7 @@ void nmethod::cleanup_inline_caches() { if( cb != NULL && cb->is_nmethod() ) { nmethod* nm = (nmethod*)cb; // 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(is_alive()); } break; } @@ -1291,7 +1291,7 @@ void nmethod::mark_as_seen_on_stack() { // Tell if a non-entrant method can be converted to a zombie (i.e., // there are no activations on the stack, not in use by the VM, // and not in use by the ServiceThread) -bool nmethod::can_not_entrant_be_converted() { +bool nmethod::can_convert_to_zombie() { assert(is_not_entrant(), "must be a non-entrant method"); // Since the nmethod sweeper only does partial sweep the sweeper's traversal diff --git a/src/share/vm/code/nmethod.hpp b/src/share/vm/code/nmethod.hpp index b661cfe4eceecba0c9ffb6e3a09f9bfe30ef7755..b7d6890055c0f9941fe6b411091dd491820a9f4a 100644 --- a/src/share/vm/code/nmethod.hpp +++ b/src/share/vm/code/nmethod.hpp @@ -605,7 +605,7 @@ public: // See comment at definition of _last_seen_on_stack void mark_as_seen_on_stack(); - bool can_not_entrant_be_converted(); + bool can_convert_to_zombie(); // Evolution support. We make old (discarded) compiled methods point to new Method*s. void set_method(Method* method) { _method = method; } diff --git a/src/share/vm/runtime/sweeper.cpp b/src/share/vm/runtime/sweeper.cpp index 5348faab6a392df10c2ca7e481b05a0f123a3844..b4954ff861559b6f7b07712c970359b150d140ee 100644 --- a/src/share/vm/runtime/sweeper.cpp +++ b/src/share/vm/runtime/sweeper.cpp @@ -538,7 +538,7 @@ int NMethodSweeper::process_nmethod(nmethod *nm) { } else if (nm->is_not_entrant()) { // If there are no current activations of this method on the // stack we can safely convert it to a zombie method - if (nm->can_not_entrant_be_converted()) { + if (nm->can_convert_to_zombie()) { if (PrintMethodFlushing && Verbose) { tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (not entrant) being made zombie", nm->compile_id(), nm); } @@ -571,6 +571,12 @@ int NMethodSweeper::process_nmethod(nmethod *nm) { release_nmethod(nm); _flushed_count++; } else { + { + // Clean ICs of unloaded nmethods as well because they may reference other + // unloaded nmethods that may be flushed earlier in the sweeper cycle. + MutexLocker cl(CompiledIC_lock); + nm->cleanup_inline_caches(); + } // Code cache state change is tracked in make_zombie() nm->make_zombie(); _zombified_count++;