changeset 9701:91cf080dfbfd JDK-8054307-branch

JDK-8054307-branch: Runtime checks for String intrinsics.
author thartmann
date Fri, 23 Oct 2015 11:53:55 +0200
parents ae1898197056
children 15b12d2eaab9
files src/share/vm/c1/c1_GraphBuilder.cpp src/share/vm/opto/library_call.cpp src/share/vm/opto/runtime.cpp src/share/vm/opto/runtime.hpp
diffstat 4 files changed, 134 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/c1/c1_GraphBuilder.cpp	Thu Oct 22 09:49:02 2015 +0200
+++ b/src/share/vm/c1/c1_GraphBuilder.cpp	Fri Oct 23 11:53:55 2015 +0200
@@ -4199,11 +4199,15 @@
   if (is_store) {
     Value value = args->at(2);
     Instruction* store = append(new StoreIndexed(array, index, NULL, T_CHAR, value, state_before));
+#ifndef ASSERT
     store->set_flag(Instruction::NeedsRangeCheckFlag, false);
+#endif
     _memory->store_value(value);
   } else {
     Instruction* load = append(new LoadIndexed(array, index, NULL, T_CHAR, state_before));
+#ifndef ASSERT
     load->set_flag(Instruction::NeedsRangeCheckFlag, false);
+#endif
     push(load->type(), load);
   }
 }
--- a/src/share/vm/opto/library_call.cpp	Thu Oct 22 09:49:02 2015 +0200
+++ b/src/share/vm/opto/library_call.cpp	Fri Oct 23 11:53:55 2015 +0200
@@ -45,6 +45,7 @@
 #include "opto/narrowptrnode.hpp"
 #include "opto/opaquenode.hpp"
 #include "opto/parse.hpp"
+#include "opto/rootnode.hpp"
 #include "opto/runtime.hpp"
 #include "opto/subnode.hpp"
 #include "prims/nativeLookup.hpp"
@@ -178,6 +179,8 @@
   Node* generate_array_guard(Node* kls, RegionNode* region) {
     return generate_array_guard_common(kls, region, false, false);
   }
+  void generate_runtime_limit_guard(Node* array, Node* offset, Node* subseq_length);
+  void generate_runtime_negative_guard(Node* array, Node* index);
   Node* generate_non_array_guard(Node* kls, RegionNode* region) {
     return generate_array_guard_common(kls, region, false, true);
   }
@@ -1118,14 +1121,24 @@
   Node* tgt_count   = argument(3);
   Node* from_index  = argument(4);
 
-  // Java code which calls this method has range checks for from_index value.
-  src_count = _gvn.transform(new SubINode(src_count, from_index));
-
   // Multiply byte array index by 2 if String is UTF16 encoded
   Node* src_offset = (ae == StrIntrinsicNode::LL) ? from_index : _gvn.transform(new LShiftINode(from_index, intcon(1)));
+  src_count = _gvn.transform(new SubINode(src_count, from_index));
   Node* src_start = array_element_address(src, src_offset, T_BYTE);
   Node* tgt_start = array_element_address(tgt, intcon(0), T_BYTE);
 
+#ifdef ASSERT
+  // Range checks are done by caller. Verify only in debug VM.
+  generate_runtime_negative_guard(src, src_offset);
+  generate_runtime_negative_guard(src, src_count);
+  generate_runtime_negative_guard(tgt, tgt_count);
+  Node* src_byte_count = _gvn.transform(new LShiftINode(src_count, intcon(1)));
+  Node* tgt_byte_count = _gvn.transform(new LShiftINode(tgt_count, intcon(1)));
+  generate_runtime_limit_guard(src, src_offset, (ae == StrIntrinsicNode::LL) ? src_count : src_byte_count);
+  generate_runtime_limit_guard(tgt, intcon(0), (ae == StrIntrinsicNode::UU) ? tgt_byte_count : tgt_count);
+  if (stopped()) return true;
+#endif
+
   Node* result = make_string_method_node(Op_StrIndexOf, src_start, src_count, tgt_start, tgt_count, ae);
 
   // The result is index relative to from_index if substring was found, -1 otherwise.
@@ -1168,9 +1181,17 @@
 
   Node* src_offset = _gvn.transform(new LShiftINode(from_index, intcon(1)));
   Node* src_start = array_element_address(src, src_offset, T_BYTE);
-
   Node* src_count = _gvn.transform(new SubINode(max, from_index));
 
+#ifdef ASSERT
+  // Range checks are done by caller. Verify only in debug VM.
+  generate_runtime_negative_guard(src, src_offset);
+  generate_runtime_negative_guard(src, src_count);
+  Node* byte_length = _gvn.transform(new LShiftINode(src_count, intcon(1)));
+  generate_runtime_limit_guard(src, src_offset, byte_length);
+  if (stopped()) return true;
+#endif
+
   RegionNode* region = new RegionNode(3);
   Node* phi = new PhiNode(region, TypeInt::INT);
 
@@ -1235,6 +1256,17 @@
     dst_offset = _gvn.transform(new LShiftINode(dst_offset, intcon(1)));
   }
 
