Skip to content

Commit 06c44dd

Browse files
committed
8345465: Fix performance regression on x64 after JDK-8345120
Reviewed-by: mcimadamore
1 parent 2979806 commit 06c44dd

File tree

2 files changed

+29
-24
lines changed

2 files changed

+29
-24
lines changed

src/java.base/share/classes/jdk/internal/foreign/StringSupport.java

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ public static int strlenByte(final AbstractMemorySegmentImpl segment,
130130
final long toOffset) {
131131
final long length = toOffset - fromOffset;
132132
segment.checkBounds(fromOffset, length);
133-
if (length == 0) {
134-
// The state has to be checked explicitly for zero-length segments
133+
if (length < Byte.BYTES) {
134+
// There can be no null terminator present
135135
segment.scope.checkValidState();
136136
throw nullNotFound(segment, fromOffset, toOffset);
137137
}
@@ -164,7 +164,8 @@ public static int strlenShort(final AbstractMemorySegmentImpl segment,
164164
final long toOffset) {
165165
final long length = toOffset - fromOffset;
166166
segment.checkBounds(fromOffset, length);
167-
if (length == 0) {
167+
if (length < Short.BYTES) {
168+
// There can be no null terminator present
168169
segment.scope.checkValidState();
169170
throw nullNotFound(segment, fromOffset, toOffset);
170171
}
@@ -199,19 +200,23 @@ public static int strlenInt(final AbstractMemorySegmentImpl segment,
199200
final long toOffset) {
200201
final long length = toOffset - fromOffset;
201202
segment.checkBounds(fromOffset, length);
202-
if (length == 0) {
203+
if (length < Integer.BYTES) {
204+
// There can be no null terminator present
203205
segment.scope.checkValidState();
204206
throw nullNotFound(segment, fromOffset, toOffset);
205207
}
206-
final long longBytes = length & LONG_MASK;
207-
final long longLimit = fromOffset + longBytes;
208208
long offset = fromOffset;
209-
for (; offset < longLimit; offset += Long.BYTES) {
210-
long val = SCOPED_MEMORY_ACCESS.getLongUnaligned(segment.sessionImpl(), segment.unsafeGetBase(), segment.unsafeGetOffset() + offset, !Architecture.isLittleEndian());
211-
if (mightContainZeroInt(val)) {
212-
for (int j = 0; j < Long.BYTES; j += Integer.BYTES) {
213-
if (SCOPED_MEMORY_ACCESS.getIntUnaligned(segment.sessionImpl(), segment.unsafeGetBase(), segment.unsafeGetOffset() + offset + j, !Architecture.isLittleEndian()) == 0) {
214-
return requireWithinStringSize(offset + j - fromOffset, segment, fromOffset, toOffset);
209+
// For quad byte strings, it does not pay off to use long scanning on x64
210+
if (!Architecture.isX64()) {
211+
final long longBytes = length & LONG_MASK;
212+
final long longLimit = fromOffset + longBytes;
213+
for (; offset < longLimit; offset += Long.BYTES) {
214+
long val = SCOPED_MEMORY_ACCESS.getLongUnaligned(segment.sessionImpl(), segment.unsafeGetBase(), segment.unsafeGetOffset() + offset, !Architecture.isLittleEndian());
215+
if (mightContainZeroInt(val)) {
216+
for (int j = 0; j < Long.BYTES; j += Integer.BYTES) {
217+
if (SCOPED_MEMORY_ACCESS.getIntUnaligned(segment.sessionImpl(), segment.unsafeGetBase(), segment.unsafeGetOffset() + offset + j, !Architecture.isLittleEndian()) == 0) {
218+
return requireWithinStringSize(offset + j - fromOffset, segment, fromOffset, toOffset);
219+
}
215220
}
216221
}
217222
}

test/micro/org/openjdk/bench/java/lang/foreign/InternalStrLen.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,20 @@
5555
"--enable-native-access=ALL-UNNAMED"})
5656
public class InternalStrLen {
5757

58-
private AbstractMemorySegmentImpl singleByteSegment;
59-
private AbstractMemorySegmentImpl singleByteSegmentMisaligned;
60-
private AbstractMemorySegmentImpl doubleByteSegment;
61-
private AbstractMemorySegmentImpl quadByteSegment;
58+
private MemorySegment singleByteSegment;
59+
private MemorySegment singleByteSegmentMisaligned;
60+
private MemorySegment doubleByteSegment;
61+
private MemorySegment quadByteSegment;
6262

6363
@Param({"1", "4", "16", "251", "1024"})
6464
int size;
6565

6666
@Setup
6767
public void setup() {
6868
var arena = Arena.ofAuto();
69-
singleByteSegment = (AbstractMemorySegmentImpl) arena.allocate((size + 1L) * Byte.BYTES);
70-
doubleByteSegment = (AbstractMemorySegmentImpl) arena.allocate((size + 1L) * Short.BYTES);
71-
quadByteSegment = (AbstractMemorySegmentImpl) arena.allocate((size + 1L) * Integer.BYTES);
69+
singleByteSegment = arena.allocate((size + 1L) * Byte.BYTES);
70+
doubleByteSegment = arena.allocate((size + 1L) * Short.BYTES);
71+
quadByteSegment = arena.allocate((size + 1L) * Integer.BYTES);
7272
Stream.of(singleByteSegment, doubleByteSegment, quadByteSegment)
7373
.forEach(s -> IntStream.range(0, (int) s.byteSize() - 1)
7474
.forEach(i -> s.set(
@@ -79,7 +79,7 @@ public void setup() {
7979
singleByteSegment.set(ValueLayout.JAVA_BYTE, singleByteSegment.byteSize() - Byte.BYTES, (byte) 0);
8080
doubleByteSegment.set(ValueLayout.JAVA_SHORT, doubleByteSegment.byteSize() - Short.BYTES, (short) 0);
8181
quadByteSegment.set(ValueLayout.JAVA_INT, quadByteSegment.byteSize() - Integer.BYTES, 0);
82-
singleByteSegmentMisaligned = (AbstractMemorySegmentImpl) arena.allocate(singleByteSegment.byteSize() + 1).
82+
singleByteSegmentMisaligned = arena.allocate(singleByteSegment.byteSize() + 1).
8383
asSlice(1);
8484
MemorySegment.copy(singleByteSegment, 0, singleByteSegmentMisaligned, 0, singleByteSegment.byteSize());
8585
}
@@ -106,22 +106,22 @@ public int elementQuad() {
106106

107107
@Benchmark
108108
public int chunkedSingle() {
109-
return StringSupport.strlenByte(singleByteSegment, 0, singleByteSegment.byteSize());
109+
return StringSupport.strlenByte((AbstractMemorySegmentImpl) singleByteSegment, 0, singleByteSegment.byteSize());
110110
}
111111

112112
@Benchmark
113113
public int chunkedSingleMisaligned() {
114-
return StringSupport.strlenByte(singleByteSegmentMisaligned, 0, singleByteSegment.byteSize());
114+
return StringSupport.strlenByte((AbstractMemorySegmentImpl) singleByteSegmentMisaligned, 0, singleByteSegment.byteSize());
115115
}
116116

117117
@Benchmark
118118
public int chunkedDouble() {
119-
return StringSupport.strlenShort(doubleByteSegment, 0, doubleByteSegment.byteSize());
119+
return StringSupport.strlenShort((AbstractMemorySegmentImpl) doubleByteSegment, 0, doubleByteSegment.byteSize());
120120
}
121121

122122
@Benchmark
123123
public int changedElementQuad() {
124-
return StringSupport.strlenInt(quadByteSegment, 0, quadByteSegment.byteSize());
124+
return StringSupport.strlenInt((AbstractMemorySegmentImpl) quadByteSegment, 0, quadByteSegment.byteSize());
125125
}
126126

127127
// These are the legacy methods

0 commit comments

Comments
 (0)