--- a/hotspot/src/share/vm/opto/library_call.cpp Thu Nov 26 15:37:04 2015 +0000
+++ b/hotspot/src/share/vm/opto/library_call.cpp Fri Nov 27 09:36:46 2015 +0100
@@ -152,6 +152,8 @@
Node* generate_limit_guard(Node* offset, Node* subseq_length,
Node* array_length,
RegionNode* region);
+ void generate_string_range_check(Node* array, Node* offset,
+ Node* length, bool char_count);
Node* generate_current_thread(Node* &tls_output);
Node* load_mirror_from_klass(Node* klass);
Node* load_klass_from_mirror_common(Node* mirror, bool never_see_null,
@@ -204,6 +206,8 @@
bool inline_string_compareTo(StrIntrinsicNode::ArgEnc ae);
bool inline_string_indexOf(StrIntrinsicNode::ArgEnc ae);
bool inline_string_indexOfI(StrIntrinsicNode::ArgEnc ae);
+ Node* make_indexOf_node(Node* src_start, Node* src_count, Node* tgt_start, Node* tgt_count,
+ RegionNode* region, Node* phi, StrIntrinsicNode::ArgEnc ae);
bool inline_string_indexOfChar();
bool inline_string_equals(StrIntrinsicNode::ArgEnc ae);
bool inline_string_toBytesU();
@@ -897,6 +901,31 @@
return is_over;
}
+// Emit range checks for the given String.value byte array
+void LibraryCallKit::generate_string_range_check(Node* array, Node* offset, Node* count, bool char_count) {
+ if (stopped()) {
+ return; // already stopped
+ }
+ RegionNode* bailout = new RegionNode(1);
+ record_for_igvn(bailout);
+ if (char_count) {
+ // Convert char count to byte count
+ count = _gvn.transform(new LShiftINode(count, intcon(1)));
+ }
+
+ // Offset and count must not be negative
+ generate_negative_guard(offset, bailout);
+ generate_negative_guard(count, bailout);
+ // Offset + count must not exceed length of array
+ generate_limit_guard(offset, count, load_array_length(array), bailout);
+
+ if (bailout->req() > 1) {
+ PreserveJVMState pjvms(this);
+ set_control(_gvn.transform(bailout));
+ uncommon_trap(Deoptimization::Reason_intrinsic,
+ Deoptimization::Action_maybe_recompile);
+ }
+}
//--------------------------generate_current_thread--------------------
Node* LibraryCallKit::generate_current_thread(Node* &tls_output) {
@@ -1016,7 +1045,9 @@
//------------------------------inline_hasNegatives------------------------------
bool LibraryCallKit::inline_hasNegatives() {
- if (too_many_traps(Deoptimization::Reason_intrinsic)) return false;
+ 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
@@ -1024,26 +1055,14 @@
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));
- }
+ // Range checks
+ generate_string_range_check(ba, offset, len, false);
+ if (stopped()) {
+ return true;
+ }
+ 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;
}
@@ -1124,30 +1143,10 @@
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);
- }
- }
-
- 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());
+ Node* result = make_indexOf_node(src_start, src_count, tgt_start, tgt_count, result_rgn, result_phi, ae);
+ if (result != NULL) {
+ result_phi->init_req(3, result);
+ result_rgn->init_req(3, control());
}
set_control(_gvn.transform(result_rgn));
record_for_igvn(result_rgn);
@@ -1158,44 +1157,53 @@
//-----------------------------inline_string_indexOf-----------------------
bool LibraryCallKit::inline_string_indexOfI(StrIntrinsicNode::ArgEnc ae) {
+ if (too_many_traps(Deoptimization::Reason_intrinsic)) {
+ return false;
+ }
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* src_count = argument(1); // char count
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));
+ Node* tgt_count = argument(3); // char count
+ Node* from_index = argument(4); // char 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);
- 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);
+ // Range checks
+ generate_string_range_check(src, src_offset, src_count, ae != StrIntrinsicNode::LL);
+ generate_string_range_check(tgt, intcon(0), tgt_count, ae == StrIntrinsicNode::UU);
+ if (stopped()) {
+ return true;
+ }
+
+ RegionNode* region = new RegionNode(5);
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());
+ Node* result = make_indexOf_node(src_start, src_count, tgt_start, tgt_count, region, phi, ae);
+ if (result != NULL) {
+ // The result is index relative to from_index if substring was found, -1 otherwise.
+ // Generate code which will fold into cmove.
+ 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(3, result);
+ region->init_req(3, if_lt);
+ }
+ if (!stopped()) {
+ result = _gvn.transform(new AddINode(result, from_index));
+ phi->init_req(4, result);
+ region->init_req(4, control());
+ }
}
set_control(_gvn.transform(region));
@@ -1205,8 +1213,38 @@
return true;
}
+// Create StrIndexOfNode with fast path checks
+Node* LibraryCallKit::make_indexOf_node(Node* src_start, Node* src_count, Node* tgt_start, Node* tgt_count,
+ RegionNode* region, Node* phi, StrIntrinsicNode::ArgEnc ae) {
+ // 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) {
+ phi->init_req(1, intcon(-1));
+ region->init_req(1, 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) {
+ phi->init_req(2, intcon(0));
+ region->init_req(2, if_zero);
+ }
+ }
+ if (!stopped()) {
+ return make_string_method_node(Op_StrIndexOf, src_start, src_count, tgt_start, tgt_count, ae);
+ }
+ return NULL;
+}
+
//-----------------------------inline_string_indexOfChar-----------------------
bool LibraryCallKit::inline_string_indexOfChar() {
+ if (too_many_traps(Deoptimization::Reason_intrinsic)) {
+ return false;
+ }
if (!Matcher::has_match_rule(Op_StrIndexOfChar) || !(UseSSE > 4)) {
return false;
}
@@ -1218,9 +1256,14 @@
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));
+ // Range checks
+ generate_string_range_check(src, src_offset, src_count, true);
+ if (stopped()) {
+ return true;
+ }
+
RegionNode* region = new RegionNode(3);
Node* phi = new PhiNode(region, TypeInt::INT);
@@ -1256,6 +1299,9 @@
// 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) {
+ if (too_many_traps(Deoptimization::Reason_intrinsic)) {
+ return false;
+ }
int nargs = 5; // 2 oops, 3 ints
assert(callee()->signature()->size() == nargs, "string copy has 5 arguments");
@@ -1278,6 +1324,13 @@
(!compress && src_elem == T_BYTE && (dst_elem == T_BYTE || dst_elem == T_CHAR)),
"Unsupported array types for inline_string_copy");
+ // Range checks
+ generate_string_range_check(src, src_offset, length, compress && src_elem == T_BYTE);
+ generate_string_range_check(dst, dst_offset, length, !compress && dst_elem == T_BYTE);
+ if (stopped()) {
+ return true;
+ }
+
// Convert char[] offsets to byte[] offsets
if (compress && src_elem == T_BYTE) {
src_offset = _gvn.transform(new LShiftINode(src_offset, intcon(1)));
@@ -1329,6 +1382,9 @@
//------------------------inline_string_toBytesU--------------------------
// public static byte[] StringUTF16.toBytes(char[] value, int off, int len)
bool LibraryCallKit::inline_string_toBytesU() {
+ if (too_many_traps(Deoptimization::Reason_intrinsic)) {
+ return false;
+ }
// Get the arguments.
Node* value = argument(0);
Node* offset = argument(1);
@@ -1347,8 +1403,11 @@
RegionNode* bailout = new RegionNode(1);
record_for_igvn(bailout);
+ // Range checks
+ generate_negative_guard(offset, bailout);
+ generate_negative_guard(length, bailout);
+ generate_limit_guard(offset, length, load_array_length(value), 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) {
@@ -1357,9 +1416,9 @@
uncommon_trap(Deoptimization::Reason_intrinsic,
Deoptimization::Action_maybe_recompile);
}
- if (stopped()) return true;
-
- // Range checks are done by caller.
+ if (stopped()) {
+ return true;
+ }
Node* size = _gvn.transform(new LShiftINode(length, intcon(1)));
Node* klass_node = makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_BYTE)));
@@ -1412,12 +1471,14 @@
}
//------------------------inline_string_getCharsU--------------------------
-// public void StringUTF16.getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin)
+// public void StringUTF16.getChars(byte[] src, int srcBegin, int srcEnd, char dst[], int dstBegin)
bool LibraryCallKit::inline_string_getCharsU() {
- if (too_many_traps(Deoptimization::Reason_intrinsic)) return false;
+ if (too_many_traps(Deoptimization::Reason_intrinsic)) {
+ return false;
+ }
// Get the arguments.
- Node* value = argument(0);
+ Node* src = argument(0);
Node* src_begin = argument(1);
Node* src_end = argument(2); // exclusive offset (i < src_end)
Node* dst = argument(3);
@@ -1428,21 +1489,26 @@
AllocateArrayNode* alloc = tightly_coupled_allocation(dst, NULL);
// Check if a null path was taken unconditionally.
- value = null_check(value);
+ src = null_check(src);
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)));
+ // Range checks
+ generate_string_range_check(src, src_begin, length, true);
+ generate_string_range_check(dst, dst_begin, length, false);
+ if (stopped()) {
+ return true;
+ }
+
if (!stopped()) {
// Calculate starting addresses.
- Node* src_start = array_element_address(value, src_begin, T_BYTE);
+ Node* src_start = array_element_address(src, src_begin, T_BYTE);
Node* dst_start = array_element_address(dst, dst_begin, T_CHAR);
// Check if array addresses are aligned to HeapWordSize