< prev index next >

src/share/vm/opto/library_call.cpp

Print this page

        

*** 150,159 **** --- 150,161 ---- // resulting CastII of index: Node* *pos_index = NULL); 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, RegionNode* region, int null_path, int offset);
*** 202,211 **** --- 204,215 ---- 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); + 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(); bool inline_string_getCharsU(); bool inline_string_copy(bool compress);
*** 895,904 **** --- 899,933 ---- Node* bol_lt = _gvn.transform(new BoolNode(cmp_lt, BoolTest::lt)); Node* is_over = generate_guard(bol_lt, region, PROB_MIN); 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) { ciKlass* thread_klass = env()->Thread_klass(); const Type* thread_type = TypeOopPtr::make_from_klass(thread_klass)->cast_to_ptr_type(TypePtr::NotNull);
*** 1014,1051 **** return true; } //------------------------------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; } bool LibraryCallKit::inline_objects_checkIndex() { Node* index = argument(0); --- 1043,1070 ---- return true; } //------------------------------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); ! // 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; } bool LibraryCallKit::inline_objects_checkIndex() { Node* index = argument(0);
*** 1122,1214 **** 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); ! } ! } ! ! 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[] --- 1141,1252 ---- if (ae == StrIntrinsicNode::UU) { // Divide substring size by 2 if String is UTF16 encoded tgt_count = _gvn.transform(new RShiftINode(tgt_count, intcon(1))); } ! 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); set_result(_gvn.transform(result_phi)); return true; } //-----------------------------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); // char count Node* tgt = argument(2); // byte[] ! 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); ! // 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* 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)); record_for_igvn(region); set_result(_gvn.transform(phi)); 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; } assert(callee()->signature()->size() == 4, "String.indexOfChar() has 4 arguments"); Node* src = argument(0); // byte[]
*** 1216,1228 **** 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 --- 1254,1271 ---- 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)); + // 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); 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
*** 1254,1263 **** --- 1297,1309 ---- // 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) { + 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"); Node* src = argument(0); Node* src_offset = argument(1);
*** 1276,1285 **** --- 1322,1338 ---- 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"); + // 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))); } else if (!compress && dst_elem == T_BYTE) { dst_offset = _gvn.transform(new LShiftINode(dst_offset, intcon(1)));
*** 1327,1336 **** --- 1380,1392 ---- #endif //_LP64 //------------------------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); Node* length = argument(2);
*** 1345,1367 **** 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); } ! 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); --- 1401,1426 ---- value = null_check(value); 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_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); } ! if (stopped()) { ! return true; ! } 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);
*** 1410,1450 **** } 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(); --- 1469,1516 ---- } return true; } //------------------------inline_string_getCharsU-------------------------- ! // 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; ! } // Get the arguments. ! Node* src = 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. ! src = null_check(src); dst = null_check(dst); if (stopped()) { return true; } // 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(src, 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();
< prev index next >