8074548: Never-taken branches cause repeated deopts in MHs.GWT case
authorvlivanov
Fri, 20 Mar 2015 11:41:34 -0700
changeset 30190 a57955ac2bc1
parent 30189 0dce8215957a
child 30191 7fad0b2b89b0
8074548: Never-taken branches cause repeated deopts in MHs.GWT case Reviewed-by: jrose, kvn
hotspot/src/share/vm/opto/library_call.cpp
--- a/hotspot/src/share/vm/opto/library_call.cpp	Fri Mar 20 11:41:34 2015 -0700
+++ b/hotspot/src/share/vm/opto/library_call.cpp	Fri Mar 20 11:41:34 2015 -0700
@@ -5873,12 +5873,46 @@
                           Deoptimization::Action_reinterpret);
       return true;
     }
+
+    // result is a boolean (0 or 1) and its profile (false_cnt & true_cnt)
+    // is a number of each value occurrences.
+    Node* result = argument(0);
+    if (false_cnt == 0 || true_cnt == 0) {
+      // According to profile, one value has been never seen.
+      int expected_val = (false_cnt == 0) ? 1 : 0;
+
+      Node* cmp  = _gvn.transform(new CmpINode(result, intcon(expected_val)));
+      Node* test = _gvn.transform(new BoolNode(cmp, BoolTest::eq));
+
+      IfNode* check = create_and_map_if(control(), test, PROB_ALWAYS, COUNT_UNKNOWN);
+      Node* fast_path = _gvn.transform(new IfTrueNode(check));
+      Node* slow_path = _gvn.transform(new IfFalseNode(check));
+
+      { // Slow path: uncommon trap for never seen value and then reexecute
+        // MethodHandleImpl::profileBoolean() to bump the count, so JIT knows
+        // the value has been seen at least once.
+        PreserveJVMState pjvms(this);
+        PreserveReexecuteState preexecs(this);
+        jvms()->set_should_reexecute(true);
+
+        set_control(slow_path);
+        set_i_o(i_o());
+
+        uncommon_trap_exact(Deoptimization::Reason_intrinsic,
+                            Deoptimization::Action_reinterpret);
+      }
+      // The guard for never seen value enables sharpening of the result and
+      // returning a constant. It allows to eliminate branches on the same value
+      // later on.
+      set_control(fast_path);
+      result = intcon(expected_val);
+    }
     // Stop profiling.
-    // MethodHandleImpl::profileBoolean() has profiling logic in it's bytecode.
-    // By replacing method's body with profile data (represented as ProfileBooleanNode
+    // MethodHandleImpl::profileBoolean() has profiling logic in its bytecode.
+    // By replacing method body with profile data (represented as ProfileBooleanNode
     // on IR level) we effectively disable profiling.
     // It enables full speed execution once optimized code is generated.
-    Node* profile = _gvn.transform(new ProfileBooleanNode(argument(0), false_cnt, true_cnt));
+    Node* profile = _gvn.transform(new ProfileBooleanNode(result, false_cnt, true_cnt));
     C->record_for_igvn(profile);
     set_result(profile);
     return true;