+#ifdef ASSERT
+  // Range checks are done by caller. Verify only in debug VM.
+  generate_runtime_negative_guard(src, src_offset);
+  generate_runtime_negative_guard(dst, dst_offset);
+  generate_runtime_negative_guard(src, length);
+  Node* byte_length = _gvn.transform(new LShiftINode(length, intcon(1)));
+  generate_runtime_limit_guard(src, src_offset, (compress && src_elem == T_BYTE) ? byte_length : length);
+  generate_runtime_limit_guard(dst, dst_offset, (!compress && dst_elem == T_BYTE) ? byte_length : length);
+  if (stopped()) return true;
+#endif
+
   Node* src_start = array_element_address(src, src_offset, src_elem);
   Node* dst_start = array_element_address(dst, dst_offset, dst_elem);
   // 'src_start' points to src array + scaled offset
@@ -1295,7 +1327,13 @@
     value = null_check(value);
     if (stopped()) return true;
 
-    // Range checks are done by caller.
+#ifdef ASSERT
+    // Range checks are done by caller. Verify only in debug VM.
+    generate_runtime_negative_guard(value, offset);
+    generate_runtime_negative_guard(value, length);
+    generate_runtime_limit_guard(value, offset, length);
+    if (stopped()) return true;
+#endif
 
     Node* size = _gvn.transform(new LShiftINode(length, intcon(1)));
     Node* klass_node = makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_BYTE)));
@@ -1370,12 +1408,21 @@
     return true;
   }
 
-  // Range checks are done by caller.
-
   // Get length and convert char[] offset to byte[] offset
   Node* length = _gvn.transform(new SubINode(src_end, src_begin));
   src_begin = _gvn.transform(new LShiftINode(src_begin, intcon(1)));
 
+#ifdef ASSERT
+  // Range checks are done by caller. Verify only in debug VM.
+  generate_runtime_negative_guard(value, length);
+  generate_runtime_negative_guard(value, src_begin);
+  generate_runtime_negative_guard(dst, dst_begin);
+  Node* byte_length = _gvn.transform(new LShiftINode(length, intcon(1)));
+  generate_runtime_limit_guard(value, src_begin, byte_length);
+  generate_runtime_limit_guard(dst, dst_begin, length);
+  if (stopped()) return true;
+#endif
+
   if (!stopped()) {
     // Calculate starting addresses.
     Node* src_start = array_element_address(value, src_begin, T_BYTE);
@@ -1437,6 +1484,14 @@
   assert (type2aelembytes(T_CHAR) == type2aelembytes(T_BYTE)*2,
           "sanity: byte[] and char[] scales agree");
 
+#ifdef ASSERT
+  // Range checks are done by caller. Verify only in debug VM.
+  generate_runtime_negative_guard(value, index);
+  Node* byte_index = _gvn.transform(new LShiftINode(index, intcon(1)));
+  generate_runtime_limit_guard(value, byte_index, intcon(2));
+  if (stopped()) return true;
+#endif
+
   Node* adr = array_element_address(value, index, T_CHAR);
   if (is_store) {
     (void) store_to_memory(control(), adr, ch, T_CHAR, TypeAryPtr::BYTES, MemNode::unordered);
@@ -3660,6 +3715,49 @@
   return generate_fair_guard(bol, region);
 }
 
+void LibraryCallKit::generate_runtime_limit_guard(Node* array, Node* offset, Node* subseq_length) {
+  RegionNode* bailout = new RegionNode(1);
+  record_for_igvn(bailout);
+
+  generate_limit_guard(offset, subseq_length, load_array_length(array), bailout);
+  if (bailout->req() > 1) {
+    PreserveJVMState pjvms(this);
+    set_control(_gvn.transform(bailout));
+    Node* call = make_runtime_call(RC_NO_LEAF,
+                                   OptoRuntime::array_out_of_bounds_Type(),
+                                   OptoRuntime::array_out_of_bounds_Java(),
+                                   "array index out of bounds",
+                                   TypeRawPtr::BOTTOM,
+                                   offset, load_array_length(array));
+    call->set_req(TypeFunc::ReturnAdr, returnadr());
+    HaltNode* halt = new HaltNode(control(), frameptr());
+    root()->add_req(halt);
+    _gvn.transform(halt);
+    stop_and_kill_map();
+  }
+}
+
+void LibraryCallKit::generate_runtime_negative_guard(Node* array, Node* index) {
+  RegionNode* bailout = new RegionNode(1);
+  record_for_igvn(bailout);
+
+  generate_negative_guard(index, bailout);
+  if (bailout->req() > 1) {
+    PreserveJVMState pjvms(this);
+    set_control(_gvn.transform(bailout));
+    Node* call = make_runtime_call(RC_NO_LEAF,
+                                   OptoRuntime::array_out_of_bounds_Type(),
+                                   OptoRuntime::array_out_of_bounds_Java(),
+                                   "array index out of bounds",
+                                   TypeRawPtr::BOTTOM,
+                                   index, load_array_length(array));
+    call->set_req(TypeFunc::ReturnAdr, returnadr());
+    HaltNode* halt = new HaltNode(control(), frameptr());
+    root()->add_req(halt);
+    _gvn.transform(halt);
+    stop_and_kill_map();
+  }
+}
 
 //-----------------------inline_native_newArray--------------------------
 // private static native Object java.lang.reflect.newArray(Class<?> componentType, int length);
--- a/src/share/vm/opto/runtime.cpp	Thu Oct 22 09:49:02 2015 +0200
+++ b/src/share/vm/opto/runtime.cpp	Fri Oct 23 11:53:55 2015 +0200
@@ -98,6 +98,7 @@
 address OptoRuntime::_monitor_notify_Java                         = NULL;
 address OptoRuntime::_monitor_notifyAll_Java                      = NULL;
 address OptoRuntime::_rethrow_Java                                = NULL;
+address OptoRuntime::_array_out_of_bounds_Java                    = NULL;
 
 address OptoRuntime::_slow_arraycopy_Java                         = NULL;
 address OptoRuntime::_register_finalizer_Java                     = NULL;
@@ -148,6 +149,7 @@
   gen(env, _monitor_notify_Java            , monitor_notify_Type          , monitor_notify_C                ,    0 , false, false, false);
   gen(env, _monitor_notifyAll_Java         , monitor_notify_Type          , monitor_notifyAll_C             ,    0 , false, false, false);
   gen(env, _rethrow_Java                   , rethrow_Type                 , rethrow_C                       ,    2 , true , false, true );
+  gen(env, _array_out_of_bounds_Java       , array_out_of_bounds_Type     , array_out_of_bounds             ,    0 , false, false, false);
 
   gen(env, _slow_arraycopy_Java            , slow_arraycopy_Type          , SharedRuntime::slow_arraycopy_C ,    0 , false, false, false);
   gen(env, _register_finalizer_Java        , register_finalizer_Type      , register_finalizer              ,    0 , false, false, false);
@@ -429,6 +431,10 @@
   thread->set_vm_result(obj);
 JRT_END
 
+JRT_ENTRY(void, OptoRuntime::array_out_of_bounds(int index, int length, JavaThread *thread))
+  fatal(err_msg_res("Array index out of bounds: index = %d, length = %d", index, length));
+JRT_END
+
 JRT_BLOCK_ENTRY(void, OptoRuntime::monitor_notify_C(oopDesc* obj, JavaThread *thread))
 
   // Very few notify/notifyAll operations find any threads on the waitset, so
@@ -604,6 +610,20 @@
   return TypeFunc::make(domain, range);
 }
 
