--- old/src/java.base/share/classes/jdk/internal/util/ArraysSupport.java 2020-06-17 16:25:52.000000000 +0100 +++ new/src/java.base/share/classes/jdk/internal/util/ArraysSupport.java 2020-06-17 16:25:52.000000000 +0100 @@ -183,7 +183,7 @@ off += i; remaining -= i; } - return ~off; + return ~remaining; } // Booleans --- old/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java 2020-06-17 16:25:54.000000000 +0100 +++ new/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java 2020-06-17 16:25:54.000000000 +0100 @@ -149,6 +149,9 @@ long i = 0; if (length > 7) { + if ((byte) BYTE_HANDLE.get(this.baseAddress(), 0) != (byte) BYTE_HANDLE.get(that.baseAddress(), 0)) { + return 0; + } i = ArraysSupport.vectorizedMismatchLarge( this.base(), this.min(), that.base(), that.min(), @@ -156,7 +159,10 @@ if (i >= 0) { return i; } - i = length - ~i; + long remaining = ~i; + if (remaining > 7) + throw new InternalError("remaining greater than 7: " + remaining); + i = length - remaining; } MemoryAddress thisAddress = this.baseAddress(); MemoryAddress thatAddress = that.baseAddress(); --- old/test/micro/org/openjdk/bench/jdk/incubator/foreign/BulkOps.java 2020-06-17 16:25:57.000000000 +0100 +++ new/test/micro/org/openjdk/bench/jdk/incubator/foreign/BulkOps.java 2020-06-17 16:25:57.000000000 +0100 @@ -35,6 +35,7 @@ import sun.misc.Unsafe; import jdk.incubator.foreign.MemorySegment; +import java.nio.ByteBuffer; import java.util.concurrent.TimeUnit; import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT; @@ -60,6 +61,36 @@ static final MemorySegment bytesSegment = MemorySegment.ofArray(bytes); static final int UNSAFE_INT_OFFSET = unsafe.arrayBaseOffset(int[].class); + // large(ish) segments/buffers with same content, 0, for mismatch, non-multiple-of-8 sized + static final int SIZE_WITH_TAIL = ALLOC_SIZE + 7; + static final MemorySegment mismatchSegmentLarge1 = MemorySegment.allocateNative(SIZE_WITH_TAIL); + static final MemorySegment mismatchSegmentLarge2 = MemorySegment.allocateNative(SIZE_WITH_TAIL); + static final ByteBuffer mismatchBufferLarge1 = ByteBuffer.allocateDirect(SIZE_WITH_TAIL); + static final ByteBuffer mismatchBufferLarge2 = ByteBuffer.allocateDirect(SIZE_WITH_TAIL); + + // mismatch at first byte + static final MemorySegment mismatchSegmentSmall1 = MemorySegment.allocateNative(7); + static final MemorySegment mismatchSegmentSmall2 = MemorySegment.allocateNative(7); + static final ByteBuffer mismatchBufferSmall1 = ByteBuffer.allocateDirect(7); + static final ByteBuffer mismatchBufferSmall2 = ByteBuffer.allocateDirect(7); + static { + mismatchSegmentSmall1.fill((byte) 0xFF); + mismatchBufferSmall1.put((byte) 0xFF).clear(); + // verify expected mismatch indices + long si = mismatchSegmentLarge1.mismatch(mismatchSegmentLarge2); + if (si != -1) + throw new AssertionError("Unexpected mismatch index:" + si); + int bi = mismatchBufferLarge1.mismatch(mismatchBufferLarge2); + if (bi != -1) + throw new AssertionError("Unexpected mismatch index:" + bi); + si = mismatchSegmentSmall1.mismatch(mismatchSegmentSmall2); + if (si != 0) + throw new AssertionError("Unexpected mismatch index:" + si); + bi = mismatchBufferSmall1.mismatch(mismatchBufferSmall2); + if (bi != 0) + throw new AssertionError("Unexpected mismatch index:" + bi); + } + static { for (int i = 0 ; i < bytes.length ; i++) { bytes[i] = i; @@ -89,4 +120,28 @@ public void segment_copy() { segment.copyFrom(bytesSegment); } + + @Benchmark + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public long mismatch_large_segment() { + return mismatchSegmentLarge1.mismatch(mismatchSegmentLarge2); + } + + @Benchmark + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public int mismatch_large_bytebuffer() { + return mismatchBufferLarge1.mismatch(mismatchBufferLarge2); + } + + @Benchmark + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public long mismatch_small_segment() { + return mismatchSegmentSmall1.mismatch(mismatchSegmentSmall2); + } + + @Benchmark + @OutputTimeUnit(TimeUnit.NANOSECONDS) + public int mismatch_small_bytebuffer() { + return mismatchBufferSmall1.mismatch(mismatchBufferSmall2); + } }