How to reinterpret MemorySegment in Java 20 Preview like Java 21 Preview MemorySegment:
MemorySegment reinterpret(long newSize) - Returns a new memory segment that has the same address and scope as this segment, but with the provided size?
Please refer to the following ccode snippet and the exception output details:
import java.lang.foreign.Arena;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.Linker;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.SymbolLookup;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.util.Arrays;
// 434: Foreign Function & Memory API (Second Preview) // https://openjdk.org/jeps/434
class ForeignFunctionMemoryAPISecondPreview {
private void radixsort() throws Throwable {
// 1. Find foreign function on the C library path
Linker linker = Linker.nativeLinker();
SymbolLookup stdlib = linker.defaultLookup();
MethodHandle radixsort = linker.downcallHandle(stdlib.find("radixsort").orElseThrow(),
FunctionDescriptor.ofVoid(ValueLayout.ADDRESS, ValueLayout.JAVA_INT, ValueLayout.ADDRESS, ValueLayout.JAVA_CHAR));
// 2. Allocate on-heap memory to store four strings
String[] javaStrings = { "mouse", "cat", "dog", "car" };
System.out.println("radixsort input: " + Arrays.toString(javaStrings));
// 3. Use try-with-resources to manage the lifetime of off-heap memory
try (Arena offHeap = Arena.openConfined()) {
// 4. Allocate a region of off-heap memory to store four pointers
MemorySegment pointers = offHeap.allocateArray(ValueLayout.ADDRESS, javaStrings.length);
// 5. Copy the strings from on-heap to off-heap
for (int i = 0; i < javaStrings.length; i++) {
MemorySegment cString = offHeap.allocateUtf8String(javaStrings[i]);
pointers.setAtIndex(ValueLayout.ADDRESS, i, cString);
}
// 6. Sort the off-heap data by calling the foreign function
radixsort.invoke(pointers, javaStrings.length, MemorySegment.NULL, '\0');
// 7. Copy the (reordered) strings from off-heap to on-heap
for (int i = 0; i < javaStrings.length; i++) {
MemorySegment cString = pointers.getAtIndex(ValueLayout.ADDRESS, i);
// Java 21 Preview
// cString = cString.reinterpret(Long.MAX_VALUE);
// javaStrings[i] = cString.getUtf8String(0);
System.out.println(cString);
}
}
// 8. All off-heap memory is deallocated here
System.out.println("radixsort output: " + Arrays.toString(javaStrings));
}
public static void main(String[] args) throws Throwable {
System.out.println(String.format("Java Version: %s", System.getProperty("java.version")));
var previewForeignFunctionMemoryAPISecond = new ForeignFunctionMemoryAPISecondPreview();
previewForeignFunctionMemoryAPISecond.radixsort();
}
}
// Output
/*
WARNING: Using incubator modules: jdk.incubator.vector, jdk.incubator.concurrent
Note: ForeignFunctionMemoryAPISecondPreview.java uses preview features of Java SE 20.
Note: Recompile with -Xlint:preview for details.
Java Version: 20.0.2
radixsort input: [mouse, cat, dog, car]
Exception in thread "main" java.lang.IndexOutOfBoundsException: Out of bound access on segment MemorySegment{ array: Optional.empty address:105553152688144 limit: 0 }; new offset = 0; new length = 1
at java.base/jdk.internal.foreign.AbstractMemorySegmentImpl.outOfBoundException(AbstractMemorySegmentImpl.java:371)
at java.base/jdk.internal.foreign.AbstractMemorySegmentImpl.apply(AbstractMemorySegmentImpl.java:357)
at java.base/jdk.internal.foreign.AbstractMemorySegmentImpl.apply(AbstractMemorySegmentImpl.java:70)
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:98)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:124)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:448)
at java.base/jdk.internal.foreign.AbstractMemorySegmentImpl.checkBounds(AbstractMemorySegmentImpl.java:346)
at java.base/jdk.internal.foreign.AbstractMemorySegmentImpl.checkAccess(AbstractMemorySegmentImpl.java:311)
at java.base/java.lang.invoke.VarHandleSegmentAsBytes.checkAddress(VarHandleSegmentAsBytes.java:81)
at java.base/java.lang.invoke.VarHandleSegmentAsBytes.get(VarHandleSegmentAsBytes.java:108)
at java.base/java.lang.foreign.MemorySegment.get(MemorySegment.java:1388)
at java.base/jdk.internal.foreign.abi.SharedUtils.strlen(SharedUtils.java:199)
at java.base/jdk.internal.foreign.abi.SharedUtils.toJavaStringInternal(SharedUtils.java:190)
at java.base/java.lang.foreign.MemorySegment.getUtf8String(MemorySegment.java:890)
at ForeignFunctionMemoryAPISecondPreview.radixsort(ForeignFunctionMemoryAPISecondPreview.java:43)
at ForeignFunctionMemoryAPISecondPreview.main(ForeignFunctionMemoryAPISecondPreview.java:56)
[1]: https://docs.oracle.com/en/java/javase/21/docs//api/java.base/java/lang/foreign/MemorySegment.html#reinterpret(long)
In java 20, you can use MemorySegment::ofAddress
instead of reinterpret
:
cString = MemorySegment.ofAddress(cString.address(), Long.MAX_VALUE);