Mercurial > hg > truffle
comparison src/cpu/x86/vm/assembler_x86.cpp @ 2320:41d4973cf100
6942326: x86 code in string_indexof() could read beyond reserved heap space
Summary: copy small (<8) strings on stack if str+16 crosses a page boundary and load from stack into XMM. Back up pointer when loading string's tail.
Reviewed-by: never
author | kvn |
---|---|
date | Sat, 26 Feb 2011 12:10:54 -0800 |
parents | 6bbaedb03534 |
children | 8033953d67ff |
comparison
equal
deleted
inserted
replaced
2319:8190d4b75e09 | 2320:41d4973cf100 |
---|---|
1599 emit_byte(0x0F); | 1599 emit_byte(0x0F); |
1600 emit_byte(0x7E); | 1600 emit_byte(0x7E); |
1601 emit_byte(0xC0 | encode); | 1601 emit_byte(0xC0 | encode); |
1602 } | 1602 } |
1603 | 1603 |
1604 void Assembler::movdl(XMMRegister dst, Address src) { | |
1605 NOT_LP64(assert(VM_Version::supports_sse2(), "")); | |
1606 InstructionMark im(this); | |
1607 emit_byte(0x66); | |
1608 prefix(src, dst); | |
1609 emit_byte(0x0F); | |
1610 emit_byte(0x6E); | |
1611 emit_operand(dst, src); | |
1612 } | |
1613 | |
1614 | |
1604 void Assembler::movdqa(XMMRegister dst, Address src) { | 1615 void Assembler::movdqa(XMMRegister dst, Address src) { |
1605 NOT_LP64(assert(VM_Version::supports_sse2(), "")); | 1616 NOT_LP64(assert(VM_Version::supports_sse2(), "")); |
1606 InstructionMark im(this); | 1617 InstructionMark im(this); |
1607 emit_byte(0x66); | 1618 emit_byte(0x66); |
1608 prefix(src, dst); | 1619 prefix(src, dst); |
2410 emit_operand(dst, src); | 2421 emit_operand(dst, src); |
2411 emit_byte(mode & 0xFF); | 2422 emit_byte(mode & 0xFF); |
2412 } | 2423 } |
2413 | 2424 |
2414 void Assembler::psrlq(XMMRegister dst, int shift) { | 2425 void Assembler::psrlq(XMMRegister dst, int shift) { |
2415 // HMM Table D-1 says sse2 or mmx | 2426 // Shift 64 bit value logically right by specified number of bits. |
2427 // HMM Table D-1 says sse2 or mmx. | |
2428 // Do not confuse it with psrldq SSE2 instruction which | |
2429 // shifts 128 bit value in xmm register by number of bytes. | |
2416 NOT_LP64(assert(VM_Version::supports_sse(), "")); | 2430 NOT_LP64(assert(VM_Version::supports_sse(), "")); |
2417 | 2431 |
2418 int encode = prefixq_and_encode(xmm2->encoding(), dst->encoding()); | 2432 int encode = prefixq_and_encode(xmm2->encoding(), dst->encoding()); |
2433 emit_byte(0x66); | |
2434 emit_byte(0x0F); | |
2435 emit_byte(0x73); | |
2436 emit_byte(0xC0 | encode); | |
2437 emit_byte(shift); | |
2438 } | |
2439 | |
2440 void Assembler::psrldq(XMMRegister dst, int shift) { | |
2441 // Shift 128 bit value in xmm register by number of bytes. | |
2442 NOT_LP64(assert(VM_Version::supports_sse2(), "")); | |
2443 | |
2444 int encode = prefixq_and_encode(xmm3->encoding(), dst->encoding()); | |
2419 emit_byte(0x66); | 2445 emit_byte(0x66); |
2420 emit_byte(0x0F); | 2446 emit_byte(0x0F); |
2421 emit_byte(0x73); | 2447 emit_byte(0x73); |
2422 emit_byte(0xC0 | encode); | 2448 emit_byte(0xC0 | encode); |
2423 emit_byte(shift); | 2449 emit_byte(shift); |
8565 movptr(r12_heapbase, ExternalAddress((address)Universe::narrow_oop_base_addr())); | 8591 movptr(r12_heapbase, ExternalAddress((address)Universe::narrow_oop_base_addr())); |
8566 } | 8592 } |
8567 } | 8593 } |
8568 #endif // _LP64 | 8594 #endif // _LP64 |
8569 | 8595 |
8570 // IndexOf substring. | 8596 // IndexOf for constant substrings with size >= 8 chars |
8571 void MacroAssembler::string_indexof(Register str1, Register str2, | 8597 // which don't need to be loaded through stack. |
8572 Register cnt1, Register cnt2, Register result, | 8598 void MacroAssembler::string_indexofC8(Register str1, Register str2, |
8573 XMMRegister vec, Register tmp) { | 8599 Register cnt1, Register cnt2, |
8600 int int_cnt2, Register result, | |
8601 XMMRegister vec, Register tmp) { | |
8574 assert(UseSSE42Intrinsics, "SSE4.2 is required"); | 8602 assert(UseSSE42Intrinsics, "SSE4.2 is required"); |
8575 | 8603 |
8576 Label RELOAD_SUBSTR, PREP_FOR_SCAN, SCAN_TO_SUBSTR, | 8604 // This method uses pcmpestri inxtruction with bound registers |
8577 SCAN_SUBSTR, RET_NOT_FOUND, CLEANUP; | |
8578 | |
8579 push(str1); // string addr | |
8580 push(str2); // substr addr | |
8581 push(cnt2); // substr count | |
8582 jmpb(PREP_FOR_SCAN); | |
8583 | |
8584 // Substr count saved at sp | |
8585 // Substr saved at sp+1*wordSize | |
8586 // String saved at sp+2*wordSize | |
8587 | |
8588 // Reload substr for rescan | |
8589 bind(RELOAD_SUBSTR); | |
8590 movl(cnt2, Address(rsp, 0)); | |
8591 movptr(str2, Address(rsp, wordSize)); | |
8592 // We came here after the beginninig of the substring was | |
8593 // matched but the rest of it was not so we need to search | |
8594 // again. Start from the next element after the previous match. | |
8595 subptr(str1, result); // Restore counter | |
8596 shrl(str1, 1); | |
8597 addl(cnt1, str1); | |
8598 decrementl(cnt1); | |
8599 lea(str1, Address(result, 2)); // Reload string | |
8600 | |
8601 // Load substr | |
8602 bind(PREP_FOR_SCAN); | |
8603 movdqu(vec, Address(str2, 0)); | |
8604 addl(cnt1, 8); // prime the loop | |
8605 subptr(str1, 16); | |
8606 | |
8607 // Scan string for substr in 16-byte vectors | |
8608 bind(SCAN_TO_SUBSTR); | |
8609 subl(cnt1, 8); | |
8610 addptr(str1, 16); | |
8611 | |
8612 // pcmpestri | |
8613 // inputs: | 8605 // inputs: |
8614 // xmm - substring | 8606 // xmm - substring |
8615 // rax - substring length (elements count) | 8607 // rax - substring length (elements count) |
8616 // mem - scaned string | 8608 // mem - scanned string |
8617 // rdx - string length (elements count) | 8609 // rdx - string length (elements count) |
8618 // 0xd - mode: 1100 (substring search) + 01 (unsigned shorts) | 8610 // 0xd - mode: 1100 (substring search) + 01 (unsigned shorts) |
8619 // outputs: | 8611 // outputs: |
8620 // rcx - matched index in string | 8612 // rcx - matched index in string |
8621 assert(cnt1 == rdx && cnt2 == rax && tmp == rcx, "pcmpestri"); | 8613 assert(cnt1 == rdx && cnt2 == rax && tmp == rcx, "pcmpestri"); |
8622 | 8614 |
8623 pcmpestri(vec, Address(str1, 0), 0x0d); | 8615 Label RELOAD_SUBSTR, SCAN_TO_SUBSTR, SCAN_SUBSTR, |
8624 jcc(Assembler::above, SCAN_TO_SUBSTR); // CF == 0 && ZF == 0 | 8616 RET_FOUND, RET_NOT_FOUND, EXIT, FOUND_SUBSTR, |
8625 jccb(Assembler::aboveEqual, RET_NOT_FOUND); // CF == 0 | 8617 MATCH_SUBSTR_HEAD, RELOAD_STR, FOUND_CANDIDATE; |
8626 | 8618 |
8627 // Fallthrough: found a potential substr | 8619 // Note, inline_string_indexOf() generates checks: |
8620 // if (substr.count > string.count) return -1; | |
8621 // if (substr.count == 0) return 0; | |
8622 assert(int_cnt2 >= 8, "this code isused only for cnt2 >= 8 chars"); | |
8623 | |
8624 // Load substring. | |
8625 movdqu(vec, Address(str2, 0)); | |
8626 movl(cnt2, int_cnt2); | |
8627 movptr(result, str1); // string addr | |
8628 | |
8629 if (int_cnt2 > 8) { | |
8630 jmpb(SCAN_TO_SUBSTR); | |
8631 | |
8632 // Reload substr for rescan, this code | |
8633 // is executed only for large substrings (> 8 chars) | |
8634 bind(RELOAD_SUBSTR); | |
8635 movdqu(vec, Address(str2, 0)); | |
8636 negptr(cnt2); // Jumped here with negative cnt2, convert to positive | |
8637 | |
8638 bind(RELOAD_STR); | |
8639 // We came here after the beginning of the substring was | |
8640 // matched but the rest of it was not so we need to search | |
8641 // again. Start from the next element after the previous match. | |
8642 | |
8643 // cnt2 is number of substring reminding elements and | |
8644 // cnt1 is number of string reminding elements when cmp failed. | |
8645 // Restored cnt1 = cnt1 - cnt2 + int_cnt2 | |
8646 subl(cnt1, cnt2); | |
8647 addl(cnt1, int_cnt2); | |
8648 movl(cnt2, int_cnt2); // Now restore cnt2 | |
8649 | |
8650 decrementl(cnt1); // Shift to next element | |
8651 cmpl(cnt1, cnt2); | |
8652 jccb(Assembler::negative, RET_NOT_FOUND); // Left less then substring | |
8653 | |
8654 addptr(result, 2); | |
8655 | |
8656 } // (int_cnt2 > 8) | |
8657 | |
8658 // Scan string for start of substr in 16-byte vectors | |
8659 bind(SCAN_TO_SUBSTR); | |
8660 pcmpestri(vec, Address(result, 0), 0x0d); | |
8661 jccb(Assembler::below, FOUND_CANDIDATE); // CF == 1 | |
8662 subl(cnt1, 8); | |
8663 jccb(Assembler::lessEqual, RET_NOT_FOUND); // Scanned full string | |
8664 cmpl(cnt1, cnt2); | |
8665 jccb(Assembler::negative, RET_NOT_FOUND); // Left less then substring | |
8666 addptr(result, 16); | |
8667 jmpb(SCAN_TO_SUBSTR); | |
8668 | |
8669 // Found a potential substr | |
8670 bind(FOUND_CANDIDATE); | |
8671 // Matched whole vector if first element matched (tmp(rcx) == 0). | |
8672 if (int_cnt2 == 8) { | |
8673 jccb(Assembler::overflow, RET_FOUND); // OF == 1 | |
8674 } else { // int_cnt2 > 8 | |
8675 jccb(Assembler::overflow, FOUND_SUBSTR); | |
8676 } | |
8677 // After pcmpestri tmp(rcx) contains matched element index | |
8678 // Compute start addr of substr | |
8679 lea(result, Address(result, tmp, Address::times_2)); | |
8628 | 8680 |
8629 // Make sure string is still long enough | 8681 // Make sure string is still long enough |
8630 subl(cnt1, tmp); | 8682 subl(cnt1, tmp); |
8631 cmpl(cnt1, cnt2); | 8683 cmpl(cnt1, cnt2); |
8632 jccb(Assembler::negative, RET_NOT_FOUND); | 8684 if (int_cnt2 == 8) { |
8633 // Compute start addr of substr | 8685 jccb(Assembler::greaterEqual, SCAN_TO_SUBSTR); |
8634 lea(str1, Address(str1, tmp, Address::times_2)); | 8686 } else { // int_cnt2 > 8 |
8635 movptr(result, str1); // save | 8687 jccb(Assembler::greaterEqual, MATCH_SUBSTR_HEAD); |
8636 | 8688 } |
8637 // Compare potential substr | 8689 // Left less then substring. |
8638 addl(cnt1, 8); // prime the loop | |
8639 addl(cnt2, 8); | |
8640 subptr(str1, 16); | |
8641 subptr(str2, 16); | |
8642 | |
8643 // Scan 16-byte vectors of string and substr | |
8644 bind(SCAN_SUBSTR); | |
8645 subl(cnt1, 8); | |
8646 subl(cnt2, 8); | |
8647 addptr(str1, 16); | |
8648 addptr(str2, 16); | |
8649 movdqu(vec, Address(str2, 0)); | |
8650 pcmpestri(vec, Address(str1, 0), 0x0d); | |
8651 jcc(Assembler::noOverflow, RELOAD_SUBSTR); // OF == 0 | |
8652 jcc(Assembler::positive, SCAN_SUBSTR); // SF == 0 | |
8653 | |
8654 // Compute substr offset | |
8655 subptr(result, Address(rsp, 2*wordSize)); | |
8656 shrl(result, 1); // index | |
8657 jmpb(CLEANUP); | |
8658 | 8690 |
8659 bind(RET_NOT_FOUND); | 8691 bind(RET_NOT_FOUND); |
8660 movl(result, -1); | 8692 movl(result, -1); |
8693 jmpb(EXIT); | |
8694 | |
8695 if (int_cnt2 > 8) { | |
8696 // This code is optimized for the case when whole substring | |
8697 // is matched if its head is matched. | |
8698 bind(MATCH_SUBSTR_HEAD); | |
8699 pcmpestri(vec, Address(result, 0), 0x0d); | |
8700 // Reload only string if does not match | |
8701 jccb(Assembler::noOverflow, RELOAD_STR); // OF == 0 | |
8702 | |
8703 Label CONT_SCAN_SUBSTR; | |
8704 // Compare the rest of substring (> 8 chars). | |
8705 bind(FOUND_SUBSTR); | |
8706 // First 8 chars are already matched. | |
8707 negptr(cnt2); | |
8708 addptr(cnt2, 8); | |
8709 | |
8710 bind(SCAN_SUBSTR); | |
8711 subl(cnt1, 8); | |
8712 cmpl(cnt2, -8); // Do not read beyond substring | |
8713 jccb(Assembler::lessEqual, CONT_SCAN_SUBSTR); | |
8714 // Back-up strings to avoid reading beyond substring: | |
8715 // cnt1 = cnt1 - cnt2 + 8 | |
8716 addl(cnt1, cnt2); // cnt2 is negative | |
8717 addl(cnt1, 8); | |
8718 movl(cnt2, 8); negptr(cnt2); | |
8719 bind(CONT_SCAN_SUBSTR); | |
8720 if (int_cnt2 < (int)G) { | |
8721 movdqu(vec, Address(str2, cnt2, Address::times_2, int_cnt2*2)); | |
8722 pcmpestri(vec, Address(result, cnt2, Address::times_2, int_cnt2*2), 0x0d); | |
8723 } else { | |
8724 // calculate index in register to avoid integer overflow (int_cnt2*2) | |
8725 movl(tmp, int_cnt2); | |
8726 addptr(tmp, cnt2); | |
8727 movdqu(vec, Address(str2, tmp, Address::times_2, 0)); | |
8728 pcmpestri(vec, Address(result, tmp, Address::times_2, 0), 0x0d); | |
8729 } | |
8730 // Need to reload strings pointers if not matched whole vector | |
8731 jccb(Assembler::noOverflow, RELOAD_SUBSTR); // OF == 0 | |
8732 addptr(cnt2, 8); | |
8733 jccb(Assembler::negative, SCAN_SUBSTR); | |
8734 // Fall through if found full substring | |
8735 | |
8736 } // (int_cnt2 > 8) | |
8737 | |
8738 bind(RET_FOUND); | |
8739 // Found result if we matched full small substring. | |
8740 // Compute substr offset | |
8741 subptr(result, str1); | |
8742 shrl(result, 1); // index | |
8743 bind(EXIT); | |
8744 | |
8745 } // string_indexofC8 | |
8746 | |
8747 // Small strings are loaded through stack if they cross page boundary. | |
8748 void MacroAssembler::string_indexof(Register str1, Register str2, | |
8749 Register cnt1, Register cnt2, | |
8750 int int_cnt2, Register result, | |
8751 XMMRegister vec, Register tmp) { | |
8752 assert(UseSSE42Intrinsics, "SSE4.2 is required"); | |
8753 // | |
8754 // int_cnt2 is length of small (< 8 chars) constant substring | |
8755 // or (-1) for non constant substring in which case its length | |
8756 // is in cnt2 register. | |
8757 // | |
8758 // Note, inline_string_indexOf() generates checks: | |
8759 // if (substr.count > string.count) return -1; | |
8760 // if (substr.count == 0) return 0; | |
8761 // | |
8762 assert(int_cnt2 == -1 || (0 < int_cnt2 && int_cnt2 < 8), "should be != 0"); | |
8763 | |
8764 // This method uses pcmpestri inxtruction with bound registers | |
8765 // inputs: | |
8766 // xmm - substring | |
8767 // rax - substring length (elements count) | |
8768 // mem - scanned string | |
8769 // rdx - string length (elements count) | |
8770 // 0xd - mode: 1100 (substring search) + 01 (unsigned shorts) | |
8771 // outputs: | |
8772 // rcx - matched index in string | |
8773 assert(cnt1 == rdx && cnt2 == rax && tmp == rcx, "pcmpestri"); | |
8774 | |
8775 Label RELOAD_SUBSTR, SCAN_TO_SUBSTR, SCAN_SUBSTR, ADJUST_STR, | |
8776 RET_FOUND, RET_NOT_FOUND, CLEANUP, FOUND_SUBSTR, | |
8777 FOUND_CANDIDATE; | |
8778 | |
8779 { //======================================================== | |
8780 // We don't know where these strings are located | |
8781 // and we can't read beyond them. Load them through stack. | |
8782 Label BIG_STRINGS, CHECK_STR, COPY_SUBSTR, COPY_STR; | |
8783 | |
8784 movptr(tmp, rsp); // save old SP | |
8785 | |
8786 if (int_cnt2 > 0) { // small (< 8 chars) constant substring | |
8787 if (int_cnt2 == 1) { // One char | |
8788 load_unsigned_short(result, Address(str2, 0)); | |
8789 movdl(vec, result); // move 32 bits | |
8790 } else if (int_cnt2 == 2) { // Two chars | |
8791 movdl(vec, Address(str2, 0)); // move 32 bits | |
8792 } else if (int_cnt2 == 4) { // Four chars | |
8793 movq(vec, Address(str2, 0)); // move 64 bits | |
8794 } else { // cnt2 = { 3, 5, 6, 7 } | |
8795 // Array header size is 12 bytes in 32-bit VM | |
8796 // + 6 bytes for 3 chars == 18 bytes, | |
8797 // enough space to load vec and shift. | |
8798 assert(HeapWordSize*typeArrayKlass::header_size() >= 12,"sanity"); | |
8799 movdqu(vec, Address(str2, (int_cnt2*2)-16)); | |
8800 psrldq(vec, 16-(int_cnt2*2)); | |
8801 } | |
8802 } else { // not constant substring | |
8803 cmpl(cnt2, 8); | |
8804 jccb(Assembler::aboveEqual, BIG_STRINGS); // Both strings are big enough | |
8805 | |
8806 // We can read beyond string if srt+16 does not cross page boundary | |
8807 // since heaps are aligned and mapped by pages. | |
8808 assert(os::vm_page_size() < (int)G, "default page should be small"); | |
8809 movl(result, str2); // We need only low 32 bits | |
8810 andl(result, (os::vm_page_size()-1)); | |
8811 cmpl(result, (os::vm_page_size()-16)); | |
8812 jccb(Assembler::belowEqual, CHECK_STR); | |
8813 | |
8814 // Move small strings to stack to allow load 16 bytes into vec. | |
8815 subptr(rsp, 16); | |
8816 int stk_offset = wordSize-2; | |
8817 push(cnt2); | |
8818 | |
8819 bind(COPY_SUBSTR); | |
8820 load_unsigned_short(result, Address(str2, cnt2, Address::times_2, -2)); | |
8821 movw(Address(rsp, cnt2, Address::times_2, stk_offset), result); | |
8822 decrement(cnt2); | |
8823 jccb(Assembler::notZero, COPY_SUBSTR); | |
8824 | |
8825 pop(cnt2); | |
8826 movptr(str2, rsp); // New substring address | |
8827 } // non constant | |
8828 | |
8829 bind(CHECK_STR); | |
8830 cmpl(cnt1, 8); | |
8831 jccb(Assembler::aboveEqual, BIG_STRINGS); | |
8832 | |
8833 // Check cross page boundary. | |
8834 movl(result, str1); // We need only low 32 bits | |
8835 andl(result, (os::vm_page_size()-1)); | |
8836 cmpl(result, (os::vm_page_size()-16)); | |
8837 jccb(Assembler::belowEqual, BIG_STRINGS); | |
8838 | |
8839 subptr(rsp, 16); | |
8840 int stk_offset = -2; | |
8841 if (int_cnt2 < 0) { // not constant | |
8842 push(cnt2); | |
8843 stk_offset += wordSize; | |
8844 } | |
8845 movl(cnt2, cnt1); | |
8846 | |
8847 bind(COPY_STR); | |
8848 load_unsigned_short(result, Address(str1, cnt2, Address::times_2, -2)); | |
8849 movw(Address(rsp, cnt2, Address::times_2, stk_offset), result); | |
8850 decrement(cnt2); | |
8851 jccb(Assembler::notZero, COPY_STR); | |
8852 | |
8853 if (int_cnt2 < 0) { // not constant | |
8854 pop(cnt2); | |
8855 } | |
8856 movptr(str1, rsp); // New string address | |
8857 | |
8858 bind(BIG_STRINGS); | |
8859 // Load substring. | |
8860 if (int_cnt2 < 0) { // -1 | |
8861 movdqu(vec, Address(str2, 0)); | |
8862 push(cnt2); // substr count | |
8863 push(str2); // substr addr | |
8864 push(str1); // string addr | |
8865 } else { | |
8866 // Small (< 8 chars) constant substrings are loaded already. | |
8867 movl(cnt2, int_cnt2); | |
8868 } | |
8869 push(tmp); // original SP | |
8870 | |
8871 } // Finished loading | |
8872 | |
8873 //======================================================== | |
8874 // Start search | |
8875 // | |
8876 | |
8877 movptr(result, str1); // string addr | |
8878 | |
8879 if (int_cnt2 < 0) { // Only for non constant substring | |
8880 jmpb(SCAN_TO_SUBSTR); | |
8881 | |
8882 // SP saved at sp+0 | |
8883 // String saved at sp+1*wordSize | |
8884 // Substr saved at sp+2*wordSize | |
8885 // Substr count saved at sp+3*wordSize | |
8886 | |
8887 // Reload substr for rescan, this code | |
8888 // is executed only for large substrings (> 8 chars) | |
8889 bind(RELOAD_SUBSTR); | |
8890 movptr(str2, Address(rsp, 2*wordSize)); | |
8891 movl(cnt2, Address(rsp, 3*wordSize)); | |
8892 movdqu(vec, Address(str2, 0)); | |
8893 // We came here after the beginning of the substring was | |
8894 // matched but the rest of it was not so we need to search | |
8895 // again. Start from the next element after the previous match. | |
8896 subptr(str1, result); // Restore counter | |
8897 shrl(str1, 1); | |
8898 addl(cnt1, str1); | |
8899 decrementl(cnt1); // Shift to next element | |
8900 cmpl(cnt1, cnt2); | |
8901 jccb(Assembler::negative, RET_NOT_FOUND); // Left less then substring | |
8902 | |
8903 addptr(result, 2); | |
8904 } // non constant | |
8905 | |
8906 // Scan string for start of substr in 16-byte vectors | |
8907 bind(SCAN_TO_SUBSTR); | |
8908 assert(cnt1 == rdx && cnt2 == rax && tmp == rcx, "pcmpestri"); | |
8909 pcmpestri(vec, Address(result, 0), 0x0d); | |
8910 jccb(Assembler::below, FOUND_CANDIDATE); // CF == 1 | |
8911 subl(cnt1, 8); | |
8912 jccb(Assembler::lessEqual, RET_NOT_FOUND); // Scanned full string | |
8913 cmpl(cnt1, cnt2); | |
8914 jccb(Assembler::negative, RET_NOT_FOUND); // Left less then substring | |
8915 addptr(result, 16); | |
8916 | |
8917 bind(ADJUST_STR); | |
8918 cmpl(cnt1, 8); // Do not read beyond string | |
8919 jccb(Assembler::greaterEqual, SCAN_TO_SUBSTR); | |
8920 // Back-up string to avoid reading beyond string. | |
8921 lea(result, Address(result, cnt1, Address::times_2, -16)); | |
8922 movl(cnt1, 8); | |
8923 jmpb(SCAN_TO_SUBSTR); | |
8924 | |
8925 // Found a potential substr | |
8926 bind(FOUND_CANDIDATE); | |
8927 // After pcmpestri tmp(rcx) contains matched element index | |
8928 | |
8929 // Make sure string is still long enough | |
8930 subl(cnt1, tmp); | |
8931 cmpl(cnt1, cnt2); | |
8932 jccb(Assembler::greaterEqual, FOUND_SUBSTR); | |
8933 // Left less then substring. | |
8934 | |
8935 bind(RET_NOT_FOUND); | |
8936 movl(result, -1); | |
8937 jmpb(CLEANUP); | |
8938 | |
8939 bind(FOUND_SUBSTR); | |
8940 // Compute start addr of substr | |
8941 lea(result, Address(result, tmp, Address::times_2)); | |
8942 | |
8943 if (int_cnt2 > 0) { // Constant substring | |
8944 // Repeat search for small substring (< 8 chars) | |
8945 // from new point without reloading substring. | |
8946 // Have to check that we don't read beyond string. | |
8947 cmpl(tmp, 8-int_cnt2); | |
8948 jccb(Assembler::greater, ADJUST_STR); | |
8949 // Fall through if matched whole substring. | |
8950 } else { // non constant | |
8951 assert(int_cnt2 == -1, "should be != 0"); | |
8952 | |
8953 addl(tmp, cnt2); | |
8954 // Found result if we matched whole substring. | |
8955 cmpl(tmp, 8); | |
8956 jccb(Assembler::lessEqual, RET_FOUND); | |
8957 | |
8958 // Repeat search for small substring (<= 8 chars) | |
8959 // from new point 'str1' without reloading substring. | |
8960 cmpl(cnt2, 8); | |
8961 // Have to check that we don't read beyond string. | |
8962 jccb(Assembler::lessEqual, ADJUST_STR); | |
8963 | |
8964 Label CHECK_NEXT, CONT_SCAN_SUBSTR, RET_FOUND_LONG; | |
8965 // Compare the rest of substring (> 8 chars). | |
8966 movptr(str1, result); | |
8967 | |
8968 cmpl(tmp, cnt2); | |
8969 // First 8 chars are already matched. | |
8970 jccb(Assembler::equal, CHECK_NEXT); | |
8971 | |
8972 bind(SCAN_SUBSTR); | |
8973 pcmpestri(vec, Address(str1, 0), 0x0d); | |
8974 // Need to reload strings pointers if not matched whole vector | |
8975 jcc(Assembler::noOverflow, RELOAD_SUBSTR); // OF == 0 | |
8976 | |
8977 bind(CHECK_NEXT); | |
8978 subl(cnt2, 8); | |
8979 jccb(Assembler::lessEqual, RET_FOUND_LONG); // Found full substring | |
8980 addptr(str1, 16); | |
8981 addptr(str2, 16); | |
8982 subl(cnt1, 8); | |
8983 cmpl(cnt2, 8); // Do not read beyond substring | |
8984 jccb(Assembler::greaterEqual, CONT_SCAN_SUBSTR); | |
8985 // Back-up strings to avoid reading beyond substring. | |
8986 lea(str2, Address(str2, cnt2, Address::times_2, -16)); | |
8987 lea(str1, Address(str1, cnt2, Address::times_2, -16)); | |
8988 subl(cnt1, cnt2); | |
8989 movl(cnt2, 8); | |
8990 addl(cnt1, 8); | |
8991 bind(CONT_SCAN_SUBSTR); | |
8992 movdqu(vec, Address(str2, 0)); | |
8993 jmpb(SCAN_SUBSTR); | |
8994 | |
8995 bind(RET_FOUND_LONG); | |
8996 movptr(str1, Address(rsp, wordSize)); | |
8997 } // non constant | |
8998 | |
8999 bind(RET_FOUND); | |
9000 // Compute substr offset | |
9001 subptr(result, str1); | |
9002 shrl(result, 1); // index | |
8661 | 9003 |
8662 bind(CLEANUP); | 9004 bind(CLEANUP); |
8663 addptr(rsp, 3*wordSize); | 9005 pop(rsp); // restore SP |
8664 } | 9006 |
9007 } // string_indexof | |
8665 | 9008 |
8666 // Compare strings. | 9009 // Compare strings. |
8667 void MacroAssembler::string_compare(Register str1, Register str2, | 9010 void MacroAssembler::string_compare(Register str1, Register str2, |
8668 Register cnt1, Register cnt2, Register result, | 9011 Register cnt1, Register cnt2, Register result, |
8669 XMMRegister vec1) { | 9012 XMMRegister vec1) { |