8281146: Replace StringCoding.hasNegatives with countPositives
Co-authored-by: Lutz Schmidt <lucy@openjdk.org> Co-authored-by: Martin Doerr <mdoerr@openjdk.org> Reviewed-by: kvn, lucy, rriggs
This commit is contained in:
parent
249d553659
commit
beedae1141
@ -17080,13 +17080,13 @@ instruct array_equalsC(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result,
|
||||
ins_pipe(pipe_class_memory);
|
||||
%}
|
||||
|
||||
instruct has_negatives(iRegP_R1 ary1, iRegI_R2 len, iRegI_R0 result, rFlagsReg cr)
|
||||
instruct count_positives(iRegP_R1 ary1, iRegI_R2 len, iRegI_R0 result, rFlagsReg cr)
|
||||
%{
|
||||
match(Set result (HasNegatives ary1 len));
|
||||
match(Set result (CountPositives ary1 len));
|
||||
effect(USE_KILL ary1, USE_KILL len, KILL cr);
|
||||
format %{ "has negatives byte[] $ary1,$len -> $result" %}
|
||||
format %{ "count positives byte[] $ary1,$len -> $result" %}
|
||||
ins_encode %{
|
||||
address tpc = __ has_negatives($ary1$$Register, $len$$Register, $result$$Register);
|
||||
address tpc = __ count_positives($ary1$$Register, $len$$Register, $result$$Register);
|
||||
if (tpc == NULL) {
|
||||
ciEnv::current()->record_failure("CodeCache is full");
|
||||
return;
|
||||
|
@ -4339,16 +4339,17 @@ void MacroAssembler::remove_frame(int framesize) {
|
||||
}
|
||||
|
||||
|
||||
// This method checks if provided byte array contains byte with highest bit set.
|
||||
address MacroAssembler::has_negatives(Register ary1, Register len, Register result) {
|
||||
// This method counts leading positive bytes (highest bit not set) in provided byte array
|
||||
address MacroAssembler::count_positives(Register ary1, Register len, Register result) {
|
||||
// Simple and most common case of aligned small array which is not at the
|
||||
// end of memory page is placed here. All other cases are in stub.
|
||||
Label LOOP, END, STUB, STUB_LONG, SET_RESULT, DONE;
|
||||
const uint64_t UPPER_BIT_MASK=0x8080808080808080;
|
||||
assert_different_registers(ary1, len, result);
|
||||
|
||||
mov(result, len);
|
||||
cmpw(len, 0);
|
||||
br(LE, SET_RESULT);
|
||||
br(LE, DONE);
|
||||
cmpw(len, 4 * wordSize);
|
||||
br(GE, STUB_LONG); // size > 32 then go to stub
|
||||
|
||||
@ -4367,19 +4368,20 @@ address MacroAssembler::has_negatives(Register ary1, Register len, Register resu
|
||||
subs(len, len, wordSize);
|
||||
br(GE, LOOP);
|
||||
cmpw(len, -wordSize);
|
||||
br(EQ, SET_RESULT);
|
||||
br(EQ, DONE);
|
||||
|
||||
BIND(END);
|
||||
ldr(result, Address(ary1));
|
||||
sub(len, zr, len, LSL, 3); // LSL 3 is to get bits from bytes
|
||||
lslv(result, result, len);
|
||||
tst(result, UPPER_BIT_MASK);
|
||||
b(SET_RESULT);
|
||||
ldr(rscratch1, Address(ary1));
|
||||
sub(rscratch2, zr, len, LSL, 3); // LSL 3 is to get bits from bytes
|
||||
lslv(rscratch1, rscratch1, rscratch2);
|
||||
tst(rscratch1, UPPER_BIT_MASK);
|
||||
br(NE, SET_RESULT);
|
||||
b(DONE);
|
||||
|
||||
BIND(STUB);
|
||||
RuntimeAddress has_neg = RuntimeAddress(StubRoutines::aarch64::has_negatives());
|
||||
assert(has_neg.target() != NULL, "has_negatives stub has not been generated");
|
||||
address tpc1 = trampoline_call(has_neg);
|
||||
RuntimeAddress count_pos = RuntimeAddress(StubRoutines::aarch64::count_positives());
|
||||
assert(count_pos.target() != NULL, "count_positives stub has not been generated");
|
||||
address tpc1 = trampoline_call(count_pos);
|
||||
if (tpc1 == NULL) {
|
||||
DEBUG_ONLY(reset_labels(STUB_LONG, SET_RESULT, DONE));
|
||||
postcond(pc() == badAddress);
|
||||
@ -4388,9 +4390,9 @@ address MacroAssembler::has_negatives(Register ary1, Register len, Register resu
|
||||
b(DONE);
|
||||
|
||||
BIND(STUB_LONG);
|
||||
RuntimeAddress has_neg_long = RuntimeAddress(StubRoutines::aarch64::has_negatives_long());
|
||||
assert(has_neg_long.target() != NULL, "has_negatives stub has not been generated");
|
||||
address tpc2 = trampoline_call(has_neg_long);
|
||||
RuntimeAddress count_pos_long = RuntimeAddress(StubRoutines::aarch64::count_positives_long());
|
||||
assert(count_pos_long.target() != NULL, "count_positives_long stub has not been generated");
|
||||
address tpc2 = trampoline_call(count_pos_long);
|
||||
if (tpc2 == NULL) {
|
||||
DEBUG_ONLY(reset_labels(SET_RESULT, DONE));
|
||||
postcond(pc() == badAddress);
|
||||
@ -4399,7 +4401,9 @@ address MacroAssembler::has_negatives(Register ary1, Register len, Register resu
|
||||
b(DONE);
|
||||
|
||||
BIND(SET_RESULT);
|
||||
cset(result, NE); // set true or false
|
||||
|
||||
add(len, len, wordSize);
|
||||
sub(result, result, len);
|
||||
|
||||
BIND(DONE);
|
||||
postcond(pc() != badAddress);
|
||||
|
@ -1234,7 +1234,7 @@ public:
|
||||
Register table0, Register table1, Register table2, Register table3,
|
||||
bool upper = false);
|
||||
|
||||
address has_negatives(Register ary1, Register len, Register result);
|
||||
address count_positives(Register ary1, Register len, Register result);
|
||||
|
||||
address arrays_equals(Register a1, Register a2, Register result, Register cnt1,
|
||||
Register tmp1, Register tmp2, Register tmp3, int elem_size);
|
||||
|
@ -4657,7 +4657,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
return start;
|
||||
}
|
||||
|
||||
address generate_has_negatives(address &has_negatives_long) {
|
||||
address generate_count_positives(address &count_positives_long) {
|
||||
const u1 large_loop_size = 64;
|
||||
const uint64_t UPPER_BIT_MASK=0x8080808080808080;
|
||||
int dcache_line = VM_Version::dcache_line_size();
|
||||
@ -4666,13 +4666,15 @@ class StubGenerator: public StubCodeGenerator {
|
||||
|
||||
__ align(CodeEntryAlignment);
|
||||
|
||||
StubCodeMark mark(this, "StubRoutines", "has_negatives");
|
||||
StubCodeMark mark(this, "StubRoutines", "count_positives");
|
||||
|
||||
address entry = __ pc();
|
||||
|
||||
__ enter();
|
||||
// precondition: a copy of len is already in result
|
||||
// __ mov(result, len);
|
||||
|
||||
Label RET_TRUE, RET_TRUE_NO_POP, RET_FALSE, ALIGNED, LOOP16, CHECK_16,
|
||||
Label RET_ADJUST, RET_ADJUST_16, RET_ADJUST_LONG, RET_NO_POP, RET_LEN, ALIGNED, LOOP16, CHECK_16,
|
||||
LARGE_LOOP, POST_LOOP16, LEN_OVER_15, LEN_OVER_8, POST_LOOP16_LOAD_TAIL;
|
||||
|
||||
__ cmp(len, (u1)15);
|
||||
@ -4686,25 +4688,26 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ sub(rscratch1, zr, len, __ LSL, 3); // LSL 3 is to get bits from bytes.
|
||||
__ lsrv(rscratch2, rscratch2, rscratch1);
|
||||
__ tst(rscratch2, UPPER_BIT_MASK);
|
||||
__ cset(result, Assembler::NE);
|
||||
__ csel(result, zr, result, Assembler::NE);
|
||||
__ leave();
|
||||
__ ret(lr);
|
||||
__ bind(LEN_OVER_8);
|
||||
__ ldp(rscratch1, rscratch2, Address(ary1, -16));
|
||||
__ sub(len, len, 8); // no data dep., then sub can be executed while loading
|
||||
__ tst(rscratch2, UPPER_BIT_MASK);
|
||||
__ br(Assembler::NE, RET_TRUE_NO_POP);
|
||||
__ br(Assembler::NE, RET_NO_POP);
|
||||
__ sub(rscratch2, zr, len, __ LSL, 3); // LSL 3 is to get bits from bytes
|
||||
__ lsrv(rscratch1, rscratch1, rscratch2);
|
||||
__ tst(rscratch1, UPPER_BIT_MASK);
|
||||
__ cset(result, Assembler::NE);
|
||||
__ bind(RET_NO_POP);
|
||||
__ csel(result, zr, result, Assembler::NE);
|
||||
__ leave();
|
||||
__ ret(lr);
|
||||
|
||||
Register tmp1 = r3, tmp2 = r4, tmp3 = r5, tmp4 = r6, tmp5 = r7, tmp6 = r10;
|
||||
const RegSet spilled_regs = RegSet::range(tmp1, tmp5) + tmp6;
|
||||
|
||||
has_negatives_long = __ pc(); // 2nd entry point
|
||||
count_positives_long = __ pc(); // 2nd entry point
|
||||
|
||||
__ enter();
|
||||
|
||||
@ -4716,10 +4719,10 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ mov(tmp5, 16);
|
||||
__ sub(rscratch1, tmp5, rscratch2); // amount of bytes until aligned address
|
||||
__ add(ary1, ary1, rscratch1);
|
||||
__ sub(len, len, rscratch1);
|
||||
__ orr(tmp6, tmp6, tmp1);
|
||||
__ tst(tmp6, UPPER_BIT_MASK);
|
||||
__ br(Assembler::NE, RET_TRUE);
|
||||
__ br(Assembler::NE, RET_ADJUST);
|
||||
__ sub(len, len, rscratch1);
|
||||
|
||||
__ bind(ALIGNED);
|
||||
__ cmp(len, large_loop_size);
|
||||
@ -4734,7 +4737,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ sub(len, len, 16);
|
||||
__ orr(tmp6, tmp6, tmp1);
|
||||
__ tst(tmp6, UPPER_BIT_MASK);
|
||||
__ br(Assembler::NE, RET_TRUE);
|
||||
__ br(Assembler::NE, RET_ADJUST_16);
|
||||
__ cmp(len, large_loop_size);
|
||||
__ br(Assembler::LT, CHECK_16);
|
||||
|
||||
@ -4766,7 +4769,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ orr(rscratch1, rscratch1, tmp6);
|
||||
__ orr(tmp2, tmp2, rscratch1);
|
||||
__ tst(tmp2, UPPER_BIT_MASK);
|
||||
__ br(Assembler::NE, RET_TRUE);
|
||||
__ br(Assembler::NE, RET_ADJUST_LONG);
|
||||
__ cmp(len, large_loop_size);
|
||||
__ br(Assembler::GE, LARGE_LOOP);
|
||||
|
||||
@ -4779,7 +4782,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ sub(len, len, 16);
|
||||
__ orr(tmp2, tmp2, tmp3);
|
||||
__ tst(tmp2, UPPER_BIT_MASK);
|
||||
__ br(Assembler::NE, RET_TRUE);
|
||||
__ br(Assembler::NE, RET_ADJUST_16);
|
||||
__ cmp(len, (u1)16);
|
||||
__ br(Assembler::GE, LOOP16); // 16-byte load loop end
|
||||
|
||||
@ -4787,31 +4790,36 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ cmp(len, (u1)8);
|
||||
__ br(Assembler::LE, POST_LOOP16_LOAD_TAIL);
|
||||
__ ldr(tmp3, Address(__ post(ary1, 8)));
|
||||
__ sub(len, len, 8);
|
||||
__ tst(tmp3, UPPER_BIT_MASK);
|
||||
__ br(Assembler::NE, RET_TRUE);
|
||||
__ br(Assembler::NE, RET_ADJUST);
|
||||
__ sub(len, len, 8);
|
||||
|
||||
__ bind(POST_LOOP16_LOAD_TAIL);
|
||||
__ cbz(len, RET_FALSE); // Can't shift left by 64 when len==0
|
||||
__ cbz(len, RET_LEN); // Can't shift left by 64 when len==0
|
||||
__ ldr(tmp1, Address(ary1));
|
||||
__ mov(tmp2, 64);
|
||||
__ sub(tmp4, tmp2, len, __ LSL, 3);
|
||||
__ lslv(tmp1, tmp1, tmp4);
|
||||
__ tst(tmp1, UPPER_BIT_MASK);
|
||||
__ br(Assembler::NE, RET_TRUE);
|
||||
__ br(Assembler::NE, RET_ADJUST);
|
||||
// Fallthrough
|
||||
|
||||
__ bind(RET_FALSE);
|
||||
__ bind(RET_LEN);
|
||||
__ pop(spilled_regs, sp);
|
||||
__ leave();
|
||||
__ mov(result, zr);
|
||||
__ ret(lr);
|
||||
|
||||
__ bind(RET_TRUE);
|
||||
// difference result - len is the count of guaranteed to be
|
||||
// positive bytes
|
||||
|
||||
__ bind(RET_ADJUST_LONG);
|
||||
__ add(len, len, (u1)(large_loop_size - 16));
|
||||
__ bind(RET_ADJUST_16);
|
||||
__ add(len, len, 16);
|
||||
__ bind(RET_ADJUST);
|
||||
__ pop(spilled_regs, sp);
|
||||
__ bind(RET_TRUE_NO_POP);
|
||||
__ leave();
|
||||
__ mov(result, 1);
|
||||
__ sub(result, result, len);
|
||||
__ ret(lr);
|
||||
|
||||
return entry;
|
||||
@ -7515,8 +7523,8 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// arraycopy stubs used by compilers
|
||||
generate_arraycopy_stubs();
|
||||
|
||||
// has negatives stub for large arrays.
|
||||
StubRoutines::aarch64::_has_negatives = generate_has_negatives(StubRoutines::aarch64::_has_negatives_long);
|
||||
// countPositives stub for large arrays.
|
||||
StubRoutines::aarch64::_count_positives = generate_count_positives(StubRoutines::aarch64::_count_positives_long);
|
||||
|
||||
// array equals stub for large arrays.
|
||||
if (!UseSimpleArrayEquals) {
|
||||
|
@ -45,8 +45,8 @@ address StubRoutines::aarch64::_float_sign_flip = NULL;
|
||||
address StubRoutines::aarch64::_double_sign_mask = NULL;
|
||||
address StubRoutines::aarch64::_double_sign_flip = NULL;
|
||||
address StubRoutines::aarch64::_zero_blocks = NULL;
|
||||
address StubRoutines::aarch64::_has_negatives = NULL;
|
||||
address StubRoutines::aarch64::_has_negatives_long = NULL;
|
||||
address StubRoutines::aarch64::_count_positives = NULL;
|
||||
address StubRoutines::aarch64::_count_positives_long = NULL;
|
||||
address StubRoutines::aarch64::_large_array_equals = NULL;
|
||||
address StubRoutines::aarch64::_compare_long_string_LL = NULL;
|
||||
address StubRoutines::aarch64::_compare_long_string_UU = NULL;
|
||||
|
@ -76,8 +76,8 @@ class aarch64 {
|
||||
|
||||
public:
|
||||
|
||||
static address _has_negatives;
|
||||
static address _has_negatives_long;
|
||||
static address _count_positives;
|
||||
static address _count_positives_long;
|
||||
|
||||
static address get_previous_sp_entry()
|
||||
{
|
||||
@ -132,12 +132,12 @@ class aarch64 {
|
||||
return _zero_blocks;
|
||||
}
|
||||
|
||||
static address has_negatives() {
|
||||
return _has_negatives;
|
||||
static address count_positives() {
|
||||
return _count_positives;
|
||||
}
|
||||
|
||||
static address has_negatives_long() {
|
||||
return _has_negatives_long;
|
||||
static address count_positives_long() {
|
||||
return _count_positives_long;
|
||||
}
|
||||
|
||||
static address large_array_equals() {
|
||||
|
@ -565,16 +565,16 @@ void C2_MacroAssembler::string_indexof_char(Register result, Register haystack,
|
||||
} // string_indexof_char
|
||||
|
||||
|
||||
void C2_MacroAssembler::has_negatives(Register src, Register cnt, Register result,
|
||||
Register tmp1, Register tmp2) {
|
||||
void C2_MacroAssembler::count_positives(Register src, Register cnt, Register result,
|
||||
Register tmp1, Register tmp2) {
|
||||
const Register tmp0 = R0;
|
||||
assert_different_registers(src, result, cnt, tmp0, tmp1, tmp2);
|
||||
Label Lfastloop, Lslow, Lloop, Lnoneg, Ldone;
|
||||
Label Lfastloop, Lslow, Lloop, Ldone;
|
||||
|
||||
// Check if cnt >= 8 (= 16 bytes)
|
||||
lis(tmp1, (int)(short)0x8080); // tmp1 = 0x8080808080808080
|
||||
srwi_(tmp2, cnt, 4);
|
||||
li(result, 1); // Assume there's a negative byte.
|
||||
mr(result, src); // Use result reg to point to the current position.
|
||||
beq(CCR0, Lslow);
|
||||
ori(tmp1, tmp1, 0x8080);
|
||||
rldimi(tmp1, tmp1, 32, 0);
|
||||
@ -582,30 +582,28 @@ void C2_MacroAssembler::has_negatives(Register src, Register cnt, Register resul
|
||||
|
||||
// 2x unrolled loop
|
||||
bind(Lfastloop);
|
||||
ld(tmp2, 0, src);
|
||||
ld(tmp0, 8, src);
|
||||
ld(tmp2, 0, result);
|
||||
ld(tmp0, 8, result);
|
||||
|
||||
orr(tmp0, tmp2, tmp0);
|
||||
|
||||
and_(tmp0, tmp0, tmp1);
|
||||
bne(CCR0, Ldone); // Found negative byte.
|
||||
addi(src, src, 16);
|
||||
|
||||
bne(CCR0, Lslow); // Found negative byte.
|
||||
addi(result, result, 16);
|
||||
bdnz(Lfastloop);
|
||||
|
||||
bind(Lslow); // Fallback to slow version
|
||||
rldicl_(tmp0, cnt, 0, 64-4);
|
||||
beq(CCR0, Lnoneg);
|
||||
bind(Lslow); // Fallback to slow version.
|
||||
subf(tmp0, src, result); // Bytes known positive.
|
||||
subf_(tmp0, tmp0, cnt); // Remaining Bytes.
|
||||
beq(CCR0, Ldone);
|
||||
mtctr(tmp0);
|
||||
bind(Lloop);
|
||||
lbz(tmp0, 0, src);
|
||||
addi(src, src, 1);
|
||||
lbz(tmp0, 0, result);
|
||||
andi_(tmp0, tmp0, 0x80);
|
||||
bne(CCR0, Ldone); // Found negative byte.
|
||||
addi(result, result, 1);
|
||||
bdnz(Lloop);
|
||||
bind(Lnoneg);
|
||||
li(result, 0);
|
||||
|
||||
bind(Ldone);
|
||||
subf(result, src, result); // Result is offset from src.
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,6 @@
|
||||
void string_indexof_char(Register result, Register haystack, Register haycnt,
|
||||
Register needle, jchar needleChar, Register tmp1, Register tmp2, bool is_byte);
|
||||
|
||||
void has_negatives(Register src, Register cnt, Register result, Register tmp1, Register tmp2);
|
||||
void count_positives(Register src, Register cnt, Register result, Register tmp1, Register tmp2);
|
||||
|
||||
#endif // CPU_PPC_C2_MACROASSEMBLER_PPC_HPP
|
||||
|
@ -12779,16 +12779,16 @@ instruct string_inflate(Universe dummy, rarg1RegP src, rarg2RegP dst, iRegIsrc l
|
||||
%}
|
||||
|
||||
// StringCoding.java intrinsics
|
||||
instruct has_negatives(rarg1RegP ary1, iRegIsrc len, iRegIdst result, iRegLdst tmp1, iRegLdst tmp2,
|
||||
regCTR ctr, flagsRegCR0 cr0)
|
||||
instruct count_positives(iRegPsrc ary1, iRegIsrc len, iRegIdst result, iRegLdst tmp1, iRegLdst tmp2,
|
||||
regCTR ctr, flagsRegCR0 cr0)
|
||||
%{
|
||||
match(Set result (HasNegatives ary1 len));
|
||||
effect(TEMP_DEF result, USE_KILL ary1, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0);
|
||||
match(Set result (CountPositives ary1 len));
|
||||
effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0);
|
||||
ins_cost(300);
|
||||
format %{ "has negatives byte[] $ary1,$len -> $result \t// KILL $tmp1, $tmp2" %}
|
||||
format %{ "count positives byte[] $ary1,$len -> $result \t// KILL $tmp1, $tmp2" %}
|
||||
ins_encode %{
|
||||
__ has_negatives($ary1$$Register, $len$$Register, $result$$Register,
|
||||
$tmp1$$Register, $tmp2$$Register);
|
||||
__ count_positives($ary1$$Register, $len$$Register, $result$$Register,
|
||||
$tmp1$$Register, $tmp2$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_class_default);
|
||||
%}
|
||||
|
@ -823,52 +823,64 @@ unsigned int C2_MacroAssembler::string_inflate_const(Register src, Register dst,
|
||||
return offset() - block_start;
|
||||
}
|
||||
|
||||
// Kills src.
|
||||
unsigned int C2_MacroAssembler::has_negatives(Register result, Register src, Register cnt,
|
||||
Register odd_reg, Register even_reg, Register tmp) {
|
||||
int block_start = offset();
|
||||
Label Lloop1, Lloop2, Lslow, Lnotfound, Ldone;
|
||||
const Register addr = src, mask = tmp;
|
||||
// Returns the number of non-negative bytes (aka US-ASCII characters) found
|
||||
// before the first negative byte is encountered.
|
||||
unsigned int C2_MacroAssembler::count_positives(Register result, Register src, Register cnt, Register tmp) {
|
||||
const unsigned int block_start = offset();
|
||||
const unsigned int byte_mask = 0x80;
|
||||
const unsigned int twobyte_mask = byte_mask<<8 | byte_mask;
|
||||
const unsigned int unroll_factor = 16;
|
||||
const unsigned int log_unroll_factor = exact_log2(unroll_factor);
|
||||
Register pos = src; // current position in src array, restored at end
|
||||
Register ctr = result; // loop counter, result value
|
||||
Register mask = tmp; // holds the sign detection mask
|
||||
Label unrolledLoop, unrolledDone, byteLoop, allDone;
|
||||
|
||||
BLOCK_COMMENT("has_negatives {");
|
||||
assert_different_registers(result, src, cnt, tmp);
|
||||
|
||||
z_llgfr(Z_R1, cnt); // Number of bytes to read. (Must be a positive simm32.)
|
||||
z_llilf(mask, 0x80808080);
|
||||
z_lhi(result, 1); // Assume true.
|
||||
// Last possible addr for fast loop.
|
||||
z_lay(odd_reg, -16, Z_R1, src);
|
||||
z_chi(cnt, 16);
|
||||
z_brl(Lslow);
|
||||
BLOCK_COMMENT("count_positives {");
|
||||
|
||||
// ind1: index, even_reg: index increment, odd_reg: index limit
|
||||
z_iihf(mask, 0x80808080);
|
||||
z_lghi(even_reg, 16);
|
||||
lgr_if_needed(pos, src); // current position in src array
|
||||
z_srak(ctr, cnt, log_unroll_factor); // # iterations of unrolled loop
|
||||
z_brnh(unrolledDone); // array too short for unrolled loop
|
||||
|
||||
bind(Lloop1); // 16 bytes per iteration.
|
||||
z_lg(Z_R0, Address(addr));
|
||||
z_lg(Z_R1, Address(addr, 8));
|
||||
z_ogr(Z_R0, Z_R1);
|
||||
z_ngr(Z_R0, mask);
|
||||
z_brne(Ldone); // If found return 1.
|
||||
z_brxlg(addr, even_reg, Lloop1);
|
||||
z_iilf(mask, twobyte_mask<<16 | twobyte_mask);
|
||||
z_iihf(mask, twobyte_mask<<16 | twobyte_mask);
|
||||
|
||||
bind(Lslow);
|
||||
z_aghi(odd_reg, 16-1); // Last possible addr for slow loop.
|
||||
z_lghi(even_reg, 1);
|
||||
z_cgr(addr, odd_reg);
|
||||
z_brh(Lnotfound);
|
||||
bind(unrolledLoop);
|
||||
z_lmg(Z_R0, Z_R1, 0, pos);
|
||||
z_ogr(Z_R0, Z_R1);
|
||||
z_ngr(Z_R0, mask);
|
||||
z_brne(unrolledDone); // There is a negative byte somewhere.
|
||||
// ctr and pos are not updated yet ->
|
||||
// delegate finding correct pos to byteLoop.
|
||||
add2reg(pos, unroll_factor);
|
||||
z_brct(ctr, unrolledLoop);
|
||||
|
||||
bind(Lloop2); // 1 byte per iteration.
|
||||
z_cli(Address(addr), 0x80);
|
||||
z_brnl(Ldone); // If found return 1.
|
||||
z_brxlg(addr, even_reg, Lloop2);
|
||||
// Once we arrive here, we have to examine at most (unroll_factor - 1) bytes more.
|
||||
// We then either have reached the end of the array or we hit a negative byte.
|
||||
bind(unrolledDone);
|
||||
z_sll(ctr, log_unroll_factor); // calculate # bytes not processed by unrolled loop
|
||||
// > 0 only if a negative byte was found
|
||||
z_lr(Z_R0, cnt); // calculate remainder bytes
|
||||
z_nilf(Z_R0, unroll_factor - 1);
|
||||
z_ar(ctr, Z_R0); // remaining bytes
|
||||
z_brnh(allDone); // shortcut if nothing left to do
|
||||
|
||||
bind(Lnotfound);
|
||||
z_lhi(result, 0);
|
||||
bind(byteLoop);
|
||||
z_cli(0, pos, byte_mask); // unsigned comparison! byte@pos must be smaller that byte_mask
|
||||
z_brnl(allDone); // negative byte found.
|
||||
|
||||
bind(Ldone);
|
||||
add2reg(pos, 1);
|
||||
z_brct(ctr, byteLoop);
|
||||
|
||||
BLOCK_COMMENT("} has_negatives");
|
||||
bind(allDone);
|
||||
|
||||
z_srk(ctr, cnt, ctr); // # bytes actually processed (= cnt or index of first negative byte)
|
||||
z_sgfr(pos, ctr); // restore src
|
||||
z_lgfr(result, ctr); // unnecessary. Only there to be sure the high word has a defined state.
|
||||
|
||||
BLOCK_COMMENT("} count_positives");
|
||||
|
||||
return offset() - block_start;
|
||||
}
|
||||
|
@ -57,9 +57,7 @@
|
||||
// len is signed int. Counts # characters, not bytes.
|
||||
unsigned int string_inflate_const(Register src, Register dst, Register tmp, int len);
|
||||
|
||||
// Kills src.
|
||||
unsigned int has_negatives(Register result, Register src, Register cnt,
|
||||
Register odd_reg, Register even_reg, Register tmp);
|
||||
unsigned int count_positives(Register result, Register src, Register cnt, Register tmp);
|
||||
|
||||
unsigned int string_compare(Register str1, Register str2, Register cnt1, Register cnt2,
|
||||
Register odd_reg, Register even_reg, Register result, int ae);
|
||||
|
@ -10273,14 +10273,13 @@ instruct string_inflate_const(Universe dummy, iRegP src, iRegP dst, iRegI tmp, i
|
||||
%}
|
||||
|
||||
// StringCoding.java intrinsics
|
||||
instruct has_negatives(rarg5RegP ary1, iRegI len, iRegI result, roddRegI oddReg, revenRegI evenReg, iRegI tmp, flagsReg cr) %{
|
||||
match(Set result (HasNegatives ary1 len));
|
||||
effect(TEMP_DEF result, USE_KILL ary1, TEMP oddReg, TEMP evenReg, TEMP tmp, KILL cr); // R0, R1 are killed, too.
|
||||
instruct count_positives(iRegP ary1, iRegI len, iRegI result, iRegI tmp, flagsReg cr) %{
|
||||
match(Set result (CountPositives ary1 len));
|
||||
effect(TEMP_DEF result, TEMP tmp, KILL cr); // R0, R1 are killed, too.
|
||||
ins_cost(300);
|
||||
format %{ "has negatives byte[] $ary1($len) -> $result" %}
|
||||
format %{ "count positives byte[] $ary1($len) -> $result" %}
|
||||
ins_encode %{
|
||||
__ has_negatives($result$$Register, $ary1$$Register, $len$$Register,
|
||||
$oddReg$$Register, $evenReg$$Register, $tmp$$Register);
|
||||
__ count_positives($result$$Register, $ary1$$Register, $len$$Register, $tmp$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_class_dummy);
|
||||
%}
|
||||
|
@ -3374,18 +3374,19 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2,
|
||||
}
|
||||
|
||||
// Search for Non-ASCII character (Negative byte value) in a byte array,
|
||||
// return true if it has any and false otherwise.
|
||||
// return the index of the first such character, otherwise the length
|
||||
// of the array segment searched.
|
||||
// ..\jdk\src\java.base\share\classes\java\lang\StringCoding.java
|
||||
// @IntrinsicCandidate
|
||||
// private static boolean hasNegatives(byte[] ba, int off, int len) {
|
||||
// public static int countPositives(byte[] ba, int off, int len) {
|
||||
// for (int i = off; i < off + len; i++) {
|
||||
// if (ba[i] < 0) {
|
||||
// return true;
|
||||
// return i - off;
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// return len;
|
||||
// }
|
||||
void C2_MacroAssembler::has_negatives(Register ary1, Register len,
|
||||
void C2_MacroAssembler::count_positives(Register ary1, Register len,
|
||||
Register result, Register tmp1,
|
||||
XMMRegister vec1, XMMRegister vec2, KRegister mask1, KRegister mask2) {
|
||||
// rsi: byte array
|
||||
@ -3394,17 +3395,18 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len,
|
||||
ShortBranchVerifier sbv(this);
|
||||
assert_different_registers(ary1, len, result, tmp1);
|
||||
assert_different_registers(vec1, vec2);
|
||||
Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_CHAR, COMPARE_VECTORS, COMPARE_BYTE;
|
||||
Label ADJUST, TAIL_ADJUST, DONE, TAIL_START, CHAR_ADJUST, COMPARE_CHAR, COMPARE_VECTORS, COMPARE_BYTE;
|
||||
|
||||
movl(result, len); // copy
|
||||
// len == 0
|
||||
testl(len, len);
|
||||
jcc(Assembler::zero, FALSE_LABEL);
|
||||
jcc(Assembler::zero, DONE);
|
||||
|
||||
if ((AVX3Threshold == 0) && (UseAVX > 2) && // AVX512
|
||||
VM_Version::supports_avx512vlbw() &&
|
||||
VM_Version::supports_bmi2()) {
|
||||
|
||||
Label test_64_loop, test_tail;
|
||||
Label test_64_loop, test_tail, BREAK_LOOP;
|
||||
Register tmp3_aliased = len;
|
||||
|
||||
movl(tmp1, len);
|
||||
@ -3421,16 +3423,15 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len,
|
||||
// Check whether our 64 elements of size byte contain negatives
|
||||
evpcmpgtb(mask1, vec2, Address(ary1, len, Address::times_1), Assembler::AVX_512bit);
|
||||
kortestql(mask1, mask1);
|
||||
jcc(Assembler::notZero, TRUE_LABEL);
|
||||
jcc(Assembler::notZero, BREAK_LOOP);
|
||||
|
||||
addptr(len, 64);
|
||||
jccb(Assembler::notZero, test_64_loop);
|
||||
|
||||
|
||||
bind(test_tail);
|
||||
// bail out when there is nothing to be done
|
||||
testl(tmp1, -1);
|
||||
jcc(Assembler::zero, FALSE_LABEL);
|
||||
jcc(Assembler::zero, DONE);
|
||||
|
||||
// ~(~0 << len) applied up to two times (for 32-bit scenario)
|
||||
#ifdef _LP64
|
||||
@ -3467,21 +3468,30 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len,
|
||||
#endif
|
||||
evpcmpgtb(mask1, mask2, vec2, Address(ary1, 0), Assembler::AVX_512bit);
|
||||
ktestq(mask1, mask2);
|
||||
jcc(Assembler::notZero, TRUE_LABEL);
|
||||
jcc(Assembler::zero, DONE);
|
||||
|
||||
jmp(FALSE_LABEL);
|
||||
bind(BREAK_LOOP);
|
||||
// At least one byte in the last 64 bytes is negative.
|
||||
// Set up to look at the last 64 bytes as if they were a tail
|
||||
lea(ary1, Address(ary1, len, Address::times_1));
|
||||
addptr(result, len);
|
||||
// Ignore the very last byte: if all others are positive,
|
||||
// it must be negative, so we can skip right to the 2+1 byte
|
||||
// end comparison at this point
|
||||
orl(result, 63);
|
||||
movl(len, 63);
|
||||
// Fallthru to tail compare
|
||||
} else {
|
||||
movl(result, len); // copy
|
||||
|
||||
if (UseAVX >= 2 && UseSSE >= 2) {
|
||||
// With AVX2, use 32-byte vector compare
|
||||
Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
|
||||
Label COMPARE_WIDE_VECTORS, BREAK_LOOP;
|
||||
|
||||
// Compare 32-byte vectors
|
||||
andl(result, 0x0000001f); // tail count (in bytes)
|
||||
andl(len, 0xffffffe0); // vector count (in bytes)
|
||||
jccb(Assembler::zero, COMPARE_TAIL);
|
||||
testl(len, 0xffffffe0); // vector count (in bytes)
|
||||
jccb(Assembler::zero, TAIL_START);
|
||||
|
||||
andl(len, 0xffffffe0);
|
||||
lea(ary1, Address(ary1, len, Address::times_1));
|
||||
negptr(len);
|
||||
|
||||
@ -3492,30 +3502,42 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len,
|
||||
bind(COMPARE_WIDE_VECTORS);
|
||||
vmovdqu(vec1, Address(ary1, len, Address::times_1));
|
||||
vptest(vec1, vec2);
|
||||
jccb(Assembler::notZero, TRUE_LABEL);
|
||||
jccb(Assembler::notZero, BREAK_LOOP);
|
||||
addptr(len, 32);
|
||||
jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
|
||||
jccb(Assembler::notZero, COMPARE_WIDE_VECTORS);
|
||||
|
||||
testl(result, result);
|
||||
jccb(Assembler::zero, FALSE_LABEL);
|
||||
testl(result, 0x0000001f); // any bytes remaining?
|
||||
jcc(Assembler::zero, DONE);
|
||||
|
||||
vmovdqu(vec1, Address(ary1, result, Address::times_1, -32));
|
||||
vptest(vec1, vec2);
|
||||
jccb(Assembler::notZero, TRUE_LABEL);
|
||||
jmpb(FALSE_LABEL);
|
||||
|
||||
bind(COMPARE_TAIL); // len is zero
|
||||
// Quick test using the already prepared vector mask
|
||||
movl(len, result);
|
||||
andl(len, 0x0000001f);
|
||||
vmovdqu(vec1, Address(ary1, len, Address::times_1, -32));
|
||||
vptest(vec1, vec2);
|
||||
jcc(Assembler::zero, DONE);
|
||||
// There are zeros, jump to the tail to determine exactly where
|
||||
jmpb(TAIL_START);
|
||||
|
||||
bind(BREAK_LOOP);
|
||||
// At least one byte in the last 32-byte vector is negative.
|
||||
// Set up to look at the last 32 bytes as if they were a tail
|
||||
lea(ary1, Address(ary1, len, Address::times_1));
|
||||
addptr(result, len);
|
||||
// Ignore the very last byte: if all others are positive,
|
||||
// it must be negative, so we can skip right to the 2+1 byte
|
||||
// end comparison at this point
|
||||
orl(result, 31);
|
||||
movl(len, 31);
|
||||
// Fallthru to tail compare
|
||||
} else if (UseSSE42Intrinsics) {
|
||||
// With SSE4.2, use double quad vector compare
|
||||
Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
|
||||
Label COMPARE_WIDE_VECTORS, BREAK_LOOP;
|
||||
|
||||
// Compare 16-byte vectors
|
||||
andl(result, 0x0000000f); // tail count (in bytes)
|
||||
andl(len, 0xfffffff0); // vector count (in bytes)
|
||||
jcc(Assembler::zero, COMPARE_TAIL);
|
||||
testl(len, 0xfffffff0); // vector count (in bytes)
|
||||
jcc(Assembler::zero, TAIL_START);
|
||||
|
||||
andl(len, 0xfffffff0);
|
||||
lea(ary1, Address(ary1, len, Address::times_1));
|
||||
negptr(len);
|
||||
|
||||
@ -3526,23 +3548,36 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len,
|
||||
bind(COMPARE_WIDE_VECTORS);
|
||||
movdqu(vec1, Address(ary1, len, Address::times_1));
|
||||
ptest(vec1, vec2);
|
||||
jcc(Assembler::notZero, TRUE_LABEL);
|
||||
jccb(Assembler::notZero, BREAK_LOOP);
|
||||
addptr(len, 16);
|
||||
jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
|
||||
jccb(Assembler::notZero, COMPARE_WIDE_VECTORS);
|
||||
|
||||
testl(result, result);
|
||||
jcc(Assembler::zero, FALSE_LABEL);
|
||||
testl(result, 0x0000000f); // len is zero, any bytes remaining?
|
||||
jcc(Assembler::zero, DONE);
|
||||
|
||||
movdqu(vec1, Address(ary1, result, Address::times_1, -16));
|
||||
ptest(vec1, vec2);
|
||||
jccb(Assembler::notZero, TRUE_LABEL);
|
||||
jmpb(FALSE_LABEL);
|
||||
|
||||
bind(COMPARE_TAIL); // len is zero
|
||||
// Quick test using the already prepared vector mask
|
||||
movl(len, result);
|
||||
andl(len, 0x0000000f); // tail count (in bytes)
|
||||
movdqu(vec1, Address(ary1, len, Address::times_1, -16));
|
||||
ptest(vec1, vec2);
|
||||
jcc(Assembler::zero, DONE);
|
||||
jmpb(TAIL_START);
|
||||
|
||||
bind(BREAK_LOOP);
|
||||
// At least one byte in the last 16-byte vector is negative.
|
||||
// Set up and look at the last 16 bytes as if they were a tail
|
||||
lea(ary1, Address(ary1, len, Address::times_1));
|
||||
addptr(result, len);
|
||||
// Ignore the very last byte: if all others are positive,
|
||||
// it must be negative, so we can skip right to the 2+1 byte
|
||||
// end comparison at this point
|
||||
orl(result, 15);
|
||||
movl(len, 15);
|
||||
// Fallthru to tail compare
|
||||
}
|
||||
}
|
||||
|
||||
bind(TAIL_START);
|
||||
// Compare 4-byte vectors
|
||||
andl(len, 0xfffffffc); // vector count (in bytes)
|
||||
jccb(Assembler::zero, COMPARE_CHAR);
|
||||
@ -3553,34 +3588,45 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len,
|
||||
bind(COMPARE_VECTORS);
|
||||
movl(tmp1, Address(ary1, len, Address::times_1));
|
||||
andl(tmp1, 0x80808080);
|
||||
jccb(Assembler::notZero, TRUE_LABEL);
|
||||
jccb(Assembler::notZero, TAIL_ADJUST);
|
||||
addptr(len, 4);
|
||||
jcc(Assembler::notZero, COMPARE_VECTORS);
|
||||
jccb(Assembler::notZero, COMPARE_VECTORS);
|
||||
|
||||
// Compare trailing char (final 2 bytes), if any
|
||||
// Compare trailing char (final 2-3 bytes), if any
|
||||
bind(COMPARE_CHAR);
|
||||
|
||||
testl(result, 0x2); // tail char
|
||||
jccb(Assembler::zero, COMPARE_BYTE);
|
||||
load_unsigned_short(tmp1, Address(ary1, 0));
|
||||
andl(tmp1, 0x00008080);
|
||||
jccb(Assembler::notZero, TRUE_LABEL);
|
||||
subptr(result, 2);
|
||||
jccb(Assembler::notZero, CHAR_ADJUST);
|
||||
lea(ary1, Address(ary1, 2));
|
||||
|
||||
bind(COMPARE_BYTE);
|
||||
testl(result, 0x1); // tail byte
|
||||
jccb(Assembler::zero, FALSE_LABEL);
|
||||
jccb(Assembler::zero, DONE);
|
||||
load_unsigned_byte(tmp1, Address(ary1, 0));
|
||||
andl(tmp1, 0x00000080);
|
||||
jccb(Assembler::notEqual, TRUE_LABEL);
|
||||
jmpb(FALSE_LABEL);
|
||||
|
||||
bind(TRUE_LABEL);
|
||||
movl(result, 1); // return true
|
||||
testl(tmp1, 0x00000080);
|
||||
jccb(Assembler::zero, DONE);
|
||||
subptr(result, 1);
|
||||
jmpb(DONE);
|
||||
|
||||
bind(FALSE_LABEL);
|
||||
xorl(result, result); // return false
|
||||
bind(TAIL_ADJUST);
|
||||
// there are negative bits in the last 4 byte block.
|
||||
// Adjust result and check the next three bytes
|
||||
addptr(result, len);
|
||||
orl(result, 3);
|
||||
lea(ary1, Address(ary1, len, Address::times_1));
|
||||
jmpb(COMPARE_CHAR);
|
||||
|
||||
bind(CHAR_ADJUST);
|
||||
// We are looking at a char + optional byte tail, and found that one
|
||||
// of the bytes in the char is negative. Adjust the result, check the
|
||||
// first byte and readjust if needed.
|
||||
andl(result, 0xfffffffc);
|
||||
testl(tmp1, 0x00000080); // little-endian, so lowest byte comes first
|
||||
jccb(Assembler::notZero, DONE);
|
||||
addptr(result, 1);
|
||||
|
||||
// That's it
|
||||
bind(DONE);
|
||||
@ -3590,6 +3636,7 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len,
|
||||
vpxor(vec2, vec2);
|
||||
}
|
||||
}
|
||||
|
||||
// Compare char[] or byte[] arrays aligned to 4 bytes or substrings.
|
||||
void C2_MacroAssembler::arrays_equals(bool is_array_equ, Register ary1, Register ary2,
|
||||
Register limit, Register result, Register chr,
|
||||
|
@ -271,11 +271,10 @@ public:
|
||||
XMMRegister vec1, int ae, KRegister mask = knoreg);
|
||||
|
||||
// Search for Non-ASCII character (Negative byte value) in a byte array,
|
||||
// return true if it has any and false otherwise.
|
||||
void has_negatives(Register ary1, Register len,
|
||||
Register result, Register tmp1,
|
||||
XMMRegister vec1, XMMRegister vec2, KRegister mask1 = knoreg, KRegister mask2 = knoreg);
|
||||
|
||||
// return index of the first such character, otherwise len.
|
||||
void count_positives(Register ary1, Register len,
|
||||
Register result, Register tmp1,
|
||||
XMMRegister vec1, XMMRegister vec2, KRegister mask1 = knoreg, KRegister mask2 = knoreg);
|
||||
// Compare char[] or byte[] arrays.
|
||||
void arrays_equals(bool is_array_equ, Register ary1, Register ary2,
|
||||
Register limit, Register result, Register chr,
|
||||
|
@ -12122,34 +12122,34 @@ instruct array_equalsC_evex(eDIRegP ary1, eSIRegP ary2, eAXRegI result,
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct has_negatives(eSIRegP ary1, eCXRegI len, eAXRegI result,
|
||||
regD tmp1, regD tmp2, eBXRegI tmp3, eFlagsReg cr)
|
||||
instruct count_positives(eSIRegP ary1, eCXRegI len, eAXRegI result,
|
||||
regD tmp1, regD tmp2, eBXRegI tmp3, eFlagsReg cr)
|
||||
%{
|
||||
predicate(!VM_Version::supports_avx512vlbw() || !VM_Version::supports_bmi2());
|
||||
match(Set result (HasNegatives ary1 len));
|
||||
match(Set result (CountPositives ary1 len));
|
||||
effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr);
|
||||
|
||||
format %{ "has negatives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %}
|
||||
format %{ "countPositives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %}
|
||||
ins_encode %{
|
||||
__ has_negatives($ary1$$Register, $len$$Register,
|
||||
$result$$Register, $tmp3$$Register,
|
||||
$tmp1$$XMMRegister, $tmp2$$XMMRegister, knoreg, knoreg);
|
||||
__ count_positives($ary1$$Register, $len$$Register,
|
||||
$result$$Register, $tmp3$$Register,
|
||||
$tmp1$$XMMRegister, $tmp2$$XMMRegister, knoreg, knoreg);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct has_negatives_evex(eSIRegP ary1, eCXRegI len, eAXRegI result,
|
||||
regD tmp1, regD tmp2, kReg ktmp1, kReg ktmp2, eBXRegI tmp3, eFlagsReg cr)
|
||||
instruct count_positives_evex(eSIRegP ary1, eCXRegI len, eAXRegI result,
|
||||
regD tmp1, regD tmp2, kReg ktmp1, kReg ktmp2, eBXRegI tmp3, eFlagsReg cr)
|
||||
%{
|
||||
predicate(VM_Version::supports_avx512vlbw() && VM_Version::supports_bmi2());
|
||||
match(Set result (HasNegatives ary1 len));
|
||||
match(Set result (CountPositives ary1 len));
|
||||
effect(TEMP tmp1, TEMP tmp2, TEMP ktmp1, TEMP ktmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr);
|
||||
|
||||
format %{ "has negatives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %}
|
||||
format %{ "countPositives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %}
|
||||
ins_encode %{
|
||||
__ has_negatives($ary1$$Register, $len$$Register,
|
||||
$result$$Register, $tmp3$$Register,
|
||||
$tmp1$$XMMRegister, $tmp2$$XMMRegister, $ktmp1$$KRegister, $ktmp2$$KRegister);
|
||||
__ count_positives($ary1$$Register, $len$$Register,
|
||||
$result$$Register, $tmp3$$Register,
|
||||
$tmp1$$XMMRegister, $tmp2$$XMMRegister, $ktmp1$$KRegister, $ktmp2$$KRegister);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
@ -11685,34 +11685,34 @@ instruct array_equalsC_evex(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result,
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct has_negatives(rsi_RegP ary1, rcx_RegI len, rax_RegI result,
|
||||
legRegD tmp1, legRegD tmp2, rbx_RegI tmp3, rFlagsReg cr,)
|
||||
instruct count_positives(rsi_RegP ary1, rcx_RegI len, rax_RegI result,
|
||||
legRegD tmp1, legRegD tmp2, rbx_RegI tmp3, rFlagsReg cr,)
|
||||
%{
|
||||
predicate(!VM_Version::supports_avx512vlbw() || !VM_Version::supports_bmi2());
|
||||
match(Set result (HasNegatives ary1 len));
|
||||
match(Set result (CountPositives ary1 len));
|
||||
effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr);
|
||||
|
||||
format %{ "has negatives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %}
|
||||
format %{ "countPositives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %}
|
||||
ins_encode %{
|
||||
__ has_negatives($ary1$$Register, $len$$Register,
|
||||
$result$$Register, $tmp3$$Register,
|
||||
$tmp1$$XMMRegister, $tmp2$$XMMRegister, knoreg, knoreg);
|
||||
__ count_positives($ary1$$Register, $len$$Register,
|
||||
$result$$Register, $tmp3$$Register,
|
||||
$tmp1$$XMMRegister, $tmp2$$XMMRegister, knoreg, knoreg);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
||||
instruct has_negatives_evex(rsi_RegP ary1, rcx_RegI len, rax_RegI result,
|
||||
legRegD tmp1, legRegD tmp2, kReg ktmp1, kReg ktmp2, rbx_RegI tmp3, rFlagsReg cr,)
|
||||
instruct count_positives_evex(rsi_RegP ary1, rcx_RegI len, rax_RegI result,
|
||||
legRegD tmp1, legRegD tmp2, kReg ktmp1, kReg ktmp2, rbx_RegI tmp3, rFlagsReg cr,)
|
||||
%{
|
||||
predicate(VM_Version::supports_avx512vlbw() && VM_Version::supports_bmi2());
|
||||
match(Set result (HasNegatives ary1 len));
|
||||
match(Set result (CountPositives ary1 len));
|
||||
effect(TEMP tmp1, TEMP tmp2, TEMP ktmp1, TEMP ktmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr);
|
||||
|
||||
format %{ "has negatives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %}
|
||||
format %{ "countPositives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %}
|
||||
ins_encode %{
|
||||
__ has_negatives($ary1$$Register, $len$$Register,
|
||||
$result$$Register, $tmp3$$Register,
|
||||
$tmp1$$XMMRegister, $tmp2$$XMMRegister, $ktmp1$$KRegister, $ktmp2$$KRegister);
|
||||
__ count_positives($ary1$$Register, $len$$Register,
|
||||
$result$$Register, $tmp3$$Register,
|
||||
$tmp1$$XMMRegister, $tmp2$$XMMRegister, $ktmp1$$KRegister, $ktmp2$$KRegister);
|
||||
%}
|
||||
ins_pipe( pipe_slow );
|
||||
%}
|
||||
|
@ -612,7 +612,7 @@ bool InstructForm::needs_anti_dependence_check(FormDict &globals) const {
|
||||
strcmp(_matrule->_rChild->_opType,"StrEquals" )==0 ||
|
||||
strcmp(_matrule->_rChild->_opType,"StrIndexOf" )==0 ||
|
||||
strcmp(_matrule->_rChild->_opType,"StrIndexOfChar" )==0 ||
|
||||
strcmp(_matrule->_rChild->_opType,"HasNegatives" )==0 ||
|
||||
strcmp(_matrule->_rChild->_opType,"CountPositives" )==0 ||
|
||||
strcmp(_matrule->_rChild->_opType,"AryEq" )==0 ))
|
||||
return true;
|
||||
|
||||
@ -902,7 +902,7 @@ uint InstructForm::oper_input_base(FormDict &globals) {
|
||||
strcmp(_matrule->_rChild->_opType,"StrCompressedCopy" )==0 ||
|
||||
strcmp(_matrule->_rChild->_opType,"StrIndexOf")==0 ||
|
||||
strcmp(_matrule->_rChild->_opType,"StrIndexOfChar")==0 ||
|
||||
strcmp(_matrule->_rChild->_opType,"HasNegatives")==0 ||
|
||||
strcmp(_matrule->_rChild->_opType,"CountPositives")==0 ||
|
||||
strcmp(_matrule->_rChild->_opType,"EncodeISOArray")==0)) {
|
||||
// String.(compareTo/equals/indexOf) and Arrays.equals
|
||||
// and sun.nio.cs.iso8859_1$Encoder.EncodeISOArray
|
||||
|
@ -229,7 +229,7 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) {
|
||||
case vmIntrinsics::_loadFence:
|
||||
case vmIntrinsics::_storeFence:
|
||||
case vmIntrinsics::_fullFence:
|
||||
case vmIntrinsics::_hasNegatives:
|
||||
case vmIntrinsics::_countPositives:
|
||||
case vmIntrinsics::_Reference_get:
|
||||
break;
|
||||
default:
|
||||
|
@ -354,9 +354,9 @@ class methodHandle;
|
||||
do_signature(Preconditions_checkLongIndex_signature, "(JJLjava/util/function/BiFunction;)J") \
|
||||
\
|
||||
do_class(java_lang_StringCoding, "java/lang/StringCoding") \
|
||||
do_intrinsic(_hasNegatives, java_lang_StringCoding, hasNegatives_name, hasNegatives_signature, F_S) \
|
||||
do_name( hasNegatives_name, "hasNegatives") \
|
||||
do_signature(hasNegatives_signature, "([BII)Z") \
|
||||
do_intrinsic(_countPositives, java_lang_StringCoding, countPositives_name, countPositives_signature, F_S) \
|
||||
do_name( countPositives_name, "countPositives") \
|
||||
do_signature(countPositives_signature, "([BII)I") \
|
||||
\
|
||||
do_class(sun_nio_cs_iso8859_1_Encoder, "sun/nio/cs/ISO_8859_1$Encoder") \
|
||||
do_intrinsic(_encodeISOArray, sun_nio_cs_iso8859_1_Encoder, encodeISOArray_name, encodeISOArray_signature, F_S) \
|
||||
@ -459,9 +459,8 @@ class methodHandle;
|
||||
\
|
||||
/* support for sun.security.provider.DigestBase */ \
|
||||
do_class(sun_security_provider_digestbase, "sun/security/provider/DigestBase") \
|
||||
do_intrinsic(_digestBase_implCompressMB, sun_security_provider_digestbase, implCompressMB_name, implCompressMB_signature, F_R) \
|
||||
do_intrinsic(_digestBase_implCompressMB, sun_security_provider_digestbase, implCompressMB_name, countPositives_signature, F_R) \
|
||||
do_name( implCompressMB_name, "implCompressMultiBlock0") \
|
||||
do_signature(implCompressMB_signature, "([BII)I") \
|
||||
\
|
||||
/* support for java.util.Base64.Encoder*/ \
|
||||
do_class(java_util_Base64_Encoder, "java/util/Base64$Encoder") \
|
||||
|
@ -567,7 +567,7 @@ void ShenandoahBarrierC2Support::verify(RootNode* root) {
|
||||
{ { 2, ShenandoahLoad }, { 3, ShenandoahLoad } },
|
||||
Op_EncodeISOArray,
|
||||
{ { 2, ShenandoahLoad }, { 3, ShenandoahStore } },
|
||||
Op_HasNegatives,
|
||||
Op_CountPositives,
|
||||
{ { 2, ShenandoahLoad }, { -1, ShenandoahNone} },
|
||||
Op_CastP2X,
|
||||
{ { 1, ShenandoahLoad }, { -1, ShenandoahNone} },
|
||||
|
@ -742,8 +742,8 @@
|
||||
|
||||
#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
|
||||
static_field(VM_Version, _zva_length, int) \
|
||||
static_field(StubRoutines::aarch64, _has_negatives, address) \
|
||||
static_field(StubRoutines::aarch64, _has_negatives_long, address) \
|
||||
static_field(StubRoutines::aarch64, _count_positives, address) \
|
||||
static_field(StubRoutines::aarch64, _count_positives_long, address) \
|
||||
static_field(VM_Version, _rop_protection, bool) \
|
||||
volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*)
|
||||
|
||||
|
@ -234,8 +234,8 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt
|
||||
case vmIntrinsics::_encodeByteISOArray:
|
||||
if (!Matcher::match_rule_supported(Op_EncodeISOArray)) return false;
|
||||
break;
|
||||
case vmIntrinsics::_hasNegatives:
|
||||
if (!Matcher::match_rule_supported(Op_HasNegatives)) return false;
|
||||
case vmIntrinsics::_countPositives:
|
||||
if (!Matcher::match_rule_supported(Op_CountPositives)) return false;
|
||||
break;
|
||||
case vmIntrinsics::_bitCount_i:
|
||||
if (!Matcher::match_rule_supported(Op_PopCountI)) return false;
|
||||
|
@ -174,7 +174,7 @@ macro(FmaD)
|
||||
macro(FmaF)
|
||||
macro(Goto)
|
||||
macro(Halt)
|
||||
macro(HasNegatives)
|
||||
macro(CountPositives)
|
||||
macro(If)
|
||||
macro(RangeCheck)
|
||||
macro(IfFalse)
|
||||
|
@ -635,7 +635,7 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de
|
||||
break;
|
||||
}
|
||||
case Op_AryEq:
|
||||
case Op_HasNegatives:
|
||||
case Op_CountPositives:
|
||||
case Op_StrComp:
|
||||
case Op_StrEquals:
|
||||
case Op_StrIndexOf:
|
||||
@ -773,7 +773,7 @@ void ConnectionGraph::add_final_edges(Node *n) {
|
||||
break;
|
||||
}
|
||||
case Op_AryEq:
|
||||
case Op_HasNegatives:
|
||||
case Op_CountPositives:
|
||||
case Op_StrComp:
|
||||
case Op_StrEquals:
|
||||
case Op_StrIndexOf:
|
||||
@ -3344,7 +3344,8 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
|
||||
memnode_worklist.append_if_missing(use);
|
||||
} else if (!(op == Op_CmpP || op == Op_Conv2B ||
|
||||
op == Op_CastP2X || op == Op_StoreCM ||
|
||||
op == Op_FastLock || op == Op_AryEq || op == Op_StrComp || op == Op_HasNegatives ||
|
||||
op == Op_FastLock || op == Op_AryEq || op == Op_StrComp ||
|
||||
op == Op_CountPositives ||
|
||||
op == Op_StrCompressedCopy || op == Op_StrInflatedCopy ||
|
||||
op == Op_StrEquals || op == Op_StrIndexOf || op == Op_StrIndexOfChar ||
|
||||
op == Op_SubTypeCheck ||
|
||||
@ -3475,7 +3476,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
|
||||
// They overwrite memory edge corresponding to destination array,
|
||||
memnode_worklist.append_if_missing(use);
|
||||
} else if (!(BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(use) ||
|
||||
op == Op_AryEq || op == Op_StrComp || op == Op_HasNegatives ||
|
||||
op == Op_AryEq || op == Op_StrComp || op == Op_CountPositives ||
|
||||
op == Op_StrCompressedCopy || op == Op_StrInflatedCopy ||
|
||||
op == Op_StrEquals || op == Op_StrIndexOf || op == Op_StrIndexOfChar)) {
|
||||
n->dump();
|
||||
|
@ -157,13 +157,13 @@ class AryEqNode: public StrIntrinsicNode {
|
||||
virtual const Type* bottom_type() const { return TypeInt::BOOL; }
|
||||
};
|
||||
|
||||
//------------------------------HasNegatives---------------------------------
|
||||
class HasNegativesNode: public StrIntrinsicNode {
|
||||
//------------------------------CountPositives------------------------------
|
||||
class CountPositivesNode: public StrIntrinsicNode {
|
||||
public:
|
||||
HasNegativesNode(Node* control, Node* char_array_mem, Node* s1, Node* c1):
|
||||
CountPositivesNode(Node* control, Node* char_array_mem, Node* s1, Node* c1):
|
||||
StrIntrinsicNode(control, char_array_mem, s1, c1, none) {};
|
||||
virtual int Opcode() const;
|
||||
virtual const Type* bottom_type() const { return TypeInt::BOOL; }
|
||||
virtual const Type* bottom_type() const { return TypeInt::POS; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -203,7 +203,7 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo
|
||||
case Op_StrInflatedCopy:
|
||||
case Op_StrCompressedCopy:
|
||||
case Op_EncodeISOArray:
|
||||
case Op_HasNegatives:
|
||||
case Op_CountPositives:
|
||||
// Not a legit memory op for implicit null check regardless of
|
||||
// embedded loads
|
||||
continue;
|
||||
|
@ -617,8 +617,8 @@ bool LibraryCallKit::try_to_inline(int predicate) {
|
||||
case vmIntrinsics::_isCompileConstant:
|
||||
return inline_isCompileConstant();
|
||||
|
||||
case vmIntrinsics::_hasNegatives:
|
||||
return inline_hasNegatives();
|
||||
case vmIntrinsics::_countPositives:
|
||||
return inline_countPositives();
|
||||
|
||||
case vmIntrinsics::_fmaD:
|
||||
case vmIntrinsics::_fmaF:
|
||||
@ -1011,13 +1011,13 @@ bool LibraryCallKit::inline_array_equals(StrIntrinsicNode::ArgEnc ae) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------inline_hasNegatives------------------------------
|
||||
bool LibraryCallKit::inline_hasNegatives() {
|
||||
//------------------------------inline_countPositives------------------------------
|
||||
bool LibraryCallKit::inline_countPositives() {
|
||||
if (too_many_traps(Deoptimization::Reason_intrinsic)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(callee()->signature()->size() == 3, "hasNegatives has 3 parameters");
|
||||
assert(callee()->signature()->size() == 3, "countPositives has 3 parameters");
|
||||
// no receiver since it is static method
|
||||
Node* ba = argument(0);
|
||||
Node* offset = argument(1);
|
||||
@ -1031,7 +1031,7 @@ bool LibraryCallKit::inline_hasNegatives() {
|
||||
return true;
|
||||
}
|
||||
Node* ba_start = array_element_address(ba, offset, T_BYTE);
|
||||
Node* result = new HasNegativesNode(control(), memory(TypeAryPtr::BYTES), ba_start, len);
|
||||
Node* result = new CountPositivesNode(control(), memory(TypeAryPtr::BYTES), ba_start, len);
|
||||
set_result(_gvn.transform(result));
|
||||
return true;
|
||||
}
|
||||
|
@ -296,7 +296,7 @@ class LibraryCallKit : public GraphKit {
|
||||
bool inline_updateBytesAdler32();
|
||||
bool inline_updateByteBufferAdler32();
|
||||
bool inline_multiplyToLen();
|
||||
bool inline_hasNegatives();
|
||||
bool inline_countPositives();
|
||||
bool inline_squareToLen();
|
||||
bool inline_mulAdd();
|
||||
bool inline_montgomeryMultiply();
|
||||
|
@ -828,7 +828,7 @@ bool IdealLoopTree::policy_maximally_unroll(PhaseIdealLoop* phase) const {
|
||||
case Op_StrIndexOfChar:
|
||||
case Op_EncodeISOArray:
|
||||
case Op_AryEq:
|
||||
case Op_HasNegatives: {
|
||||
case Op_CountPositives: {
|
||||
return false;
|
||||
}
|
||||
#if INCLUDE_RTM_OPT
|
||||
@ -981,7 +981,7 @@ bool IdealLoopTree::policy_unroll(PhaseIdealLoop *phase) {
|
||||
case Op_StrIndexOfChar:
|
||||
case Op_EncodeISOArray:
|
||||
case Op_AryEq:
|
||||
case Op_HasNegatives: {
|
||||
case Op_CountPositives: {
|
||||
// Do not unroll a loop with String intrinsics code.
|
||||
// String intrinsics are large and have loops.
|
||||
return false;
|
||||
|
@ -5775,7 +5775,7 @@ void PhaseIdealLoop::build_loop_late_post_work(Node *n, bool pinned) {
|
||||
case Op_StrIndexOf:
|
||||
case Op_StrIndexOfChar:
|
||||
case Op_AryEq:
|
||||
case Op_HasNegatives:
|
||||
case Op_CountPositives:
|
||||
pinned = false;
|
||||
}
|
||||
if (n->is_CMove() || n->is_ConstraintCast()) {
|
||||
|
@ -1066,7 +1066,7 @@ static void match_alias_type(Compile* C, Node* n, Node* m) {
|
||||
case Op_StrIndexOf:
|
||||
case Op_StrIndexOfChar:
|
||||
case Op_AryEq:
|
||||
case Op_HasNegatives:
|
||||
case Op_CountPositives:
|
||||
case Op_MemBarVolatile:
|
||||
case Op_MemBarCPUOrder: // %%% these ideals should have narrower adr_type?
|
||||
case Op_StrInflatedCopy:
|
||||
@ -2252,7 +2252,7 @@ bool Matcher::find_shared_visit(MStack& mstack, Node* n, uint opcode, bool& mem_
|
||||
case Op_StrIndexOf:
|
||||
case Op_StrIndexOfChar:
|
||||
case Op_AryEq:
|
||||
case Op_HasNegatives:
|
||||
case Op_CountPositives:
|
||||
case Op_StrInflatedCopy:
|
||||
case Op_StrCompressedCopy:
|
||||
case Op_EncodeISOArray:
|
||||
|
@ -525,56 +525,63 @@ public final class String
|
||||
this.value = "".value;
|
||||
this.coder = "".coder;
|
||||
} else if (charset == UTF_8.INSTANCE) {
|
||||
if (COMPACT_STRINGS && !StringCoding.hasNegatives(bytes, offset, length)) {
|
||||
this.value = Arrays.copyOfRange(bytes, offset, offset + length);
|
||||
this.coder = LATIN1;
|
||||
} else {
|
||||
if (COMPACT_STRINGS) {
|
||||
int dp = StringCoding.countPositives(bytes, offset, length);
|
||||
if (dp == length) {
|
||||
this.value = Arrays.copyOfRange(bytes, offset, offset + length);
|
||||
this.coder = LATIN1;
|
||||
return;
|
||||
}
|
||||
int sl = offset + length;
|
||||
int dp = 0;
|
||||
byte[] dst = null;
|
||||
if (COMPACT_STRINGS) {
|
||||
dst = new byte[length];
|
||||
while (offset < sl) {
|
||||
int b1 = bytes[offset];
|
||||
if (b1 >= 0) {
|
||||
dst[dp++] = (byte)b1;
|
||||
byte[] dst = new byte[length];
|
||||
if (dp > 0) {
|
||||
System.arraycopy(bytes, offset, dst, 0, dp);
|
||||
offset += dp;
|
||||
}
|
||||
while (offset < sl) {
|
||||
int b1 = bytes[offset++];
|
||||
if (b1 >= 0) {
|
||||
dst[dp++] = (byte)b1;
|
||||
continue;
|
||||
}
|
||||
if ((b1 & 0xfe) == 0xc2 && offset < sl) { // b1 either 0xc2 or 0xc3
|
||||
int b2 = bytes[offset];
|
||||
if (b2 < -64) { // continuation bytes are always negative values in the range -128 to -65
|
||||
dst[dp++] = (byte)decode2(b1, b2);
|
||||
offset++;
|
||||
continue;
|
||||
}
|
||||
if ((b1 & 0xfe) == 0xc2 && offset + 1 < sl) { // b1 either 0xc2 or 0xc3
|
||||
int b2 = bytes[offset + 1];
|
||||
if (!isNotContinuation(b2)) {
|
||||
dst[dp++] = (byte)decode2(b1, b2);
|
||||
offset += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// anything not a latin1, including the repl
|
||||
// we have to go with the utf16
|
||||
break;
|
||||
}
|
||||
if (offset == sl) {
|
||||
if (dp != dst.length) {
|
||||
dst = Arrays.copyOf(dst, dp);
|
||||
}
|
||||
this.value = dst;
|
||||
this.coder = LATIN1;
|
||||
return;
|
||||
// anything not a latin1, including the REPL
|
||||
// we have to go with the utf16
|
||||
offset--;
|
||||
break;
|
||||
}
|
||||
if (offset == sl) {
|
||||
if (dp != dst.length) {
|
||||
dst = Arrays.copyOf(dst, dp);
|
||||
}
|
||||
this.value = dst;
|
||||
this.coder = LATIN1;
|
||||
return;
|
||||
}
|
||||
if (dp == 0 || dst == null) {
|
||||
dst = new byte[length << 1];
|
||||
} else {
|
||||
byte[] buf = new byte[length << 1];
|
||||
StringLatin1.inflate(dst, 0, buf, 0, dp);
|
||||
dst = buf;
|
||||
}
|
||||
byte[] buf = new byte[length << 1];
|
||||
StringLatin1.inflate(dst, 0, buf, 0, dp);
|
||||
dst = buf;
|
||||
dp = decodeUTF8_UTF16(bytes, offset, sl, dst, dp, true);
|
||||
if (dp != length) {
|
||||
dst = Arrays.copyOf(dst, dp << 1);
|
||||
}
|
||||
this.value = dst;
|
||||
this.coder = UTF16;
|
||||
} else { // !COMPACT_STRINGS
|
||||
byte[] dst = new byte[length << 1];
|
||||
int dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, true);
|
||||
if (dp != length) {
|
||||
dst = Arrays.copyOf(dst, dp << 1);
|
||||
}
|
||||
this.value = dst;
|
||||
this.coder = UTF16;
|
||||
}
|
||||
} else if (charset == ISO_8859_1.INSTANCE) {
|
||||
if (COMPACT_STRINGS) {
|
||||
@ -682,41 +689,43 @@ public final class String
|
||||
if (length == 0) {
|
||||
return "";
|
||||
}
|
||||
if (COMPACT_STRINGS && !StringCoding.hasNegatives(bytes, offset, length)) {
|
||||
return new String(Arrays.copyOfRange(bytes, offset, offset + length), LATIN1);
|
||||
} else {
|
||||
int dp;
|
||||
byte[] dst;
|
||||
if (COMPACT_STRINGS) {
|
||||
dp = StringCoding.countPositives(bytes, offset, length);
|
||||
int sl = offset + length;
|
||||
int dp = 0;
|
||||
byte[] dst = null;
|
||||
if (COMPACT_STRINGS) {
|
||||
dst = new byte[length];
|
||||
while (offset < sl) {
|
||||
int b1 = bytes[offset];
|
||||
if (b1 >= 0) {
|
||||
dst[dp++] = (byte) b1;
|
||||
if (dp == length) {
|
||||
return new String(Arrays.copyOfRange(bytes, offset, offset + length), LATIN1);
|
||||
}
|
||||
dst = new byte[length];
|
||||
System.arraycopy(bytes, offset, dst, 0, dp);
|
||||
offset += dp;
|
||||
while (offset < sl) {
|
||||
int b1 = bytes[offset++];
|
||||
if (b1 >= 0) {
|
||||
dst[dp++] = (byte)b1;
|
||||
continue;
|
||||
}
|
||||
if ((b1 & 0xfe) == 0xc2 && offset < sl) { // b1 either 0xc2 or 0xc3
|
||||
int b2 = bytes[offset];
|
||||
if (b2 < -64) { // continuation bytes are always negative values in the range -128 to -65
|
||||
dst[dp++] = (byte)decode2(b1, b2);
|
||||
offset++;
|
||||
continue;
|
||||
}
|
||||
if ((b1 & 0xfe) == 0xc2 && offset + 1 < sl) { // b1 either 0xc2 or 0xc3
|
||||
int b2 = bytes[offset + 1];
|
||||
if (!isNotContinuation(b2)) {
|
||||
dst[dp++] = (byte) decode2(b1, b2);
|
||||
offset += 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// anything not a latin1, including the REPL
|
||||
// we have to go with the utf16
|
||||
break;
|
||||
}
|
||||
if (offset == sl) {
|
||||
if (dp != dst.length) {
|
||||
dst = Arrays.copyOf(dst, dp);
|
||||
}
|
||||
return new String(dst, LATIN1);
|
||||
}
|
||||
// anything not a latin1, including the REPL
|
||||
// we have to go with the utf16
|
||||
offset--;
|
||||
break;
|
||||
}
|
||||
if (dp == 0 || dst == null) {
|
||||
if (offset == sl) {
|
||||
if (dp != dst.length) {
|
||||
dst = Arrays.copyOf(dst, dp);
|
||||
}
|
||||
return new String(dst, LATIN1);
|
||||
}
|
||||
if (dp == 0) {
|
||||
dst = new byte[length << 1];
|
||||
} else {
|
||||
byte[] buf = new byte[length << 1];
|
||||
@ -724,11 +733,14 @@ public final class String
|
||||
dst = buf;
|
||||
}
|
||||
dp = decodeUTF8_UTF16(bytes, offset, sl, dst, dp, false);
|
||||
if (dp != length) {
|
||||
dst = Arrays.copyOf(dst, dp << 1);
|
||||
}
|
||||
return new String(dst, UTF16);
|
||||
} else { // !COMPACT_STRINGS
|
||||
dst = new byte[length << 1];
|
||||
dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, false);
|
||||
}
|
||||
if (dp != length) {
|
||||
dst = Arrays.copyOf(dst, dp << 1);
|
||||
}
|
||||
return new String(dst, UTF16);
|
||||
}
|
||||
|
||||
static String newStringNoRepl(byte[] src, Charset cs) throws CharacterCodingException {
|
||||
@ -1019,17 +1031,9 @@ public final class String
|
||||
*/
|
||||
/* package-private */
|
||||
static int decodeASCII(byte[] sa, int sp, char[] da, int dp, int len) {
|
||||
if (!StringCoding.hasNegatives(sa, sp, len)) {
|
||||
StringLatin1.inflate(sa, sp, da, dp, len);
|
||||
return len;
|
||||
} else {
|
||||
int start = sp;
|
||||
int end = sp + len;
|
||||
while (sp < end && sa[sp] >= 0) {
|
||||
da[dp++] = (char) sa[sp++];
|
||||
}
|
||||
return sp - start;
|
||||
}
|
||||
int count = StringCoding.countPositives(sa, sp, len);
|
||||
StringLatin1.inflate(sa, sp, da, dp, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
private static boolean isNotContinuation(int b) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,14 +34,27 @@ class StringCoding {
|
||||
|
||||
private StringCoding() { }
|
||||
|
||||
@IntrinsicCandidate
|
||||
public static boolean hasNegatives(byte[] ba, int off, int len) {
|
||||
for (int i = off; i < off + len; i++) {
|
||||
return countPositives(ba, off, len) != len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of leading positive bytes in the range.
|
||||
*
|
||||
* @implSpec the implementation must return len if there are no negative
|
||||
* bytes in the range. If there are negative bytes, the implementation must return
|
||||
* a value that is less than or equal to the index of the first negative byte
|
||||
* in the range.
|
||||
*/
|
||||
@IntrinsicCandidate
|
||||
public static int countPositives(byte[] ba, int off, int len) {
|
||||
int limit = off + len;
|
||||
for (int i = off; i < limit; i++) {
|
||||
if (ba[i] < 0) {
|
||||
return true;
|
||||
return i - off;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return len;
|
||||
}
|
||||
|
||||
@IntrinsicCandidate
|
||||
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package compiler.intrinsics.string;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8999999
|
||||
* @summary Validates StringCoding.countPositives intrinsic with a small range of tests.
|
||||
* @library /compiler/patches
|
||||
*
|
||||
* @build java.base/java.lang.Helper
|
||||
* @run main compiler.intrinsics.string.TestCountPositives
|
||||
*/
|
||||
|
||||
public class TestCountPositives {
|
||||
|
||||
private static byte[] tBa = new byte[4096 + 16];
|
||||
|
||||
/**
|
||||
* Completely initialize the test array, preparing it for tests of the
|
||||
* StringCoding.hasNegatives method with a given array segment offset,
|
||||
* length, and number of negative bytes.
|
||||
*/
|
||||
public static void initialize(int off, int len, int neg) {
|
||||
assert (len + off <= tBa.length);
|
||||
// insert "canary" (negative) values before offset
|
||||
for (int i = 0; i < off; ++i) {
|
||||
tBa[i] = (byte) (((i + 15) & 0x7F) | 0x80);
|
||||
}
|
||||
// fill the array segment
|
||||
for (int i = off; i < len + off; ++i) {
|
||||
tBa[i] = (byte) (((i - off + 15) & 0x7F));
|
||||
}
|
||||
if (neg != 0) {
|
||||
// modify a number (neg) disparate array bytes inside
|
||||
// segment to be negative.
|
||||
int div = (neg > 1) ? (len - 1) / (neg - 1) : 0;
|
||||
int idx;
|
||||
for (int i = 0; i < neg; ++i) {
|
||||
idx = off + (len - 1) - div * i;
|
||||
tBa[idx] = (byte) (0x80 | tBa[idx]);
|
||||
}
|
||||
}
|
||||
// insert "canary" negative values after array segment
|
||||
for (int i = len + off; i < tBa.length; ++i) {
|
||||
tBa[i] = (byte) (((i + 15) & 0x7F) | 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sizes of array segments to test. */
|
||||
private static int sizes[] = { 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 13, 17, 19, 23, 37, 61, 131,
|
||||
4099 };
|
||||
|
||||
/**
|
||||
* Test different array segment sizes, offsets, and number of negative
|
||||
* bytes.
|
||||
*/
|
||||
public static void test_countPositives() throws Exception {
|
||||
int len, off;
|
||||
int ng;
|
||||
|
||||
for (ng = 0; ng < 57; ++ng) { // number of negatives in array segment
|
||||
for (off = 0; off < 8; ++off) { // starting offset of array segment
|
||||
for (int i = 0; i < sizes.length; ++i) { // array segment size
|
||||
// choice
|
||||
len = sizes[i];
|
||||
if (len + off > tBa.length)
|
||||
continue;
|
||||
initialize(off, len, ng);
|
||||
int calculated = Helper.StringCodingCountPositives(tBa, off, len);
|
||||
int expected = countPositives(tBa, off, len);
|
||||
if (calculated != expected) {
|
||||
if (expected != len && calculated >= 0 && calculated < expected) {
|
||||
// allow intrinsics to return early with a lower value,
|
||||
// but only if we're not expecting the full length (no
|
||||
// negative bytes)
|
||||
continue;
|
||||
}
|
||||
throw new Exception("Failed test countPositives " + "offset: " + off + " "
|
||||
+ "length: " + len + " " + "return: " + calculated + " expected: " + expected + " negatives: "
|
||||
+ ng);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int countPositives(byte[] ba, int off, int len) {
|
||||
int limit = off + len;
|
||||
for (int i = off; i < limit; i++) {
|
||||
if (ba[i] < 0) {
|
||||
return i - off;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
public void run() throws Exception {
|
||||
// iterate to eventually get intrinsic inlined
|
||||
for (int j = 0; j < 1000; ++j) {
|
||||
test_countPositives();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
(new TestCountPositives()).run();
|
||||
System.out.println("countPositives validated");
|
||||
}
|
||||
}
|
@ -32,6 +32,11 @@ public class Helper {
|
||||
return StringCoding.hasNegatives(ba, off, len);
|
||||
}
|
||||
|
||||
@jdk.internal.vm.annotation.ForceInline
|
||||
public static int StringCodingCountPositives(byte[] ba, int off, int len) {
|
||||
return StringCoding.countPositives(ba, off, len);
|
||||
}
|
||||
|
||||
@jdk.internal.vm.annotation.ForceInline
|
||||
public static byte[] compressByte(byte[] src, int srcOff, int dstSize, int dstOff, int len) {
|
||||
byte[] dst = new byte[dstSize];
|
||||
|
@ -87,7 +87,7 @@ public class StringDecode {
|
||||
bh.consume(new String(asciiString, charset));
|
||||
bh.consume(new String(longAsciiString, 0, 15, charset));
|
||||
bh.consume(new String(asciiString, 0, 3, charset));
|
||||
bh.consume(new String(longAsciiString, 512, 512 + 7, charset));
|
||||
bh.consume(new String(longAsciiString, 512, 7, charset));
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@ -103,7 +103,7 @@ public class StringDecode {
|
||||
bh.consume(new String(latin1String, charset));
|
||||
bh.consume(new String(latin1String, 0, 15, charset));
|
||||
bh.consume(new String(latin1String, 0, 3, charset));
|
||||
bh.consume(new String(longLatin1OnlyString, 512, 512 + 7, charset));
|
||||
bh.consume(new String(longLatin1OnlyString, 512, 7, charset));
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
|
Loading…
Reference in New Issue
Block a user