hotspot/src/share/vm/opto/library_call.cpp
changeset 33628 09241459a8b8
parent 33465 6063f28a6efb
child 34157 4fde32e81092
child 33638 ef49ed90010b
--- a/hotspot/src/share/vm/opto/library_call.cpp	Mon Nov 02 12:34:27 2015 +0000
+++ b/hotspot/src/share/vm/opto/library_call.cpp	Tue Nov 03 09:41:03 2015 +0100
@@ -200,12 +200,16 @@
   }
   Node * load_field_from_object(Node * fromObj, const char * fieldName, const char * fieldTypeString, bool is_exact, bool is_static, ciInstanceKlass * fromKls);
 
-  Node* make_string_method_node(int opcode, Node* str1_start, Node* cnt1, Node* str2_start, Node* cnt2);
-  Node* make_string_method_node(int opcode, Node* str1, Node* str2);
-  bool inline_string_compareTo();
-  bool inline_string_indexOf();
-  Node* string_indexOf(Node* string_object, ciTypeArray* target_array, jint offset, jint cache_i, jint md2_i);
-  bool inline_string_equals();
+  Node* make_string_method_node(int opcode, Node* str1_start, Node* cnt1, Node* str2_start, Node* cnt2, StrIntrinsicNode::ArgEnc ae);
+  bool inline_string_compareTo(StrIntrinsicNode::ArgEnc ae);
+  bool inline_string_indexOf(StrIntrinsicNode::ArgEnc ae);
+  bool inline_string_indexOfI(StrIntrinsicNode::ArgEnc ae);
+  bool inline_string_indexOfChar();
+  bool inline_string_equals(StrIntrinsicNode::ArgEnc ae);
+  bool inline_string_toBytesU();
+  bool inline_string_getCharsU();
+  bool inline_string_copy(bool compress);
+  bool inline_string_char_access(bool is_store);
   Node* round_double_node(Node* n);
   bool runtime_math(const TypeFunc* call_type, address funcAddr, const char* funcName);
   bool inline_math_native(vmIntrinsics::ID id);
@@ -251,7 +255,7 @@
   bool inline_native_newArray();
   bool inline_native_getLength();
   bool inline_array_copyOf(bool is_copyOfRange);
-  bool inline_array_equals();
+  bool inline_array_equals(StrIntrinsicNode::ArgEnc ae);
   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();
@@ -298,6 +302,7 @@
   bool inline_updateBytesAdler32();
   bool inline_updateByteBufferAdler32();
   bool inline_multiplyToLen();
+  bool inline_hasNegatives();
   bool inline_squareToLen();
   bool inline_mulAdd();
   bool inline_montgomeryMultiply();
@@ -458,6 +463,7 @@
 bool LibraryCallKit::try_to_inline(int predicate) {
   // Handle symbolic names for otherwise undistinguished boolean switches:
   const bool is_store       = true;
+  const bool is_compress    = true;
   const bool is_native_ptr  = true;
   const bool is_static      = true;
   const bool is_volatile    = true;
@@ -512,9 +518,31 @@
 
   case vmIntrinsics::_arraycopy:                return inline_arraycopy();
 
-  case vmIntrinsics::_compareTo:                return inline_string_compareTo();
-  case vmIntrinsics::_indexOf:                  return inline_string_indexOf();
-  case vmIntrinsics::_equals:                   return inline_string_equals();
+  case vmIntrinsics::_compareToL:               return inline_string_compareTo(StrIntrinsicNode::LL);
+  case vmIntrinsics::_compareToU:               return inline_string_compareTo(StrIntrinsicNode::UU);
+  case vmIntrinsics::_compareToLU:              return inline_string_compareTo(StrIntrinsicNode::LU);
+  case vmIntrinsics::_compareToUL:              return inline_string_compareTo(StrIntrinsicNode::UL);
+
+  case vmIntrinsics::_indexOfL:                 return inline_string_indexOf(StrIntrinsicNode::LL);
+  case vmIntrinsics::_indexOfU:                 return inline_string_indexOf(StrIntrinsicNode::UU);
+  case vmIntrinsics::_indexOfUL:                return inline_string_indexOf(StrIntrinsicNode::UL);
+  case vmIntrinsics::_indexOfIL:                return inline_string_indexOfI(StrIntrinsicNode::LL);
+  case vmIntrinsics::_indexOfIU:                return inline_string_indexOfI(StrIntrinsicNode::UU);
+  case vmIntrinsics::_indexOfIUL:               return inline_string_indexOfI(StrIntrinsicNode::UL);
+  case vmIntrinsics::_indexOfU_char:            return inline_string_indexOfChar();
+
+  case vmIntrinsics::_equalsL:                  return inline_string_equals(StrIntrinsicNode::LL);
+  case vmIntrinsics::_equalsU:                  return inline_string_equals(StrIntrinsicNode::UU);
+
+  case vmIntrinsics::_toBytesStringU:           return inline_string_toBytesU();
+  case vmIntrinsics::_getCharsStringU:          return inline_string_getCharsU();
+  case vmIntrinsics::_getCharStringU:           return inline_string_char_access(!is_store);
+  case vmIntrinsics::_putCharStringU:           return inline_string_char_access( is_store);
+
+  case vmIntrinsics::_compressStringC:
+  case vmIntrinsics::_compressStringB:          return inline_string_copy( is_compress);
+  case vmIntrinsics::_inflateStringC:
+  case vmIntrinsics::_inflateStringB:           return inline_string_copy(!is_compress);
 
   case vmIntrinsics::_getObject:                return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT,  !is_volatile);
   case vmIntrinsics::_getBoolean:               return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, !is_volatile);
@@ -617,7 +645,8 @@
   case vmIntrinsics::_getLength:                return inline_native_getLength();
   case vmIntrinsics::_copyOf:                   return inline_array_copyOf(false);
   case vmIntrinsics::_copyOfRange:              return inline_array_copyOf(true);
-  case vmIntrinsics::_equalsC:                  return inline_array_equals();
+  case vmIntrinsics::_equalsB:                  return inline_array_equals(StrIntrinsicNode::LL);
+  case vmIntrinsics::_equalsC:                  return inline_array_equals(StrIntrinsicNode::UU);
   case vmIntrinsics::_clone:                    return inline_native_clone(intrinsic()->is_virtual());
 
   case vmIntrinsics::_isAssignableFrom:         return inline_native_subtype_check();