+const TypeFunc *OptoRuntime::array_out_of_bounds_Type() {
+  // create input type (domain)
+  const Type **fields = TypeTuple::fields(2);
+  fields[TypeFunc::Parms+0] = TypeInt::INT; // index
+  fields[TypeFunc::Parms+1] = TypeInt::INT; // length
+  const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+2, fields);
+
+  // create result type (range)
+  fields = TypeTuple::fields(0);
+  const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+0, fields);
+
+  return TypeFunc::make(domain, range);
+}
+
 # ifdef ENABLE_ZAP_DEAD_LOCALS
 // Type used for stub generation for zap_dead_locals.
 // No inputs or outputs
--- a/src/share/vm/opto/runtime.hpp	Thu Oct 22 09:49:02 2015 +0200
+++ b/src/share/vm/opto/runtime.hpp	Fri Oct 23 11:53:55 2015 +0200
@@ -148,6 +148,7 @@
   static address _rethrow_Java;
   static address _monitor_notify_Java;
   static address _monitor_notifyAll_Java;
+  static address _array_out_of_bounds_Java;
 
   static address _slow_arraycopy_Java;
   static address _register_finalizer_Java;
@@ -183,6 +184,8 @@
   static void g1_wb_pre_C(oopDesc* orig, JavaThread* thread);
   static void g1_wb_post_C(void* card_addr, JavaThread* thread);
 
+  static void array_out_of_bounds(int index, int length, JavaThread *thread);
+
 public:
   // Slow-path Locking and Unlocking
   static void complete_monitor_locking_C(oopDesc* obj, BasicLock* lock, JavaThread* thread);
@@ -252,6 +255,7 @@
   static address complete_monitor_locking_Java()         { return _complete_monitor_locking_Java; }
   static address monitor_notify_Java()                   { return _monitor_notify_Java; }
   static address monitor_notifyAll_Java()                { return _monitor_notifyAll_Java; }
+  static address array_out_of_bounds_Java()              { return _array_out_of_bounds_Java; }
 
   static address slow_arraycopy_Java()                   { return _slow_arraycopy_Java; }
   static address register_finalizer_Java()               { return _register_finalizer_Java; }
@@ -301,6 +305,7 @@
   static const TypeFunc* modf_Type();
   static const TypeFunc* l2f_Type();
   static const TypeFunc* void_long_Type();
+  static const TypeFunc* array_out_of_bounds_Type();
 
   static const TypeFunc* flush_windows_Type();