mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 14:24:46 +02:00
8294432: Add provisions to calculate hash values from MemorySegments
Reviewed-by: mcimadamore
This commit is contained in:
parent
4a22c1fefc
commit
a1473ec302
3 changed files with 338 additions and 0 deletions
|
@ -28,7 +28,9 @@ package jdk.internal.foreign;
|
|||
import jdk.internal.misc.ScopedMemoryAccess;
|
||||
import jdk.internal.util.Architecture;
|
||||
import jdk.internal.util.ArraysSupport;
|
||||
import jdk.internal.util.ByteArrayLittleEndian;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
import java.lang.foreign.MemorySegment;
|
||||
|
||||
|
@ -156,6 +158,94 @@ public final class SegmentBulkOperations {
|
|||
}
|
||||
}
|
||||
|
||||
private static final @Stable int[] POWERS_OF_31 = new int[]{
|
||||
0x0000001f, 0x000003c1, 0x0000745f, 0x000e1781,
|
||||
0x01b4d89f, 0x34e63b41, 0x67e12cdf, 0x94446f01};
|
||||
|
||||
/**
|
||||
* {@return a 32-bit hash value calculated from the content in the provided
|
||||
* {@code segment} between the provided offsets}
|
||||
* <p>
|
||||
* The method is implemented as a 32-bit polynomial hash function equivalent to:
|
||||
* {@snippet lang=java :
|
||||
* final long length = toOffset - fromOffset;
|
||||
* segment.checkBounds(fromOffset, length);
|
||||
* int result = 1;
|
||||
* for (long i = fromOffset; i < toOffset; i++) {
|
||||
* result = 31 * result + segment.get(JAVA_BYTE, i);
|
||||
* }
|
||||
* return result;
|
||||
* }
|
||||
* but is potentially more performant.
|
||||
*
|
||||
* @param segment from which a content hash should be computed
|
||||
* @param fromOffset starting offset (inclusive) in the segment
|
||||
* @param toOffset ending offset (non-inclusive) in the segment
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code srcSegment.isAccessibleBy(T) == false}
|
||||
* @throws IllegalStateException if the {@linkplain MemorySegment#scope() scope}
|
||||
* associated with {@code segment} is not
|
||||
* {@linkplain MemorySegment.Scope#isAlive() alive}
|
||||
* @throws IndexOutOfBoundsException if either {@code fromOffset} or {@code toOffset}
|
||||
* are {@code > segment.byteSize}
|
||||
* @throws IndexOutOfBoundsException if either {@code fromOffset} or {@code toOffset}
|
||||
* are {@code < 0}
|
||||
* @throws IndexOutOfBoundsException if {@code toOffset - fromOffset} is {@code < 0}
|
||||
*/
|
||||
@ForceInline
|
||||
public static int contentHash(AbstractMemorySegmentImpl segment, long fromOffset, long toOffset) {
|
||||
final long length = toOffset - fromOffset;
|
||||
segment.checkBounds(fromOffset, length);
|
||||
if (length == 0) {
|
||||
// The state has to be checked explicitly for zero-length segments
|
||||
segment.scope.checkValidState();
|
||||
return 1;
|
||||
}
|
||||
int result = 1;
|
||||
final long longBytes = length & ((1L << 62) - 8);
|
||||
final long limit = fromOffset + longBytes;
|
||||
for (; fromOffset < limit; fromOffset += 8) {
|
||||
long val = SCOPED_MEMORY_ACCESS.getLongUnaligned(segment.sessionImpl(), segment.unsafeGetBase(), segment.unsafeGetOffset() + fromOffset, !Architecture.isLittleEndian());
|
||||
result = result * POWERS_OF_31[7]
|
||||
+ ((byte) (val >>> 56)) * POWERS_OF_31[6]
|
||||
+ ((byte) (val >>> 48)) * POWERS_OF_31[5]
|
||||
+ ((byte) (val >>> 40)) * POWERS_OF_31[4]
|
||||
+ ((byte) (val >>> 32)) * POWERS_OF_31[3]
|
||||
+ ((byte) (val >>> 24)) * POWERS_OF_31[2]
|
||||
+ ((byte) (val >>> 16)) * POWERS_OF_31[1]
|
||||
+ ((byte) (val >>> 8)) * POWERS_OF_31[0]
|
||||
+ ((byte) val);
|
||||
}
|
||||
int remaining = (int) (length - longBytes);
|
||||
// 0...0X00
|
||||
if (remaining >= 4) {
|
||||
int val = SCOPED_MEMORY_ACCESS.getIntUnaligned(segment.sessionImpl(), segment.unsafeGetBase(), segment.unsafeGetOffset() + fromOffset, !Architecture.isLittleEndian());
|
||||
result = result * POWERS_OF_31[3]
|
||||
+ ((byte) (val >>> 24)) * POWERS_OF_31[2]
|
||||
+ ((byte) (val >>> 16)) * POWERS_OF_31[1]
|
||||
+ ((byte) (val >>> 8)) * POWERS_OF_31[0]
|
||||
+ ((byte) val);
|
||||
fromOffset += 4;
|
||||
remaining -= 4;
|
||||
}
|
||||
// 0...00X0
|
||||
if (remaining >= 2) {
|
||||
short val = SCOPED_MEMORY_ACCESS.getShortUnaligned(segment.sessionImpl(), segment.unsafeGetBase(), segment.unsafeGetOffset() + fromOffset, !Architecture.isLittleEndian());
|
||||
result = result * POWERS_OF_31[1]
|
||||
+ ((byte) (val >>> 8)) * POWERS_OF_31[0]
|
||||
+ ((byte) val);
|
||||
fromOffset += 2;
|
||||
remaining -= 2;
|
||||
}
|
||||
// 0...000X
|
||||
if (remaining == 1) {
|
||||
byte val = SCOPED_MEMORY_ACCESS.getByte(segment.sessionImpl(), segment.unsafeGetBase(), segment.unsafeGetOffset() + fromOffset);
|
||||
result = result * POWERS_OF_31[0]
|
||||
+ val;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
public static long mismatch(AbstractMemorySegmentImpl src, long srcFromOffset, long srcToOffset,
|
||||
AbstractMemorySegmentImpl dst, long dstFromOffset, long dstToOffset) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue