8308281: Java snippets in the FFM API need to be updated
Reviewed-by: mcimadamore
This commit is contained in:
parent
26227a6ff8
commit
eb11508eff
@ -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.
|
||||
|
@ -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
|
||||
* }
|
||||
* }
|
||||
|
@ -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) {
|
||||
|
@ -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()}.
|
||||
|
@ -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},
|
||||
|
@ -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)
|
||||
* );
|
||||
*
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user