8173338: C2: continuous CallSite relinkage eventually disables compilation for a method
authorvlivanov
Tue, 31 Jan 2017 01:11:40 +0300
changeset 43675 a2b322083029
parent 43674 5d984252fc26
child 43676 c6eed495a42b
child 43677 5228814c1da2
8173338: C2: continuous CallSite relinkage eventually disables compilation for a method Reviewed-by: jrose, dlong, kvn
hotspot/src/share/vm/ci/ciEnv.cpp
hotspot/src/share/vm/ci/ciEnv.hpp
hotspot/src/share/vm/code/codeCache.cpp
hotspot/src/share/vm/code/nmethod.cpp
--- a/hotspot/src/share/vm/ci/ciEnv.cpp	Mon Jan 30 16:04:22 2017 +0300
+++ b/hotspot/src/share/vm/ci/ciEnv.cpp	Tue Jan 31 01:11:40 2017 +0300
@@ -101,6 +101,7 @@
   _debug_info = NULL;
   _dependencies = NULL;
   _failure_reason = NULL;
+  _inc_decompile_count_on_failure = true;
   _compilable = MethodCompilable;
   _break_at_compile = false;
   _compiler_data = NULL;
@@ -161,6 +162,7 @@
   _debug_info = NULL;
   _dependencies = NULL;
   _failure_reason = NULL;
+  _inc_decompile_count_on_failure = true;
   _compilable = MethodCompilable_never;
   _break_at_compile = false;
   _compiler_data = NULL;
@@ -902,7 +904,12 @@
     if (deps.is_klass_type())  continue;  // skip klass dependencies
     Klass* witness = deps.check_dependency();
     if (witness != NULL) {
-      record_failure("invalid non-klass dependency");
+      if (deps.type() == Dependencies::call_site_target_value) {
+        _inc_decompile_count_on_failure = false;
+        record_failure("call site target change");
+      } else {
+        record_failure("invalid non-klass dependency");
+      }
       return;
     }
   }
@@ -1017,7 +1024,7 @@
     if (failing()) {
       // While not a true deoptimization, it is a preemptive decompile.
       MethodData* mdo = method()->method_data();
-      if (mdo != NULL) {
+      if (mdo != NULL && _inc_decompile_count_on_failure) {
         mdo->inc_decompile_count();
       }
 
--- a/hotspot/src/share/vm/ci/ciEnv.hpp	Mon Jan 30 16:04:22 2017 +0300
+++ b/hotspot/src/share/vm/ci/ciEnv.hpp	Tue Jan 31 01:11:40 2017 +0300
@@ -55,6 +55,7 @@
   DebugInformationRecorder* _debug_info;
   Dependencies*    _dependencies;
   const char*      _failure_reason;
+  bool             _inc_decompile_count_on_failure;
   int              _compilable;
   bool             _break_at_compile;
   int              _num_inlined_bytecodes;
--- a/hotspot/src/share/vm/code/codeCache.cpp	Mon Jan 30 16:04:22 2017 +0300
+++ b/hotspot/src/share/vm/code/codeCache.cpp	Tue Jan 31 01:11:40 2017 +0300
@@ -1211,7 +1211,7 @@
   CompiledMethodIterator iter;
   while(iter.next_alive()) {
     CompiledMethod* nm = iter.method();
-    if (nm->is_marked_for_deoptimization()) {
+    if (nm->is_marked_for_deoptimization() && !nm->is_not_entrant()) {
       nm->make_not_entrant();
     }
   }
--- a/hotspot/src/share/vm/code/nmethod.cpp	Mon Jan 30 16:04:22 2017 +0300
+++ b/hotspot/src/share/vm/code/nmethod.cpp	Tue Jan 31 01:11:40 2017 +0300
@@ -1146,6 +1146,14 @@
   assert(state == zombie || state == not_entrant, "must be zombie or not_entrant");
   assert(!is_zombie(), "should not already be a zombie");
 
+  if (_state == state) {
+    // Avoid taking the lock if already in required state.
+    // This is safe from races because the state is an end-state,
+    // which the nmethod cannot back out of once entered.
+    // No need for fencing either.
+    return false;
+  }
+
   // 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());