@@ -687,6 +716,7 @@
     return inline_ghash_processBlocks();
 
   case vmIntrinsics::_encodeISOArray:
+  case vmIntrinsics::_encodeByteISOArray:
     return inline_encodeISOArray();
 
   case vmIntrinsics::_updateCRC32:
@@ -711,6 +741,9 @@
   case vmIntrinsics::_isCompileConstant:
     return inline_isCompileConstant();
 
+  case vmIntrinsics::_hasNegatives:
+    return inline_hasNegatives();
+
   default:
     // If you get here, it may be that someone has added a new intrinsic
     // to the list in vmSymbols.hpp without implementing it here.
@@ -876,75 +909,24 @@
 
 
 //------------------------------make_string_method_node------------------------
-// Helper method for String intrinsic functions. This version is called
-// with str1 and str2 pointing to String object nodes.
-//
-Node* LibraryCallKit::make_string_method_node(int opcode, Node* str1, Node* str2) {
-  Node* no_ctrl = NULL;
-
-  // Get start addr of string
-  Node* str1_value   = load_String_value(no_ctrl, str1);
-  Node* str1_offset  = load_String_offset(no_ctrl, str1);
-  Node* str1_start   = array_element_address(str1_value, str1_offset, T_CHAR);
-
-  // Get length of string 1
-  Node* str1_len  = load_String_length(no_ctrl, str1);
-
-  Node* str2_value   = load_String_value(no_ctrl, str2);
-  Node* str2_offset  = load_String_offset(no_ctrl, str2);
-  Node* str2_start   = array_element_address(str2_value, str2_offset, T_CHAR);
-
-  Node* str2_len = NULL;
-  Node* result = NULL;
-
-  switch (opcode) {
-  case Op_StrIndexOf:
-    // Get length of string 2
-    str2_len = load_String_length(no_ctrl, str2);
-
-    result = new StrIndexOfNode(control(), memory(TypeAryPtr::CHARS),
-                                str1_start, str1_len, str2_start, str2_len);
-    break;
-  case Op_StrComp:
-    // Get length of string 2
-    str2_len = load_String_length(no_ctrl, str2);
-
-    result = new StrCompNode(control(), memory(TypeAryPtr::CHARS),
-                             str1_start, str1_len, str2_start, str2_len);
-    break;
-  case Op_StrEquals:
-    result = new StrEqualsNode(control(), memory(TypeAryPtr::CHARS),
-                               str1_start, str2_start, str1_len);
-    break;
-  default:
-    ShouldNotReachHere();
-    return NULL;
-  }
-
-  // All these intrinsics have checks.
-  C->set_has_split_ifs(true); // Has chance for split-if optimization
-
-  return _gvn.transform(result);
-}
-
-// Helper method for String intrinsic functions. This version is called
-// with str1 and str2 pointing to char[] nodes, with cnt1 and cnt2 pointing
-// to Int nodes containing the lenghts of str1 and str2.
-//
-Node* LibraryCallKit::make_string_method_node(int opcode, Node* str1_start, Node* cnt1, Node* str2_start, Node* cnt2) {
+// Helper method for String intrinsic functions. This version is called with
+// str1 and str2 pointing to byte[] nodes containing Latin1 or UTF16 encoded
+// characters (depending on 'is_byte'). cnt1 and cnt2 are pointing to Int nodes
+// containing the lengths of str1 and str2.
+Node* LibraryCallKit::make_string_method_node(int opcode, Node* str1_start, Node* cnt1, Node* str2_start, Node* cnt2, StrIntrinsicNode::ArgEnc ae) {
   Node* result = NULL;
   switch (opcode) {
   case Op_StrIndexOf:
-    result = new StrIndexOfNode(control(), memory(TypeAryPtr::CHARS),
-                                str1_start, cnt1, str2_start, cnt2);
+    result = new StrIndexOfNode(control(), memory(TypeAryPtr::BYTES),
+                                str1_start, cnt1, str2_start, cnt2, ae);
     break;
   case Op_StrComp:
-    result = new StrCompNode(control(), memory(TypeAryPtr::CHARS),
-                             str1_start, cnt1, str2_start, cnt2);
+    result = new StrCompNode(control(), memory(TypeAryPtr::BYTES),
+                             str1_start, cnt1, str2_start, cnt2, ae);
     break;
   case Op_StrEquals:
-    result = new StrEqualsNode(control(), memory(TypeAryPtr::CHARS),
-                               str1_start, str2_start, cnt1);
+    result = new StrEqualsNode(control(), memory(TypeAryPtr::BYTES),
+                               str1_start, str2_start, cnt1, ae);
     break;
   default:
     ShouldNotReachHere();
@@ -958,98 +940,54 @@
 }
 
 //------------------------------inline_string_compareTo------------------------
-// public int java.lang.String.compareTo(String anotherString);
-bool LibraryCallKit::inline_string_compareTo() {
-  Node* receiver = null_check(argument(0));
-  Node* arg      = null_check(argument(1));
-  if (stopped()) {
-    return true;
-  }
-  set_result(make_string_method_node(Op_StrComp, receiver, arg));
+bool LibraryCallKit::inline_string_compareTo(StrIntrinsicNode::ArgEnc ae) {
+  Node* arg1 = argument(0);
+  Node* arg2 = argument(1);
+
+  // Get start addr and length of first argument
+  Node* arg1_start  = array_element_address(arg1, intcon(0), T_BYTE);
+  Node* arg1_cnt    = load_array_length(arg1);
+
+  // Get start addr and length of second argument
+  Node* arg2_start  = array_element_address(arg2, intcon(0), T_BYTE);
+  Node* arg2_cnt    = load_array_length(arg2);
+
+  Node* result = make_string_method_node(Op_StrComp, arg1_start, arg1_cnt, arg2_start, arg2_cnt, ae);
+  set_result(result);
   return true;
 }
 
 //------------------------------inline_string_equals------------------------
-bool LibraryCallKit::inline_string_equals() {
-  Node* receiver = null_check_receiver();
-  // NOTE: Do not null check argument for String.equals() because spec
-  // allows to specify NULL as argument.
-  Node* argument = this->argument(1);
-  if (stopped()) {
-    return true;
-  }
+bool LibraryCallKit::inline_string_equals(StrIntrinsicNode::ArgEnc ae) {
+  Node* arg1 = argument(0);
+  Node* arg2 = argument(1);
 
   // paths (plus control) merge
-  RegionNode* region = new RegionNode(5);
+  RegionNode* region = new RegionNode(3);
   Node* phi = new PhiNode(region, TypeInt::BOOL);
 
-  // does source == target string?
-  Node* cmp = _gvn.transform(new CmpPNode(receiver, argument));
-  Node* bol = _gvn.transform(new BoolNode(cmp, BoolTest::eq));
-
-  Node* if_eq = generate_slow_guard(bol, NULL);
-  if (if_eq != NULL) {
-    // receiver == argument
-    phi->init_req(2, intcon(1));
-    region->init_req(2, if_eq);
-  }
-
-  // get String klass for instanceOf
-  ciInstanceKlass* klass = env()->String_klass();
-
   if (!stopped()) {
-    Node* inst = gen_instanceof(argument, makecon(TypeKlassPtr::make(klass)));
-    Node* cmp  = _gvn.transform(new CmpINode(inst, intcon(1)));
-    Node* bol  = _gvn.transform(new BoolNode(cmp, BoolTest::ne));
-
-    Node* inst_false = generate_guard(bol, NULL, PROB_MIN);
-    //instanceOf == true, fallthrough
-
-    if (inst_false != NULL) {
-      phi->init_req(3, intcon(0));
-      region->init_req(3, inst_false);
-    }
-  }
-
-  if (!stopped()) {
-    const TypeOopPtr* string_type = TypeOopPtr::make_from_klass(klass);
-
-    // Properly cast the argument to String
-    argument = _gvn.transform(new CheckCastPPNode(control(), argument, string_type));
-    // This path is taken only when argument's type is String:NotNull.
-    argument = cast_not_null(argument, false);
-
-    Node* no_ctrl = NULL;
-
-    // Get start addr of receiver
-    Node* receiver_val    = load_String_value(no_ctrl, receiver);
-    Node* receiver_offset = load_String_offset(no_ctrl, receiver);
-    Node* receiver_start = array_element_address(receiver_val, receiver_offset, T_CHAR);
-
-    // Get length of receiver
-    Node* receiver_cnt  = load_String_length(no_ctrl, receiver);
-
-    // Get start addr of argument
-    Node* argument_val    = load_String_value(no_ctrl, argument);
-    Node* argument_offset = load_String_offset(no_ctrl, argument);
-    Node* argument_start = array_element_address(argument_val, argument_offset, T_CHAR);
-
-    // Get length of argument
-    Node* argument_cnt  = load_String_length(no_ctrl, argument);
-
-    // Check for receiver count != argument count
-    Node* cmp = _gvn.transform(new CmpINode(receiver_cnt, argument_cnt));
+    // Get start addr and length of first argument
+    Node* arg1_start  = array_element_address(arg1, intcon(0), T_BYTE);
+    Node* arg1_cnt    = load_array_length(arg1);
+
+    // Get start addr and length of second argument
+    Node* arg2_start  = array_element_address(arg2, intcon(0), T_BYTE);
+    Node* arg2_cnt    = load_array_length(arg2);
+
+    // Check for arg1_cnt != arg2_cnt
+    Node* cmp = _gvn.transform(new CmpINode(arg1_cnt, arg2_cnt));
     Node* bol = _gvn.transform(new BoolNode(cmp, BoolTest::ne));
     Node* if_ne = generate_slow_guard(bol, NULL);
     if (if_ne != NULL) {
-      phi->init_req(4, intcon(0));
-      region->init_req(4, if_ne);
+      phi->init_req(2, intcon(0));
+      region->init_req(2, if_ne);
     }
 
     // Check for count == 0 is done by assembler code for StrEquals.
 
     if (!stopped()) {
-      Node* equals = make_string_method_node(Op_StrEquals, receiver_start, receiver_cnt, argument_start, argument_cnt);
+      Node* equals = make_string_method_node(Op_StrEquals, arg1_start, arg1_cnt, arg2_start, arg2_cnt, ae);
       phi->init_req(1, equals);
       region->init_req(1, control());
     }
@@ -1064,289 +1002,462 @@
 }
 
 //------------------------------inline_array_equals----------------------------
-bool LibraryCallKit::inline_array_equals() {
+bool LibraryCallKit::inline_array_equals(StrIntrinsicNode::ArgEnc ae) {
+  assert(ae == StrIntrinsicNode::UU || ae == StrIntrinsicNode::LL, "unsupported array types");
   Node* arg1 = argument(0);
   Node* arg2 = argument(1);
-  set_result(_gvn.transform(new AryEqNode(control(), memory(TypeAryPtr::CHARS), arg1, arg2)));
+
+  const TypeAryPtr* mtype = (ae == StrIntrinsicNode::UU) ? TypeAryPtr::CHARS : TypeAryPtr::BYTES;
+  set_result(_gvn.transform(new AryEqNode(control(), memory(mtype), arg1, arg2, ae)));
   return true;
 }
 
-// Java version of String.indexOf(constant string)
-// class StringDecl {
-//   StringDecl(char[] ca) {
-//     offset = 0;
-//     count = ca.length;
-//     value = ca;
-//   }
-//   int offset;
-//   int count;
-//   char[] value;
-// }
-//
-// static int string_indexOf_J(StringDecl string_object, char[] target_object,
-//                             int targetOffset, int cache_i, int md2) {
-//   int cache = cache_i;
-//   int sourceOffset = string_object.offset;
-//   int sourceCount = string_object.count;
-//   int targetCount = target_object.length;
-//
-//   int targetCountLess1 = targetCount - 1;
-//   int sourceEnd = sourceOffset + sourceCount - targetCountLess1;
-//
-//   char[] source = string_object.value;
-//   char[] target = target_object;
-//   int lastChar = target[targetCountLess1];
-//
-//  outer_loop:
-//   for (int i = sourceOffset; i < sourceEnd; ) {
-//     int src = source[i + targetCountLess1];
-//     if (src == lastChar) {
-//       // With random strings and a 4-character alphabet,
-//       // reverse matching at this point sets up 0.8% fewer
-//       // frames, but (paradoxically) makes 0.3% more probes.
-//       // Since those probes are nearer the lastChar probe,
-//       // there is may be a net D$ win with reverse matching.
-//       // But, reversing loop inhibits unroll of inner loop
-//       // for unknown reason.  So, does running outer loop from
-//       // (sourceOffset - targetCountLess1) to (sourceOffset + sourceCount)
-//       for (int j = 0; j < targetCountLess1; j++) {
-//         if (target[targetOffset + j] != source[i+j]) {
-//           if ((cache & (1 << source[i+j])) == 0) {
-//             if (md2 < j+1) {
-//               i += j+1;
-//               continue outer_loop;
-//             }
-//           }
-//           i += md2;
-//           continue outer_loop;
-//         }
-//       }
-//       return i - sourceOffset;
-//     }
-//     if ((cache & (1 << src)) == 0) {
-//       i += targetCountLess1;
-//     } // using "i += targetCount;" and an "else i++;" causes a jump to jump.
-//     i++;
-//   }
-//   return -1;
-// }
-
-//------------------------------string_indexOf------------------------
-Node* LibraryCallKit::string_indexOf(Node* string_object, ciTypeArray* target_array, jint targetOffset_i,
-                                     jint cache_i, jint md2_i) {
-
-  Node* no_ctrl  = NULL;
-  float likely   = PROB_LIKELY(0.9);
-  float unlikely = PROB_UNLIKELY(0.9);
-
-  const int nargs = 0; // no arguments to push back for uncommon trap in predicate
-
-  Node* source        = load_String_value(no_ctrl, string_object);
-  Node* sourceOffset  = load_String_offset(no_ctrl, string_object);
-  Node* sourceCount   = load_String_length(no_ctrl, string_object);
-
-  Node* target = _gvn.transform( makecon(TypeOopPtr::make_from_constant(target_array, true)));
-  jint target_length = target_array->length();
-  const TypeAry* target_array_type = TypeAry::make(TypeInt::CHAR, TypeInt::make(0, target_length, Type::WidenMin));
-  const TypeAryPtr* target_type = TypeAryPtr::make(TypePtr::BotPTR, target_array_type, target_array->klass(), true, Type::OffsetBot);
-
-  // String.value field is known to be @Stable.
-  if (UseImplicitStableValues) {
-    target = cast_array_to_stable(target, target_type);
-  }
-
-  IdealKit kit(this, false, true);
-#define __ kit.
-  Node* zero             = __ ConI(0);
-  Node* one              = __ ConI(1);
-  Node* cache            = __ ConI(cache_i);
-  Node* md2              = __ ConI(md2_i);
-  Node* lastChar         = __ ConI(target_array->char_at(target_length - 1));
-  Node* targetCountLess1 = __ ConI(target_length - 1);
-  Node* targetOffset     = __ ConI(targetOffset_i);
-  Node* sourceEnd        = __ SubI(__ AddI(sourceOffset, sourceCount), targetCountLess1);
-
-  IdealVariable rtn(kit), i(kit), j(kit); __ declarations_done();
-  Node* outer_loop = __ make_label(2 /* goto */);
-  Node* return_    = __ make_label(1);
-
-  __ set(rtn,__ ConI(-1));
-  __ loop(this, nargs, i, sourceOffset, BoolTest::lt, sourceEnd); {
-       Node* i2  = __ AddI(__ value(i), targetCountLess1);
-       // pin to prohibit loading of "next iteration" value which may SEGV (rare)
-       Node* src = load_array_element(__ ctrl(), source, i2, TypeAryPtr::CHARS);
-       __ if_then(src, BoolTest::eq, lastChar, unlikely); {
-         __ loop(this, nargs, j, zero, BoolTest::lt, targetCountLess1); {
-              Node* tpj = __ AddI(targetOffset, __ value(j));
-              Node* targ = load_array_element(no_ctrl, target, tpj, target_type);
-              Node* ipj  = __ AddI(__ value(i), __ value(j));
-              Node* src2 = load_array_element(no_ctrl, source, ipj, TypeAryPtr::CHARS);
-              __ if_then(targ, BoolTest::ne, src2); {
-                __ if_then(__ AndI(cache, __ LShiftI(one, src2)), BoolTest::eq, zero); {
-                  __ if_then(md2, BoolTest::lt, __ AddI(__ value(j), one)); {
-                    __ increment(i, __ AddI(__ value(j), one));
-                    __ goto_(outer_loop);
-                  } __ end_if(); __ dead(j);
-                }__ end_if(); __ dead(j);
-                __ increment(i, md2);
-                __ goto_(outer_loop);
-              }__ end_if();
-              __ increment(j, one);
-         }__ end_loop(); __ dead(j);
-         __ set(rtn, __ SubI(__ value(i), sourceOffset)); __ dead(i);
-         __ goto_(return_);
-       }__ end_if();
-       __ if_then(__ AndI(cache, __ LShiftI(one, src)), BoolTest::eq, zero, likely); {
-         __ increment(i, targetCountLess1);
-       }__ end_if();
-       __ increment(i, one);
-       __ bind(outer_loop);
-  }__ end_loop(); __ dead(i);
-  __ bind(return_);
-
-  // Final sync IdealKit and GraphKit.
-  final_sync(kit);
-  Node* result = __ value(rtn);
-#undef __
-  C->set_has_loops(true);
-  return result;
+//------------------------------inline_hasNegatives------------------------------
+bool LibraryCallKit::inline_hasNegatives() {
+  if (too_many_traps(Deoptimization::Reason_intrinsic))  return false;
+
+  assert(callee()->signature()->size() == 3, "hasNegatives has 3 parameters");
+  // no receiver since it is static method
+  Node* ba         = argument(0);
+  Node* offset     = argument(1);
+  Node* len        = argument(2);
+
+  RegionNode* bailout = new RegionNode(1);
+  record_for_igvn(bailout);
+
+  // offset must not be negative.
+  generate_negative_guard(offset, bailout);
+
+  // offset + length must not exceed length of ba.
+  generate_limit_guard(offset, len, load_array_length(ba), bailout);
+
+  if (bailout->req() > 1) {
+    PreserveJVMState pjvms(this);
+    set_control(_gvn.transform(bailout));
+    uncommon_trap(Deoptimization::Reason_intrinsic,
+                  Deoptimization::Action_maybe_recompile);
+  }
+  if (!stopped()) {
+    Node* ba_start = array_element_address(ba, offset, T_BYTE);
+    Node* result = new HasNegativesNode(control(), memory(TypeAryPtr::BYTES), ba_start, len);
+    set_result(_gvn.transform(result));
+  }
+  return true;
 }
 
 //------------------------------inline_string_indexOf------------------------
-bool LibraryCallKit::inline_string_indexOf() {
-  Node* receiver = argument(0);
-  Node* arg      = argument(1);
-
-  Node* result;
-  if (Matcher::has_match_rule(Op_StrIndexOf) &&
-      UseSSE42Intrinsics) {
-    // Generate SSE4.2 version of indexOf
-    // We currently only have match rules that use SSE4.2
-
-    receiver = null_check(receiver);
-    arg      = null_check(arg);
-    if (stopped()) {
-      return true;
-    }
-
-    // Make the merge point
-    RegionNode* result_rgn = new RegionNode(4);
-    Node*       result_phi = new PhiNode(result_rgn, TypeInt::INT);
-    Node* no_ctrl  = NULL;
-
-    // Get start addr of source string
-    Node* source = load_String_value(no_ctrl, receiver);
-    Node* source_offset = load_String_offset(no_ctrl, receiver);
-    Node* source_start = array_element_address(source, source_offset, T_CHAR);
-
-    // Get length of source string
-    Node* source_cnt  = load_String_length(no_ctrl, receiver);
-
-    // Get start addr of substring
-    Node* substr = load_String_value(no_ctrl, arg);
-    Node* substr_offset = load_String_offset(no_ctrl, arg);
-    Node* substr_start = array_element_address(substr, substr_offset, T_CHAR);
-
-    // Get length of source string
-    Node* substr_cnt  = load_String_length(no_ctrl, arg);
-
-    // Check for substr count > string count
-    Node* cmp = _gvn.transform(new CmpINode(substr_cnt, source_cnt));
-    Node* bol = _gvn.transform(new BoolNode(cmp, BoolTest::gt));
-    Node* if_gt = generate_slow_guard(bol, NULL);
-    if (if_gt != NULL) {
-      result_phi->init_req(2, intcon(-1));
-      result_rgn->init_req(2, if_gt);
-    }
-
-    if (!stopped()) {
-      // Check for substr count == 0
-      cmp = _gvn.transform(new CmpINode(substr_cnt, intcon(0)));
-      bol = _gvn.transform(new BoolNode(cmp, BoolTest::eq));
-      Node* if_zero = generate_slow_guard(bol, NULL);
-      if (if_zero != NULL) {
-        result_phi->init_req(3, intcon(0));
-        result_rgn->init_req(3, if_zero);
-      }
-    }
-
-    if (!stopped()) {
-      result = make_string_method_node(Op_StrIndexOf, source_start, source_cnt, substr_start, substr_cnt);
-      result_phi->init_req(1, result);
-      result_rgn->init_req(1, control());
+bool LibraryCallKit::inline_string_indexOf(StrIntrinsicNode::ArgEnc ae) {
+  if (!Matcher::has_match_rule(Op_StrIndexOf) || !UseSSE42Intrinsics) {
+    return false;
+  }
+  Node* src = argument(0);
+  Node* tgt = argument(1);
+
+  // Make the merge point
+  RegionNode* result_rgn = new RegionNode(4);
+  Node*       result_phi = new PhiNode(result_rgn, TypeInt::INT);
+
+  // Get start addr and length of source string
+  Node* src_start = array_element_address(src, intcon(0), T_BYTE);
+  Node* src_count = load_array_length(src);
+
+  // Get start addr and length of substring
+  Node* tgt_start = array_element_address(tgt, intcon(0), T_BYTE);
+  Node* tgt_count = load_array_length(tgt);
+
+  if (ae == StrIntrinsicNode::UU || ae == StrIntrinsicNode::UL) {
+    // Divide src size by 2 if String is UTF16 encoded
+    src_count = _gvn.transform(new RShiftINode(src_count, intcon(1)));
+  }
+  if (ae == StrIntrinsicNode::UU) {
+    // Divide substring size by 2 if String is UTF16 encoded
+    tgt_count = _gvn.transform(new RShiftINode(tgt_count, intcon(1)));
+  }
+
+  // Check for substr count > string count
+  Node* cmp = _gvn.transform(new CmpINode(tgt_count, src_count));
+  Node* bol = _gvn.transform(new BoolNode(cmp, BoolTest::gt));
+  Node* if_gt = generate_slow_guard(bol, NULL);
+  if (if_gt != NULL) {
+    result_phi->init_req(2, intcon(-1));
+    result_rgn->init_req(2, if_gt);
+  }
+
+  if (!stopped()) {
+    // Check for substr count == 0
+    cmp = _gvn.transform(new CmpINode(tgt_count, intcon(0)));
+    bol = _gvn.transform(new BoolNode(cmp, BoolTest::eq));
+    Node* if_zero = generate_slow_guard(bol, NULL);
+    if (if_zero != NULL) {
+      result_phi->init_req(3, intcon(0));
+      result_rgn->init_req(3, if_zero);
     }
-    set_control(_gvn.transform(result_rgn));
-    record_for_igvn(result_rgn);
-    result = _gvn.transform(result_phi);
-
-  } else { // Use LibraryCallKit::string_indexOf
-    // don't intrinsify if argument isn't a constant string.
-    if (!arg->is_Con()) {
-     return false;
-    }
-    const TypeOopPtr* str_type = _gvn.type(arg)->isa_oopptr();
-    if (str_type == NULL) {
-      return false;
-    }
-    ciInstanceKlass* klass = env()->String_klass();
-    ciObject* str_const = str_type->const_oop();
-    if (str_const == NULL || str_const->klass() != klass) {
-      return false;
-    }
-    ciInstance* str = str_const->as_instance();
-    assert(str != NULL, "must be instance");
-
-    ciObject* v = str->field_value_by_offset(java_lang_String::value_offset_in_bytes()).as_object();
-    ciTypeArray* pat = v->as_type_array(); // pattern (argument) character array
-
-    int o;
-    int c;
-    if (java_lang_String::has_offset_field()) {
-      o = str->field_value_by_offset(java_lang_String::offset_offset_in_bytes()).as_int();
-      c = str->field_value_by_offset(java_lang_String::count_offset_in_bytes()).as_int();
-    } else {
-      o = 0;
-      c = pat->length();
+  }
+
+  if (!stopped()) {
+    Node* result = make_string_method_node(Op_StrIndexOf, src_start, src_count, tgt_start, tgt_count, ae);
+    result_phi->init_req(1, result);
+    result_rgn->init_req(1, control());
+  }
+  set_control(_gvn.transform(result_rgn));
+  record_for_igvn(result_rgn);
+  set_result(_gvn.transform(result_phi));
+
+  return true;
+}
+
+//-----------------------------inline_string_indexOf-----------------------
+bool LibraryCallKit::inline_string_indexOfI(StrIntrinsicNode::ArgEnc ae) {
+  if (!Matcher::has_match_rule(Op_StrIndexOf) || !UseSSE42Intrinsics) {
+    return false;
+  }
+  assert(callee()->signature()->size() == 5, "String.indexOf() has 5 arguments");
+  Node* src         = argument(0); // byte[]
+  Node* src_count   = argument(1);
+  Node* tgt         = argument(2); // byte[]
+  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)));
+  Node* src_start = array_element_address(src, src_offset, T_BYTE);
+  Node* tgt_start = array_element_address(tgt, intcon(0), T_BYTE);
+
+  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.
+  // Generate code which will fold into cmove.
+  RegionNode* region = new RegionNode(3);
+  Node* phi = new PhiNode(region, TypeInt::INT);
+
+  Node* cmp = _gvn.transform(new CmpINode(result, intcon(0)));
+  Node* bol = _gvn.transform(new BoolNode(cmp, BoolTest::lt));
+
+  Node* if_lt = generate_slow_guard(bol, NULL);
+  if (if_lt != NULL) {
+    // result == -1
+    phi->init_req(2, result);
+    region->init_req(2, if_lt);
+  }
+  if (!stopped()) {
+    result = _gvn.transform(new AddINode(result, from_index));
+    phi->init_req(1, result);
+    region->init_req(1, control());
+  }
+
+  set_control(_gvn.transform(region));
+  record_for_igvn(region);
+  set_result(_gvn.transform(phi));
+
+  return true;
+}
+
+//-----------------------------inline_string_indexOfChar-----------------------
+bool LibraryCallKit::inline_string_indexOfChar() {
+  if (!Matcher::has_match_rule(Op_StrIndexOfChar) || !(UseSSE > 4)) {
+    return false;
+  }
+  assert(callee()->signature()->size() == 4, "String.indexOfChar() has 4 arguments");
+  Node* src         = argument(0); // byte[]
+  Node* tgt         = argument(1); // tgt is int ch
+  Node* from_index  = argument(2);
+  Node* max         = argument(3);
+
+  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));
+
+  RegionNode* region = new RegionNode(3);
+  Node* phi = new PhiNode(region, TypeInt::INT);
+
+  Node* result = new StrIndexOfCharNode(control(), memory(TypeAryPtr::BYTES), src_start, src_count, tgt, StrIntrinsicNode::none);
+  C->set_has_split_ifs(true); // Has chance for split-if optimization
+  _gvn.transform(result);
+
+  Node* cmp = _gvn.transform(new CmpINode(result, intcon(0)));
+  Node* bol = _gvn.transform(new BoolNode(cmp, BoolTest::lt));
+
+  Node* if_lt = generate_slow_guard(bol, NULL);
+  if (if_lt != NULL) {
+    // result == -1
+    phi->init_req(2, result);
+    region->init_req(2, if_lt);
+  }
+  if (!stopped()) {
+    result = _gvn.transform(new AddINode(result, from_index));
+    phi->init_req(1, result);
+    region->init_req(1, control());
+  }
+  set_control(_gvn.transform(region));
+  record_for_igvn(region);
+  set_result(_gvn.transform(phi));
+
+  return true;
+}
+//---------------------------inline_string_copy---------------------
+// compressIt == true --> generate a compressed copy operation (compress char[]/byte[] to byte[])
+//   int StringUTF16.compress(char[] src, int srcOff, byte[] dst, int dstOff, int len)
+//   int StringUTF16.compress(byte[] src, int srcOff, byte[] dst, int dstOff, int len)
+// compressIt == false --> generate an inflated copy operation (inflate byte[] to char[]/byte[])
+//   void StringLatin1.inflate(byte[] src, int srcOff, char[] dst, int dstOff, int len)
+//   void StringLatin1.inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len)
+bool LibraryCallKit::inline_string_copy(bool compress) {
+  int nargs = 5;  // 2 oops, 3 ints
+  assert(callee()->signature()->size() == nargs, "string copy has 5 arguments");
+
+  Node* src         = argument(0);
+  Node* src_offset  = argument(1);
+  Node* dst         = argument(2);
+  Node* dst_offset  = argument(3);
+  Node* length      = argument(4);
+
+  // Check for allocation before we add nodes that would confuse
+  // tightly_coupled_allocation()
+  AllocateArrayNode* alloc = tightly_coupled_allocation(dst, NULL);
+
+  // Figure out the size and type of the elements we will be copying.
+  const Type* src_type = src->Value(&_gvn);
+  const Type* dst_type = dst->Value(&_gvn);
+  BasicType src_elem = src_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
+  BasicType dst_elem = dst_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
+  assert((compress && dst_elem == T_BYTE && (src_elem == T_BYTE || src_elem == T_CHAR)) ||
+         (!compress && src_elem == T_BYTE && (dst_elem == T_BYTE || dst_elem == T_CHAR)),
+         "Unsupported array types for inline_string_copy");
+
+  // Convert char[] offsets to byte[] offsets
+  if (compress && src_elem == T_BYTE) {
+    src_offset = _gvn.transform(new LShiftINode(src_offset, intcon(1)));
+  } else if (!compress && dst_elem == T_BYTE) {
+    dst_offset = _gvn.transform(new LShiftINode(dst_offset, intcon(1)));
+  }
+
+  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
+  // 'dst_start' points to dst array + scaled offset
+  Node* count;
+  if (compress) {
+    count = compress_string(src_start, dst_start, length);
+  } else {
+    inflate_string(src_start, dst_start, length);
+  }
+
+  if (alloc != NULL) {
+    if (alloc->maybe_set_complete(&_gvn)) {
+      // "You break it, you buy it."
+      InitializeNode* init = alloc->initialization();
+      assert(init->is_complete(), "we just did this");
+      init->set_complete_with_arraycopy();
+      assert(dst->is_CheckCastPP(), "sanity");
+      assert(dst->in(0)->in(0) == init, "dest pinned");
     }
-
-    // constant strings have no offset and count == length which
-    // simplifies the resulting code somewhat so lets optimize for that.
-    if (o != 0 || c != pat->length()) {
-     return false;
+    // Do not let stores that initialize this object be reordered with
+    // a subsequent store that would make this object accessible by
+    // other threads.
+    // Record what AllocateNode this StoreStore protects so that
+    // escape analysis can go from the MemBarStoreStoreNode to the
+    // AllocateNode and eliminate the MemBarStoreStoreNode if possible
+    // based on the escape status of the AllocateNode.
+    insert_mem_bar(Op_MemBarStoreStore, alloc->proj_out(AllocateNode::RawAddress));
+  }
+  if (compress) {
+    set_result(_gvn.transform(count));
+  }
+  return true;
+}
+
+#ifdef _LP64
+#define XTOP ,top() /*additional argument*/
+#else  //_LP64
+#define XTOP        /*no additional argument*/
+#endif //_LP64
+
+//------------------------inline_string_toBytesU--------------------------
+// public static byte[] StringUTF16.toBytes(char[] value, int off, int len)
+bool LibraryCallKit::inline_string_toBytesU() {
+  // Get the arguments.
+  Node* value     = argument(0);
+  Node* offset    = argument(1);
+  Node* length    = argument(2);
+
+  Node* newcopy = NULL;
+
+  // Set the original stack and the reexecute bit for the interpreter to reexecute
+  // the bytecode that invokes StringUTF16.toBytes() if deoptimization happens.
+  { PreserveReexecuteState preexecs(this);
+    jvms()->set_should_reexecute(true);
+
+    // Check if a null path was taken unconditionally.
+    value = null_check(value);
+
+    RegionNode* bailout = new RegionNode(1);
+    record_for_igvn(bailout);
+
+    // Make sure that resulting byte[] length does not overflow Integer.MAX_VALUE
+    generate_negative_guard(length, bailout);
+    generate_limit_guard(length, intcon(0), intcon(max_jint/2), bailout);
+
+    if (bailout->req() > 1) {
+      PreserveJVMState pjvms(this);
+      set_control(_gvn.transform(bailout));
+      uncommon_trap(Deoptimization::Reason_intrinsic,
+                    Deoptimization::Action_maybe_recompile);
     }
-
-    receiver = null_check(receiver, T_OBJECT);
-    // NOTE: No null check on the argument is needed since it's a constant String oop.
-    if (stopped()) {
-      return true;
-    }
-
-    // The null string as a pattern always returns 0 (match at beginning of string)
-    if (c == 0) {
-      set_result(intcon(0));
-      return true;
+    if (stopped()) return true;
+
+    // Range checks are done by caller.
+
+    Node* size = _gvn.transform(new LShiftINode(length, intcon(1)));
+    Node* klass_node = makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_BYTE)));
+    newcopy = new_array(klass_node, size, 0);  // no arguments to push
+    AllocateArrayNode* alloc = tightly_coupled_allocation(newcopy, NULL);
+
+    // Calculate starting addresses.
+    Node* src_start = array_element_address(value, offset, T_CHAR);
+    Node* dst_start = basic_plus_adr(newcopy, arrayOopDesc::base_offset_in_bytes(T_BYTE));
+
+    // Check if src array address is aligned to HeapWordSize (dst is always aligned)
+    const TypeInt* toffset = gvn().type(offset)->is_int();
+    bool aligned = toffset->is_con() && ((toffset->get_con() * type2aelembytes(T_CHAR)) % HeapWordSize == 0);
+
+    // Figure out which arraycopy runtime method to call (disjoint, uninitialized).
+    const char* copyfunc_name = "arraycopy";
+    address     copyfunc_addr = StubRoutines::select_arraycopy_function(T_CHAR, aligned, true, copyfunc_name, true);
+    Node* call = make_runtime_call(RC_LEAF|RC_NO_FP,
+                      OptoRuntime::fast_arraycopy_Type(),
+                      copyfunc_addr, copyfunc_name, TypeRawPtr::BOTTOM,
+                      src_start, dst_start, ConvI2X(length) XTOP);
+    // Do not let reads from the cloned object float above the arraycopy.
+    if (alloc != NULL) {
+      if (alloc->maybe_set_complete(&_gvn)) {
+        // "You break it, you buy it."
+        InitializeNode* init = alloc->initialization();
+        assert(init->is_complete(), "we just did this");
+        init->set_complete_with_arraycopy();
+        assert(newcopy->is_CheckCastPP(), "sanity");
+        assert(newcopy->in(0)->in(0) == init, "dest pinned");
+      }
+      // Do not let stores that initialize this object be reordered with
+      // a subsequent store that would make this object accessible by
+      // other threads.
+      // Record what AllocateNode this StoreStore protects so that
+      // escape analysis can go from the MemBarStoreStoreNode to the
+      // AllocateNode and eliminate the MemBarStoreStoreNode if possible
+      // based on the escape status of the AllocateNode.
+      insert_mem_bar(Op_MemBarStoreStore, alloc->proj_out(AllocateNode::RawAddress));
+    } else {
+      insert_mem_bar(Op_MemBarCPUOrder);
     }
-
-    // Generate default indexOf
-    jchar lastChar = pat->char_at(o + (c - 1));
-    int cache = 0;
-    int i;
-    for (i = 0; i < c - 1; i++) {
-      assert(i < pat->length(), "out of range");
-      cache |= (1 << (pat->char_at(o + i) & (sizeof(cache) * BitsPerByte - 1)));
+  } // original reexecute is set back here
+
+  C->set_has_split_ifs(true); // Has chance for split-if optimization
+  if (!stopped()) {
+    set_result(newcopy);
+  }
+  return true;
+}
+
+//------------------------inline_string_getCharsU--------------------------
+// public void StringUTF16.getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin)
+bool LibraryCallKit::inline_string_getCharsU() {
+  if (too_many_traps(Deoptimization::Reason_intrinsic))  return false;
+
+  // Get the arguments.
+  Node* value     = argument(0);
+  Node* src_begin = argument(1);
+  Node* src_end   = argument(2); // exclusive offset (i < src_end)
+  Node* dst       = argument(3);
+  Node* dst_begin = argument(4);
+
+  // Check for allocation before we add nodes that would confuse
+  // tightly_coupled_allocation()
+  AllocateArrayNode* alloc = tightly_coupled_allocation(dst, NULL);
+
+  // Check if a null path was taken unconditionally.
+  value = null_check(value);
+  dst = null_check(dst);
+  if (stopped()) {
+    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)));
+
+  if (!stopped()) {
+    // Calculate starting addresses.
+    Node* src_start = array_element_address(value, src_begin, T_BYTE);
+    Node* dst_start = array_element_address(dst, dst_begin, T_CHAR);
+
+    // Check if array addresses are aligned to HeapWordSize
+    const TypeInt* tsrc = gvn().type(src_begin)->is_int();
+    const TypeInt* tdst = gvn().type(dst_begin)->is_int();
+    bool aligned = tsrc->is_con() && ((tsrc->get_con() * type2aelembytes(T_BYTE)) % HeapWordSize == 0) &&
+                   tdst->is_con() && ((tdst->get_con() * type2aelembytes(T_CHAR)) % HeapWordSize == 0);
+
+    // Figure out which arraycopy runtime method to call (disjoint, uninitialized).
+    const char* copyfunc_name = "arraycopy";
+    address     copyfunc_addr = StubRoutines::select_arraycopy_function(T_CHAR, aligned, true, copyfunc_name, true);
+    Node* call = make_runtime_call(RC_LEAF|RC_NO_FP,
+                      OptoRuntime::fast_arraycopy_Type(),
+                      copyfunc_addr, copyfunc_name, TypeRawPtr::BOTTOM,
+                      src_start, dst_start, ConvI2X(length) XTOP);
+    // Do not let reads from the cloned object float above the arraycopy.
+    if (alloc != NULL) {
+      if (alloc->maybe_set_complete(&_gvn)) {
+        // "You break it, you buy it."
+        InitializeNode* init = alloc->initialization();
+        assert(init->is_complete(), "we just did this");
+        init->set_complete_with_arraycopy();
+        assert(dst->is_CheckCastPP(), "sanity");
+        assert(dst->in(0)->in(0) == init, "dest pinned");
+      }
+      // Do not let stores that initialize this object be reordered with
+      // a subsequent store that would make this object accessible by
+      // other threads.
+      // Record what AllocateNode this StoreStore protects so that
+      // escape analysis can go from the MemBarStoreStoreNode to the
+      // AllocateNode and eliminate the MemBarStoreStoreNode if possible
+      // based on the escape status of the AllocateNode.
+      insert_mem_bar(Op_MemBarStoreStore, alloc->proj_out(AllocateNode::RawAddress));
+    } else {
+      insert_mem_bar(Op_MemBarCPUOrder);
     }
-
-    int md2 = c;
-    for (i = 0; i < c - 1; i++) {
-      assert(i < pat->length(), "out of range");
-      if (pat->char_at(o + i) == lastChar) {
-        md2 = (c - 1) - i;
-      }
-    }
-
-    result = string_indexOf(receiver, pat, o, cache, md2);
-  }
-  set_result(result);
+  }
+
+  C->set_has_split_ifs(true); // Has chance for split-if optimization
+  return true;
+}
+
+//----------------------inline_string_char_access----------------------------
+// Store/Load char to/from byte[] array.
+// static void StringUTF16.putChar(byte[] val, int index, int c)
+// static char StringUTF16.getChar(byte[] val, int index)
+bool LibraryCallKit::inline_string_char_access(bool is_store) {
+  Node* value  = argument(0);
+  Node* index  = argument(1);
+  Node* ch = is_store ? argument(2) : NULL;
+
+  // This intrinsic accesses byte[] array as char[] array. Computing the offsets
+  // correctly requires matched array shapes.
+  assert (arrayOopDesc::base_offset_in_bytes(T_CHAR) == arrayOopDesc::base_offset_in_bytes(T_BYTE),
+          "sanity: byte[] and char[] bases agree");
+  assert (type2aelembytes(T_CHAR) == type2aelembytes(T_BYTE)*2,
+          "sanity: byte[] and char[] scales agree");
+
+  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);
+  } else {
+    ch = make_load(control(), adr, TypeInt::CHAR, T_CHAR, MemNode::unordered);
+    set_result(ch);
+  }
   return true;
 }
 
@@ -4189,12 +4300,6 @@
   return true;
 }
 
