diff --git a/src/java.base/share/classes/java/lang/foreign/Arena.java b/src/java.base/share/classes/java/lang/foreign/Arena.java
index 287f466b7f7..f111368d7d5 100644
--- a/src/java.base/share/classes/java/lang/foreign/Arena.java
+++ b/src/java.base/share/classes/java/lang/foreign/Arena.java
@@ -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
* after the automatic arena (and all the segments allocated by it) become
* unreachable, 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.
diff --git a/src/java.base/share/classes/java/lang/foreign/Linker.java b/src/java.base/share/classes/java/lang/foreign/Linker.java
index d192c46148a..8a57f51d150 100644
--- a/src/java.base/share/classes/java/lang/foreign/Linker.java
+++ b/src/java.base/share/classes/java/lang/foreign/Linker.java
@@ -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
* }
* }
*
Describing C signatures
@@ -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
* }
* }
diff --git a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
index 0734d3678da..78f3e6758f6 100644
--- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
@@ -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 packed struct layout:
*
* {@snippet lang = java:
- * structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2))
+ * structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2));
* }
*/
static StructLayout structLayout(MemoryLayout... elements) {
diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java
index 7efc8ef8da0..36e2decc4dd 100644
--- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java
+++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java
@@ -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
* }
*
* Slicing memory segments
@@ -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 {
*
* 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()}.
diff --git a/src/java.base/share/classes/java/lang/foreign/ValueLayout.java b/src/java.base/share/classes/java/lang/foreign/ValueLayout.java
index 61ddd50e0a1..88163d61054 100644
--- a/src/java.base/share/classes/java/lang/foreign/ValueLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/ValueLayout.java
@@ -117,8 +117,8 @@ public sealed interface ValueLayout extends MemoryLayout permits
*
* 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},
diff --git a/src/java.base/share/classes/java/lang/foreign/package-info.java b/src/java.base/share/classes/java/lang/foreign/package-info.java
index a0ec03854c9..c905be4c249 100644
--- a/src/java.base/share/classes/java/lang/foreign/package-info.java
+++ b/src/java.base/share/classes/java/lang/foreign/package-info.java
@@ -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)
* );
*
diff --git a/src/java.base/share/classes/java/lang/foreign/snippet-files/Snippets.java b/src/java.base/share/classes/java/lang/foreign/snippet-files/Snippets.java
new file mode 100644
index 00000000000..b2143fe3c55
--- /dev/null
+++ b/src/java.base/share/classes/java/lang/foreign/snippet-files/Snippets.java
@@ -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 get() throws Throwable;
+
+ }
+
+ 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);
+ }
+
+ }
+
+}