< prev index next >

src/share/vm/opto/loopTransform.cpp

Print this page
rev 9032 : 8215265: C2: range check elimination may allow illegal out of bound access
Reviewed-by: thartmann, kvn

@@ -1535,17 +1535,24 @@
   return _phase->dom_lca_internal(ctrl, backedge) == ctrl;
 }
 
 //------------------------------adjust_limit-----------------------------------
 // Helper function for add_constraint().
-Node* PhaseIdealLoop::adjust_limit(int stride_con, Node * scale, Node *offset, Node *rc_limit, Node *loop_limit, Node *pre_ctrl) {
+Node* PhaseIdealLoop::adjust_limit(int stride_con, Node * scale, Node *offset, Node *rc_limit, Node *loop_limit, Node *pre_ctrl, bool round_up) {
   // Compute "I :: (limit-offset)/scale"
   Node *con = new (C) SubINode(rc_limit, offset);
   register_new_node(con, pre_ctrl);
   Node *X = new (C) DivINode(0, con, scale);
   register_new_node(X, pre_ctrl);
 
+  // When the absolute value of scale is greater than one, the integer
+  // division may round limit down so add one to the limit.
+  if (round_up) {
+    X = new (C) AddINode(X, _igvn.intcon(1));
+    register_new_node(X, pre_ctrl);
+  }
+
   // Adjust loop limit
   loop_limit = (stride_con > 0)
                ? (Node*)(new (C) MinINode(loop_limit, X))
                : (Node*)(new (C) MaxINode(loop_limit, X));
   register_new_node(loop_limit, pre_ctrl);

@@ -1582,11 +1589,11 @@
     //   )
     //
     // (upper_limit-offset) may overflow or underflow.
     // But it is fine since main loop will either have
     // less iterations or will be skipped in such case.
-    *main_limit = adjust_limit(stride_con, scale, offset, upper_limit, *main_limit, pre_ctrl);
+    *main_limit = adjust_limit(stride_con, scale, offset, upper_limit, *main_limit, pre_ctrl, false);
 
     // The underflow limit: low_limit <= scale*I+offset.
     // For pre-loop compute
     //   NOT(scale*I+offset >= low_limit)
     //   scale*I+offset < low_limit

@@ -1618,11 +1625,12 @@
       // since (0-min_int) == min_int. It may be fine for stride > 0
       // but for stride < 0 X will be < original_limit. To avoid it
       // max(pre_limit, original_limit) is used in do_range_check().
     }
     // Pass (-stride) to indicate pre_loop_cond = NOT(main_loop_cond);
-    *pre_limit = adjust_limit((-stride_con), scale, offset, low_limit, *pre_limit, pre_ctrl);
+    *pre_limit = adjust_limit((-stride_con), scale, offset, low_limit, *pre_limit, pre_ctrl,
+                              scale_con > 1 && stride_con > 0);
 
   } else { // stride_con*scale_con < 0
     // For negative stride*scale pre-loop checks for overflow and
     // post-loop for underflow.
     //

@@ -1644,11 +1652,12 @@
     set_ctrl(one, C->root());
 
     Node *plus_one = new (C) AddINode(offset, one);
     register_new_node( plus_one, pre_ctrl );
     // Pass (-stride) to indicate pre_loop_cond = NOT(main_loop_cond);
-    *pre_limit = adjust_limit((-stride_con), scale, plus_one, upper_limit, *pre_limit, pre_ctrl);
+    *pre_limit = adjust_limit((-stride_con), scale, plus_one, upper_limit, *pre_limit, pre_ctrl,
+                              scale_con < -1 && stride_con > 0);
 
     if (low_limit->get_int() == -max_jint) {
       if (!RangeLimitCheck) return;
       // We need this guard when scale*main_limit+offset >= limit
       // due to underflow. So we need execute main-loop while

@@ -1679,11 +1688,12 @@
     //       I < (low_limit-(offset+1))/scale
     //     else /* scale > 0 and stride < 0 */
     //       I > (low_limit-(offset+1))/scale
     //   )
 
-    *main_limit = adjust_limit(stride_con, scale, plus_one, low_limit, *main_limit, pre_ctrl);
+    *main_limit = adjust_limit(stride_con, scale, plus_one, low_limit, *main_limit, pre_ctrl,
+                               false);
   }
 }
 
 
 //------------------------------is_scaled_iv---------------------------------
< prev index next >