changeset 7546:be740540f60c

8134493: Cleaning inline caches of unloaded nmethods should be done in sweeper Summary: Clean ICs of unloaded nmethods in sweeper to avoid impact on safepoint duration. Reviewed-by: kvn, mdoerr
author thartmann
date Thu, 08 Oct 2015 09:38:24 +0200
parents c1950f51ed60
children 15ef554f2f2e 3f47111161d7
files src/share/vm/code/codeCache.cpp src/share/vm/code/compiledIC.cpp src/share/vm/code/compiledIC.hpp src/share/vm/code/nmethod.cpp src/share/vm/code/nmethod.hpp src/share/vm/runtime/sweeper.cpp
diffstat 6 files changed, 20 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/code/codeCache.cpp	Thu Oct 08 09:37:51 2015 +0200
+++ b/src/share/vm/code/codeCache.cpp	Thu Oct 08 09:38:24 2015 +0200
@@ -521,13 +521,12 @@
 
 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());
--- a/src/share/vm/code/compiledIC.cpp	Thu Oct 08 09:37:51 2015 +0200
+++ b/src/share/vm/code/compiledIC.cpp	Thu Oct 08 09:38:24 2015 +0200
@@ -287,6 +287,7 @@
   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 @@
 }
 
 
-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 @@
 
   // 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
--- a/src/share/vm/code/compiledIC.hpp	Thu Oct 08 09:37:51 2015 +0200
+++ b/src/share/vm/code/compiledIC.hpp	Thu Oct 08 09:38:24 2015 +0200
@@ -228,7 +228,7 @@
   //
   // 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();
 
--- a/src/share/vm/code/nmethod.cpp	Thu Oct 08 09:37:51 2015 +0200
+++ b/src/share/vm/code/nmethod.cpp	Thu Oct 08 09:38:24 2015 +0200
@@ -1191,7 +1191,7 @@
         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 @@
 // 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
--- a/src/share/vm/code/nmethod.hpp	Thu Oct 08 09:37:51 2015 +0200
+++ b/src/share/vm/code/nmethod.hpp	Thu Oct 08 09:38:24 2015 +0200
@@ -605,7 +605,7 @@
 
   // 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; }
--- a/src/share/vm/runtime/sweeper.cpp	Thu Oct 08 09:37:51 2015 +0200
+++ b/src/share/vm/runtime/sweeper.cpp	Thu Oct 08 09:38:24 2015 +0200
@@ -538,7 +538,7 @@
   } 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 @@
       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++;