8308281: Java snippets in the FFM API need to be updated

Reviewed-by: mcimadamore
This commit is contained in:
Per Minborg 2023-05-23 11:29:05 +00:00
parent 26227a6ff8
commit eb11508eff
7 changed files with 734 additions and 49 deletions

View File

@ -48,7 +48,7 @@ import java.lang.foreign.MemorySegment.Scope;
* accessible and their backing regions of memory are never deallocated. Moreover, memory segments allocated with the
* global arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread.
* {@snippet lang = java:
* MemorySegment segment = Arena.global().allocate(100, 1);
* MemorySegment segment = Arena.global().allocate(100, 1); // @highlight regex='global()'
* ...
* // segment is never deallocated!
*}
@ -58,9 +58,8 @@ import java.lang.foreign.MemorySegment.Scope;
* of memory backing memory segments allocated with the automatic arena are deallocated at some unspecified time
* <em>after</em> the automatic arena (and all the segments allocated by it) become
* <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>, as shown below:
*
* {@snippet lang = java:
* MemorySegment segment = Arena.ofAuto().allocate(100, 1);
* MemorySegment segment = Arena.ofAuto().allocate(100, 1); // @highlight regex='ofAuto()'
* ...
* segment = null; // the segment region becomes available for deallocation after this point
*}
@ -77,7 +76,7 @@ import java.lang.foreign.MemorySegment.Scope;
*
* {@snippet lang = java:
* MemorySegment segment = null;
* try (Arena arena = Arena.ofConfined()) {
* try (Arena arena = Arena.ofConfined()) { // @highlight regex='ofConfined()'
* segment = arena.allocate(100);
* ...
* } // segment region deallocated here
@ -157,24 +156,25 @@ import java.lang.foreign.MemorySegment.Scope;
*
* {@snippet lang = java:
* class SlicingArena implements Arena {
* final Arena arena = Arena.ofConfined();
* final SegmentAllocator slicingAllocator;
* final Arena arena = Arena.ofConfined();
* final SegmentAllocator slicingAllocator;
*
* SlicingArena(long size) {
* slicingAllocator = SegmentAllocator.slicingAllocator(arena.allocate(size));
* }
* SlicingArena(long size) {
* slicingAllocator = SegmentAllocator.slicingAllocator(arena.allocate(size));
* }
*
* public void allocate(long byteSize, long byteAlignment) {
* return slicingAllocator.allocate(byteSize, byteAlignment);
* }
* public MemorySegment allocate(long byteSize, long byteAlignment) {
* return slicingAllocator.allocate(byteSize, byteAlignment);
* }
*
* public MemorySegment.Scope scope() {
* return arena.scope();
* }
* public MemorySegment.Scope scope() {
* return arena.scope();
* }
*
* public void close() {
* arena.close();
* }
*
* public void close() {
* return arena.close();
* }
* }
* }
*
@ -183,10 +183,10 @@ import java.lang.foreign.MemorySegment.Scope;
*
* {@snippet lang = java:
* try (Arena slicingArena = new SlicingArena(1000)) {
* for (int i = 0 ; i < 10 ; i++) {
* MemorySegment s = slicingArena.allocateArray(JAVA_INT, 1, 2, 3, 4, 5);
* ...
* }
* for (int i = 0; i < 10; i++) {
* MemorySegment s = slicingArena.allocateArray(JAVA_INT, 1, 2, 3, 4, 5);
* ...
* }
* } // all memory allocated is released here
* }
*
@ -253,8 +253,8 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
* {@code S1, S2} returned by this method, the following invariant must hold:
*
* {@snippet lang = java:
* S1.overlappingSlice(S2).isEmpty() == true
*}
* S1.asOverlappingSlice(S2).isEmpty() == true
* }
*
* @param byteSize the size (in bytes) of the off-heap memory block backing the native memory segment.
* @param byteAlignment the alignment constraint (in bytes) of the off-heap region of memory backing the native memory segment.

View File

@ -77,7 +77,7 @@ import java.util.stream.Stream;
* {@snippet lang = java:
* Linker linker = Linker.nativeLinker();
* MethodHandle strlen = linker.downcallHandle(
* linker.defaultLookup().find("strlen").get(),
* linker.defaultLookup().find("strlen").orElseThrow(),
* FunctionDescriptor.of(JAVA_LONG, ADDRESS)
* );
* }
@ -91,9 +91,9 @@ import java.util.stream.Stream;
* The obtained downcall method handle is then invoked as follows:
*
* {@snippet lang = java:
* try (Arena arena = Arena.openConfined()) {
* try (Arena arena = Arena.ofConfined()) {
* MemorySegment str = arena.allocateUtf8String("Hello");
* long len = strlen.invoke(str); // 5
* long len = (long) strlen.invokeExact(str); // 5
* }
* }
* <h3 id="describing-c-sigs">Describing C signatures</h3>
@ -226,7 +226,7 @@ import java.util.stream.Stream;
* {@snippet lang = java:
* Linker linker = Linker.nativeLinker();
* MethodHandle qsort = linker.downcallHandle(
* linker.defaultLookup().find("qsort").get(),
* linker.defaultLookup().find("qsort").orElseThrow(),
* FunctionDescriptor.ofVoid(ADDRESS, JAVA_LONG, JAVA_LONG, ADDRESS)
* );
* }
@ -240,7 +240,7 @@ import java.util.stream.Stream;
*
* {@snippet lang = java:
* class Qsort {
* static int qsortCompare(MemorySegment elem1, MemorySegmet elem2) {
* static int qsortCompare(MemorySegment elem1, MemorySegment elem2) {
* return Integer.compare(elem1.get(JAVA_INT, 0), elem2.get(JAVA_INT, 0));
* }
* }
@ -268,7 +268,7 @@ import java.util.stream.Stream;
* {@snippet lang = java:
* try (Arena arena = Arena.ofConfined()) {
* MemorySegment comparFunc = linker.upcallStub(comparHandle, comparDesc, arena);
* MemorySegment array = session.allocateArray(0, 9, 3, 4, 6, 5, 1, 8, 2, 7);
* MemorySegment array = arena.allocateArray(JAVA_INT, 0, 9, 3, 4, 6, 5, 1, 8, 2, 7);
* qsort.invokeExact(array, 10L, 4L, comparFunc);
* int[] sorted = array.toArray(JAVA_INT); // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
* }
@ -307,12 +307,12 @@ import java.util.stream.Stream;
* Linker linker = Linker.nativeLinker();
*
* MethodHandle malloc = linker.downcallHandle(
* linker.defaultLookup().find("malloc").get(),
* linker.defaultLookup().find("malloc").orElseThrow(),
* FunctionDescriptor.of(ADDRESS, JAVA_LONG)
* );
*
* MethodHandle free = linker.downcallHandle(
* linker.defaultLookup().find("free").get(),
* linker.defaultLookup().find("free").orElseThrow(),
* FunctionDescriptor.ofVoid(ADDRESS)
* );
* }
@ -334,9 +334,15 @@ import java.util.stream.Stream;
* method, as follows:
*
* {@snippet lang = java:
* MemorySegment allocateMemory(long byteSize, Arena arena) {
* MemorySegment segment = (MemorySegment)malloc.invokeExact(byteSize); // size = 0, scope = always alive
* return segment.reinterpret(byteSize, arena, s -> free.invokeExact(s)); // size = byteSize, scope = arena.scope()
* MemorySegment allocateMemory(long byteSize, Arena arena) throws Throwable {
* MemorySegment segment = (MemorySegment) malloc.invokeExact(byteSize); // size = 0, scope = always alive
* return segment.reinterpret(byteSize, arena, s -> {
* try {
* free.invokeExact(s);
* } catch (Throwable e) {
* throw new RuntimeException(e);
* }
* }); // size = byteSize, scope = arena.scope()
* }
* }
*
@ -389,7 +395,7 @@ import java.util.stream.Stream;
* {@snippet lang = java:
* Linker linker = Linker.nativeLinker();
* MethodHandle printf = linker.downcallHandle(
* linker.defaultLookup().lookup("printf").get(),
* linker.defaultLookup().find("printf").orElseThrow(),
* FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT, JAVA_INT, JAVA_INT),
* Linker.Option.firstVariadicArg(1) // first int is variadic
* );
@ -616,12 +622,12 @@ public sealed interface Linker permits AbstractLinker {
* Linker.Option ccs = Linker.Option.captureCallState("errno");
* MethodHandle handle = Linker.nativeLinker().downcallHandle(targetAddress, FunctionDescriptor.ofVoid(), ccs);
*
* StructLayout capturedStateLayout = Linker.Option.capturedStateLayout();
* StructLayout capturedStateLayout = Linker.Option.captureStateLayout();
* VarHandle errnoHandle = capturedStateLayout.varHandle(PathElement.groupElement("errno"));
* try (Arena arena = Arena.ofConfined()) {
* MemorySegment capturedState = arena.allocate(capturedStateLayout);
* handle.invoke(capturedState);
* int errno = errnoHandle.get(capturedState);
* int errno = (int) errnoHandle.get(capturedState);
* // use errno
* }
* }

View File

@ -660,20 +660,20 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* padding layout} elements. As such, the following struct layout creation will fail with an exception:
*
* {@snippet lang = java:
* structLayout(JAVA_SHORT, JAVA_INT)
* structLayout(JAVA_SHORT, JAVA_INT);
* }
*
* To avoid the exception, clients can either insert additional padding layout elements:
*
* {@snippet lang = java:
* structLayout(JAVA_SHORT, MemoryLayout.ofPadding(2), JAVA_INT)
* structLayout(JAVA_SHORT, MemoryLayout.paddingLayout(2), JAVA_INT);
* }
*
* Or, alternatively, they can use a member layout which features a smaller alignment constraint. This will result
* in a <em>packed</em> struct layout:
*
* {@snippet lang = java:
* structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2))
* structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2));
* }
*/
static StructLayout structLayout(MemoryLayout... elements) {

View File

@ -142,7 +142,7 @@ import jdk.internal.vm.annotation.ForceInline;
* MethodType.methodType(long.class, long.class, long.class));
* intHandle = MethodHandles.filterCoordinates(intHandle, 1,
* MethodHandles.insertArguments(multiplyExact, 0, 4L));
* intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
* int value = (int) intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
* }
*
* Alternatively, complex var handles can can be obtained
@ -152,7 +152,7 @@ import jdk.internal.vm.annotation.ForceInline;
* {@snippet lang=java :
* MemorySegment segment = ...
* VarHandle intHandle = ValueLayout.JAVA_INT.arrayElementVarHandle();
* intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
* int value = (int) intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
* }
*
* <h2 id="slicing">Slicing memory segments</h2>
@ -756,8 +756,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* segment. Equivalent to (but likely more efficient than) the following code:
*
* {@snippet lang=java :
* byteHandle = MemoryLayout.ofSequence(ValueLayout.JAVA_BYTE)
* .varHandle(byte.class, MemoryLayout.PathElement.sequenceElement());
* var byteHandle = MemoryLayout.sequenceLayout(ValueLayout.JAVA_BYTE)
* .varHandle(MemoryLayout.PathElement.sequenceElement());
* for (long l = 0; l < segment.byteSize(); l++) {
* byteHandle.set(segment.address(), l, value);
* }
@ -785,7 +785,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <p>
* Calling this method is equivalent to the following code:
* {@snippet lang=java :
* MemorySegment.copy(src, 0, this, 0, src.byteSize);
* MemorySegment.copy(src, 0, this, 0, src.byteSize());
* }
* @param src the source segment.
* @throws IndexOutOfBoundsException if {@code src.byteSize() > this.byteSize()}.

View File

@ -117,8 +117,8 @@ public sealed interface ValueLayout extends MemoryLayout permits
* <p>
* Consider the following access expressions:
* {@snippet lang=java :
* int value1 = arrayHandle.get(10, 2, 4); // ok, accessed offset = 8176
* int value2 = arrayHandle.get(0, 0, 30); // out of bounds value for z
* int value1 = (int) arrayHandle.get(10, 2, 4); // ok, accessed offset = 8176
* int value2 = (int) arrayHandle.get(0, 0, 30); // out of bounds value for z
* }
* In the first case, access is well-formed, as the values for {@code x}, {@code y} and {@code z} conform to
* the bounds specified above. In the second case, access fails with {@link IndexOutOfBoundsException},

View File

@ -89,7 +89,7 @@
* Linker linker = Linker.nativeLinker();
* SymbolLookup stdlib = linker.defaultLookup();
* MethodHandle strlen = linker.downcallHandle(
* stdlib.find("strlen").get(),
* stdlib.find("strlen").orElseThrow(),
* FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)
* );
*

