--- old/src/share/vm/code/nmethod.cpp 2013-08-14 15:08:13.879502226 +0200 +++ new/src/share/vm/code/nmethod.cpp 2013-08-14 15:08:13.555502231 +0200 @@ -1302,6 +1302,13 @@ methodHandle the_method(method()); No_Safepoint_Verifier nsv; + // during patching, depending on the nmethod state we must notify the GC that + // the code has been unloaded, unregistering it. We cannot do this right while + // holding the Patching_lock because we need to use the CodeCache_lock, but + // CodeCache_lock has a higher mutex level. Deadlock detection will complain. + // 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. @@ -1334,10 +1341,11 @@ inc_decompile_count(); } - // If the state is becoming a zombie, unregister the nmethod with heap + // If the state is becoming a zombie, signal to unregister the nmethod with + // the heap. // This nmethod may have already been unloaded during a full GC. if ((state == zombie) && !is_unloaded()) { - Universe::heap()->unregister_nmethod(this); + nmethod_needs_unregister = true; } // Change state @@ -1375,6 +1383,9 @@ // safepoint can sneak in, otherwise the oops used by the // dependency logic could have become stale. MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + if (nmethod_needs_unregister) { + Universe::heap()->unregister_nmethod(this); + } flush_dependencies(NULL); } @@ -1838,7 +1849,8 @@ // oops. void nmethod::oops_do(OopClosure* f, bool do_strong_roots_only) { // make sure the oops ready to receive visitors - assert(!is_zombie() && !is_unloaded(), + assert(NMethodSweeper::is_sweeping(this) || is_marked_for_deoptimization() || + (!is_zombie() && !is_unloaded()), "should not call follow on zombie or unloaded nmethod"); // If the method is not entrant or zombie then a JMP is plastered over the --- old/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp 2013-08-14 15:08:23.415502058 +0200 +++ new/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp 2013-08-14 15:08:22.975502065 +0200 @@ -6689,12 +6689,16 @@ }; void G1CollectedHeap::register_nmethod(nmethod* nm) { + CollectedHeap::register_nmethod(nm); + guarantee(nm != NULL, "sanity"); RegisterNMethodOopClosure reg_cl(this, nm); nm->oops_do(®_cl); } void G1CollectedHeap::unregister_nmethod(nmethod* nm) { + CollectedHeap::unregister_nmethod(nm); + guarantee(nm != NULL, "sanity"); UnregisterNMethodOopClosure reg_cl(this, nm); nm->oops_do(®_cl); --- old/src/share/vm/gc_interface/collectedHeap.hpp 2013-08-14 15:08:48.343501618 +0200 +++ new/src/share/vm/gc_interface/collectedHeap.hpp 2013-08-14 15:08:48.063501623 +0200 @@ -605,9 +605,9 @@ void print_heap_after_gc(); // Registering and unregistering an nmethod (compiled code) with the heap. - // Override with specific mechanism for each specialized heap type - virtual void register_nmethod(nmethod* nm) {} - virtual void unregister_nmethod(nmethod* nm) {} + // Override with specific mechanism for each specialized heap type. + virtual void register_nmethod(nmethod* nm); + virtual void unregister_nmethod(nmethod* nm); void trace_heap_before_gc(GCTracer* gc_tracer); void trace_heap_after_gc(GCTracer* gc_tracer);