The C2 compiler should be able to hoist alignment checks out of loops but appears to be failing under certain conditions:
```
Benchmark (size) Mode Cnt Score Error Units
InternalStrLen.legacyQuadByte 1 avgt 30 1.910 ? 0.025 ns/op
InternalStrLen.legacyQuadByte 4 avgt 30 3.768 ? 0.021 ns/op
InternalStrLen.legacyQuadByte 16 avgt 30 11.427 ? 0.149 ns/op
InternalStrLen.legacyQuadByte 251 avgt 30 166.094 ? 0.833 ns/op
InternalStrLen.legacyQuadByte 1024 avgt 30 655.468 ? 5.847 ns/op
InternalStrLen.legacyQuadByteUnaligned 1 avgt 30 1.414 ? 0.019 ns/op
InternalStrLen.legacyQuadByteUnaligned 4 avgt 30 3.772 ? 0.069 ns/op
InternalStrLen.legacyQuadByteUnaligned 16 avgt 30 6.786 ? 0.029 ns/op
InternalStrLen.legacyQuadByteUnaligned 251 avgt 30 47.473 ? 0.206 ns/op
InternalStrLen.legacyQuadByteUnaligned 1024 avgt 30 192.409 ? 0.832 ns/op
```
Code:
```
@Benchmark
public int legacyQuadByte() {
return legacy_strlen_int(quadByteSegment, 0);
}
@Benchmark
public int legacyQuadByteUnaligned() {
return unaligned_legacy_strlen_int(quadByteSegment, 0);
}
private static int legacy_strlen_int(MemorySegment segment, long start) {
// iterate until overflow (String can only hold a byte[], whose length can be expressed as an int)
for (int offset = 0; offset >= 0; offset += 4) {
int curr = segment.get(JAVA_INT, start + offset);
if (curr == 0) {
return offset;
}
}
throw new IllegalArgumentException("String too large");
}
public static int unaligned_legacy_strlen_int(MemorySegment segment, long start) {
for (int offset = 0; offset < InternalStrLen.ArraySupport.SOFT_MAX_ARRAY_LENGTH; offset += Integer.BYTES) {
// We are guaranteed to be aligned here so, we can use unaligned access.
int curr = segment.get(JAVA_INT_UNALIGNED, start + offset);
if (curr == 0) {
return offset;
}
}
throw new IllegalArgumentException("String too large");
}
static class ArraySupport {
private ArraySupport() {}
public static final int SOFT_MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;
}
```
```
Benchmark (size) Mode Cnt Score Error Units
InternalStrLen.legacyQuadByte 1 avgt 30 1.910 ? 0.025 ns/op
InternalStrLen.legacyQuadByte 4 avgt 30 3.768 ? 0.021 ns/op
InternalStrLen.legacyQuadByte 16 avgt 30 11.427 ? 0.149 ns/op
InternalStrLen.legacyQuadByte 251 avgt 30 166.094 ? 0.833 ns/op
InternalStrLen.legacyQuadByte 1024 avgt 30 655.468 ? 5.847 ns/op
InternalStrLen.legacyQuadByteUnaligned 1 avgt 30 1.414 ? 0.019 ns/op
InternalStrLen.legacyQuadByteUnaligned 4 avgt 30 3.772 ? 0.069 ns/op
InternalStrLen.legacyQuadByteUnaligned 16 avgt 30 6.786 ? 0.029 ns/op
InternalStrLen.legacyQuadByteUnaligned 251 avgt 30 47.473 ? 0.206 ns/op
InternalStrLen.legacyQuadByteUnaligned 1024 avgt 30 192.409 ? 0.832 ns/op
```
Code:
```
@Benchmark
public int legacyQuadByte() {
return legacy_strlen_int(quadByteSegment, 0);
}
@Benchmark
public int legacyQuadByteUnaligned() {
return unaligned_legacy_strlen_int(quadByteSegment, 0);
}
private static int legacy_strlen_int(MemorySegment segment, long start) {
// iterate until overflow (String can only hold a byte[], whose length can be expressed as an int)
for (int offset = 0; offset >= 0; offset += 4) {
int curr = segment.get(JAVA_INT, start + offset);
if (curr == 0) {
return offset;
}
}
throw new IllegalArgumentException("String too large");
}
public static int unaligned_legacy_strlen_int(MemorySegment segment, long start) {
for (int offset = 0; offset < InternalStrLen.ArraySupport.SOFT_MAX_ARRAY_LENGTH; offset += Integer.BYTES) {
// We are guaranteed to be aligned here so, we can use unaligned access.
int curr = segment.get(JAVA_INT_UNALIGNED, start + offset);
if (curr == 0) {
return offset;
}
}
throw new IllegalArgumentException("String too large");
}
static class ArraySupport {
private ArraySupport() {}
public static final int SOFT_MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;
}
```