-#ifdef _LP64
-#define XTOP ,top() /*additional argument*/
-#else  //_LP64
-#define XTOP        /*no additional argument*/
-#endif //_LP64
-
 //----------------------inline_unsafe_copyMemory-------------------------
 // public native void sun.misc.Unsafe.copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes);
 bool LibraryCallKit::inline_unsafe_copyMemory() {
@@ -5003,10 +5108,11 @@
   // Figure out the size and type of the elements we will be copying.
   BasicType src_elem = src_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
   BasicType dst_elem = dst_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
-  if (src_elem != T_CHAR || dst_elem != T_BYTE) {
+  if (!((src_elem == T_CHAR) || (src_elem== T_BYTE)) || dst_elem != T_BYTE) {
     return false;
   }
-  Node* src_start = array_element_address(src, src_offset, src_elem);
+
+  Node* src_start = array_element_address(src, src_offset, T_CHAR);
   Node* dst_start = array_element_address(dst, dst_offset, dst_elem);
   // 'src_start' points to src array + scaled offset
   // 'dst_start' points to dst array + scaled offset
@@ -5124,7 +5230,7 @@
 
 //-------------inline_squareToLen------------------------------------
 bool LibraryCallKit::inline_squareToLen() {
-  assert(UseSquareToLenIntrinsic, "not implementated on this platform");
+  assert(UseSquareToLenIntrinsic, "not implemented on this platform");
 
   address stubAddr = StubRoutines::squareToLen();
   if (stubAddr == NULL) {
@@ -5170,7 +5276,7 @@
 
 //-------------inline_mulAdd------------------------------------------
 bool LibraryCallKit::inline_mulAdd() {
-  assert(UseMulAddIntrinsic, "not implementated on this platform");
+  assert(UseMulAddIntrinsic, "not implemented on this platform");
 
   address stubAddr = StubRoutines::mulAdd();
   if (stubAddr == NULL) {