For the following code:
public static void payload(int[] ints) {
Objects.checkFromIndexSize(0, 10, ints.length);
}
C2 generates the following bounds checks:
mov r11d, dword ptr [rdx + 0xc] // Windows, so rdx = arg0. Load ints.length
mov ebp, r11d
or ebp, 0xa
test ebp, ebp // check if (ints.length | 10) < 0 (huh?)
jl 0x1b5ee511261
cmp r11d, 0xa // check if ints.length < 10 (I get this one)
jl 0x1b5ee511278
The first of the two checks is redundant, but C2 can not eliminate it since OrINode::add_ring doesn't track positiveness. Looking at the check in Preconditions (which is called by Objects.checkFromIndexSize):
public static <X extends RuntimeException>
int checkFromIndexSize(int fromIndex, int size, int length,
BiFunction<String, List<Number>, X> oobef) {
if ((length | fromIndex | size) < 0 || size > length - fromIndex)
throw outOfBoundsCheckFromIndexSize(oobef, fromIndex, size, length);
return fromIndex;
}
the result of (length | fromIndex | size) might be negative, from C2's perspective, and as a result the check if it's less than 0 doesn't fold away.
We could track positivity of types in OrINode/OrLNode::add_ring as well, which would make this check fold away.