< prev index next >

src/hotspot/share/opto/loopUnswitch.cpp

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.

@@ -27,10 +27,14 @@
 #include "opto/connode.hpp"
 #include "opto/convertnode.hpp"
 #include "opto/loopnode.hpp"
 #include "opto/opaquenode.hpp"
 #include "opto/rootnode.hpp"
+#include "utilities/macros.hpp"
+#if INCLUDE_SHENANDOAHGC
+#include "gc/shenandoah/c2/shenandoahBarrierSetC2.hpp"
+#endif
 
 //================= Loop Unswitching =====================
 //
 // orig:                       transformed:
 //                               if (invariant-test) then

@@ -52,11 +56,11 @@
 // Note: the "else" clause may be empty
 
 //------------------------------policy_unswitching-----------------------------
 // Return TRUE or FALSE if the loop should be unswitched
 // (ie. clone loop with an invariant test that does not exit the loop)
-bool IdealLoopTree::policy_unswitching( PhaseIdealLoop *phase ) const {
+bool IdealLoopTree::policy_unswitching(PhaseIdealLoop *phase, bool shenandoah_opts) const {
   if( !LoopUnswitching ) {
     return false;
   }
   if (!_head->is_Loop()) {
     return false;

@@ -73,21 +77,22 @@
   }
   LoopNode* head = _head->as_Loop();
   if (head->unswitch_count() + 1 > head->unswitch_max()) {
     return false;
   }
-  return phase->find_unswitching_candidate(this) != NULL;
+  return phase->find_unswitching_candidate(this, shenandoah_opts) != NULL;
 }
 
 //------------------------------find_unswitching_candidate-----------------------------
 // Find candidate "if" for unswitching
-IfNode* PhaseIdealLoop::find_unswitching_candidate(const IdealLoopTree *loop) const {
+IfNode* PhaseIdealLoop::find_unswitching_candidate(const IdealLoopTree *loop, bool shenandoah_opts) const {
 
   // Find first invariant test that doesn't exit the loop
   LoopNode *head = loop->_head->as_Loop();
   IfNode* unswitch_iff = NULL;
   Node* n = head->in(LoopNode::LoopBackControl);
+  int loop_has_sfpts = -1;
   while (n != head) {
     Node* n_dom = idom(n);
     if (n->is_Region()) {
       if (n_dom->is_If()) {
         IfNode* iff = n_dom->as_If();

@@ -97,10 +102,33 @@
             // If condition is invariant and not a loop exit,
             // then found reason to unswitch.
             if (loop->is_invariant(bol) && !loop->is_loop_exit(iff)) {
               unswitch_iff = iff;
             }
+#if INCLUDE_SHENANDOAHGC
+            else if (shenandoah_opts &&
+                       (ShenandoahWriteBarrierNode::is_heap_stable_test(iff)) &&
+                       (loop_has_sfpts == -1 || loop_has_sfpts == 0)) {
+              assert(UseShenandoahGC, "shenandoah only");
+              assert(!loop->is_loop_exit(iff), "both branches should be in the loop");
+              if (loop_has_sfpts == -1) {
+                for(uint i = 0; i < loop->_body.size(); i++) {
+                  Node *m = loop->_body[i];
+                  if (m->is_SafePoint() && !m->is_CallLeaf()) {
+                    loop_has_sfpts = 1;
+                    break;
+                  }
+                }
+                if (loop_has_sfpts == -1) {
+                  loop_has_sfpts = 0;
+                }
+              }
+              if (!loop_has_sfpts) {
+                unswitch_iff = iff;
+              }
+            }
+#endif
           }
         }
       }
     }
     n = n_dom;

@@ -110,16 +138,23 @@
 
 //------------------------------do_unswitching-----------------------------
 // Clone loop with an invariant test (that does not exit) and
 // insert a clone of the test that selects which version to
 // execute.
-void PhaseIdealLoop::do_unswitching (IdealLoopTree *loop, Node_List &old_new) {
+void PhaseIdealLoop::do_unswitching(IdealLoopTree *loop, Node_List &old_new, bool shenandoah_opts) {
 
   // Find first invariant test that doesn't exit the loop
   LoopNode *head = loop->_head->as_Loop();
 
-  IfNode* unswitch_iff = find_unswitching_candidate((const IdealLoopTree *)loop);
+  IfNode* unswitch_iff = find_unswitching_candidate((const IdealLoopTree *)loop, shenandoah_opts);
+
+#if INCLUDE_SHENANDOAHGC
+  if (ShenandoahWriteBarrierNode::is_heap_stable_test(unswitch_iff)) {
+    ShenandoahWriteBarrierNode::move_heap_stable_test_out_of_loop(unswitch_iff, this);
+  }
+#endif
+
   assert(unswitch_iff != NULL, "should be at least one");
 
 #ifndef PRODUCT
   if (TraceLoopOpts) {
     tty->print("Unswitch   %d ", head->unswitch_count()+1);
< prev index next >