Skip to content

Commit

Permalink
8331098: [Aarch64] Fix crash in Arrays.equals() intrinsic with -CCP
Browse files Browse the repository at this point in the history
  • Loading branch information
rkennke committed Apr 25, 2024
1 parent 87e864b commit a59e11e
Showing 1 changed file with 62 additions and 16 deletions.
78 changes: 62 additions & 16 deletions src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5545,6 +5545,14 @@ address MacroAssembler::arrays_equals(Register a1, Register a2, Register tmp3,
int length_offset = arrayOopDesc::length_offset_in_bytes();
int base_offset
= arrayOopDesc::base_offset_in_bytes(elem_size == 2 ? T_CHAR : T_BYTE);
// When the base is not aligned to 8 bytes, then we let
// the compare loop include the array length, and skip
// the explicit comparison of length.
bool is_8aligned = is_aligned(base_offset, BytesPerWord);
assert(is_aligned(base_offset, BytesPerWord) || is_aligned(length_offset, BytesPerWord),
"base_offset or length_offset must be 8-byte aligned");
int start_offset = is_8aligned ? base_offset : length_offset;
int extra_length = is_8aligned ? 0 : BytesPerInt / elem_size;
int stubBytesThreshold = 3 * 64 + (UseSIMDForArrayEquals ? 0 : 16);

assert(elem_size == 1 || elem_size == 2, "must be char or byte");
Expand Down Expand Up @@ -5579,10 +5587,21 @@ address MacroAssembler::arrays_equals(Register a1, Register a2, Register tmp3,
bind(A_IS_NOT_NULL);
ldrw(cnt1, Address(a1, length_offset));
ldrw(cnt2, Address(a2, length_offset));
eorw(tmp5, cnt1, cnt2);
cbnzw(tmp5, DONE);
lea(a1, Address(a1, base_offset));
lea(a2, Address(a2, base_offset));
if (extra_length != 0) {
// Increase loop counter by size of length field.
addw(cnt1, cnt1, extra_length);
addw(cnt2, cnt2, extra_length);
}
if (is_8aligned) {
// Check if lenghts are equal. When bases are
// not aligned, we compare the lengths in the
// main loop and don't need to compare it
// explicitely ahead of the loop.
eorw(tmp5, cnt1, cnt2);
cbnzw(tmp5, DONE);
}
lea(a1, Address(a1, start_offset));
lea(a2, Address(a2, start_offset));
// Check for short strings, i.e. smaller than wordSize.
subs(cnt1, cnt1, elem_per_word);
br(Assembler::LT, SHORT);
Expand Down Expand Up @@ -5646,17 +5665,28 @@ address MacroAssembler::arrays_equals(Register a1, Register a2, Register tmp3,
ldrw(cnt1, Address(a1, length_offset));
cbz(a2, DONE);
ldrw(cnt2, Address(a2, length_offset));
if (extra_length != 0) {
// Increase loop counter by size of length field.
addw(cnt1, cnt1, extra_length);
addw(cnt2, cnt2, extra_length);
}
// on most CPUs a2 is still "locked"(surprisingly) in ldrw and it's
// faster to perform another branch before comparing a1 and a2
cmp(cnt1, (u1)elem_per_word);
br(LE, SHORT); // short or same
ldr(tmp3, Address(pre(a1, base_offset)));
ldr(tmp3, Address(pre(a1, start_offset)));
subs(zr, cnt1, stubBytesThreshold);
br(GE, STUB);
ldr(tmp4, Address(pre(a2, base_offset)));
ldr(tmp4, Address(pre(a2, start_offset)));
sub(tmp5, zr, cnt1, LSL, 3 + log_elem_size);
cmp(cnt2, cnt1);
br(NE, DONE);
if (is_8aligned) {
// Check if lenghts are equal. When bases are
// not aligned, we compare the lengths in the
// main loop and don't need to compare it
// explicitely ahead of the loop.
cmp(cnt2, cnt1);
br(NE, DONE);
}

// Main 16 byte comparison loop with 2 exits
bind(NEXT_DWORD); {
Expand Down Expand Up @@ -5688,9 +5718,15 @@ address MacroAssembler::arrays_equals(Register a1, Register a2, Register tmp3,
b(LAST_CHECK);

bind(STUB);
ldr(tmp4, Address(pre(a2, base_offset)));
cmp(cnt2, cnt1);
br(NE, DONE);
ldr(tmp4, Address(pre(a2, start_offset)));
if (is_8aligned) {
// Check if lenghts are equal. When bases are
// not aligned, we compare the lengths in the
// main loop and don't need to compare it
// explicitely ahead of the loop.
cmp(cnt2, cnt1);
br(NE, DONE);
}
if (elem_size == 2) { // convert to byte counter
lsl(cnt1, cnt1, 1);
}
Expand All @@ -5711,12 +5747,22 @@ address MacroAssembler::arrays_equals(Register a1, Register a2, Register tmp3,
mov(result, a2);
b(DONE);
bind(SHORT);
cmp(cnt2, cnt1);
br(NE, DONE);
cbz(cnt1, SAME);
if (is_8aligned) {
// Check if lenghts are equal. When bases are
// not aligned, we compare the lengths in the
// main loop and don't need to compare it
// explicitely ahead of the loop.
cmp(cnt2, cnt1);
br(NE, DONE);
// We only need to check if length == 0 when
// bases are aligned, because otherwise we'll
// compare array lengths in 'the loops', and
// cnt1 can not be 0.
cbz(cnt1, SAME);
}
sub(tmp5, zr, cnt1, LSL, 3 + log_elem_size);
ldr(tmp3, Address(a1, base_offset));
ldr(tmp4, Address(a2, base_offset));
ldr(tmp3, Address(pre(a1, start_offset)));
ldr(tmp4, Address(pre(a2, start_offset)));
bind(LAST_CHECK);
eor(tmp4, tmp3, tmp4);
lslv(tmp5, tmp4, tmp5);
Expand Down

0 comments on commit a59e11e

Please sign in to comment.