8042997: Make intrinsic some or all check index/range methods
authorroland
Mon, 16 Nov 2015 09:55:25 +0100
changeset 34180 f0ec91019db2
parent 34176 c1b52e665b47
child 34181 663d662fdff0
8042997: Make intrinsic some or all check index/range methods Summary: Objects.checkIndex() intrinsic Reviewed-by: vlivanov, shade
hotspot/src/share/vm/classfile/vmSymbols.hpp
hotspot/src/share/vm/opto/c2compiler.cpp
hotspot/src/share/vm/opto/ifnode.cpp
hotspot/src/share/vm/opto/library_call.cpp
hotspot/src/share/vm/opto/loopPredicate.cpp
hotspot/src/share/vm/opto/loopnode.cpp
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp	Fri Nov 13 18:14:41 2015 +0300
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp	Mon Nov 16 09:55:25 2015 +0100
@@ -109,6 +109,7 @@
   template(java_io_ByteArrayInputStream,              "java/io/ByteArrayInputStream")             \
   template(java_io_Serializable,                      "java/io/Serializable")                     \
   template(java_util_Arrays,                          "java/util/Arrays")                         \
+  template(java_util_Objects,                         "java/util/Objects")                         \
   template(java_util_Properties,                      "java/util/Properties")                     \
   template(java_util_Vector,                          "java/util/Vector")                         \
   template(java_util_AbstractList,                    "java/util/AbstractList")                   \
@@ -883,6 +884,9 @@
   do_intrinsic(_equalsL,                  java_lang_StringLatin1,equals_name, equalsB_signature,                 F_S)   \
   do_intrinsic(_equalsU,                  java_lang_StringUTF16, equals_name, equalsB_signature,                 F_S)   \
                                                                                                                         \
+  do_intrinsic(_Objects_checkIndex,       java_util_Objects,      checkIndex_name, Objects_checkIndex_signature, F_S)   \
+   do_signature(Objects_checkIndex_signature,                     "(IILjava/util/function/BiFunction;)I")               \
+                                                                                                                        \
   do_class(java_nio_Buffer,               "java/nio/Buffer")                                                            \
   do_intrinsic(_checkIndex,               java_nio_Buffer,        checkIndex_name, int_int_signature,            F_R)   \
    do_name(     checkIndex_name,                                 "checkIndex")                                          \
--- a/hotspot/src/share/vm/opto/c2compiler.cpp	Fri Nov 13 18:14:41 2015 +0300
+++ b/hotspot/src/share/vm/opto/c2compiler.cpp	Mon Nov 16 09:55:25 2015 +0100
@@ -451,6 +451,7 @@
   case vmIntrinsics::_updateByteBufferAdler32:
   case vmIntrinsics::_profileBoolean:
   case vmIntrinsics::_isCompileConstant:
+  case vmIntrinsics::_Objects_checkIndex:
     break;
   default:
     return false;
--- a/hotspot/src/share/vm/opto/ifnode.cpp	Fri Nov 13 18:14:41 2015 +0300
+++ b/hotspot/src/share/vm/opto/ifnode.cpp	Mon Nov 16 09:55:25 2015 +0100
@@ -485,7 +485,7 @@
     return NULL;
   }
   if (l->is_top())  return NULL;   // Top input means dead test
-  if (r->Opcode() != Op_LoadRange)  return NULL;
+  if (r->Opcode() != Op_LoadRange && !is_RangeCheck())  return NULL;
 
   // We have recognized one of these forms:
   //  Flip 1:  If (Bool[<] CmpU(l, LoadRange)) ...
@@ -525,9 +525,9 @@
     return 0;
   } else if (l->Opcode() == Op_AddI) {
     if ((off = l->in(1)->find_int_con(0)) != 0) {
-      ind = l->in(2);
+      ind = l->in(2)->uncast();
     } else if ((off = l->in(2)->find_int_con(0)) != 0) {
-      ind = l->in(1);
+      ind = l->in(1)->uncast();
     }
   } else if ((off = l->find_int_con(-1)) >= 0) {
     // constant offset with no variable index
--- a/hotspot/src/share/vm/opto/library_call.cpp	Fri Nov 13 18:14:41 2015 +0300
+++ b/hotspot/src/share/vm/opto/library_call.cpp	Mon Nov 16 09:55:25 2015 +0100
@@ -256,6 +256,7 @@
   bool inline_native_getLength();
   bool inline_array_copyOf(bool is_copyOfRange);
   bool inline_array_equals(StrIntrinsicNode::ArgEnc ae);
+  bool inline_objects_checkIndex();
   void copy_to_clone(Node* obj, Node* alloc_obj, Node* obj_size, bool is_array, bool card_mark);
   bool inline_native_clone(bool is_virtual);
   bool inline_native_Reflection_getCallerClass();
@@ -647,6 +648,7 @@
   case vmIntrinsics::_copyOfRange:              return inline_array_copyOf(true);
   case vmIntrinsics::_equalsB:                  return inline_array_equals(StrIntrinsicNode::LL);
   case vmIntrinsics::_equalsC:                  return inline_array_equals(StrIntrinsicNode::UU);
+  case vmIntrinsics::_Objects_checkIndex:       return inline_objects_checkIndex();
   case vmIntrinsics::_clone:                    return inline_native_clone(intrinsic()->is_virtual());
 
   case vmIntrinsics::_isAssignableFrom:         return inline_native_subtype_check();
@@ -1045,6 +1047,54 @@
   return true;
 }
 