View File

@ -0,0 +1,679 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang.foreign.snippets;
import java.lang.foreign.AddressLayout;
import java.lang.foreign.Arena;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.Linker;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.SegmentAllocator;
import java.lang.foreign.SequenceLayout;
import java.lang.foreign.StructLayout;
import java.lang.foreign.SymbolLookup;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.nio.ByteOrder;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import static java.lang.foreign.MemoryLayout.sequenceLayout;
import static java.lang.foreign.MemoryLayout.structLayout;
import static java.lang.foreign.SymbolLookup.libraryLookup;
import static java.lang.foreign.SymbolLookup.loaderLookup;
import static java.lang.foreign.ValueLayout.*;
import static java.nio.ByteOrder.BIG_ENDIAN;
/**
* Snippets for the java.lang.foreign documentation.
*/
class Snippets {
/**
* Creates a new snippet.
*/
public Snippets() {
}
static class ArenaSnippets {
void globalArena() {
// @start region="global-allocation":
MemorySegment segment = Arena.global().allocate(100, 1); // @highlight regex='global()'
// ...
// segment is never deallocated!
// @end
}
void autoArena() {
// @start region="auto-allocation":
MemorySegment segment = Arena.ofAuto().allocate(100, 1); // @highlight regex='ofAuto()'
// ...
segment = null; // the segment region becomes available for deallocation after this point
// @end
}
void confinedArena() {
// @start region="confined-allocation":
MemorySegment segment = null;
try (Arena arena = Arena.ofConfined()) { // @highlight regex='ofConfined()'
segment = arena.allocate(100);
// ...
} // segment region deallocated here
segment.get(ValueLayout.JAVA_BYTE, 0); // throws IllegalStateException
// @end
}
static
// @start region="slicing-arena":
class SlicingArena implements Arena {
final Arena arena = Arena.ofConfined();
final SegmentAllocator slicingAllocator;
SlicingArena(long size) {
slicingAllocator = SegmentAllocator.slicingAllocator(arena.allocate(size));
}
public MemorySegment allocate(long byteSize, long byteAlignment) {
return slicingAllocator.allocate(byteSize, byteAlignment);
}
public MemorySegment.Scope scope() {
return arena.scope();
}
public void close() {
arena.close();
}
}
// @end
public static void main(String[] args) {
// @start region="slicing-arena-main":
try (Arena slicingArena = new SlicingArena(1000)) {
for (int i = 0; i < 10; i++) {
MemorySegment s = slicingArena.allocateArray(JAVA_INT, 1, 2, 3, 4, 5);
// ...
}
} // all memory allocated is released here
// @end
}
void arenaOverlap() {
try (var arena = Arena.ofConfined()) {
var S1 = arena.allocate(16L);
var S2 = arena.allocate(16L);
if (
// @start region="arena-overlap":
S1.asOverlappingSlice(S2).isEmpty() == true
// @end
) {}
}
}
}
static class AddressLayoutSnippets {
void withTargetLayout() {
AddressLayout addressLayout = ADDRESS;
AddressLayout unboundedLayout = addressLayout.withTargetLayout(
sequenceLayout(ValueLayout.JAVA_BYTE));
}
}
static class FunctionDescriptionSnippets {
}
static class GroupLayoutSnippets {
}
static class LinkerSnippets {
void downcall() throws Throwable {
Linker linker = Linker.nativeLinker();
MethodHandle strlen = linker.downcallHandle(
linker.defaultLookup().find("strlen").orElseThrow(),
FunctionDescriptor.of(JAVA_LONG, ADDRESS)
);
try (Arena arena = Arena.ofConfined()) {
MemorySegment str = arena.allocateUtf8String("Hello");
long len = (long) strlen.invokeExact(str); // 5
}
}
void qsort() throws Throwable {
Linker linker = Linker.nativeLinker();
MethodHandle qsort = linker.downcallHandle(
linker.defaultLookup().find("qsort").orElseThrow(),
FunctionDescriptor.ofVoid(ADDRESS, JAVA_LONG, JAVA_LONG, ADDRESS)
);
class Qsort {
static int qsortCompare(MemorySegment elem1, MemorySegment elem2) {
return Integer.compare(elem1.get(JAVA_INT, 0), elem2.get(JAVA_INT, 0));
}
}
FunctionDescriptor compareDesc = FunctionDescriptor.of(JAVA_INT,
ADDRESS.withTargetLayout(JAVA_INT),
ADDRESS.withTargetLayout(JAVA_INT));
MethodHandle compareHandle = MethodHandles.lookup()
.findStatic(Qsort.class, "qsortCompare",
compareDesc.toMethodType());
try (Arena arena = Arena.ofConfined()) {
MemorySegment compareFunc = linker.upcallStub(compareHandle, compareDesc, arena);
MemorySegment array = arena.allocateArray(JAVA_INT, 0, 9, 3, 4, 6, 5, 1, 8, 2, 7);
qsort.invokeExact(array, 10L, 4L, compareFunc);
int[] sorted = array.toArray(JAVA_INT); // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
}
}
void returnPointer() throws Throwable {
Linker linker = Linker.nativeLinker();
MethodHandle malloc = linker.downcallHandle(
linker.defaultLookup().find("malloc").orElseThrow(),
FunctionDescriptor.of(ADDRESS, JAVA_LONG)
);
MethodHandle free = linker.downcallHandle(
linker.defaultLookup().find("free").orElseThrow(),
FunctionDescriptor.ofVoid(ADDRESS)
);
MemorySegment segment = (MemorySegment) malloc.invokeExact(100);
class AllocateMemory {
MemorySegment allocateMemory(long byteSize, Arena arena) throws Throwable {
MemorySegment segment = (MemorySegment) malloc.invokeExact(byteSize); // size = 0, scope = always alive
return segment.reinterpret(byteSize, arena, s -> {
try {
free.invokeExact(s);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}); // size = byteSize, scope = arena.scope()
}
}
class AllocateMemory2 {
MemorySegment allocateMemory(long byteSize, Arena arena) {
MemorySegment segment = trySupplier(() -> (MemorySegment) malloc.invokeExact(byteSize)); // size = 0, scope = always alive
return segment.reinterpret(byteSize, arena, s -> trySupplier(() -> free.invokeExact(s))); // size = byteSize, scope = arena.scope()
}
@FunctionalInterface
interface ThrowingSupplier<T> {
T get() throws Throwable;
}
<T> T trySupplier(ThrowingSupplier<? extends T> supplier) {
try {
return supplier.get();
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
}
class AllocateMemory3 {
MemorySegment allocateMemory(long byteSize, Arena arena) throws Throwable {
MemorySegment segment = (MemorySegment) malloc.invokeExact(byteSize); // size = 0, scope = always alive
return segment.reinterpret(byteSize, arena, this::freeMemory); // size = byteSize, scope = arena.scope()
}
void freeMemory(MemorySegment segment) {
try {
free.invokeExact(segment);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
}
void variadicFunc() throws Throwable {
Linker linker = Linker.nativeLinker();
MethodHandle printf = linker.downcallHandle(
linker.defaultLookup().find("printf").orElseThrow(),
FunctionDescriptor.of(JAVA_INT, ADDRESS, JAVA_INT, JAVA_INT, JAVA_INT),
Linker.Option.firstVariadicArg(1) // first int is variadic
);
try (Arena arena = Arena.ofConfined()) {
int res = (int) printf.invokeExact(arena.allocateUtf8String("%d plus %d equals %d"), 2, 2, 4); //prints "2 plus 2 equals 4"
}
}
void downcallHandle() {
Linker linker = Linker.nativeLinker();
FunctionDescriptor function = null;
MemorySegment symbol = null;
linker.downcallHandle(function).bindTo(symbol);
}
void captureCallState() throws Throwable {
MemorySegment targetAddress = null; // ...
Linker.Option ccs = Linker.Option.captureCallState("errno");
MethodHandle handle = Linker.nativeLinker().downcallHandle(targetAddress, FunctionDescriptor.ofVoid(), ccs);
StructLayout capturedStateLayout = Linker.Option.captureStateLayout();
VarHandle errnoHandle = capturedStateLayout.varHandle(PathElement.groupElement("errno"));
try (Arena arena = Arena.ofConfined()) {
MemorySegment capturedState = arena.allocate(capturedStateLayout);
handle.invoke(capturedState);
int errno = (int) errnoHandle.get(capturedState);
// use errno
}
}
void captureStateLayout() {
String capturedNames = Linker.Option.captureStateLayout().memberLayouts().stream()
.map(MemoryLayout::name)
.flatMap(Optional::stream)
.map(Objects::toString)
.collect(Collectors.joining(", "));
}
}
static class MemoryLayoutSnippets {
void header() throws Throwable {
SequenceLayout taggedValues = sequenceLayout(5,
structLayout(
ValueLayout.JAVA_BYTE.withName("kind"),
MemoryLayout.paddingLayout(24),
ValueLayout.JAVA_INT.withName("value")
)
).withName("TaggedValues");
long valueOffset = taggedValues.byteOffset(PathElement.sequenceElement(0),
PathElement.groupElement("value")); // yields 4
MemoryLayout value = taggedValues.select(PathElement.sequenceElement(),
PathElement.groupElement("value"));
VarHandle valueHandle = taggedValues.varHandle(PathElement.sequenceElement(),
PathElement.groupElement("value"));
MethodHandle offsetHandle = taggedValues.byteOffsetHandle(PathElement.sequenceElement(),
PathElement.groupElement("kind"));
long offset1 = (long) offsetHandle.invokeExact(1L); // 8
long offset2 = (long) offsetHandle.invokeExact(2L); // 16
}
void sliceHandle() {
MemorySegment segment = null;
long offset = 0;
MemoryLayout layout = null;
segment.asSlice(offset, layout.byteSize());
}
void sequenceLayout0() {
MemoryLayout elementLayout = JAVA_INT;
sequenceLayout(Long.MAX_VALUE / elementLayout.byteSize(), elementLayout);
}
void structLayout0() {
MemoryLayout elementLayout = JAVA_INT;
structLayout(JAVA_SHORT, JAVA_INT);
structLayout(JAVA_SHORT, MemoryLayout.paddingLayout(16), JAVA_INT);
structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2));
}
}
static class MemorySegmentSnippets {
void header() throws NoSuchMethodException, IllegalAccessException {
{
MemorySegment segment = null; // ...
int value = segment.get(ValueLayout.JAVA_INT, 0);
}
{
MemorySegment segment = null; // ...
int value = segment.get(ValueLayout.JAVA_INT.withOrder(BIG_ENDIAN), 0);
}
{
MemorySegment segment = null; // ...
VarHandle intHandle = MethodHandles.memorySegmentViewVarHandle(ValueLayout.JAVA_INT);
MethodHandle multiplyExact = MethodHandles.lookup()
.findStatic(Math.class, "multiplyExact",
MethodType.methodType(long.class, long.class, long.class));
intHandle = MethodHandles.filterCoordinates(intHandle, 1,
MethodHandles.insertArguments(multiplyExact, 0, 4L));
int value = (int) intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
}
{
MemorySegment segment = null; // ...
VarHandle intHandle = ValueLayout.JAVA_INT.arrayElementVarHandle();
int value = (int) intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
}
{
Arena arena = Arena.ofConfined();
MemorySegment segment = arena.allocate(100);
MemorySegment slice = segment.asSlice(50, 10);
slice.get(ValueLayout.JAVA_INT, 20); // Out of bounds!
arena.close();
slice.get(ValueLayout.JAVA_INT, 0); // Already closed!
}
{
try (Arena arena = Arena.ofShared()) {
SequenceLayout SEQUENCE_LAYOUT = MemoryLayout.sequenceLayout(1024, ValueLayout.JAVA_INT);
MemorySegment segment = arena.allocate(SEQUENCE_LAYOUT);
int sum = segment.elements(ValueLayout.JAVA_INT).parallel()
.mapToInt(s -> s.get(ValueLayout.JAVA_INT, 0))
.sum();
}
}
{
MemorySegment byteSegment = MemorySegment.ofArray(new byte[10]);
byteSegment.get(ValueLayout.JAVA_INT, 0); // fails: layout alignment is 4, segment max alignment is 1
}
{
MemorySegment longSegment = MemorySegment.ofArray(new long[10]);
longSegment.get(ValueLayout.JAVA_INT, 0); // ok: layout alignment is 4, segment max alignment is 8
}
{
MemorySegment byteSegment = MemorySegment.ofArray(new byte[10]);
byteSegment.get(ValueLayout.JAVA_INT_UNALIGNED, 0); // ok: layout alignment is 1, segment max alignment is 1
}
{
MemorySegment segment = null;
long offset = 42;
MemorySegment z = segment.get(ValueLayout.ADDRESS, offset); // size = 0
MemorySegment ptr = z.reinterpret(16); // size = 16
int x = ptr.getAtIndex(ValueLayout.JAVA_INT, 3); // ok
}
{
MemorySegment segment = null;
long offset = 42;
MemorySegment ptr = null;
try (Arena arena = Arena.ofConfined()) {
MemorySegment z = segment.get(ValueLayout.ADDRESS, offset); // size = 0, scope = always alive
ptr = z.reinterpret(16, arena, null); // size = 4, scope = arena.scope()
int x = ptr.getAtIndex(ValueLayout.JAVA_INT, 3); // ok
}
int x = ptr.getAtIndex(ValueLayout.JAVA_INT, 3); // throws IllegalStateException
}
{
MemorySegment segment = null;
long offset = 42;
AddressLayout intArrPtrLayout = ValueLayout.ADDRESS.withTargetLayout(
MemoryLayout.sequenceLayout(4, ValueLayout.JAVA_INT)); // layout for int (*ptr)[4]
MemorySegment ptr = segment.get(intArrPtrLayout, offset); // size = 16
int x = ptr.getAtIndex(ValueLayout.JAVA_INT, 3); // ok
}
}
boolean isAligned(MemorySegment segment, long offset, MemoryLayout layout) {
return ((segment.address() + offset) % layout.byteAlignment()) == 0;
}
void elements() {
MemorySegment segment = null;
MemoryLayout elementLayout = JAVA_INT;
StreamSupport.stream(segment.spliterator(elementLayout), false);
}
void asSlice() {
MemorySegment segment = null;
long offset = 42;
MemoryLayout layout = JAVA_INT;
segment.asSlice(offset, layout.byteSize(), 1);
segment.asSlice(offset, layout.byteSize(), layout.byteAlignment());
segment.asSlice(offset, segment.byteSize() - offset);
}
void reinterpret() {
MemorySegment segment = null;
MemorySegment cleanupSegment = MemorySegment.ofAddress(segment.address());
}
void segmentOffset() {
MemorySegment segment = null;
MemorySegment other = null;
long offset = other.address() - segment.address();
}
void fill() {
MemorySegment segment = null;
byte value = 42;
var byteHandle = MemoryLayout.sequenceLayout(ValueLayout.JAVA_BYTE)
.varHandle(MemoryLayout.PathElement.sequenceElement());
for (long l = 0; l < segment.byteSize(); l++) {
byteHandle.set(segment.address(), l, value);
}
}
void copyFrom() {
MemorySegment src = null;
MemorySegment dst = null;
// MemorySegment.copy(src, 0, this, 0, src.byteSize());
MemorySegment.copy(src, 0, dst, 0, src.byteSize());
}
void copy() {
MemorySegment srcSegment = null;
long srcOffset = 42;
MemorySegment dstSegment = null;
long dstOffset = 13;
long bytes = 3;
MemorySegment.copy(srcSegment, ValueLayout.JAVA_BYTE, srcOffset, dstSegment, ValueLayout.JAVA_BYTE, dstOffset, bytes);
}
}
static class PackageInfoSnippets {
void header() throws Throwable {
try (Arena arena = Arena.ofConfined()) {
MemorySegment segment = arena.allocate(10 * 4);
for (int i = 0; i < 10; i++) {
segment.setAtIndex(ValueLayout.JAVA_INT, i, i);
}
}
Linker linker = Linker.nativeLinker();
SymbolLookup stdlib = linker.defaultLookup();
MethodHandle strlen = linker.downcallHandle(
stdlib.find("strlen").orElseThrow(),
FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)
);
try (Arena arena = Arena.ofConfined()) {
MemorySegment cString = arena.allocateUtf8String("Hello");
long len = (long) strlen.invokeExact(cString); // 5
}
}
}
static class PaddingLayoutSnippets {
}
static class SegmentAllocatorSnippets {
void prefixAllocator() {
MemorySegment segment = null; //...
SegmentAllocator prefixAllocator = (size, align) -> segment.asSlice(0, size);
}
}
static class SequenceLayoutSnippets {
void header() {
MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN));
MemoryLayout.structLayout(
ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN),
ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN),
ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN));
}
void reshape() {
var seq = MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT));
var reshapeSeq = MemoryLayout.sequenceLayout(2, MemoryLayout.sequenceLayout(6, ValueLayout.JAVA_INT));
var reshapeSeqImplicit1 = seq.reshape(-1, 6);
var reshapeSeqImplicit2 = seq.reshape(2, -1);
}
void flatten() {
var seq = MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT));
var flattenedSeq = MemoryLayout.sequenceLayout(12, ValueLayout.JAVA_INT);
}
}
static class StructLayoutSnippets {
}
static class SymbolLookupSnippets {
void header() {
try (Arena arena = Arena.ofConfined()) {
SymbolLookup libGL = libraryLookup("libGL.so", arena); // libGL.so loaded here
MemorySegment glGetString = libGL.find("glGetString").orElseThrow();
// ...
} // libGL.so unloaded here
System.loadLibrary("GL"); // libGL.so loaded here
// ...
SymbolLookup libGL = loaderLookup();
MemorySegment glGetString = libGL.find("glGetString").orElseThrow();
Arena arena = Arena.ofAuto();
libraryLookup("libGL.so", arena).find("glGetString").isPresent(); // true
loaderLookup().find("glGetString").isPresent(); // false
libraryLookup("libGL.so", arena).find("glGetString").isPresent(); // true
loaderLookup().find("glGetString").isPresent(); // false
Linker nativeLinker = Linker.nativeLinker();
SymbolLookup stdlib = nativeLinker.defaultLookup();
MemorySegment malloc = stdlib.find("malloc").orElseThrow();
}
}
static class UnionLayoutSnippets {
}
static class ValueLayoutSnippets {
void arrayElementVarHandle() {
VarHandle arrayHandle = ValueLayout.JAVA_INT.arrayElementVarHandle(10, 20);
SequenceLayout arrayLayout = MemoryLayout.sequenceLayout(
MemoryLayout.sequenceLayout(10,
MemoryLayout.sequenceLayout(20, ValueLayout.JAVA_INT)));
int value1 = (int) arrayHandle.get(10, 2, 4); // ok, accessed offset = 8176
int value2 = (int) arrayHandle.get(0, 0, 30); // out of bounds value for z
}
void statics() {
ADDRESS.withByteAlignment(1);
JAVA_CHAR.withByteAlignment(1);
JAVA_SHORT.withByteAlignment(1);
JAVA_INT.withByteAlignment(1);
JAVA_LONG.withByteAlignment(1);
JAVA_FLOAT.withByteAlignment(1);
JAVA_DOUBLE.withByteAlignment(1);
}
}
}