src/share/vm/code/nmethod.cpp

Print this page
rev 5061 : imported patch nmethod_changes_original
rev 5062 : fix nmethod unregister synchronization

@@ -1300,10 +1300,17 @@
   // Make sure neither the nmethod nor the method is flushed in case of a safepoint in code below.
   nmethodLocker nml(this);
   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.
     // This logic is equivalent to the logic below for patching the
     // verified entry point of regular methods.

@@ -1332,14 +1339,15 @@
       // It's a true state change, so mark the method as decompiled.
       // Do it only for transition from alive.
       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
     _state = state;
 

@@ -1373,10 +1381,13 @@
     {
       // Flushing dependecies must be done before any possible
       // 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);
     }
 
     // zombie only - if a JVMTI agent has enabled the CompiledMethodUnload
     // event and it hasn't already been reported for this nmethod then

@@ -1836,11 +1847,12 @@
 // only in the second case. The weak roots in the nmethod
 // are the oops in the ExceptionCache and the InlineCache
 // 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
   // first few bytes.  If an oop in the old code was there, that oop
   // should not get GC'd.  Skip the first few bytes of oops on