+bool LibraryCallKit::inline_objects_checkIndex() {
+  Node* index = argument(0);
+  Node* length = argument(1);
+  if (too_many_traps(Deoptimization::Reason_intrinsic) || too_many_traps(Deoptimization::Reason_range_check)) {
+    return false;
+  }
+
+  Node* len_pos_cmp = _gvn.transform(new CmpINode(length, intcon(0)));
+  Node* len_pos_bol = _gvn.transform(new BoolNode(len_pos_cmp, BoolTest::ge));
+
+  {
+    BuildCutout unless(this, len_pos_bol, PROB_MAX);
+    uncommon_trap(Deoptimization::Reason_intrinsic,
+                  Deoptimization::Action_make_not_entrant);
+  }
+
+  if (stopped()) {
+    return false;
+  }
+
+  Node* rc_cmp = _gvn.transform(new CmpUNode(index, length));
+  BoolTest::mask btest = BoolTest::lt;
+  Node* rc_bool = _gvn.transform(new BoolNode(rc_cmp, btest));
+  RangeCheckNode* rc = new RangeCheckNode(control(), rc_bool, PROB_MAX, COUNT_UNKNOWN);
+  _gvn.set_type(rc, rc->Value(&_gvn));
+  if (!rc_bool->is_Con()) {
+    record_for_igvn(rc);
+  }
+  set_control(_gvn.transform(new IfTrueNode(rc)));
+  {
+    PreserveJVMState pjvms(this);
+    set_control(_gvn.transform(new IfFalseNode(rc)));
+    uncommon_trap(Deoptimization::Reason_range_check,
+                  Deoptimization::Action_make_not_entrant);
+  }
+
+  if (stopped()) {
+    return false;
+  }
+
+  Node* result = new CastIINode(index, TypeInt::make(0, _gvn.type(length)->is_int()->_hi, Type::WidenMax));
+  result->set_req(0, control());
+  result = _gvn.transform(result);
+  set_result(result);
+  replace_in_map(index, result);
+  return true;
+}
+
 //------------------------------inline_string_indexOf------------------------
 bool LibraryCallKit::inline_string_indexOf(StrIntrinsicNode::ArgEnc ae) {
   if (!Matcher::has_match_rule(Op_StrIndexOf) || !UseSSE42Intrinsics) {
--- a/hotspot/src/share/vm/opto/loopPredicate.cpp	Fri Nov 13 18:14:41 2015 +0300
+++ b/hotspot/src/share/vm/opto/loopPredicate.cpp	Mon Nov 16 09:55:25 2015 +0100
@@ -569,7 +569,7 @@
     return false;
   }
   Node* range = cmp->in(2);
-  if (range->Opcode() != Op_LoadRange) {
+  if (range->Opcode() != Op_LoadRange && !iff->is_RangeCheck()) {
     const TypeInt* tint = phase->_igvn.type(range)->isa_int();
     if (tint == NULL || tint->empty() || tint->_lo < 0) {
       // Allow predication on positive values that aren't LoadRanges.
--- a/hotspot/src/share/vm/opto/loopnode.cpp	Fri Nov 13 18:14:41 2015 +0300
+++ b/hotspot/src/share/vm/opto/loopnode.cpp	Mon Nov 16 09:55:25 2015 +0100
@@ -329,6 +329,9 @@
 
   Node* phi_incr = NULL;
   // Trip-counter increment must be commutative & associative.
+  if (incr->Opcode() == Op_CastII) {
+    incr = incr->in(1);
+  }
   if (incr->is_Phi()) {
     if (incr->as_Phi()->region() != x || incr->req() != 3)
       return false; // Not simple trip counter expression
@@ -356,6 +359,9 @@
     xphi = stride;
     stride = tmp;
   }
+  if (xphi->Opcode() == Op_CastII) {
+    xphi = xphi->in(1);
+  }
   // Stride must be constant
   int stride_con = stride->get_int();
   if (stride_con == 0)