8308645: Javadoc of FFM API needs to be refreshed

8309398: ValueLayout:: arrayElementVarHandle doesn't throws UnsupportedOperationException - if byteAlignment() > byteSize()
8308812: SequenceLayout::withElementCount(long elementCount) doesn't throw IllegalArgumentException - if elementCount < 0 for some cases

Reviewed-by: jvernee
This commit is contained in:
Maurizio Cimadamore 2023-06-12 15:55:49 +00:00
parent 07275072aa
commit a6ad42e00e
28 changed files with 826 additions and 607 deletions

View File

@ -37,7 +37,7 @@ import java.util.Optional;
/**
* A value layout used to model the address of some region of memory. The carrier associated with an address layout is
* {@code MemorySegment.class}. The size and alignment of an address layout are platform dependent
* {@code MemorySegment.class}. The size and alignment of an address layout are platform-dependent
* (e.g. on a 64-bit platform, the size and alignment of an address layout are set to 8 bytes).
* <p>
* An address layout may optionally feature a {@linkplain #targetLayout() target layout}. An address layout with
@ -113,9 +113,9 @@ public sealed interface AddressLayout extends ValueLayout permits ValueLayouts.O
/**
* Returns an address layout with the same carrier, alignment constraint, name and order as this address layout,
* but without any specified target layout.
* <p>
* This can be useful to compare two address layouts that have different target layouts, but are otherwise equal.
* but with no target layout.
*
* @apiNote This can be useful to compare two address layouts that have different target layouts, but are otherwise equal.
*
* @return an address layout with same characteristics as this layout, but with no target layout.
* @see #targetLayout()

View File

@ -56,7 +56,7 @@ import java.lang.foreign.MemorySegment.Scope;
* Alternatively, clients can obtain an {@linkplain Arena#ofAuto() automatic arena}, that is an arena
* which features a <em>bounded lifetime</em> that is managed, automatically, by the garbage collector. As such, the regions
* 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
* <em>after</em> the automatic arena (and all the segments allocated by it) becomes
* <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>, as shown below:
* {@snippet lang = java:
* MemorySegment segment = Arena.ofAuto().allocate(100, 1); // @highlight regex='ofAuto()'
@ -202,7 +202,7 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
/**
* Creates a new arena that is managed, automatically, by the garbage collector.
* Segments obtained with the returned arena can be
* Segments allocated with the returned arena can be
* {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
* Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}.
*
@ -213,7 +213,7 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
}
/**
* Obtains the global arena. Segments obtained with the global arena can be
* Obtains the global arena. Segments allocated with the global arena can be
* {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
* Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}.
*
@ -227,14 +227,17 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
}
/**
* {@return a new confined arena, owned by the current thread}
* {@return a new confined arena} Segments allocated with the confined arena can be
* {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the thread that created the arena,
* the arena's <em>owner thread</em>.
*/
static Arena ofConfined() {
return MemorySessionImpl.createConfined(Thread.currentThread()).asArena();
}
/**
* {@return a new shared arena}
* {@return a new shared arena} Segments allocated with the global arena can be
* {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
*/
static Arena ofShared() {
return MemorySessionImpl.createShared().asArena();
@ -244,7 +247,7 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
* Returns a native memory segment with the given size (in bytes) and alignment constraint (in bytes).
* The returned segment is associated with this {@linkplain #scope() arena scope}.
* The segment's {@link MemorySegment#address() address} is the starting address of the
* allocated off-heap memory region backing the segment, and the address is
* allocated off-heap region of memory backing the segment, and the address is
* aligned according the provided alignment constraint.
*
* @implSpec
@ -256,14 +259,14 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
* S1.asOverlappingSlice(S2).isEmpty() == true
* }
*
* @param byteSize the size (in bytes) of the off-heap memory block backing the native memory segment.
* @param byteSize the size (in bytes) of the off-heap region of memory backing the native memory segment.
* @param byteAlignment the alignment constraint (in bytes) of the off-heap region of memory backing the native memory segment.
* @return a new native memory segment.
* @throws IllegalArgumentException if {@code bytesSize < 0}, {@code alignmentBytes <= 0}, or if {@code alignmentBytes}
* @throws IllegalArgumentException if {@code bytesSize < 0}, {@code byteAlignment <= 0}, or if {@code byteAlignment}
* is not a power of 2.
* @throws IllegalStateException if this arena has already been {@linkplain #close() closed}.
* @throws WrongThreadException if this arena is confined, and this method is called from a thread {@code T}
* other than the arena owner thread.
* @throws WrongThreadException if this arena is confined, and this method is called from a thread
* other than the arena's owner thread.
*/
@Override
default MemorySegment allocate(long byteSize, long byteAlignment) {
@ -293,9 +296,9 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
* @throws IllegalStateException if the arena has already been closed.
* @throws IllegalStateException if a segment associated with this arena is being accessed concurrently, e.g.
* by a {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle}.
* @throws WrongThreadException if this arena is confined, and this method is called from a thread {@code T}
* other than the arena owner thread.
* @throws UnsupportedOperationException if this arena does not support explicit closure.
* @throws WrongThreadException if this arena is confined, and this method is called from a thread
* other than the arena's owner thread.
* @throws UnsupportedOperationException if this arena cannot be closed explicitly.
*/
@Override
void close();

View File

@ -34,9 +34,9 @@ import jdk.internal.foreign.FunctionDescriptorImpl;
import jdk.internal.javac.PreviewFeature;
/**
* A function descriptor models the signature of foreign functions. A function descriptor is made up of zero or more
* argument layouts and zero or one return layout. A function descriptor is typically used when creating
* {@linkplain Linker#downcallHandle(MemorySegment, FunctionDescriptor, Linker.Option...) downcall method handles} or
* A function descriptor models the signature of a foreign function. A function descriptor is made up of zero or more
* argument layouts, and zero or one return layout. A function descriptor is used to create
* {@linkplain Linker#downcallHandle(MemorySegment, FunctionDescriptor, Linker.Option...) downcall method handles} and
* {@linkplain Linker#upcallStub(MethodHandle, FunctionDescriptor, Arena, Linker.Option...) upcall stubs}.
*
* @implSpec
@ -49,21 +49,21 @@ import jdk.internal.javac.PreviewFeature;
public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
/**
* {@return the return layout (if any) associated with this function descriptor}
* {@return the return layout (if any) of this function descriptor}
*/
Optional<MemoryLayout> returnLayout();
/**
* {@return the argument layouts associated with this function descriptor (as an immutable list)}.
* {@return the argument layouts of this function descriptor (as an unmodifiable list)}.
*/
List<MemoryLayout> argumentLayouts();
/**
* Returns a function descriptor with the given argument layouts appended to the argument layout array
* Returns a function descriptor with the given argument layouts appended to the argument layouts
* of this function descriptor.
* @param addedLayouts the argument layouts to append.
* @throws IllegalArgumentException if one of the layouts in {@code addedLayouts} is a padding layout.
* @return the new function descriptor.
* @return a new function descriptor, with the provided additional argument layouts.
*/
FunctionDescriptor appendArgumentLayouts(MemoryLayout... addedLayouts);
@ -72,42 +72,38 @@ public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
* layout array of this function descriptor.
* @param index the index at which to insert the arguments
* @param addedLayouts the argument layouts to insert at given index.
* @return the new function descriptor.
* @return a new function descriptor, with the provided additional argument layouts.
* @throws IllegalArgumentException if one of the layouts in {@code addedLayouts} is a padding layout.
* @throws IllegalArgumentException if {@code index < 0 || index > argumentLayouts().size()}.
*/
FunctionDescriptor insertArgumentLayouts(int index, MemoryLayout... addedLayouts);
/**
* Returns a function descriptor with the given memory layout as the new return layout.
* Returns a function descriptor with the provided return layout.
* @param newReturn the new return layout.
* @throws IllegalArgumentException if {@code newReturn} is a padding layout.
* @return the new function descriptor.
* @return a new function descriptor, with the provided return layout.
*/
FunctionDescriptor changeReturnLayout(MemoryLayout newReturn);
/**
* Returns a function descriptor with the return layout dropped. This is useful to model functions
* which return no values.
* @return the new function descriptor.
* {@return a new function descriptor, with no return layout}
*/
FunctionDescriptor dropReturnLayout();
/**
* Returns the method type consisting of the carrier types of the layouts in this function descriptor.
* <p>
* The carrier type of a layout is determined as follows:
* The carrier type of a layout {@code L} is determined as follows:
* <ul>
* <li>If the layout is a {@link ValueLayout} the carrier type is determined through {@link ValueLayout#carrier()}.</li>
* <li>If the layout is a {@link GroupLayout} or a {@link SequenceLayout}, the carrier type is {@link MemorySegment}.</li>
* <li>If {@code L} is a {@link ValueLayout} the carrier type is determined through {@link ValueLayout#carrier()}.</li>
* <li>If {@code L} is a {@link GroupLayout} or a {@link SequenceLayout}, the carrier type is {@link MemorySegment}.</li>
* </ul>
*
* @apiNote A function descriptor cannot, by construction, contain any padding layouts. As such, it is not
* necessary to specify how padding layout should be mapped to carrier types.
*
* @return the method type consisting of the carrier types of the layouts in this function descriptor
* @throws IllegalArgumentException if one or more layouts in the function descriptor can not be mapped to carrier
* types (e.g. if they are sequence layouts or padding layouts).
* @return the method type consisting of the carrier types of the layouts in this function descriptor.
*/
MethodType toMethodType();
@ -117,7 +113,7 @@ public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
* @param argLayouts the argument layouts.
* @throws IllegalArgumentException if {@code resLayout} is a padding layout.
* @throws IllegalArgumentException if one of the layouts in {@code argLayouts} is a padding layout.
* @return the new function descriptor.
* @return a new function descriptor with the provided return and argument layouts.
*/
static FunctionDescriptor of(MemoryLayout resLayout, MemoryLayout... argLayouts) {
Objects.requireNonNull(resLayout);
@ -126,10 +122,11 @@ public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
}
/**
* Creates a function descriptor with the given argument layouts and no return layout.
* Creates a function descriptor with the given argument layouts and no return layout. This is useful to model functions
* that return no values.
* @param argLayouts the argument layouts.
* @throws IllegalArgumentException if one of the layouts in {@code argLayouts} is a padding layout.
* @return the new function descriptor.
* @return a new function descriptor with the provided argument layouts.
*/
static FunctionDescriptor ofVoid(MemoryLayout... argLayouts) {
// Null checks are implicit in List.of(argLayouts)

View File

@ -29,10 +29,10 @@ import java.util.List;
import jdk.internal.javac.PreviewFeature;
/**
* A compound layout that aggregates multiple <em>member layouts</em>. There are two ways in which member layouts
* can be combined: if member layouts are laid out one after the other, the resulting group layout is said to be a <em>struct layout</em>
* (see {@link MemoryLayout#structLayout(MemoryLayout...)}); conversely, if all member layouts are laid out at the same starting offset,
* the resulting group layout is said to be a <em>union layout</em> (see {@link MemoryLayout#unionLayout(MemoryLayout...)}).
* A compound layout that is an aggregation of multiple, heterogeneous <em>member layouts</em>. There are two ways in which member layouts
* can be combined: if member layouts are laid out one after the other, the resulting group layout is a
* {@linkplain StructLayout struct layout}; conversely, if all member layouts are laid out at the same starting offset,
* the resulting group layout is a {@linkplain UnionLayout union layout}.
*
* @implSpec
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
@ -43,13 +43,11 @@ import jdk.internal.javac.PreviewFeature;
public sealed interface GroupLayout extends MemoryLayout permits StructLayout, UnionLayout {
/**
* Returns the member layouts associated with this group.
* {@return the member layouts of this group layout}
*
* @apiNote the order in which member layouts are returned is the same order in which member layouts have
* been passed to one of the group layout factory methods (see {@link MemoryLayout#structLayout(MemoryLayout...)},
* {@link MemoryLayout#unionLayout(MemoryLayout...)}).
*
* @return the member layouts associated with this group.
*/
List<MemoryLayout> memberLayouts();

View File

@ -197,16 +197,41 @@ import java.util.stream.Stream;
* </tbody>
* </table></blockquote>
* <p>
* All the native linker implementations limit the function descriptors that they support to those that contain
* only so-called <em>canonical</em> layouts. A canonical layout has the following characteristics:
* All native linker implementations operate on a subset of memory layouts. More formally, a layout {@code L}
* is supported by a native linker {@code NL} if:
* <ul>
* <li>{@code L} is a value layout {@code V} and {@code V.withoutName()} is {@linkplain MemoryLayout#equals(Object) equal}
* to one of the following layout constants:
* <ul>
* <li>{@link ValueLayout#JAVA_BOOLEAN}</li>
* <li>{@link ValueLayout#JAVA_BYTE}</li>
* <li>{@link ValueLayout#JAVA_CHAR}</li>
* <li>{@link ValueLayout#JAVA_SHORT}</li>
* <li>{@link ValueLayout#JAVA_INT}</li>
* <li>{@link ValueLayout#JAVA_LONG}</li>
* <li>{@link ValueLayout#JAVA_FLOAT}</li>
* <li>{@link ValueLayout#JAVA_DOUBLE}</li>
* </ul></li>
* <li>{@code L} is an address layout {@code A} and {@code A.withoutTargetLayout().withoutName()} is
* {@linkplain MemoryLayout#equals(Object) equal} to {@link ValueLayout#ADDRESS}</li>
* <li>{@code L} is a sequence layout {@code S} and all the following conditions hold:
* <ol>
* <li>Its alignment constraint is set to its <a href="MemoryLayout.html#layout-align">natural alignment</a></li>
* <li>If it is a {@linkplain ValueLayout value layout}, its {@linkplain ValueLayout#order() byte order} is
* the {@linkplain ByteOrder#nativeOrder() native byte order}.
* <li>If it is a {@linkplain GroupLayout group layout}, its size is a multiple of its alignment constraint, and</li>
* <li>It does not contain padding other than what is strictly required to align its non-padding layout elements,
* or to satisfy constraint 3</li>
* <li>the alignment constraint of {@code S} is set to its <a href="MemoryLayout.html#layout-align">natural alignment</a>, and</li>
* <li>{@code S.elementLayout()} is a layout supported by {@code NL}.</li>
* </ol>
* </li>
* <li>{@code L} is a group layout {@code G} and all the following conditions hold:
* <ol>
* <li>the alignment constraint of {@code G} is set to its <a href="MemoryLayout.html#layout-align">natural alignment</a>;</li>
* <li>the size of {@code G} is a multiple of its alignment constraint;</li>
* <li>each member layout in {@code G.memberLayouts()} is either a padding layout or a layout supported by {@code NL}, and</li>
* <li>{@code G} does not contain padding other than what is strictly required to align its non-padding layout elements, or to satisfy (2).</li>
* </ol>
* </li>
* </ul>
*
* A native linker only supports function descriptors whose argument/return layouts are layouts supported by that linker
* and are not sequence layouts.
*
* <h3 id="function-pointers">Function pointers</h3>
*
@ -317,8 +342,8 @@ import java.util.stream.Stream;
* );
* }
*
* When interacting with a native functions returning a pointer (such as {@code malloc}), the Java runtime has no insight
* into the size or the lifetime of the returned pointer. Consider the following code:
* When a native function returning a pointer (such as {@code malloc}) is invoked using a downcall method handle,
* the Java runtime has no insight into the size or the lifetime of the returned pointer. Consider the following code:
*
* {@snippet lang = java:
* MemorySegment segment = (MemorySegment)malloc.invokeExact(100);
@ -330,8 +355,8 @@ import java.util.stream.Stream;
* unsafely, resize the segment to the desired size (100, in this case). It might also be desirable to
* attach the segment to some existing {@linkplain Arena arena}, so that the lifetime of the region of memory
* backing the segment can be managed automatically, as for any other native segment created directly from Java code.
* Both these operations are accomplished using the restricted {@link MemorySegment#reinterpret(long, Arena, Consumer)}
* method, as follows:
* Both of these operations are accomplished using the restricted method {@link MemorySegment#reinterpret(long, Arena, Consumer)},
* as follows:
*
* {@snippet lang = java:
* MemorySegment allocateMemory(long byteSize, Arena arena) throws Throwable {
@ -415,12 +440,12 @@ import java.util.stream.Stream;
* }
*
* To perform an equivalent call using a downcall method handle we must create a function descriptor which
* describes the specialized signature of the C function we want to call. This descriptor must include layouts for any
* additional variadic argument we intend to provide. In this case, the specialized signature of the C
* function is {@code (char*, int, int, int)} as the format string accepts three integer parameters. Then, we need to use
* a linker option to specify the position of the first variadic layout in the provided function descriptor (starting from 0).
* In this case, since the first parameter is the format string (a non-variadic argument), the first variadic index
* needs to be set to 1, as follows:
* describes the specialized signature of the C function we want to call. This descriptor must include an additional layout
* for each variadic argument we intend to provide. In this case, the specialized signature of the C
* function is {@code (char*, int, int, int)} as the format string accepts three integer parameters. We then need to use
* a {@linkplain Linker.Option#firstVariadicArg(int) linker option} to specify the position of the first variadic layout
* in the provided function descriptor (starting from 0). In this case, since the first parameter is the format string
* (a non-variadic argument), the first variadic index needs to be set to 1, as follows:
*
* {@snippet lang = java:
* Linker linker = Linker.nativeLinker();
@ -447,10 +472,9 @@ import java.util.stream.Stream;
* through an invalid linkage request (e.g. by specifying a function descriptor featuring too many argument layouts),
* the result of such interaction is unspecified and can lead to JVM crashes.
* <p>
* When creating upcall stubs the linker runtime validates the type of the target method handle against the provided
* function descriptor and report an error if any mismatch is detected. As for downcalls, JVM crashes might occur,
* if the foreign code casts the function pointer associated with an upcall stub to a type
* that is incompatible with the provided function descriptor. Moreover, if the target method
* When an upcall stub is passed to a foreign function, a JVM crash might occur, if the foreign code casts the function pointer
* associated with the upcall stub to a type that is incompatible with the type of the upcall stub, and then attempts to
* invoke the function through the resulting function pointer. Moreover, if the method
* handle associated with an upcall stub returns a {@linkplain MemorySegment memory segment}, clients must ensure
* that this address cannot become invalid after the upcall completes. This can lead to unspecified behavior,
* and even JVM crashes, since an upcall is typically executed in the context of a downcall method handle invocation.
@ -464,7 +488,7 @@ import java.util.stream.Stream;
public sealed interface Linker permits AbstractLinker {
/**
* Returns a linker for the ABI associated with the underlying native platform. The underlying native platform
* {@return a linker for the ABI associated with the underlying native platform} The underlying native platform
* is the combination of OS and processor where the Java runtime is currently executing.
*
* @apiNote It is not currently possible to obtain a linker for a different combination of OS and processor.
@ -472,7 +496,6 @@ public sealed interface Linker permits AbstractLinker {
* linker are the native libraries loaded in the process where the Java runtime is currently executing. For example,
* on Linux, these libraries typically include {@code libc}, {@code libm} and {@code libdl}.
*
* @return a linker for the ABI associated with the underlying native platform.
* @throws UnsupportedOperationException if the underlying native platform is not supported.
*/
static Linker nativeLinker() {
@ -492,17 +515,20 @@ public sealed interface Linker permits AbstractLinker {
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
* restricted methods, and use safe and supported functionalities, where possible.
*
* @param symbol the address of the target function.
* @param function the function descriptor of the target function.
* @param options any linker options.
* @return a downcall method handle. The method handle type is <a href="Linker.html#downcall-method-handles"><em>inferred</em></a>
* @param address the native memory segment whose {@linkplain MemorySegment#address() base address} is the
* address of the target foreign function.
* @param function the function descriptor of the target foreign function.
* @param options the linker options associated with this linkage request.
* @return a downcall method handle.
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker.
* or if the symbol is {@link MemorySegment#NULL}
* @throws IllegalArgumentException if {@code !address.isNative()}, or if {@code address.equals(MemorySegment.NULL)}.
* @throws IllegalArgumentException if an invalid combination of linker options is given.
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled.
*
* @see SymbolLookup
*/
@CallerSensitive
MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Option... options);
MethodHandle downcallHandle(MemorySegment address, FunctionDescriptor function, Option... options);
/**
* Creates a method handle which is used to call a foreign function with the given signature.
@ -514,22 +540,22 @@ public sealed interface Linker permits AbstractLinker {
* downcall method handle accepts an additional leading parameter of type {@link SegmentAllocator}, which is used by
* the linker runtime to allocate the memory region associated with the struct returned by the downcall method handle.
* <p>
* Upon invoking a downcall method handle, the linker runtime will guarantee the following for any argument
* Upon invoking a downcall method handle, the linker provides the following guarantees for any argument
* {@code A} of type {@link MemorySegment} whose corresponding layout is an {@linkplain AddressLayout address layout}:
* <ul>
* <li>{@code A.scope().isAlive() == true}. Otherwise, the invocation throws {@link IllegalStateException};</li>
* <li>The invocation occurs in a thread {@code T} such that {@code A.isAccessibleBy(T) == true}.
* Otherwise, the invocation throws {@link WrongThreadException}; and</li>
* <li>{@code A} is kept alive during the invocation. For instance, if {@code A} has been obtained using a
* {@linkplain Arena#ofShared()} shared arena}, any attempt to {@linkplain Arena#close() close}
* the shared arena while the downcall method handle is executing will result in an {@link IllegalStateException}.</li>
* {@linkplain Arena#ofShared() shared arena}, any attempt to {@linkplain Arena#close() close}
* the arena while the downcall method handle is still executing will result in an {@link IllegalStateException}.</li>
*</ul>
* <p>
* Moreover, if the provided function descriptor's return layout is an {@linkplain AddressLayout address layout},
* invoking the returned method handle will return a native segment associated with
* a fresh scope that is always alive. Under normal conditions, the size of the returned segment is {@code 0}.
* However, if the function descriptor's return layout has a {@linkplain AddressLayout#targetLayout()} {@code T},
* then the size of the returned segment is set to {@code T.byteSize()}.
* However, if the function descriptor's return layout has a {@linkplain AddressLayout#targetLayout() target layout}
* {@code T}, then the size of the returned segment is set to {@code T.byteSize()}.
* <p>
* The returned method handle will throw an {@link IllegalArgumentException} if the {@link MemorySegment}
* representing the target address of the foreign function is the {@link MemorySegment#NULL} address.
@ -540,10 +566,9 @@ public sealed interface Linker permits AbstractLinker {
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
* restricted methods, and use safe and supported functionalities, where possible.
*
* @param function the function descriptor of the target function.
* @param options any linker options.
* @return a downcall method handle. The method handle type is <a href="Linker.html#downcall-method-handles"><em>inferred</em></a>
* from the provided function descriptor.
* @param function the function descriptor of the target foreign function.
* @param options the linker options associated with this linkage request.
* @return a downcall method handle.
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker.
* @throws IllegalArgumentException if an invalid combination of linker options is given.
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled.
@ -552,7 +577,7 @@ public sealed interface Linker permits AbstractLinker {
MethodHandle downcallHandle(FunctionDescriptor function, Option... options);
/**
* Creates a stub which can be passed to other foreign functions as a function pointer, associated with the given
* Creates an upcall stub which can be passed to other foreign functions as a function pointer, associated with the given
* arena. Calling such a function pointer from foreign code will result in the execution of the provided
* method handle.
* <p>
@ -564,14 +589,14 @@ public sealed interface Linker permits AbstractLinker {
* An upcall stub argument whose corresponding layout is an {@linkplain AddressLayout address layout}
* is a native segment associated with a fresh scope that is always alive.
* Under normal conditions, the size of this segment argument is {@code 0}.
* However, if the address layout has a {@linkplain AddressLayout#targetLayout()} {@code T}, then the size of the
* However, if the address layout has a {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size of the
* segment argument is set to {@code T.byteSize()}.
* <p>
* The target method handle should not throw any exceptions. If the target method handle does throw an exception,
* the VM will exit with a non-zero exit code. To avoid the VM aborting due to an uncaught exception, clients
* could wrap all code in the target method handle in a try/catch block that catches any {@link Throwable}, for
* instance by using the {@link java.lang.invoke.MethodHandles#catchException(MethodHandle, Class, MethodHandle)}
* method handle combinator, and handle exceptions as desired in the corresponding catch block.
* the JVM will terminate abruptly. To avoid this, clients should wrap the code in the target method handle in a
* try/catch block to catch any unexpected exceptions. This can be done using the
* {@link java.lang.invoke.MethodHandles#catchException(MethodHandle, Class, MethodHandle)} method handle combinator,
* and handle exceptions as desired in the corresponding catch block.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -581,11 +606,12 @@ public sealed interface Linker permits AbstractLinker {
* @param target the target method handle.
* @param function the upcall stub function descriptor.
* @param arena the arena associated with the returned upcall stub segment.
* @param options any linker options.
* @param options the linker options associated with this linkage request.
* @return a zero-length segment whose address is the address of the upcall stub.
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker.
* @throws IllegalArgumentException if it is determined that the target method handle can throw an exception, or if the target method handle
* has a type that does not match the upcall stub <a href="Linker.html#upcall-stubs"><em>inferred type</em></a>.
* @throws IllegalArgumentException if the type of {@code target} is incompatible with the
* type {@linkplain FunctionDescriptor#toMethodType() derived} from {@code function}.
* @throws IllegalArgumentException if it is determined that the target method handle can throw an exception.
* @throws IllegalStateException if {@code arena.scope().isAlive() == false}
* @throws WrongThreadException if {@code arena} is a confined arena, and this method is called from a
* thread {@code T}, other than the arena's owner thread.
@ -610,8 +636,7 @@ public sealed interface Linker permits AbstractLinker {
SymbolLookup defaultLookup();
/**
* A linker option is used to indicate additional linking requirements to the linker,
* besides what is described by a function descriptor.
* A linker option is used to provide additional parameters to a linkage request.
* @since 20
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
@ -619,9 +644,10 @@ public sealed interface Linker permits AbstractLinker {
permits LinkerOptions.LinkerOptionImpl {
/**
* {@return a linker option used to denote the index of the first variadic argument layout in a
* foreign function call}
* @param index the index of the first variadic argument in a downcall handle linkage request.
* {@return a linker option used to denote the index of the first variadic argument layout in the
* function descriptor associated with a downcall linkage request}
* @param index the index of the first variadic argument layout in the function descriptor associated
* with a downcall linkage request.
*/
static Option firstVariadicArg(int index) {
return new LinkerOptions.FirstVariadicArg(index);
@ -637,11 +663,12 @@ public sealed interface Linker permits AbstractLinker {
* For this purpose, a downcall method handle linked with this
* option will feature an additional {@link MemorySegment} parameter directly
* following the target address, and optional {@link SegmentAllocator} parameters.
* This parameter, called the 'capture state segment', represents the native segment into which
* This parameter, the <em>capture state segment</em>, represents the native segment into which
* the captured state is written.
* <p>
* The capture state segment should have the layout returned by {@linkplain #captureStateLayout}.
* This layout is a struct layout which has a named field for each captured value.
* The capture state segment must have size and alignment compatible with the layout returned by
* {@linkplain #captureStateLayout}. This layout is a struct layout which has a named field for
* each captured value.
* <p>
* Captured state can be retrieved from the capture state segment by constructing var handles
* from the {@linkplain #captureStateLayout capture state layout}.
@ -677,9 +704,9 @@ public sealed interface Linker permits AbstractLinker {
/**
* {@return a struct layout that represents the layout of the capture state segment that is passed
* to a downcall handle linked with {@link #captureCallState(String...)}}.
* to a downcall handle linked with {@link #captureCallState(String...)}}
* <p>
* The capture state layout is <em>platform dependent</em> but is guaranteed to be
* The capture state layout is <em>platform-dependent</em> but is guaranteed to be
* a {@linkplain StructLayout struct layout} containing only {@linkplain ValueLayout value layouts}
* and possibly {@linkplain PaddingLayout padding layouts}.
* As an example, on Windows, the returned layout might contain three value layouts named:
@ -688,13 +715,13 @@ public sealed interface Linker permits AbstractLinker {
* <li>WSAGetLastError</li>
* <li>errno</li>
* </ul>
* The following snipet shows how to obtain the names of the supported captured value layouts:
* <p>
* Clients can obtain the names of the supported captured value layouts as follows:
* {@snippet lang = java:
* String capturedNames = Linker.Option.captureStateLayout().memberLayouts().stream()
* List<String> capturedNames = Linker.Option.captureStateLayout().memberLayouts().stream()
* .map(MemoryLayout::name)
* .flatMap(Optional::stream)
* .map(Objects::toString)
* .collect(Collectors.joining(", "));
* .toList();
* }
*
* @see #captureCallState(String...)

View File

@ -33,7 +33,6 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;
import jdk.internal.foreign.LayoutPath;
@ -48,14 +47,19 @@ import jdk.internal.javac.PreviewFeature;
/**
* A memory layout describes the contents of a memory segment.
* There are two leaves in the layout hierarchy, <em>value layouts</em>, which are used to represent values of given size and kind (see
* {@link ValueLayout}) and <em>padding layouts</em> which are used, as the name suggests, to represent a portion of a memory
* segment whose contents should be ignored, and which are primarily present for alignment reasons (see {@link MemoryLayout#paddingLayout(long)}).
* Some common value layout constants are defined in the {@link ValueLayout} class.
* <p>
* More complex layouts can be derived from simpler ones: a <em>sequence layout</em> denotes a repetition of one or more
* element layout (see {@link SequenceLayout}); a <em>group layout</em> denotes an aggregation of (typically) heterogeneous
* member layouts (see {@link GroupLayout}).
* There are two leaves in the layout hierarchy, {@linkplain ValueLayout value layouts}, which are used to represent values of given size and kind (see
* and {@linkplain PaddingLayout padding layouts} which are used, as the name suggests, to represent a portion of a memory
* segment whose contents should be ignored, and which are primarily present for alignment reasons.
* Some common value layout constants, such as {@link ValueLayout#JAVA_INT} and {@link ValueLayout#JAVA_FLOAT_UNALIGNED}
* are defined in the {@link ValueLayout} class. A special kind of value layout, namely an {@linkplain AddressLayout address layout},
* is used to model values that denote the address of a region of memory.
* <p>
* More complex layouts can be derived from simpler ones: a {@linkplain SequenceLayout sequence layout} denotes a
* homogeneous repetition of zero or more occurrences of an element layout; a {@linkplain GroupLayout group layout}
* denotes a heterogeneous aggregation of zero or more member layouts. Group layouts come in two
* flavors: {@linkplain StructLayout struct layouts}, where member layouts are laid out one after the other, and
* {@linkplain UnionLayout union layouts} where member layouts are laid out at the same starting offset.
* <p>
* Layouts can be optionally associated with a <em>name</em>. A layout name can be referred to when
* constructing <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>.
@ -81,47 +85,50 @@ import jdk.internal.javac.PreviewFeature;
* ).withName("TaggedValues");
* }
*
* <h2 id="layout-align">Size, alignment and byte order</h2>
* <h2 id="layout-align">Characteristics of memory layouts</h2>
*
* All layouts have a size; layout size for value and padding layouts is always explicitly denoted; this means that a layout description
* always has the same size in bytes, regardless of the platform in which it is used. For derived layouts, the size is computed
* as follows:
* All layouts have a <em>size</em> (expressed in bytes), which is defined as follows:
* <ul>
* <li>for a sequence layout <em>S</em> whose element layout is <em>E</em> and size is <em>L</em>,
* the size of <em>S</em> is that of <em>E</em>, multiplied by <em>L</em></li>
* <li>for a group layout <em>G</em> with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose sizes are
* <em>S1</em>, <em>S2</em>, ... <em>Sn</em>, respectively, the size of <em>G</em> is either <em>S1 + S2 + ... + Sn</em> or
* <em>max(S1, S2, ... Sn)</em> depending on whether the group is a <em>struct</em> or an <em>union</em>, respectively</li>
* <li>The size of a value layout is determined by the {@linkplain ValueLayout#carrier()}
* associated with the value layout. That is, the constant {@link ValueLayout#JAVA_INT} has carrier {@code int}, and
* size of 4 bytes;</li>
* <li>The size of an address layout is platform-dependent. That is, the constant {@link ValueLayout#ADDRESS}
* has size of 8 bytes on a 64-bit platform;</li>
* <li>The size of a padding layout is always provided explicitly, on {@linkplain MemoryLayout#paddingLayout(long) construction};</li>
* <li>The size of a sequence layout whose element layout is <em>E</em> and element count is <em>L</em>,
* is the size of <em>E</em>, multiplied by <em>L</em>;</li>
* <li>The size of a struct layout with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose sizes are
* <em>S1</em>, <em>S2</em>, ... <em>Sn</em>, respectively, is <em>S1 + S2 + ... + Sn</em>;</li>
* <li>The size of a union layout <em>U</em> with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose sizes are
* <em>S1</em>, <em>S2</em>, ... <em>Sn</em>, respectively, is <em>max(S1, S2, ... Sn).</em></li>
* </ul>
* <p>
* Furthermore, all layouts feature a <em>natural alignment</em> which can be inferred as follows:
* Furthermore, all layouts have a <em>natural alignment</em> (expressed in bytes) which is defined as follows:
* <ul>
* <li>for a padding layout <em>L</em>, the natural alignment is 1, regardless of its size; that is, in the absence
* of an explicit alignment constraint, a padding layout should not affect the alignment constraint of the group
* layout it is nested into</li>
* <li>for a value layout <em>L</em> whose size is <em>N</em>, the natural alignment of <em>L</em> is <em>N</em></li>
* <li>for a sequence layout <em>S</em> whose element layout is <em>E</em>, the natural alignment of <em>S</em> is that of <em>E</em></li>
* <li>for a group layout <em>G</em> with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose alignments are
* <em>A1</em>, <em>A2</em>, ... <em>An</em>, respectively, the natural alignment of <em>G</em> is <em>max(A1, A2 ... An)</em></li>
* <li>The natural alignment of a padding layout is 1;</li>
* <li>The natural alignment of a value layout whose size is <em>N</em> is <em>N</em>;</li>
* <li>The natural alignment of a sequence layout whose element layout is <em>E</em> is the alignment of <em>E</em>;</li>
* <li>The natural alignment of a group layout with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose
* alignments are <em>A1</em>, <em>A2</em>, ... <em>An</em>, respectively, is <em>max(A1, A2 ... An)</em>.</li>
* </ul>
* A layout's natural alignment can be overridden if needed (see {@link MemoryLayout#withByteAlignment(long)}), which can be useful to describe
* hyper-aligned layouts.
* <p>
* All value layouts have an <em>explicit</em> byte order (see {@link java.nio.ByteOrder}) which is set when the layout is created.
* A layout's alignment can be overridden if needed (see {@link MemoryLayout#withByteAlignment(long)}), which can be useful to describe
* layouts with weaker or stronger alignment constraints.
*
* <h2 id="layout-paths">Layout paths</h2>
*
* A <em>layout path</em> originates from a <em>root</em> layout (typically a group or a sequence layout) and terminates
* at a layout nested within the root layout - this is the layout <em>selected</em> by the layout path.
* Layout paths are typically expressed as a sequence of one or more {@link PathElement} instances.
* A <em>layout path</em> is used to unambiguously select a layout that is nested in some other layout.
* Layout paths are typically expressed as a sequence of one or more {@linkplain PathElement path elements}.
* (A more formal definition of layout paths is provided <a href="#well-formedness">below</a>).
* <p>
* Layout paths are for example useful in order to obtain {@linkplain MemoryLayout#byteOffset(PathElement...) offsets} of
* arbitrarily nested layouts inside another layout, to quickly obtain a {@linkplain #varHandle(PathElement...) memory access handle}
* corresponding to the selected layout, or to {@linkplain #select(PathElement...) select} an arbitrarily nested layout inside
* another layout.
* Layout paths can be used to:
* <ul>
* <li>obtain {@linkplain MemoryLayout#byteOffset(PathElement...) offsets} of arbitrarily nested layouts;</li>
* <li>obtain a {@linkplain #varHandle(PathElement...) var handle} that can be used to access the value corresponding
* to the selected layout;</li>
* <li>{@linkplain #select(PathElement...) select} an arbitrarily nested layout.</li>
* </ul>
* <p>
* Such <em>layout paths</em> can be constructed programmatically using the methods in this class.
* For instance, given the {@code taggedValues} layout instance constructed as above, we can obtain the offset,
* For instance, given the {@code taggedValues} sequence layout constructed above, we can obtain the offset,
* in bytes, of the member layout named <code>value</code> in the <em>first</em> sequence element, as follows:
* {@snippet lang=java :
* long valueOffset = taggedValues.byteOffset(PathElement.sequenceElement(0),
@ -134,27 +141,26 @@ import jdk.internal.javac.PreviewFeature;
* PathElement.groupElement("value"));
* }
*
* Layout paths can feature one or more <em>free dimensions</em>. For instance, a layout path traversing
* an unspecified sequence element (that is, where one of the path component was obtained with the
* {@link PathElement#sequenceElement()} method) features an additional free dimension, which will have to be bound at runtime.
* This is important when obtaining a {@linkplain MethodHandles#memorySegmentViewVarHandle(ValueLayout) memory segment view var handle}
* from layouts, as in the following code:
* <h3 id="open-path-elements">Open path elements</h3>
*
* Some layout path elements, said <em>open path elements</em>, can select multiple layouts at once. For instance,
* the open path elements {@link PathElement#sequenceElement()}, {@link PathElement#sequenceElement(long, long)} select
* an unspecified element in a sequence layout. A var handle derived from a layout path containing one or more
* open path element features additional coordinates of type {@code long}, which can be used by clients to <em>bind</em>
* the open elements in the path:
*
* {@snippet lang=java :
* VarHandle valueHandle = taggedValues.varHandle(PathElement.sequenceElement(),
* PathElement.groupElement("value"));
* MemorySegment valuesSegment = ...
* int val = (int) valueHandle.get(valuesSegment, 2); // reads the "value" field of the third struct in the array
* }
*
* Since the layout path constructed in the above example features exactly one free dimension (as it doesn't specify
* <em>which</em> member layout named {@code value} should be selected from the enclosing sequence layout),
* it follows that the var handle {@code valueHandle} will feature an <em>additional</em> {@code long}
* access coordinate.
*
* <p>A layout path with free dimensions can also be used to create an offset-computing method handle, using the
* {@link #byteOffset(PathElement...)} or {@link #byteOffsetHandle(PathElement...)} method. Again, free dimensions are
* translated into {@code long} parameters of the created method handle. The method handle can be used to compute the
* offsets of elements of a sequence at different indices, by supplying these indices when invoking the method handle.
* For instance:
* <p>
* Open path elements also affects the creation of
* {@linkplain #byteOffsetHandle(PathElement...) offset-computing method handles}. Each open path element becomes
* an additional {@code long} parameter in the obtained method handle. This parameter can be used to specify the index
* of the sequence element whose offset is to be computed:
*
* {@snippet lang=java :
* MethodHandle offsetHandle = taggedValues.byteOffsetHandle(PathElement.sequenceElement(),
@ -163,6 +169,68 @@ import jdk.internal.javac.PreviewFeature;
* long offset2 = (long) offsetHandle.invokeExact(2L); // 16
* }
*
* <h3 id="deref-path-elements">Dereference path elements</h3>
*
* A special kind of path element, called <em>dereference path element</em>, allows var handles obtained from
* memory layouts to follow pointers. Consider the following layout:
*
* {@snippet lang=java :
* StructLayout RECTANGLE = MemoryLayout.structLayout(
* ValueLayout.ADDRESS.withTargetLayout(
* MemoryLayout.sequenceLayout(4,
* MemoryLayout.structLayout(
* ValueLayout.JAVA_INT.withName("x"),
* ValueLayout.JAVA_INT.withName("y")
* ).withName("point")
* )
* ).withName("points")
* );
* }
*
* This layout is a struct layout which describe a rectangle. It contains a single field, namely {@code points},
* an address layout whose {@linkplain AddressLayout#targetLayout() target layout} is a sequence layout of four
* struct layouts. Each struct layout describes a two-dimensional point, and is defined as a pair or
* {@link ValueLayout#JAVA_INT} coordinates, with names {@code x} and {@code y}, respectively.
* <p>
* With dereference path elements, we can obtain a var handle which accesses the {@code y} coordinate of one of the
* point in the rectangle, as follows:
*
* {@snippet lang=java :
* VarHandle rectPointYs = RECTANGLE.varHandle(
* PathElement.groupElement("points"),
* PathElement.dereferenceElement(),
* PathElement.sequenceElement(),
* PathElement.groupElement("y")
* );
*
* MemorySegment rect = ...
* int rect_y_4 = (int) rectPointYs.get(rect, 2); // rect.points[2]->y
* }
*
* <h3 id="well-formedness">Layout path well-formedness</h3>
*
* A layout path is applied to a layout {@code C_0}, also called the <em>initial layout</em>. Each path element in a
* layout path can be thought of as a function which updates the current layout {@code C_i-1} to some other layout
* {@code C_i}. That is, for each path element {@code E1, E2, ... En}, in a layout path {@code P}, we compute
* {@code C_i = f_i(C_i-1)}, where {@code f_i} is the selection function associated with the path element under consideration,
* denoted as {@code E_i}. The final layout {@code C_i} is also called the <em>selected layout</em>.
* <p>
* A layout path {@code P} is considered well-formed for an initial layout {@code C_0} if all its path elements
* {@code E1, E2, ... En} are well-formed for their corresponding input layouts {@code C_0, C_1, ... C_n-1}.
* A path element {@code E} is considered well-formed for a layout {@code L} if any of the following is true:
* <ul>
* <li>{@code L} is a sequence layout and {@code E} is a sequence path element (one of {@link PathElement#sequenceElement(long)},
* {@link PathElement#sequenceElement(long, long)} or {@link PathElement#sequenceElement()}). Moreover, if {@code E}
* contains one or more sequence indices, such indices have to be compatible with the sequence layout's element count;</li>
* <li>{@code L} is a group layout and {@code E} is a group path element (one of {@link PathElement#groupElement(String)}
* or {@link PathElement#groupElement(long)}). Moreover, the group path element must refer to a valid member layout in
* {@code L}, either by name, or index;</li>
* <li>{@code L} is an address layout and {@code E} is a {@linkplain PathElement#dereferenceElement() dereference path element}.
* Moreover, {@code L} must define some {@linkplain AddressLayout#targetLayout() target layout}.</li>
* </ul>
* Any attempt to provide a layout path {@code P} that is not well-formed for an initial layout {@code C_0} will result
* in an {@link IllegalArgumentException}.
*
* @implSpec
* Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
@ -184,28 +252,23 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
Optional<String> name();
/**
* Returns a memory layout of the same type with the same size and alignment constraint as this layout,
* but with the specified name.
* {@return a memory layout with the same characteristics as this layout, but with the given name}
*
* @param name the layout name.
* @return a memory layout with the given name.
* @see MemoryLayout#name()
*/
MemoryLayout withName(String name);
/**
* Returns a memory layout of the same type with the same size and alignment constraint as this layout,
* but without a name.
* <p>
* This can be useful to compare two layouts that have different names, but are otherwise equal.
* {@return a memory layout with the same characteristics as this layout, but with no name}
*
* @return a memory layout without a name.
* @apiNote This can be useful to compare two layouts that have different names, but are otherwise equal.
* @see MemoryLayout#name()
*/
MemoryLayout withoutName();
/**
* Returns the alignment constraint associated with this layout, expressed in bytes. Layout alignment defines a power
* {@return the alignment constraint associated with this layout, expressed in bytes} Layout alignment defines a power
* of two {@code A} which is the byte-wise alignment of the layout, where {@code A} is the number of bytes that must be aligned
* for any pointer that correctly points to this layout. Thus:
*
@ -217,36 +280,27 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
*
* If no explicit alignment constraint was set on this layout (see {@link #withByteAlignment(long)}),
* then this method returns the <a href="#layout-align">natural alignment</a> constraint (in bytes) associated with this layout.
*
* @return the layout alignment constraint, in bytes.
*/
long byteAlignment();
/**
* Returns a memory layout of the same type with the same size and name as this layout,
* but with the specified alignment constraint (in bytes).
* {@return a memory layout with the same characteristics as this layout, but with the given
* alignment constraint (in bytes)}
*
* @param byteAlignment the layout alignment constraint, expressed in bytes.
* @return a memory layout with the given alignment constraint.
* @throws IllegalArgumentException if {@code byteAlignment} is not a power of two, or if it's less than 1.
* @throws IllegalArgumentException if {@code byteAlignment} is not a power of two.
*/
MemoryLayout withByteAlignment(long byteAlignment);
/**
* Computes the offset, in bytes, of the layout selected by the given layout path, where the path is considered rooted in this
* layout.
* Computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the
* path is this layout.
*
* @param elements the layout path elements.
* @return The offset, in bytes, of the layout selected by the layout path in {@code elements}.
* @throws IllegalArgumentException if the layout path does not select any layout nested in this layout, or if the
* layout path contains one or more path elements that select multiple sequence element indices
* (see {@link PathElement#sequenceElement()} and {@link PathElement#sequenceElement(long, long)}).
* @throws IllegalArgumentException if the layout path contains one or more dereference path elements
* (see {@link PathElement#dereferenceElement()}).
* @throws NullPointerException if either {@code elements == null}, or if any of the elements
* in {@code elements} is {@code null}.
* @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout.
* @throws IllegalArgumentException if the layout path contains one or more <a href=#open-path-elements>open path elements</a>.
* @throws IllegalArgumentException if the layout path contains one or more <a href=#deref-path-elements>dereference path elements</a>.
*/
default long byteOffset(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this), LayoutPath::offset,
@ -254,19 +308,21 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
}
/**
* Creates a method handle that can be used to compute the offset, in bytes, of the layout selected
* by the given layout path, where the path is considered rooted in this layout.
*
* <p>The returned method handle has a return type of {@code long}, and features as many {@code long}
* parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
* where the order of the parameters corresponds to the order of the path elements.
* The returned method handle can be used to compute a layout offset similar to {@link #byteOffset(PathElement...)},
* but where some sequence indices are specified only when invoking the method handle.
*
* <p>The final offset returned by the method handle is computed as follows:
* Creates a method handle that computes the offset, in bytes, of the layout selected
* by the given layout path, where the initial layout in the path is this layout.
* <p>
* The returned method handle has the following characteristics:
* <ul>
* <li>its return type is {@code long};</li>
* <li>it has as zero or more parameters of type {@code long}, one for each <a href=#open-path-elements>open path element</a>
* in the provided layout path. The order of these parameters corresponds to the order in which the open path
* elements occur in the provided layout path.
* </ul>
* <p>
* The final offset returned by the method handle is computed as follows:
*
* <blockquote><pre>{@code
* byteOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
* offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
* }</pre></blockquote>
*
* where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
@ -274,22 +330,32 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
* the layout path.
*
* @apiNote The returned method handle can be used to compute a layout offset, similarly to {@link #byteOffset(PathElement...)},
* but more flexibly, as some indices can be specified when invoking the method handle.
*
* @param elements the layout path elements.
* @return a method handle that can be used to compute the byte offset of the layout element
* specified by the given layout path elements, when supplied with the missing sequence element indices.
* @throws IllegalArgumentException if the layout path contains one or more path elements that select
* multiple sequence element indices (see {@link PathElement#sequenceElement(long, long)}).
* @throws IllegalArgumentException if the layout path contains one or more dereference path elements
* (see {@link PathElement#dereferenceElement()}).
* @return a method handle that computes the offset, in bytes, of the layout selected by the given layout path.
* @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout.
* @throws IllegalArgumentException if the layout path contains one or more <a href=#deref-path-elements>dereference path elements</a>.
*/
default MethodHandle byteOffsetHandle(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this), LayoutPath::offsetHandle,
EnumSet.of(PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements);
EnumSet.of(PathKind.DEREF_ELEMENT), elements);
}
/**
* Creates a var handle that can be used to access a memory segment at the layout selected by the given layout path,
* where the path is considered rooted in this layout.
* Creates a var handle that accesses a memory segment at the offset selected by the given layout path,
* where the initial layout in the path is this layout.
* <p>
* The returned var handle has the following characteristics:
* <ul>
* <li>its type is derived from the {@linkplain ValueLayout#carrier() carrier} of the
* selected value layout;</li>
* <li>it has as zero or more access coordinates of type {@code long}, one for each
* <a href=#open-path-elements>open path element</a> in the provided layout path. The order of these access
* coordinates corresponds to the order in which the open path elements occur in the provided
* layout path.
* </ul>
* <p>
* The final address accessed by the returned var handle can be computed as follows:
*
@ -300,7 +366,7 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* Where {@code base(segment)} denotes a function that returns the physical base address of the accessed
* memory segment. For native segments, this function just returns the native segment's
* {@linkplain MemorySegment#address() address}. For heap segments, this function is more complex, as the address
* of heap segments is virtualized. The {@code offset} coordinate can be expressed in the following form:
* of heap segments is virtualized. The {@code offset} value can be expressed in the following form:
*
* <blockquote><pre>{@code
* offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
@ -311,14 +377,14 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* and {@code s_1}, {@code s_2}, ... {@code s_n} are <em>static</em> stride constants which are derived from
* the layout path.
* <p>
* Additionally, the provided dynamic values must conform to some bound which is derived from the layout path, that is,
* Additionally, the provided dynamic values must conform to bounds which are derived from the layout path, that is,
* {@code 0 <= x_i < b_i}, where {@code 1 <= i <= n}, or {@link IndexOutOfBoundsException} is thrown.
* <p>
* Multiple paths can be chained, by using {@linkplain PathElement#dereferenceElement() dereference path elements}.
* A dereference path element allows to obtain a native memory segment whose base address is the address obtained
* by following the layout path elements immediately preceding the dereference path element. In other words,
* if a layout path contains one or more dereference path elements, the final address accessed by the returned
* var handle can be computed as follows:
* Multiple paths can be chained, with <a href=#deref-path-elements>dereference path elements</a>.
* A dereference path element constructs a fresh native memory segment whose base address is the address value
* read obtained by accessing a memory segment at the offset determined by the layout path elements immediately preceding
* the dereference path element. In other words, if a layout path contains one or more dereference path elements,
* the final address accessed by the returned var handle can be computed as follows:
*
* <blockquote><pre>{@code
* address_1 = base(segment) + offset_1
@ -336,16 +402,13 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* (e.g. those at addresses {@code address_1}, {@code address_2}, ..., {@code address_k-1} are performed using the
* {@link VarHandle.AccessMode#GET} access mode.
*
* @apiNote the resulting var handle will feature an additional {@code long} access coordinate for every
* unspecified sequence access component contained in this layout path. Moreover, the resulting var handle
* features certain <em>access mode restrictions</em>, which are common to all memory segment view handles.
* @apiNote The resulting var handle features certain <em>access mode restrictions</em>, which are common to all
* {@linkplain MethodHandles#memorySegmentViewVarHandle(ValueLayout) memory segment view handles}.
*
* @param elements the layout path elements.
* @return a var handle which can be used to access a memory segment at the (possibly nested) layout selected by the layout path in {@code elements}.
* @throws UnsupportedOperationException if the layout path has one or more elements with incompatible alignment constraint.
* @throws IllegalArgumentException if the layout path in {@code elements} does not select a value layout (see {@link ValueLayout}).
* @throws IllegalArgumentException if the layout path in {@code elements} contains a {@linkplain PathElement#dereferenceElement()
* dereference path element} for an address layout that has no {@linkplain AddressLayout#targetLayout() target layout}.
* @return a var handle that accesses a memory segment at the offset selected by the given layout path.
* @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout.
* @throws IllegalArgumentException if the layout selected by the provided path is not a {@linkplain ValueLayout value layout}.
* @see MethodHandles#memorySegmentViewVarHandle(ValueLayout)
*/
default VarHandle varHandle(PathElement... elements) {
@ -355,54 +418,47 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
/**
* Creates a method handle which, given a memory segment, returns a {@linkplain MemorySegment#asSlice(long,long) slice}
* corresponding to the layout selected by the given layout path, where the path is considered rooted in this layout.
*
* <p>The returned method handle has a return type of {@code MemorySegment}, features a {@code MemorySegment}
* parameter as leading parameter representing the segment to be sliced, and features as many trailing {@code long}
* parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
* where the order of the parameters corresponds to the order of the path elements.
* The returned method handle can be used to create a slice similar to using {@link MemorySegment#asSlice(long, long)},
* but where the offset argument is dynamically compute based on indices specified when invoking the method handle.
*
* <p>The offset of the returned segment is computed as follows:
*
* <blockquote><pre>{@code
* byteOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
* }</pre></blockquote>
*
* where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
* arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
* and {@code s_1}, {@code s_2}, ... {@code s_n} are <em>static</em> stride constants which are derived from
* the layout path.
*
* <p>After the offset is computed, the returned segment is created as if by calling:
* corresponding to the layout selected by the given layout path, where the initial layout in the path is this layout.
* <p>
* The returned method handle has the following characteristics:
* <ul>
* <li>its return type is {@code MemorySegment};</li>
* <li>it has a leading parameter of type {@code MemorySegment}, corresponding to the memory segment
* to be sliced;</li>
* <li>it has as zero or more parameters of type {@code long}, one for each <a href=#open-path-elements>open path element</a>
* in the provided layout path. The order of these parameters corresponds to the order in which the open path
* elements occur in the provided layout path.
* </ul>
* <p>
* The offset of the returned segment is computed as follows:
* {@snippet lang=java :
* segment.asSlice(offset, layout.byteSize());
* long offset = byteOffset(elements);
* long size = select(elements).byteSize();
* MemorySegment slice = segment.asSlice(offset, size);
* }
*
* where {@code segment} is the segment to be sliced, and where {@code layout} is the layout selected by the given
* layout path, as per {@link MemoryLayout#select(PathElement...)}.
* @apiNote The returned method handle can be used to obtain a memory segment slice, similarly to {@link MemorySegment#asSlice(long, long)},
* but more flexibly, as some indices can be specified when invoking the method handle.
*
* @param elements the layout path elements.
* @return a method handle which can be used to create a slice of the selected layout element, given a segment.
* @throws IllegalArgumentException if the layout path contains one or more dereference path elements
* (see {@link PathElement#dereferenceElement()}).
* @return a method handle which is used to slice a memory segment at the offset selected by the given layout path.
* @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout.
* @throws IllegalArgumentException if the layout path contains one or more <a href=#deref-path-elements>dereference path elements</a>.
*/
default MethodHandle sliceHandle(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this), LayoutPath::sliceHandle,
Set.of(), elements);
Set.of(PathKind.DEREF_ELEMENT), elements);
}
/**
* Selects the layout from a path rooted in this layout.
* Returns the layout selected from the provided path, where the initial layout in the path is this layout.
*
* @param elements the layout path elements.
* @return the layout selected by the layout path in {@code elements}.
* @throws IllegalArgumentException if the layout path does not select any layout nested in this layout,
* or if the layout path contains one or more path elements that select one or more sequence element indices
* (see {@link PathElement#sequenceElement(long)} and {@link PathElement#sequenceElement(long, long)}).
* @throws IllegalArgumentException if the layout path contains one or more dereference path elements
* (see {@link PathElement#dereferenceElement()}).
* @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout.
* @throws IllegalArgumentException if the layout path contains one or more <a href=#deref-path-elements>dereference path elements</a>.
* @throws IllegalArgumentException if the layout path contains one or more path elements that select one or more
* sequence element indices, such as {@link PathElement#sequenceElement(long)} and {@link PathElement#sequenceElement(long, long)}).
*/
default MemoryLayout select(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this), LayoutPath::layout,
@ -424,12 +480,15 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
/**
* An element in a <a href="MemoryLayout.html#layout-paths"><em>layout path</em></a>. There
* are two kinds of path elements: <em>group path elements</em> and <em>sequence path elements</em>. Group
* path elements are used to select a named member layout within a {@link GroupLayout}. Sequence
* path elements are used to select a sequence element layout within a {@link SequenceLayout}; selection
* of sequence element layout can be <em>explicit</em> (see {@link PathElement#sequenceElement(long)}) or
* <em>implicit</em> (see {@link PathElement#sequenceElement()}). When a path uses one or more implicit
* sequence path elements, it acquires additional <em>free dimensions</em>.
* are three kinds of path elements:
* <ul>
* <li><em>group path elements</em>, used to select a member layout within a {@link GroupLayout}, either by name or by index;</li>
* <li><em>sequence path elements</em>, used to select one or more sequence element layouts within a {@link SequenceLayout}; and</li>
* <li><em>dereference path elements</em>, used to <a href="MemoryLayout.html#deref-path-elements">dereference</a>
* an address layout as its target layout.</li>
* </ul>
* Sequence path elements selecting more than one sequence element layout are called
* <a href="MemoryLayout.html#open-path-elements">open path elements</a>.
*
* @implSpec
* Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
@ -441,15 +500,13 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
/**
* Returns a path element which selects a member layout with the given name in a group layout.
* The path element returned by this method does not alter the number of free dimensions of any path
* that is combined with such element.
*
* @implSpec in case multiple group elements with a matching name exist, the path element returned by this
* method will select the first one; that is, the group element with the lowest offset from current path is selected.
* In such cases, using {@link #groupElement(long)} might be preferable.
*
* @param name the name of the group element to be selected.
* @return a path element which selects the group element with the given name.
* @param name the name of the member layout to be selected.
* @return a path element which selects the group member layout with the given name.
*/
static PathElement groupElement(String name) {
Objects.requireNonNull(name);
@ -459,11 +516,9 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
/**
* Returns a path element which selects a member layout with the given index in a group layout.
* The path element returned by this method does not alter the number of free dimensions of any path
* that is combined with such element.
*
* @param index the index of the group element to be selected.
* @return a path element which selects the group element with the given index.
* @param index the index of the member layout element to be selected.
* @return a path element which selects the group member layout with the given index.
* @throws IllegalArgumentException if {@code index < 0}.
*/
static PathElement groupElement(long index) {
@ -476,8 +531,6 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
/**
* Returns a path element which selects the element layout at the specified position in a sequence layout.
* The path element returned by this method does not alter the number of free dimensions of any path
* that is combined with such element.
*
* @param index the index of the sequence element to be selected.
* @return a path element which selects the sequence element layout with the given index.
@ -492,24 +545,12 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
}
/**
* Returns a path element which selects the element layout in a <em>range</em> of positions in a sequence layout.
* The range is expressed as a pair of starting index (inclusive) {@code S} and step factor (which can also be negative)
* {@code F}.
* Returns an <a href="MemoryLayout.html#open-path-elements">open path element</a> which selects the element
* layout in a <em>range</em> of positions in a sequence layout. The range is expressed as a pair of starting
* index (inclusive) {@code S} and step factor (which can also be negative) {@code F}.
* <p>
* If a path with free dimensions {@code n} is combined with the path element returned by this method,
* the number of free dimensions of the resulting path will be {@code 1 + n}. If the free dimension associated
* with this path is bound by an index {@code I}, the resulting accessed offset can be obtained with the following
* formula:
*
* <blockquote><pre>{@code
* E * (S + I * F)
* }</pre></blockquote>
*
* where {@code E} is the size (in bytes) of the sequence element layout.
* <p>
* Additionally, if {@code C} is the sequence element count, it follows that {@code 0 <= I < B},
* where {@code B} is computed as follows:
*
* The exact sequence element selected by this layout is expressed as an index {@code I}. If {@code C} is the
* sequence element count, it follows that {@code 0 <= I < B}, where {@code B} is computed as follows:
* <ul>
* <li>if {@code F > 0}, then {@code B = ceilDiv(C - S, F)}</li>
* <li>if {@code F < 0}, then {@code B = ceilDiv(-(S + 1), -F)}</li>
@ -532,20 +573,11 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
}
/**
* Returns a path element which selects an unspecified element layout in a sequence layout.
* Returns an <a href="MemoryLayout.html#open-path-elements">open path element</a> which selects an unspecified
* element layout in a sequence layout.
* <p>
* If a path with free dimensions {@code n} is combined with the path element returned by this method,
* the number of free dimensions of the resulting path will be {@code 1 + n}. If the free dimension associated
* with this path is bound by an index {@code I}, the resulting accessed offset can be obtained with the following
* formula:
*
* <blockquote><pre>{@code
* E * I
* }</pre></blockquote>
*
* where {@code E} is the size (in bytes) of the sequence element layout.
* <p>
* Additionally, if {@code C} is the sequence element count, it follows that {@code 0 <= I < C}.
* The exact sequence element selected by this layout is expressed as an index {@code I}. If {@code C} is the
* sequence element count, it follows that {@code 0 <= I < C}.
*
* @return a path element which selects an unspecified sequence element layout.
*/
@ -557,10 +589,6 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
/**
* Returns a path element which dereferences an address layout as its
* {@linkplain AddressLayout#targetLayout() target layout} (where set).
* The path element returned by this method does not alter the number of free dimensions of any path
* that is combined with such element. Using this path layout to dereference an address layout
* that has no target layout results in an {@link IllegalArgumentException} (e.g. when
* a var handle is {@linkplain #varHandle(PathElement...) obtained}).
*
* @return a path element which dereferences an address layout.
*/
@ -577,11 +605,12 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* conditions must be satisfied:
* <ul>
* <li>two value layouts are considered equal if they have the same {@linkplain ValueLayout#order() order},
* and {@linkplain ValueLayout#carrier() carrier}</li>
* and {@linkplain ValueLayout#carrier() carrier}. Additionally, two address layouts are considered equal if they
* also have the same {@linkplain AddressLayout#targetLayout() target layout};</li>
* <li>two sequence layouts are considered equal if they have the same element count (see {@link SequenceLayout#elementCount()}), and
* if their element layouts (see {@link SequenceLayout#elementLayout()}) are also equal</li>
* if their element layouts (see {@link SequenceLayout#elementLayout()}) are also equal;</li>
* <li>two group layouts are considered equal if they are of the same type (see {@link StructLayout},
* {@link UnionLayout}) and if their member layouts (see {@link GroupLayout#memberLayouts()}) are also equal</li>
* {@link UnionLayout}) and if their member layouts (see {@link GroupLayout#memberLayouts()}) are also equal.</li>
* </ul>
*
* @param other the object to be compared for equality with this layout.
@ -601,7 +630,10 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
String toString();
/**
* Creates a padding layout with the given byte size and a byte-alignment of one.
* Creates a padding layout with the given byte size. The alignment constraint of the returned layout
* is 1. As such, regardless of its size, in the absence of an {@linkplain #withByteAlignment(long) explicit}
* alignment constraint, a padding layout does not affect the natural alignment of the group or sequence layout
* it is nested into.
*
* @param byteSize the padding size (expressed in bytes).
* @return the new selector layout.
@ -617,14 +649,15 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* @param elementCount the sequence element count.
* @param elementLayout the sequence element layout.
* @return the new sequence layout with the given element layout and size.
* @throws IllegalArgumentException if {@code elementCount } is negative.
* @throws IllegalArgumentException if {@code elementCount} is negative.
* @throws IllegalArgumentException if {@code elementLayout.byteSize() * elementCount} overflows.
* @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}.
*/
static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) {
MemoryLayoutUtil.requireNonNegative(elementCount);
Objects.requireNonNull(elementLayout);
Utils.checkElementAlignment(elementLayout, "Element layout size is not multiple of alignment");
return wrapOverflow(() ->
return Utils.wrapOverflow(() ->
SequenceLayoutImpl.of(elementCount, elementLayout));
}
@ -678,7 +711,7 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
*/
static StructLayout structLayout(MemoryLayout... elements) {
Objects.requireNonNull(elements);
return wrapOverflow(() ->
return Utils.wrapOverflow(() ->
StructLayoutImpl.of(Stream.of(elements)
.map(Objects::requireNonNull)
.toList()));
@ -696,12 +729,4 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
.map(Objects::requireNonNull)
.toList());
}
private static <L extends MemoryLayout> L wrapOverflow(Supplier<L> layoutSupplier) {
try {
return layoutSupplier.get();
} catch (ArithmeticException ex) {
throw new IllegalArgumentException("Layout size exceeds Long.MAX_VALUE");
}
}
}

View File

@ -108,7 +108,7 @@ import jdk.internal.vm.annotation.ForceInline;
* <p>
* Finally, access operations on a memory segment can be subject to additional thread-confinement checks.
* Heap segments can be accessed from any thread. Conversely, native segments can only be accessed compatibly with the
* <a href="ScopedArena.html#thread-confinement">confinement characteristics</a> of the arena used to obtain them.
* <a href="Arena.html#thread-confinement">confinement characteristics</a> of the arena used to obtain them.
*
* <h2 id="segment-deref">Accessing memory segments</h2>
*
@ -141,7 +141,7 @@ import jdk.internal.vm.annotation.ForceInline;
* .findStatic(Math.class, "multiplyExact",
* MethodType.methodType(long.class, long.class, long.class));
* intHandle = MethodHandles.filterCoordinates(intHandle, 1,
* MethodHandles.insertArguments(multiplyExact, 0, 4L));
* MethodHandles.insertArguments(multiplyExact, 0, ValueLayout.JAVA_INT.byteSize()));
* int value = (int) intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
* }
*
@ -260,9 +260,10 @@ import jdk.internal.vm.annotation.ForceInline;
* (e.g. because of platform considerations and/or garbage collection behavior).
* <p>
* In practice, the Java runtime lays out arrays in memory so that each n-byte element occurs at an n-byte
* aligned physical address. The runtime preserves this invariant even if the array is relocated during garbage
* collection. Access operations rely on this invariant to determine if the specified offset in a heap segment refers
* to an aligned address in physical memory. For example:
* aligned physical address (except for {@code long[]} and {@code double[]}, where alignment is platform-dependent, as explained
* below). The runtime preserves this invariant even if the array is relocated during garbage collection.
* Access operations rely on this invariant to determine if the specified offset in a heap segment refers to an aligned
* address in physical memory. For example:
* <ul>
* <li>The starting physical address of a {@code short[]} array will be 2-byte aligned (e.g. 1006) so that successive
* short elements occur at 2-byte aligned addresses (e.g. 1006, 1008, 1010, 1012, etc). A heap segment backed by a
@ -278,10 +279,10 @@ import jdk.internal.vm.annotation.ForceInline;
* constraint. In addition, the segment can be accessed at offsets 0, 4, 8, 12, etc under a 4-byte alignment constraint,
* because the target addresses (1000, 1004, 1008, 1012) are 4-byte aligned. And, the segment can be accessed at offsets
* 0, 2, 4, 6, etc under a 2-byte alignment constraint, because the target addresses (e.g. 1000, 1002, 1004, 1006) are 2-byte aligned.</li>
* <li>The starting physical address of a {@code long[]} array will be 4-byte aligned (e.g. 1000) on 32-bit platforms,
* <li>The starting physical address of a {@code long[]} array will be 4-byte aligned (e.g. 1004) on 32-bit platforms,
* so that successive long elements occur at 4-byte aligned addresses (e.g., 1004, 1008, 1012, 1016, etc.) On 32-bit
* platforms, a heap segment backed by a {@code long[]} array can be accessed at offsets 0, 4, 8, 12, etc under a 4-byte
* alignment constraint, because the target addresses (1000, 1004, 1008, 1012) are 4-byte aligned. And, the segment
* alignment constraint, because the target addresses (1004, 1008, 1012, 1016) are 4-byte aligned. And, the segment
* can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint, because the target addresses
* (e.g. 1000, 1002, 1004, 1006) are 2-byte aligned.</li>
* </ul>
@ -440,11 +441,17 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
/**
* {@return the address of this memory segment}
*
* @apiNote When using this method to pass a segment address to some external operation (e.g. a JNI function),
* clients must ensure that the segment is kept <a href="../../../java/lang/ref/package.html#reachability">reachable</a>
* for the entire duration of the operation. A failure to do so might result in the premature deallocation of the
* region of memory backing the memory segment, in case the segment has been allocated with an
* {@linkplain Arena#ofAuto() automatic arena}.
*/
long address();
/**
* Returns the Java object stored in the on-heap memory region backing this memory segment, if any. For instance, if this
* Returns the Java object stored in the on-heap region of memory backing this memory segment, if any. For instance, if this
* memory segment is a heap segment created with the {@link #ofArray(byte[])} factory method, this method will return the
* {@code byte[]} object which was used to obtain the segment. This method returns an empty {@code Optional} value
* if either this segment is a {@linkplain #isNative() native} segment, or if this segment is {@linkplain #isReadOnly() read-only}.
@ -515,7 +522,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <p>
* Equivalent to the following code:
* {@snippet lang=java :
* asSlice(offset, layout.byteSize(), 1);
* asSlice(offset, newSize, 1);
* }
*
* @see #asSlice(long, long, long)
@ -523,7 +530,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @param offset The new segment base offset (relative to the address of this segment), specified in bytes.
* @param newSize The new segment size, specified in bytes.
* @return a slice of this memory segment.
* @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}, {@code newSize < 0}, or {@code newSize > byteSize() - offset}
* @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}, {@code newSize < 0},
* or {@code newSize > byteSize() - offset}
*/
MemorySegment asSlice(long offset, long newSize);
@ -535,9 +543,11 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @param newSize The new segment size, specified in bytes.
* @param byteAlignment The alignment constraint (in bytes) of the returned slice.
* @return a slice of this memory segment.
* @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}, {@code newSize < 0}, or {@code newSize > byteSize() - offset}
* @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}, {@code newSize < 0},
* or {@code newSize > byteSize() - offset}
* @throws IllegalArgumentException if this segment cannot be accessed at {@code offset} under
* the provided alignment constraint.
* @throws IllegalArgumentException if {@code byteAlignment <= 0}, or if {@code byteAlignment} is not a power of 2.
*/
MemorySegment asSlice(long offset, long newSize, long byteAlignment);
@ -554,8 +564,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
*
* @param offset The new segment base offset (relative to the address of this segment), specified in bytes.
* @param layout The layout of the segment slice.
* @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > layout.byteSize()},
* {@code newSize < 0}, or {@code newSize > layout.byteSize() - offset}
* @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()},
* or {@code layout.byteSize() > byteSize() - offset}
* @throws IllegalArgumentException if this segment cannot be accessed at {@code offset} under
* the alignment constraint specified by {@code layout}.
* @return a slice of this memory segment.
@ -612,7 +622,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* Clients can specify an optional cleanup action that should be executed when the provided scope becomes
* invalid. This cleanup action receives a fresh memory segment that is obtained from this segment as follows:
* {@snippet lang=java :
* MemorySegment cleanupSegment = MemorySegment.ofAddress(this.address());
* MemorySegment cleanupSegment = MemorySegment.ofAddress(this.address())
* .reinterpret(byteSize());
* }
* That is, the cleanup action receives a segment that is associated with a fresh scope that is always alive,
* and is accessible from any thread. The size of the segment accepted by the cleanup action is {@link #byteSize()}.
@ -631,8 +642,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @param arena the arena to be associated with the returned segment.
* @param cleanup the cleanup action that should be executed when the provided arena is closed (can be {@code null}).
* @return a new memory segment with unbounded size.
* @throws IllegalArgumentException if {@code newSize < 0}.
* @throws IllegalStateException if {@code scope.isAlive() == false}.
* @throws IllegalStateException if {@code arena.scope().isAlive() == false}.
* @throws UnsupportedOperationException if this segment is not a {@linkplain #isNative() native} segment.
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled.
*/
@ -651,7 +661,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* Clients can specify an optional cleanup action that should be executed when the provided scope becomes
* invalid. This cleanup action receives a fresh memory segment that is obtained from this segment as follows:
* {@snippet lang=java :
* MemorySegment cleanupSegment = MemorySegment.ofAddress(this.address());
* MemorySegment cleanupSegment = MemorySegment.ofAddress(this.address())
* .reinterpret(newSize);
* }
* That is, the cleanup action receives a segment that is associated with a fresh scope that is always alive,
* and is accessible from any thread. The size of the segment accepted by the cleanup action is {@code newSize}.
@ -674,7 +685,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* that of the provided arena.
* @throws UnsupportedOperationException if this segment is not a {@linkplain #isNative() native} segment.
* @throws IllegalArgumentException if {@code newSize < 0}.
* @throws IllegalStateException if {@code scope.isAlive() == false}.
* @throws IllegalStateException if {@code arena.scope().isAlive() == false}.
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled.
*/
@CallerSensitive
@ -718,7 +729,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* at least two slices {@code L1} (from {@code S1}) and {@code L2} (from {@code S2}) that are backed by the
* same region of memory. As such, it is not possible for a
* {@linkplain #isNative() native} segment to overlap with a heap segment; in
* this case, or when no overlap occurs, {@code null} is returned.
* this case, or when no overlap occurs, an empty {@code Optional} is returned.
*
* @param other the segment to test for an overlap with this segment.
* @return a slice of this segment (where overlapping occurs).
@ -735,7 +746,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* can be computed as follows:
*
* {@snippet lang=java :
* other.address() - segment.address()
* other.address() - address()
* }
*
* If the segments share the same address, {@code 0} is returned. If
@ -744,37 +755,35 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
*
* @param other the segment to retrieve an offset to.
* @throws UnsupportedOperationException if the two segments cannot be compared, e.g. because they are of
* a different kind, or because they are backed by different Java arrays.
* different kinds, or because they are backed by different Java arrays.
* @return the relative offset, in bytes, of the provided segment.
*/
long segmentOffset(MemorySegment other);
/**
* Fills a value into this memory segment.
* Fills the contents of this memory segment with the given value.
* <p>
* More specifically, the given value is filled into each address of this
* More specifically, the given value is written into each address of this
* segment. Equivalent to (but likely more efficient than) the following code:
*
* {@snippet lang=java :
* 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);
* for (long offset = 0; offset < segment.byteSize(); offset++) {
* byteHandle.set(ValueLayout.JAVA_BYTE, offset, value);
* }
* }
*
* without any regard or guarantees on the ordering of particular memory
* But without any regard or guarantees on the ordering of particular memory
* elements being set.
* <p>
* Fill can be useful to initialize or reset the memory of a segment.
* This method can be useful to initialize or reset the contents of a memory segment.
*
* @param value the value to fill into this segment
* @return this memory segment
* @param value the value to write into this segment.
* @return this memory segment.
* @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not
* {@linkplain Scope#isAlive() alive}.
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code isAccessibleBy(T) == false}.
* @throws UnsupportedOperationException if this segment is read-only (see {@link #isReadOnly()}).
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
MemorySegment fill(byte value);
@ -797,7 +806,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* {@linkplain Scope#isAlive() alive}.
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code src.isAccessibleBy(T) == false}.
* @throws UnsupportedOperationException if this segment is read-only (see {@link #isReadOnly()}).
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
* @return this segment.
*/
default MemorySegment copyFrom(MemorySegment src) {
@ -820,9 +829,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* valid for the larger segment. Otherwise, there is no mismatch and {@code
* -1} is returned.
*
* @param other the segment to be tested for a mismatch with this segment
* @param other the segment to be tested for a mismatch with this segment.
* @return the relative offset, in bytes, of the first mismatch between this
* and the given other segment, otherwise -1 if no mismatch
* and the given other segment, otherwise -1 if no mismatch.
* @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not
* {@linkplain Scope#isAlive() alive}.
* @throws WrongThreadException if this method is called from a thread {@code T},
@ -930,23 +939,24 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
/**
* Wraps this segment in a {@link ByteBuffer}. Some properties of the returned buffer are linked to
* the properties of this segment. For instance, if this segment is <em>immutable</em>
* (e.g. the segment is a read-only segment, see {@link #isReadOnly()}), then the resulting buffer is <em>read-only</em>
* (see {@link ByteBuffer#isReadOnly()}). Additionally, if this is a native segment, the resulting buffer is
* <em>direct</em> (see {@link ByteBuffer#isDirect()}).
* the properties of this segment. More specifically, the resulting buffer has the following characteristics:
* <ul>
* <li>It is {@linkplain ByteBuffer#isReadOnly() read-only}, if this segment is a
* {@linkplain #isReadOnly() read-only segment};</li>
* <li>Its {@linkplain ByteBuffer#position() position} is set to zero;
* <li>Its {@linkplain ByteBuffer#capacity() capacity} and {@linkplain ByteBuffer#limit() limit}
* are both set to this segment' {@linkplain MemorySegment#byteSize() size}. For this reason, a byte buffer
* cannot be returned if this segment's size is greater than {@link Integer#MAX_VALUE};</li>
* <li>It is a {@linkplain ByteBuffer#isDirect() direct buffer}, if this is a native segment.</li>
* </ul>
* <p>
* The returned buffer's position (see {@link ByteBuffer#position()}) is initially set to zero, while
* the returned buffer's capacity and limit (see {@link ByteBuffer#capacity()} and {@link ByteBuffer#limit()}, respectively)
* are set to this segment' size (see {@link MemorySegment#byteSize()}). For this reason, a byte buffer cannot be
* returned if this segment' size is greater than {@link Integer#MAX_VALUE}.
* <p>
* The life-cycle of the returned buffer will be tied to that of this segment. That is, accessing the returned buffer
* The life-cycle of the returned buffer is tied to that of this segment. That is, accessing the returned buffer
* after the scope associated with this segment is no longer {@linkplain Scope#isAlive() alive}, will
* throw an {@link IllegalStateException}. Similarly, accessing the returned buffer from a thread {@code T}
* such that {@code isAccessible(T) == false} will throw a {@link WrongThreadException}.
* <p>
* If this segment is accessible from a single thread, calling read/write I/O
* operations on the resulting buffer might result in an unspecified exception being thrown. Examples of such problematic operations are
* If this segment is {@linkplain #isAccessibleBy(Thread) accessible} from a single thread, calling read/write I/O
* operations on the resulting buffer might result in unspecified exceptions being thrown. Examples of such problematic operations are
* {@link java.nio.channels.AsynchronousSocketChannel#read(ByteBuffer)} and
* {@link java.nio.channels.AsynchronousSocketChannel#write(ByteBuffer)}.
* <p>
@ -955,7 +965,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
*
* @return a {@link ByteBuffer} view of this memory segment.
* @throws UnsupportedOperationException if this segment cannot be mapped onto a {@link ByteBuffer} instance,
* e.g. because it models a heap-based segment that is not based on a {@code byte[]}), or if its size is greater
* e.g. if it is a heap segment backed by an array other than {@code byte[]}), or if its size is greater
* than {@link Integer#MAX_VALUE}.
*/
ByteBuffer asByteBuffer();
@ -984,7 +994,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalStateException if this segment's contents cannot be copied into a {@code short[]} instance,
* e.g. because {@code byteSize() % 2 != 0}, or {@code byteSize() / 2 > Integer#MAX_VALUE}
* e.g. because {@code byteSize() % 2 != 0}, or {@code byteSize() / 2 > Integer.MAX_VALUE}
*/
short[] toArray(ValueLayout.OfShort elementLayout);
@ -998,7 +1008,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalStateException if this segment's contents cannot be copied into a {@code char[]} instance,
* e.g. because {@code byteSize() % 2 != 0}, or {@code byteSize() / 2 > Integer#MAX_VALUE}.
* e.g. because {@code byteSize() % 2 != 0}, or {@code byteSize() / 2 > Integer.MAX_VALUE}.
*/
char[] toArray(ValueLayout.OfChar elementLayout);
@ -1012,7 +1022,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalStateException if this segment's contents cannot be copied into a {@code int[]} instance,
* e.g. because {@code byteSize() % 4 != 0}, or {@code byteSize() / 4 > Integer#MAX_VALUE}.
* e.g. because {@code byteSize() % 4 != 0}, or {@code byteSize() / 4 > Integer.MAX_VALUE}.
*/
int[] toArray(ValueLayout.OfInt elementLayout);
@ -1026,7 +1036,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalStateException if this segment's contents cannot be copied into a {@code float[]} instance,
* e.g. because {@code byteSize() % 4 != 0}, or {@code byteSize() / 4 > Integer#MAX_VALUE}.
* e.g. because {@code byteSize() % 4 != 0}, or {@code byteSize() / 4 > Integer.MAX_VALUE}.
*/
float[] toArray(ValueLayout.OfFloat elementLayout);
@ -1040,7 +1050,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalStateException if this segment's contents cannot be copied into a {@code long[]} instance,
* e.g. because {@code byteSize() % 8 != 0}, or {@code byteSize() / 8 > Integer#MAX_VALUE}.
* e.g. because {@code byteSize() % 8 != 0}, or {@code byteSize() / 8 > Integer.MAX_VALUE}.
*/
long[] toArray(ValueLayout.OfLong elementLayout);
@ -1054,7 +1064,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalStateException if this segment's contents cannot be copied into a {@code double[]} instance,
* e.g. because {@code byteSize() % 8 != 0}, or {@code byteSize() / 8 > Integer#MAX_VALUE}.
* e.g. because {@code byteSize() % 8 != 0}, or {@code byteSize() / 8 > Integer.MAX_VALUE}.
*/
double[] toArray(ValueLayout.OfDouble elementLayout);
@ -1069,7 +1079,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @return a Java string constructed from the bytes read from the given starting address up to (but not including)
* the first {@code '\0'} terminator character (assuming one is found).
* @throws IllegalArgumentException if the size of the UTF-8 string is greater than the largest string supported by the platform.
* @throws IndexOutOfBoundsException if {@code offset < 0} or {@code S + offset > byteSize()}, where {@code S} is the size of the UTF-8
* @throws IndexOutOfBoundsException if {@code offset < 0} or {@code offset > byteSize() - S}, where {@code S} is the size of the UTF-8
* string (including the terminator character).
* @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not
* {@linkplain Scope#isAlive() alive}.
@ -1095,7 +1105,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @param offset offset in bytes (relative to this segment address) at which this access operation will occur.
* the final address of this write operation can be expressed as {@code address() + offset}.
* @param str the Java string to be written into this segment.
* @throws IndexOutOfBoundsException if {@code offset < 0} or {@code str.getBytes().length() + offset >= byteSize()}.
* @throws IndexOutOfBoundsException if {@code offset < 0} or {@code offset > byteSize() - str.getBytes().length() + 1}.
* @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not
* {@linkplain Scope#isAlive() alive}.
* @throws WrongThreadException if this method is called from a thread {@code T},
@ -1110,7 +1120,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* Creates a memory segment that is backed by the same region of memory that backs the given {@link Buffer} instance.
* The segment starts relative to the buffer's position (inclusive) and ends relative to the buffer's limit (exclusive).
* <p>
* If the buffer is {@linkplain Buffer#isReadOnly() read-only}, the resulting segment will also be
* If the buffer is {@linkplain Buffer#isReadOnly() read-only}, the resulting segment is also
* {@linkplain ByteBuffer#isReadOnly() read-only}. Moreover, if the buffer is a {@linkplain Buffer#isDirect() direct buffer},
* the returned segment is a native segment; otherwise the returned memory segment is a heap segment.
* <p>
@ -1135,7 +1145,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
/**
* Creates a heap segment backed by the on-heap region of memory that holds the given byte array.
* The scope of the returned segment is a fresh scope that is always alive, and keeps the given byte array reachable.
* The scope of the returned segment is a fresh scope that is always alive, and keeps the given array reachable.
* The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero.
*
* @param byteArray the primitive array backing the heap memory segment.
@ -1147,7 +1157,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
/**
* Creates a heap segment backed by the on-heap region of memory that holds the given char array.
* The scope of the returned segment is a fresh scope that is always alive, and keeps the given byte array reachable.
* The scope of the returned segment is a fresh scope that is always alive, and keeps the given array reachable.
* The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero.
*
* @param charArray the primitive array backing the heap segment.
@ -1159,7 +1169,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
/**
* Creates a heap segment backed by the on-heap region of memory that holds the given short array.
* The scope of the returned segment is a fresh scope that is always alive, and keeps the given byte array reachable.
* The scope of the returned segment is a fresh scope that is always alive, and keeps the given array reachable.
* The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero.
*
* @param shortArray the primitive array backing the heap segment.
@ -1171,7 +1181,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
/**
* Creates a heap segment backed by the on-heap region of memory that holds the given int array.
* The scope of the returned segment is a fresh scope that is always alive, and keeps the given byte array reachable.
* The scope of the returned segment is a fresh scope that is always alive, and keeps the given array reachable.
* The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero.
*
* @param intArray the primitive array backing the heap segment.
@ -1183,7 +1193,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
/**
* Creates a heap segment backed by the on-heap region of memory that holds the given float array.
* The scope of the returned segment is a fresh scope that is always alive, and keeps the given byte array reachable.
* The scope of the returned segment is a fresh scope that is always alive, and keeps the given array reachable.
* The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero.
*
* @param floatArray the primitive array backing the heap segment.
@ -1195,7 +1205,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
/**
* Creates a heap segment backed by the on-heap region of memory that holds the given long array.
* The scope of the returned segment is a fresh scope that is always alive, and keeps the given byte array reachable.
* The scope of the returned segment is a fresh scope that is always alive, and keeps the given array reachable.
* The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero.
*
* @param longArray the primitive array backing the heap segment.
@ -1207,7 +1217,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
/**
* Creates a heap segment backed by the on-heap region of memory that holds the given double array.
* The scope of the returned segment is a fresh scope that is always alive, and keeps the given byte array reachable.
* The scope of the returned segment is a fresh scope that is always alive, and keeps the given array reachable.
* The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero.
*
* @param doubleArray the primitive array backing the heap segment.
@ -1224,7 +1234,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
/**
* Creates a zero-length native segment from the given {@linkplain #address() address value}.
* The returned segment is always accessible, from any thread.
* The returned segment is associated with a scope that is always alive, and is accessible from any thread.
* <p>
* On 32-bit platforms, the given address value will be normalized such that the
* highest-order ("leftmost") 32 bits of the {@link MemorySegment#address() address}
@ -1268,10 +1278,10 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* {@linkplain Scope#isAlive() alive}.
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code dstSegment.isAccessibleBy(T) == false}.
* @throws IndexOutOfBoundsException if {@code srcOffset + bytes > srcSegment.byteSize()} or if
* {@code dstOffset + bytes > dstSegment.byteSize()}, or if either {@code srcOffset}, {@code dstOffset}
* @throws IndexOutOfBoundsException if {@code srcOffset > srcSegment.byteSize() - bytes} or if
* {@code dstOffset > dstSegment.byteSize() - bytes}, or if either {@code srcOffset}, {@code dstOffset}
* or {@code bytes} are {@code < 0}.
* @throws UnsupportedOperationException if the destination segment is read-only (see {@link #isReadOnly()}).
* @throws UnsupportedOperationException if {@code dstSegment} is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
static void copy(MemorySegment srcSegment, long srcOffset,
@ -1316,10 +1326,10 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* {@linkplain Scope#isAlive() alive}.
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code dstSegment().isAccessibleBy(T) == false}.
* @throws IndexOutOfBoundsException if {@code srcOffset + (elementCount * S) > srcSegment.byteSize()} or if
* {@code dstOffset + (elementCount * S) > dstSegment.byteSize()}, where {@code S} is the byte size
* of the element layouts, or if either {@code srcOffset}, {@code dstOffset} or {@code elementCount} are {@code < 0}.
* @throws UnsupportedOperationException if the destination segment is read-only (see {@link #isReadOnly()}).
* @throws UnsupportedOperationException if {@code dstSegment} is {@linkplain #isReadOnly() read-only}.
* @throws IndexOutOfBoundsException if {@code elementCount * srcLayout.byteSize()} or {@code elementCount * dtsLayout.byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code dstOffset > dstSegment.byteSize() - (elementCount * dstLayout.byteSize())}.
* @throws IndexOutOfBoundsException if either {@code srcOffset}, {@code dstOffset} or {@code elementCount} are {@code < 0}.
*/
@ForceInline
static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long srcOffset,
@ -1344,8 +1354,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default byte get(ValueLayout.OfByte layout, long offset) {
@ -1364,8 +1373,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
@ -1385,8 +1393,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default boolean get(ValueLayout.OfBoolean layout, long offset) {
@ -1405,8 +1412,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
@ -1426,8 +1432,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default char get(ValueLayout.OfChar layout, long offset) {
@ -1446,8 +1451,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
@ -1467,8 +1471,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default short get(ValueLayout.OfShort layout, long offset) {
@ -1487,8 +1490,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
@ -1508,8 +1510,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default int get(ValueLayout.OfInt layout, long offset) {
@ -1528,8 +1529,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
@ -1549,8 +1549,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default float get(ValueLayout.OfFloat layout, long offset) {
@ -1569,8 +1568,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
@ -1590,8 +1588,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default long get(ValueLayout.OfLong layout, long offset) {
@ -1610,8 +1607,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
@ -1631,8 +1627,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default double get(ValueLayout.OfDouble layout, long offset) {
@ -1651,8 +1646,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
@ -1664,7 +1658,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* Reads an address from this segment at the given offset, with the given layout. The read address is wrapped in
* a native segment, associated with a fresh scope that is always alive. Under normal conditions,
* the size of the returned segment is {@code 0}. However, if the provided address layout has a
* {@linkplain AddressLayout#targetLayout()} {@code T}, then the size of the returned segment
* {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size of the returned segment
* is set to {@code T.byteSize()}.
* @param layout the layout of the region of memory to be read.
* @param offset offset in bytes (relative to this segment address) at which this access operation will occur.
@ -1678,8 +1672,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if provided address layout has a {@linkplain AddressLayout#targetLayout() target layout}
* {@code T}, and the address of the returned segment
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in {@code T}.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default MemorySegment get(AddressLayout layout, long offset) {
@ -1698,8 +1691,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
* @throws UnsupportedOperationException if {@code value} is not a {@linkplain #isNative() native} segment.
*/
@ -1722,8 +1714,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default byte getAtIndex(ValueLayout.OfByte layout, long index) {
@ -1746,8 +1738,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default boolean getAtIndex(ValueLayout.OfBoolean layout, long index) {
@ -1770,8 +1762,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default char getAtIndex(ValueLayout.OfChar layout, long index) {
@ -1794,8 +1786,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
@ -1819,8 +1811,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default short getAtIndex(ValueLayout.OfShort layout, long index) {
@ -1843,8 +1835,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
@ -1869,8 +1861,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
@ -1894,8 +1886,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
@ -1919,8 +1911,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default int getAtIndex(ValueLayout.OfInt layout, long index) {
@ -1943,8 +1935,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
@ -1968,8 +1960,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default float getAtIndex(ValueLayout.OfFloat layout, long index) {
@ -1992,8 +1984,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
@ -2017,8 +2009,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default long getAtIndex(ValueLayout.OfLong layout, long index) {
@ -2041,8 +2033,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
@ -2066,8 +2058,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default double getAtIndex(ValueLayout.OfDouble layout, long index) {
@ -2090,8 +2082,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
@ -2105,7 +2097,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* Reads an address from this segment at the given at the given index, scaled by the given layout size. The read address is wrapped in
* a native segment, associated with a fresh scope that is always alive. Under normal conditions,
* the size of the returned segment is {@code 0}. However, if the provided address layout has a
* {@linkplain AddressLayout#targetLayout()} {@code T}, then the size of the returned segment
* {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size of the returned segment
* is set to {@code T.byteSize()}.
* @param layout the layout of the region of memory to be read.
* @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation
@ -2121,8 +2113,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if provided address layout has a {@linkplain AddressLayout#targetLayout() target layout}
* {@code T}, and the address of the returned segment
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in {@code T}.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default MemorySegment getAtIndex(AddressLayout layout, long index) {
@ -2145,8 +2137,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IllegalArgumentException if the access operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the
* memory segment.
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
* @throws UnsupportedOperationException if {@code value} is not a {@linkplain #isNative() native} segment.
*/
@ -2162,17 +2154,17 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* object is also a memory segment, and if the two segments refer to the same location, in some region of memory.
* More specifically, for two segments {@code s1} and {@code s2} to be considered equals, all the following must be true:
* <ul>
* <li>{@code s1.array().equals(s2.array())}, that is, the two segments must be of the same kind;
* <li>{@code s1.heapBase().equals(s2.heapBase())}, that is, the two segments must be of the same kind;
* either both are {@linkplain #isNative() native segments}, backed by off-heap memory, or both are backed by
* the same on-heap Java array;
* the same on-heap {@linkplain #heapBase() Java object};
* <li>{@code s1.address() == s2.address()}, that is, the address of the two segments should be the same.
* This means that the two segments either refer to the same location in some off-heap region, or they refer
* to the same position inside their associated Java array instance.</li>
* to the same offset inside their associated {@linkplain #heapBase() Java object}.</li>
* </ul>
* @apiNote This method does not perform a structural comparison of the contents of the two memory segments. Clients can
* compare memory segments structurally by using the {@link #mismatch(MemorySegment)} method instead. Note that this
* method does <em>not</em> compare the temporal and spatial bounds of two segments. As such it is suitable
* to perform address checks, such as checking if a native segment has the {@code NULL} address.
* to check whether two segments have the same address.
*
* @param that the object to be compared for equality with this memory segment.
* @return {@code true} if the specified object is equal to this memory segment.
@ -2204,10 +2196,15 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* {@linkplain Scope#isAlive() alive}.
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code srcSegment().isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if {@code dstArray} is not an array, or if it is an array but whose type is not supported,
* if the destination array component type does not match the carrier of the source element layout, if the source
* segment/offset are <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the source element layout,
* or if the destination element layout alignment is greater than its size.
* @throws IllegalArgumentException if {@code dstArray} is not an array, or if it is an array but whose type is not supported.
* @throws IllegalArgumentException if the destination array component type does not match {@code srcLayout.carrier()}.
* @throws IllegalArgumentException if {@code offset} is <a href="MemorySegment.html#segment-alignment">incompatible
* with the alignment constraint</a> in the source element layout.
* @throws IllegalArgumentException if {@code srcLayout.byteAlignment() > srcLayout.byteSize()}.
* @throws IndexOutOfBoundsException if {@code elementCount * srcLayout.byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code srcOffset > srcSegment.byteSize() - (elementCount * srcLayout.byteSize())}.
* @throws IndexOutOfBoundsException if {@code dstIndex > dstArray.length - elementCount}.
* @throws IndexOutOfBoundsException if either {@code srcOffset}, {@code dstIndex} or {@code elementCount} are {@code < 0}.
*/
@ForceInline
static void copy(
@ -2238,10 +2235,16 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* {@linkplain Scope#isAlive() alive}.
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code dstSegment().isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if {@code srcArray} is not an array, or if it is an array but whose type is not supported,
* if the source array component type does not match the carrier of the destination element layout, if the destination
* segment/offset are <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the destination element layout,
* or if the destination element layout alignment is greater than its size.
* @throws IllegalArgumentException if {@code srcArray} is not an array, or if it is an array but whose type is not supported.
* @throws IllegalArgumentException if the source array component type does not match {@code srcLayout.carrier()}.
* @throws IllegalArgumentException if {@code offset} is <a href="MemorySegment.html#segment-alignment">incompatible
* with the alignment constraint</a> in the source element layout.
* @throws IllegalArgumentException if {@code dstLayout.byteAlignment() > dstLayout.byteSize()}.
* @throws UnsupportedOperationException if {@code dstSegment} is {@linkplain #isReadOnly() read-only}.
* @throws IndexOutOfBoundsException if {@code elementCount * dstLayout.byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code dstOffset > dstSegment.byteSize() - (elementCount * dstLayout.byteSize())}.
* @throws IndexOutOfBoundsException if {@code srcIndex > srcArray.length - elementCount}.
* @throws IndexOutOfBoundsException if either {@code srcIndex}, {@code dstOffset} or {@code elementCount} are {@code < 0}.
*/
@ForceInline
static void copy(

View File

@ -38,16 +38,21 @@ import jdk.internal.javac.PreviewFeature;
/**
* An object that may be used to allocate {@linkplain MemorySegment memory segments}. Clients implementing this interface
* must implement the {@link #allocate(long, long)} method. This interface defines several default methods
* must implement the {@link #allocate(long, long)} method. A segment allocator defines several methods
* which can be useful to create segments from several kinds of Java values such as primitives and arrays.
* This interface is a {@linkplain FunctionalInterface functional interface}: clients can easily obtain a new segment allocator
* by using either a lambda expression or a method reference.
* <p>
* This interface also defines factories for commonly used allocators:
* {@code SegmentAllocator} is a {@linkplain FunctionalInterface functional interface}. Clients can easily obtain a new
* segment allocator by using either a lambda expression or a method reference:
*
* {@snippet lang=java :
* SegmentAllocator autoAllocator = (byteSize, byteAlignment) -> Arena.ofAuto().allocate(byteSize, byteAlignment);
* }
* <p>
* This interface defines factories for commonly used allocators:
* <ul>
* <li>{@link #slicingAllocator(MemorySegment)} obtains an efficient slicing allocator, where memory
* is allocated by repeatedly slicing the provided memory segment;</li>
* <li>{@link #prefixAllocator(MemorySegment)} obtains an allocator which wraps a segment (either on-heap or off-heap)
* <li>{@link #prefixAllocator(MemorySegment)} obtains an allocator which wraps a segment
* and recycles its content upon each new allocation request.</li>
* </ul>
* <p>
@ -55,7 +60,15 @@ import jdk.internal.javac.PreviewFeature;
* the results of a certain operation (performed by the API) should be stored, as a memory segment. For instance,
* {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handles} can accept an additional
* {@link SegmentAllocator} parameter if the underlying foreign function is known to return a struct by-value. Effectively,
* the allocator parameter tells the linker runtime where to store the return value of the foreign function.
* the allocator parameter tells the linker where to store the return value of the foreign function.
*
* @apiNote Unless otherwise specified, the {@link #allocate(long, long)} method is not thread-safe.
* Furthermore, memory segments allocated by a segment allocator can be associated with different
* lifetimes, and can even be backed by overlapping regions of memory. For these reasons, clients should generally
* only interact with a segment allocator they own.
* <p>
* Clients should consider using an {@linkplain Arena arena} instead, which, provides strong thread-safety,
* lifetime and non-overlapping guarantees.
*/
@FunctionalInterface
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
@ -311,6 +324,7 @@ public interface SegmentAllocator {
* @param elementLayout the array element layout.
* @param count the array element count.
* @return a segment for the newly allocated memory block.
* @throws IllegalArgumentException if {@code elementLayout.byteSize() * count} overflows.
* @throws IllegalArgumentException if {@code count < 0}.
*/
default MemorySegment allocateArray(MemoryLayout elementLayout, long count) {
@ -338,7 +352,7 @@ public interface SegmentAllocator {
* @param byteAlignment the alignment (in bytes) of the block of memory to be allocated.
* @return a segment for the newly allocated memory block.
* @throws IllegalArgumentException if {@code byteSize < 0}, {@code byteAlignment <= 0},
* or if {@code alignmentBytes} is not a power of 2.
* or if {@code byteAlignment} is not a power of 2.
*/
MemorySegment allocate(long byteSize, long byteAlignment);
@ -347,8 +361,9 @@ public interface SegmentAllocator {
* obtained from the provided segment. Each new allocation request will return a new slice starting at the
* current offset (modulo additional padding to satisfy alignment constraint), with given size.
* <p>
* When the returned allocator cannot satisfy an allocation request, e.g. because a slice of the provided
* segment with the requested size cannot be found, an {@link IndexOutOfBoundsException} is thrown.
* The returned allocator throws {@link IndexOutOfBoundsException} when a slice of the provided
* segment with the requested size and alignment cannot be found.
* @implNote A slicing allocator is not <em>thread-safe</em>.
*
* @param segment the segment which the returned allocator should slice from.
* @return a new slicing allocator
@ -365,14 +380,15 @@ public interface SegmentAllocator {
* Equivalent to (but likely more efficient than) the following code:
* {@snippet lang=java :
* MemorySegment segment = ...
* SegmentAllocator prefixAllocator = (size, align) -> segment.asSlice(0, size);
* SegmentAllocator prefixAllocator = (size, align) -> segment.asSlice(0, size, align);
* }
* <p>
* This allocator can be useful to limit allocation requests in case a client
* The returned allocator throws {@link IndexOutOfBoundsException} when a slice of the provided
* segment with the requested size and alignment cannot be found.
*
* @apiNote A prefix allocator can be useful to limit allocation requests in case a client
* knows that they have fully processed the contents of the allocated segment before the subsequent allocation request
* takes place.
* <p>
* While the allocator returned by this method is <em>thread-safe</em>, concurrent access on the same recycling
* @implNote While a prefix allocator is <em>thread-safe</em>, concurrent access on the same recycling
* allocator might cause a thread to overwrite contents written to the underlying segment by a different thread.
*
* @param segment the memory segment to be recycled by the returned allocator.

View File

@ -29,9 +29,9 @@ import jdk.internal.foreign.layout.SequenceLayoutImpl;
import jdk.internal.javac.PreviewFeature;
/**
* A compound layout that denotes a repetition of a given <em>element layout</em>.
* The repetition count is said to be the sequence layout's <em>element count</em>. A finite sequence can be thought of as a
* group layout where the sequence layout's element layout is repeated a number of times that is equal to the sequence
* A compound layout that denotes a homogeneous repetition of a given <em>element layout</em>.
* The repetition count is said to be the sequence layout's <em>element count</em>. A sequence layout can be thought of as a
* struct layout where the sequence layout's element layout is repeated a number of times that is equal to the sequence
* layout's element count. In other words this layout:
*
* {@snippet lang=java :
@ -57,7 +57,7 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
/**
* {@return the element layout associated with this sequence layout}
* {@return the element layout of this sequence layout}
*/
MemoryLayout elementLayout();
@ -67,18 +67,17 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
long elementCount();
/**
* Returns a sequence layout with the same element layout, alignment constraint and name as this sequence layout,
* but with the specified element count.
* {@return a sequence layout with the same characteristics of this layout, but with the given element count}
* @param elementCount the new element count.
* @return a sequence layout with the given element count.
* @throws IllegalArgumentException if {@code elementCount < 0}.
* @throws IllegalArgumentException if {@code elementCount} is negative.
* @throws IllegalArgumentException if {@code elementLayout.bitSize() * elementCount} overflows.
*/
SequenceLayout withElementCount(long elementCount);
/**
* Re-arrange the elements in this sequence layout into a multi-dimensional sequence layout.
* The resulting layout is a sequence layout where element layouts in the flattened projection of this
* sequence layout (see {@link #flatten()}) are re-arranged into one or more nested sequence layouts
* Rearranges the elements in this sequence layout into a multi-dimensional sequence layout.
* The resulting layout is a sequence layout where element layouts in the {@linkplain #flatten() flattened projection}
* of this sequence layout are rearranged into one or more nested sequence layouts
* according to the provided element counts. This transformation preserves the layout size;
* that is, multiplying the provided element counts must yield the same element count
* as the flattened projection of this sequence layout.
@ -101,7 +100,7 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
* var reshapeSeqImplicit2 = seq.reshape(2, -1);
* }
* @param elementCounts an array of element counts, of which at most one can be {@code -1}.
* @return a sequence layout where element layouts in the flattened projection of this
* @return a sequence layout where element layouts in the {@linkplain #flatten() flattened projection} of this
* sequence layout (see {@link #flatten()}) are re-arranged into one or more nested sequence layouts.
* @throws IllegalArgumentException if two or more element counts are set to {@code -1}, or if one
* or more element count is {@code <= 0} (but other than {@code -1}) or, if, after any required inference,
@ -112,7 +111,16 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
/**
* Returns a flattened sequence layout. The element layout of the returned sequence layout
* is the first non-sequence element layout found by recursively traversing the element layouts of this sequence layout.
* is the first non-sequence layout found by inspecting (recursively, if needed) the element layout of this sequence layout:
* {@snippet lang=java :
* MemoryLayout flatElementLayout(SequenceLayout sequenceLayout) {
* return switch (sequenceLayout.elementLayout()) {
* case SequenceLayout nestedSequenceLayout -> flatElementLayout(nestedSequenceLayout);
* case MemoryLayout layout -> layout;
* };
* }
* }
* <p>
* This transformation preserves the layout size; nested sequence layout in this sequence layout will
* be dropped and their element counts will be incorporated into that of the returned sequence layout.
* For instance, given a sequence layout of the kind:

View File

@ -55,7 +55,7 @@ import java.util.function.BiFunction;
* <li>It can be passed to an existing {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle}, as an argument to the underlying foreign function.</li>
* <li>It can be {@linkplain MemorySegment#set(AddressLayout, long, MemorySegment) stored} inside another memory segment.</li>
* <li>It can be used to access the region of memory backing a global variable (this requires
* {@link MemorySegment#reinterpret(long)} () resizing} the segment first).</li>
* {@linkplain MemorySegment#reinterpret(long) resizing} the segment first).</li>
* </ul>
*
* <h2 id="obtaining">Obtaining a symbol lookup</h2>
@ -65,7 +65,7 @@ import java.util.function.BiFunction;
* The library is loaded if not already loaded. The symbol lookup, which is known as a <em>library lookup</em>, and its
* lifetime is controlled by an {@linkplain Arena arena}. For instance, if the provided arena is a
* confined arena, the library associated with the symbol lookup is unloaded when the confined arena
* is {@linkplain Arena#close()}:
* is {@linkplain Arena#close() closed}:
*
* {@snippet lang = java:
* try (Arena arena = Arena.ofConfined()) {
@ -210,15 +210,16 @@ public interface SymbolLookup {
* For instance, if the provided arena is a confined arena, the library
* associated with the returned lookup will be unloaded when the provided confined arena is
* {@linkplain Arena#close() closed}.
* @implNote The process of resolving a library name is OS-specific. For instance, in a POSIX-compliant OS,
* the library name is resolved according to the specification of the {@code dlopen} function for that OS.
* In Windows, the library name is resolved according to the specification of the {@code LoadLibrary} function.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
* restricted methods, and use safe and supported functionalities, where possible.
*
* @implNote The process of resolving a library name is OS-specific. For instance, in a POSIX-compliant OS,
* the library name is resolved according to the specification of the {@code dlopen} function for that OS.
* In Windows, the library name is resolved according to the specification of the {@code LoadLibrary} function.
*
* @param name the name of the library in which symbols should be looked up.
* @param arena the arena associated with symbols obtained from the returned lookup.
* @return a new symbol lookup suitable to find symbols in a library with the given name.

View File

@ -42,9 +42,11 @@ import jdk.internal.javac.PreviewFeature;
* {@linkplain MemorySegment#get(OfInt, long) accessing} a region of memory using the value layout.
* <p>
* This class defines useful value layout constants for Java primitive types and addresses.
* The layout constants in this class make implicit alignment and byte-ordering assumption: all layout
* constants in this class are byte-aligned, and their byte order is set to the {@linkplain ByteOrder#nativeOrder() platform default},
* thus making it easy to work with other APIs, such as arrays and {@link java.nio.ByteBuffer}.
* @apiNote Some characteristics of the Java layout constants are platform-dependent. For instance, the byte order of
* these constants is set to the {@linkplain ByteOrder#nativeOrder() native byte order}, thus making it easy to work
* with other APIs, such as arrays and {@link java.nio.ByteBuffer}. Moreover, the alignment constraint of
* {@link ValueLayout#JAVA_LONG} and {@link ValueLayout#JAVA_DOUBLE} is set to 8 bytes on 64-bit platforms, but only to
* 4 bytes on 32-bit platforms.
*
* @implSpec implementing classes and subclasses are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
@ -62,11 +64,9 @@ public sealed interface ValueLayout extends MemoryLayout permits
ByteOrder order();
/**
* Returns a value layout with the same carrier, alignment constraint and name as this value layout,
* but with the specified byte order.
* {@return a value layout with the same characteristics as this layout, but with the given byte order}
*
* @param order the desired byte order.
* @return a value layout with the given byte order.
*/
ValueLayout withOrder(ByteOrder order);
@ -78,12 +78,10 @@ public sealed interface ValueLayout extends MemoryLayout permits
/**
* Creates a <em>strided</em> var handle that can be used to access a memory segment as multi-dimensional
* array. The layout of this array is a sequence layout with {@code shape.length} nested sequence layouts. The element
* layout of the sequence layout at depth {@code shape.length} is this value layout.
* As a result, if {@code shape.length == 0}, the array layout will feature only one dimension.
* <p>
* The resulting var handle will feature {@code sizes.length + 1} coordinates of type {@code long}, which are
* used as indices into a multi-dimensional array.
* array. This array has a notional sequence layout featuring {@code shape.length} nested sequence layouts. The element
* layout of the innermost sequence layout in the notional sequence layout is this value layout. The resulting var handle
* is obtained as if calling the {@link #varHandle(PathElement...)} method on the notional layout, with a layout
* path containing exactly {@code shape.length + 1} {@linkplain PathElement#sequenceElement() open sequence layout path elements}.
* <p>
* For instance, the following method call:
*
@ -91,12 +89,14 @@ public sealed interface ValueLayout extends MemoryLayout permits
* VarHandle arrayHandle = ValueLayout.JAVA_INT.arrayElementVarHandle(10, 20);
* }
*
* Can be used to access a multi-dimensional array whose layout is as follows:
* Is equivalent to the following code:
*
* {@snippet lang = java:
* SequenceLayout arrayLayout = MemoryLayout.sequenceLayout(
* MemoryLayout.sequenceLayout(10,
* MemoryLayout.sequenceLayout(20, ValueLayout.JAVA_INT)));
* SequenceLayout notionalLayout = MemoryLayout.sequenceLayout(
* MemoryLayout.sequenceLayout(10, MemoryLayout.sequenceLayout(20, ValueLayout.JAVA_INT)));
* VarHandle arrayHandle = notionalLayout.varHandle(PathElement.sequenceElement(),
* PathElement.sequenceElement(),
* PathElement.sequenceElement());
*}
*
* The resulting var handle {@code arrayHandle} will feature 3 coordinates of type {@code long}; each coordinate
@ -110,7 +110,7 @@ public sealed interface ValueLayout extends MemoryLayout permits
*
* Additionally, the values of {@code x}, {@code y} and {@code z} are constrained as follows:
* <ul>
* <li>{@code 0 <= x < arrayLayout.elementCount() }</li>
* <li>{@code 0 <= x < notionalLayout.elementCount() }</li>
* <li>{@code 0 <= y < 10 }</li>
* <li>{@code 0 <= z < 20 }</li>
* </ul>
@ -448,7 +448,7 @@ public sealed interface ValueLayout extends MemoryLayout permits
}
/**
* A value layout constant whose size is the same as that of a machine address ({@code size_t}),
* An address layout constant whose size is the same as that of a machine address ({@code size_t}),
* byte alignment set to {@code sizeof(size_t)}, byte order set to {@link ByteOrder#nativeOrder()}.
*/
AddressLayout ADDRESS = ValueLayouts.OfAddressImpl.of(ByteOrder.nativeOrder());
@ -504,7 +504,7 @@ public sealed interface ValueLayout extends MemoryLayout permits
OfDouble JAVA_DOUBLE = ValueLayouts.OfDoubleImpl.of(ByteOrder.nativeOrder());
/**
* An unaligned value layout constant whose size is the same as that of a machine address ({@code size_t}),
* An unaligned address layout constant whose size is the same as that of a machine address ({@code size_t}),
* and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :

View File

@ -77,8 +77,8 @@
* <h2 id="ffa">Foreign function access</h2>
* The key abstractions introduced to support foreign function access are {@link java.lang.foreign.SymbolLookup},
* {@link java.lang.foreign.FunctionDescriptor} and {@link java.lang.foreign.Linker}. The first is used to look up symbols
* inside libraries; the second is used to model the signature of foreign functions, while the third provides
* linking capabilities which allows modelling foreign functions as {@link java.lang.invoke.MethodHandle} instances,
* inside libraries; the second is used to model the signature of foreign functions, while the third is used
* to link foreign functions as {@link java.lang.invoke.MethodHandle} instances,
* so that clients can perform foreign function calls directly in Java, without the need for intermediate layers of C/C++
* code (as is the case with the <a href="{@docRoot}/../specs/jni/index.html">Java Native Interface (JNI)</a>).
* <p>
@ -116,7 +116,7 @@
* <h2 id="restricted">Restricted methods</h2>
* Some methods in this package are considered <em>restricted</em>. Restricted methods are typically used to bind native
* foreign data and/or functions to first-class Java API elements which can then be used directly by clients. For instance
* the restricted method {@link java.lang.foreign.MemorySegment#reinterpret(long)} ()}
* the restricted method {@link java.lang.foreign.MemorySegment#reinterpret(long)}
* can be used to create a fresh segment with the same address and temporal bounds,
* but with the provided size. This can be useful to resize memory segments obtained when interacting with native functions.
* <p>

View File

@ -186,16 +186,16 @@ class Snippets {
}
}
FunctionDescriptor compareDesc = FunctionDescriptor.of(JAVA_INT,
FunctionDescriptor comparDesc = FunctionDescriptor.of(JAVA_INT,
ADDRESS.withTargetLayout(JAVA_INT),
ADDRESS.withTargetLayout(JAVA_INT));
MethodHandle compareHandle = MethodHandles.lookup()
MethodHandle comparHandle = MethodHandles.lookup()
.findStatic(Qsort.class, "qsortCompare",
compareDesc.toMethodType());
comparDesc.toMethodType());
try (Arena arena = Arena.ofConfined()) {
MemorySegment compareFunc = linker.upcallStub(compareHandle, compareDesc, arena);
MemorySegment compareFunc = linker.upcallStub(comparHandle, comparDesc, 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 ]
@ -400,7 +400,7 @@ class Snippets {
.findStatic(Math.class, "multiplyExact",
MethodType.methodType(long.class, long.class, long.class));
intHandle = MethodHandles.filterCoordinates(intHandle, 1,
MethodHandles.insertArguments(multiplyExact, 0, 4L));
MethodHandles.insertArguments(multiplyExact, 0, ValueLayout.JAVA_INT.byteSize()));
int value = (int) intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
}

View File

@ -7956,18 +7956,18 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
/**
* Creates a var handle object, which can be used to dereference a {@linkplain java.lang.foreign.MemorySegment memory segment}
* by viewing its contents as a sequence of the provided value layout.
* at a given byte offset, using the provided value layout.
*
* <p>The provided layout specifies the {@linkplain ValueLayout#carrier() carrier type},
* the {@linkplain ValueLayout#byteSize() byte size},
* the {@linkplain ValueLayout#byteAlignment() byte alignment} and the {@linkplain ValueLayout#order() byte order}
* associated with the returned var handle.
*
* <p>The returned var handle's type is {@code carrier} and the list of coordinate types is
* {@code (MemorySegment, long)}, where the {@code long} coordinate type corresponds to byte offset into
* a given memory segment. The returned var handle accesses bytes at an offset in a given
* memory segment, composing bytes to or from a value of the type {@code carrier} according to the given endianness;
* the alignment constraint (in bytes) for the resulting var handle is given by {@code alignmentBytes}.
* <p>The list of coordinate types associated with the returned var handle is {@code (MemorySegment, long)},
* where the {@code long} coordinate type corresponds to byte offset into the given memory segment coordinate.
* Thus, the returned var handle accesses bytes at an offset in a given memory segment, composing bytes to or from
* a value of the var handle type. Moreover, the access operation will honor the endianness and the
* alignment constraints expressed in the provided layout.
*
* <p>As an example, consider the memory layout expressed by a {@link GroupLayout} instance constructed as follows:
* {@snippet lang="java" :
@ -8023,7 +8023,6 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
*
* @param layout the value layout for which a memory access handle is to be obtained.
* @return the new memory segment view var handle.
* @throws IllegalArgumentException if an illegal carrier type is used, or if {@code alignmentBytes} is not a power of two.
* @throws NullPointerException if {@code layout} is {@code null}.
* @see MemoryLayout#varHandle(MemoryLayout.PathElement...)
* @since 19

View File

@ -114,6 +114,8 @@ public abstract sealed class AbstractMemorySegmentImpl
@Override
public MemorySegment asSlice(long offset, long newSize, long byteAlignment) {
checkBounds(offset, newSize);
Utils.checkAlign(byteAlignment);
if (!isAlignedForElement(offset, byteAlignment)) {
throw new IllegalArgumentException("Target offset incompatible with alignment constraints");
}

View File

@ -40,6 +40,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import jdk.internal.access.SharedSecrets;
import jdk.internal.foreign.abi.SharedUtils;
@ -166,11 +167,16 @@ public final class Utils {
}
@ForceInline
public static void checkElementAlignment(ValueLayout layout, String msg) {
public static boolean isElementAligned(ValueLayout layout) {
// Fast-path: if both size and alignment are powers of two, we can just
// check if one is greater than the other.
assert isPowerOfTwo(layout.byteSize());
if (layout.byteAlignment() > layout.byteSize()) {
return layout.byteAlignment() <= layout.byteSize();
}
@ForceInline
public static void checkElementAlignment(ValueLayout layout, String msg) {
if (!isElementAligned(layout)) {
throw new IllegalArgumentException(msg);
}
}
@ -200,6 +206,10 @@ public final class Utils {
throw new IllegalArgumentException("Invalid allocation size : " + byteSize);
}
checkAlign(byteAlignment);
}
public static void checkAlign(long byteAlignment) {
// alignment should be > 0, and power of two
if (byteAlignment <= 0 ||
((byteAlignment & (byteAlignment - 1)) != 0L)) {
@ -252,6 +262,14 @@ public final class Utils {
return (value & (value - 1)) == 0L;
}
public static <L extends MemoryLayout> L wrapOverflow(Supplier<L> layoutSupplier) {
try {
return layoutSupplier.get();
} catch (ArithmeticException ex) {
throw new IllegalArgumentException("Layout size exceeds Long.MAX_VALUE");
}
}
public static boolean containsNullChars(String s) {
return s.indexOf('\u0000') >= 0;
}

View File

@ -55,6 +55,7 @@ import java.lang.invoke.MethodType;
import java.util.List;
import java.nio.ByteOrder;
import java.util.Objects;
import java.util.Set;
public abstract sealed class AbstractLinker implements Linker permits LinuxAArch64Linker, MacOsAArch64Linker,
SysVx64Linker, WindowsAArch64Linker,
@ -173,10 +174,10 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
}
private void checkLayoutRecursive(MemoryLayout layout) {
checkHasNaturalAlignment(layout);
if (layout instanceof ValueLayout vl) {
checkByteOrder(vl);
checkSupported(vl);
} else if (layout instanceof StructLayout sl) {
checkHasNaturalAlignment(layout);
long offset = 0;
long lastUnpaddedOffset = 0;
for (MemoryLayout member : sl.memberLayouts()) {
@ -192,6 +193,7 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
}
checkGroupSize(sl, lastUnpaddedOffset);
} else if (layout instanceof UnionLayout ul) {
checkHasNaturalAlignment(layout);
long maxUnpaddedLayout = 0;
for (MemoryLayout member : ul.memberLayouts()) {
checkLayoutRecursive(member);
@ -201,6 +203,7 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
}
checkGroupSize(ul, maxUnpaddedLayout);
} else if (layout instanceof SequenceLayout sl) {
checkHasNaturalAlignment(layout);
checkLayoutRecursive(sl.elementLayout());
}
}
@ -225,6 +228,16 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
}
}
private static void checkSupported(ValueLayout valueLayout) {
valueLayout = valueLayout.withoutName();
if (valueLayout instanceof AddressLayout addressLayout) {
valueLayout = addressLayout.withoutTargetLayout();
}
if (!SUPPORTED_LAYOUTS.contains(valueLayout.withoutName())) {
throw new IllegalArgumentException("Unsupported layout: " + valueLayout);
}
}
private static void checkHasNaturalAlignment(MemoryLayout layout) {
if (!((AbstractLayout<?>) layout).hasNaturalAlignment()) {
throw new IllegalArgumentException("Layout alignment must be natural alignment: " + layout);
@ -257,9 +270,15 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
.orElseGet(() -> FunctionDescriptor.ofVoid(stripNames(function.argumentLayouts())));
}
private void checkByteOrder(ValueLayout vl) {
if (vl.order() != linkerByteOrder()) {
throw new IllegalArgumentException("Layout does not have the right byte order: " + vl);
}
}
private static final Set<MemoryLayout> SUPPORTED_LAYOUTS = Set.of(
ValueLayout.JAVA_BOOLEAN,
ValueLayout.JAVA_BYTE,
ValueLayout.JAVA_CHAR,
ValueLayout.JAVA_SHORT,
ValueLayout.JAVA_INT,
ValueLayout.JAVA_FLOAT,
ValueLayout.JAVA_LONG,
ValueLayout.JAVA_DOUBLE,
ValueLayout.ADDRESS
);
}

View File

@ -25,6 +25,8 @@
*/
package jdk.internal.foreign.layout;
import jdk.internal.foreign.Utils;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.SequenceLayout;
import java.util.Objects;
@ -68,7 +70,8 @@ public final class SequenceLayoutImpl extends AbstractLayout<SequenceLayoutImpl>
* @throws IllegalArgumentException if {@code elementCount < 0}.
*/
public SequenceLayout withElementCount(long elementCount) {
return new SequenceLayoutImpl(elementCount, elementLayout, byteAlignment(), name());
return Utils.wrapOverflow(() ->
new SequenceLayoutImpl(elementCount, elementLayout, byteAlignment(), name()));
}
/**

View File

@ -117,6 +117,9 @@ public final class ValueLayouts {
public final VarHandle arrayElementVarHandle(int... shape) {
Objects.requireNonNull(shape);
if (!Utils.isElementAligned((ValueLayout) this)) {
throw new UnsupportedOperationException("Layout alignment greater than its size");
}
MemoryLayout layout = self();
List<MemoryLayout.PathElement> path = new ArrayList<>();
for (int i = shape.length; i > 0; i--) {

View File

@ -227,6 +227,21 @@ public class TestArrayCopy {
}
}
@Test(dataProvider = "copyModesAndHelpers")
public void testCopyReadOnlyDest(CopyMode mode, CopyHelper<Object, ValueLayout> helper, String helperDebugString) {
int bytesPerElement = (int)helper.elementLayout.byteSize();
MemorySegment base = srcSegment(SEG_LENGTH_BYTES);
//CopyFrom
Object srcArr = helper.toArray(base);
MemorySegment dstSeg = helper.fromArray(srcArr).asReadOnly();
try {
helper.copyFromArray(srcArr, 0, SEG_LENGTH_BYTES / bytesPerElement, dstSeg, 0, ByteOrder.nativeOrder());
fail();
} catch (UnsupportedOperationException ex) {
//ok
}
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testNotAnArraySrc() {
MemorySegment segment = MemorySegment.ofArray(new int[] {1, 2, 3, 4});

View File

@ -130,6 +130,11 @@ public class TestDereferencePath {
A.byteOffset(PathElement.groupElement("b"), PathElement.dereferenceElement());
}
@Test(expectedExceptions = IllegalArgumentException.class)
void testBadDerefInSlice() {
A.sliceHandle(PathElement.groupElement("b"), PathElement.dereferenceElement());
}
static final MemoryLayout A_MULTI_NO_TARGET = MemoryLayout.structLayout(
ValueLayout.ADDRESS.withName("bs")
);

View File

@ -123,17 +123,17 @@ public class TestIllegalLink extends NativeTestHelper {
{
FunctionDescriptor.ofVoid(C_INT.withByteAlignment(2)),
NO_OPTIONS,
"Layout alignment must be natural alignment"
"Unsupported layout: 2%i4"
},
{
FunctionDescriptor.ofVoid(C_POINTER.withByteAlignment(2)),
NO_OPTIONS,
"Layout alignment must be natural alignment"
"Unsupported layout: 2%a8"
},
{
FunctionDescriptor.ofVoid(ValueLayout.JAVA_CHAR.withByteAlignment(4)),
NO_OPTIONS,
"Layout alignment must be natural alignment"
"Unsupported layout: 4%c2"
},
{
FunctionDescriptor.ofVoid(MemoryLayout.structLayout(
@ -142,7 +142,7 @@ public class TestIllegalLink extends NativeTestHelper {
C_INT.withName("z").withByteAlignment(1)
).withByteAlignment(1)),
NO_OPTIONS,
"Layout alignment must be natural alignment"
"Unsupported layout: 1%s2"
},
{
FunctionDescriptor.ofVoid(MemoryLayout.structLayout(
@ -152,7 +152,7 @@ public class TestIllegalLink extends NativeTestHelper {
C_INT.withName("z").withByteAlignment(1)
))),
NO_OPTIONS,
"Layout alignment must be natural alignment"
"Unsupported layout: 1%s2"
},
{
FunctionDescriptor.ofVoid(MemoryLayout.structLayout(
@ -160,7 +160,7 @@ public class TestIllegalLink extends NativeTestHelper {
C_INT.withByteAlignment(1)
))),
NO_OPTIONS,
"Layout alignment must be natural alignment"
"Unsupported layout: 1%i4"
},
{
FunctionDescriptor.ofVoid(MemoryLayout.structLayout(
@ -173,17 +173,17 @@ public class TestIllegalLink extends NativeTestHelper {
{
FunctionDescriptor.of(C_INT.withOrder(nonNativeOrder())),
NO_OPTIONS,
"Layout does not have the right byte order"
"Unsupported layout: I4"
},
{
FunctionDescriptor.of(MemoryLayout.structLayout(C_INT.withOrder(nonNativeOrder()))),
NO_OPTIONS,
"Layout does not have the right byte order"
"Unsupported layout: I4"
},
{
FunctionDescriptor.of(MemoryLayout.structLayout(MemoryLayout.sequenceLayout(C_INT.withOrder(nonNativeOrder())))),
NO_OPTIONS,
"Layout does not have the right byte order"
"Unsupported layout: I4"
},
{
FunctionDescriptor.ofVoid(MemoryLayout.structLayout(

View File

@ -122,10 +122,16 @@ public class TestLayoutPaths {
seq.varHandle(sequenceElement());
}
@Test
public void testByteOffsetHandleRange() {
SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT));
seq.byteOffsetHandle(sequenceElement(0, 1));
}
@Test(expectedExceptions = IllegalArgumentException.class)
public void testByteOffsetHandleBadRange() {
SequenceLayout seq = MemoryLayout.sequenceLayout(5, MemoryLayout.structLayout(JAVA_INT));
seq.byteOffsetHandle(sequenceElement(0, 1)); // ranges not accepted
seq.byteOffsetHandle(sequenceElement(5, 1)); // invalid range (starting position is outside the sequence)
}
@Test

View File

@ -218,6 +218,8 @@ public class TestLayouts {
() -> MemoryLayout.sequenceLayout(Long.MAX_VALUE, JAVA_SHORT));
assertThrows(IllegalArgumentException.class, // flip back to positive
() -> MemoryLayout.sequenceLayout(Long.MAX_VALUE/3, JAVA_LONG));
assertThrows(IllegalArgumentException.class, // flip back to positive
() -> MemoryLayout.sequenceLayout(0, JAVA_LONG).withElementCount(Long.MAX_VALUE));
}
@Test
@ -333,6 +335,14 @@ public class TestLayouts {
}
}
@Test(dataProvider="layoutsAndAlignments")
public void testArrayElementVarHandleBadAlignment(MemoryLayout layout, long byteAlign) {
if (layout instanceof ValueLayout) {
assertThrows(UnsupportedOperationException.class, () ->
((ValueLayout) layout).withByteAlignment(byteAlign * 2).arrayElementVarHandle());
}
}
@Test(dataProvider="layoutsAndAlignments", expectedExceptions = IllegalArgumentException.class)
public void testBadStruct(MemoryLayout layout, long byteAlign) {
layout = layout.withByteAlignment(layout.byteSize() * 2); // hyper-align

View File

@ -27,12 +27,12 @@
* @run testng/othervm --enable-native-access=ALL-UNNAMED TestMemoryAccessInstance
*/
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.Arena;
import java.lang.foreign.ValueLayout;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.function.Function;
import org.testng.annotations.*;
import org.testng.SkipException;
@ -40,14 +40,14 @@ import static org.testng.Assert.*;
public class TestMemoryAccessInstance {
static class Accessor<T, X, L extends ValueLayout> {
static class Accessor<X, L extends ValueLayout> {
interface SegmentGetter<T, X, L> {
X get(T buffer, L layout, long offset);
interface SegmentGetter<X, L> {
X get(MemorySegment segment, L layout, long offset);
}
interface SegmentSetter<T, X, L> {
void set(T buffer, L layout, long offset, X o);
interface SegmentSetter<X, L> {
void set(MemorySegment segment, L layout, long offset, X o);
}
interface BufferGetter<X> {
@ -60,16 +60,14 @@ public class TestMemoryAccessInstance {
final X value;
final L layout;
final Function<MemorySegment, T> transform;
final SegmentGetter<T, X, L> segmentGetter;
final SegmentSetter<T, X, L> segmentSetter;
final SegmentGetter<X, L> segmentGetter;
final SegmentSetter<X, L> segmentSetter;
final BufferGetter<X> bufferGetter;
final BufferSetter<X> bufferSetter;
Accessor(Function<MemorySegment, T> transform, L layout, X value,
SegmentGetter<T, X, L> segmentGetter, SegmentSetter<T, X, L> segmentSetter,
Accessor(L layout, X value,
SegmentGetter<X, L> segmentGetter, SegmentSetter<X, L> segmentSetter,
BufferGetter<X> bufferGetter, BufferSetter<X> bufferSetter) {
this.transform = transform;
this.layout = layout;
this.value = value;
this.segmentGetter = segmentGetter;
@ -82,11 +80,10 @@ public class TestMemoryAccessInstance {
try (Arena arena = Arena.ofConfined()) {
MemorySegment segment = arena.allocate(128, 1);
ByteBuffer buffer = segment.asByteBuffer();
T t = transform.apply(segment);
segmentSetter.set(t, layout, 8, value);
segmentSetter.set(segment, layout, 8, value);
assertEquals(bufferGetter.get(buffer, 8), value);
bufferSetter.set(buffer, 8, value);
assertEquals(value, segmentGetter.get(t, layout, 8));
assertEquals(value, segmentGetter.get(segment, layout, 8));
}
}
@ -94,16 +91,15 @@ public class TestMemoryAccessInstance {
void testHyperAligned() {
try (Arena arena = Arena.ofConfined()) {
MemorySegment segment = arena.allocate(64, 1);
T t = transform.apply(segment);
L alignedLayout = (L)layout.withByteAlignment(layout.byteSize() * 2);
try {
segmentSetter.set(t, alignedLayout, 0, value);
segmentSetter.set(segment, alignedLayout, 0, value);
fail();
} catch (IllegalArgumentException exception) {
assertTrue(exception.getMessage().contains("greater"));
}
try {
segmentGetter.get(t, alignedLayout, 0);
segmentGetter.get(segment, alignedLayout, 0);
fail();
} catch (IllegalArgumentException exception) {
assertTrue(exception.getMessage().contains("greater"));
@ -111,20 +107,28 @@ public class TestMemoryAccessInstance {
}
}
static <L extends ValueLayout, X> Accessor<MemorySegment, X, L> ofSegment(L layout, X value,
SegmentGetter<MemorySegment, X, L> segmentGetter, SegmentSetter<MemorySegment, X, L> segmentSetter,
BufferGetter<X> bufferGetter, BufferSetter<X> bufferSetter) {
return new Accessor<>(Function.identity(), layout, value, segmentGetter, segmentSetter, bufferGetter, bufferSetter);
X get(MemorySegment segment, long offset) {
return segmentGetter.get(segment, layout, offset);
}
void set(MemorySegment segment, long offset, X value) {
segmentSetter.set(segment, layout, offset, value);
}
static <L extends ValueLayout, X> Accessor<X, L> of(L layout, X value,
SegmentGetter<X, L> segmentGetter, SegmentSetter<X, L> segmentSetter,
BufferGetter<X> bufferGetter, BufferSetter<X> bufferSetter) {
return new Accessor<>(layout, value, segmentGetter, segmentSetter, bufferGetter, bufferSetter);
}
}
@Test(dataProvider = "segmentAccessors")
public void testSegmentAccess(String testName, Accessor<?, ?, ?> accessor) {
public void testSegmentAccess(String testName, Accessor<?, ?> accessor) {
accessor.test();
}
@Test(dataProvider = "segmentAccessors")
public void testSegmentAccessHyper(String testName, Accessor<?, ?, ?> accessor) {
public void testSegmentAccessHyper(String testName, Accessor<?, ?> accessor) {
if (testName.contains("index")) {
accessor.testHyperAligned();
} else {
@ -152,45 +156,54 @@ public class TestMemoryAccessInstance {
targetSegment.setAtIndex(ValueLayout.ADDRESS, 0, segment); // should throw
}
@Test(dataProvider = "segmentAccessors")
public <X, L extends ValueLayout> void badAccessOverflowInIndexedAccess(String testName, Accessor<X, L> accessor) {
MemorySegment segment = MemorySegment.ofArray(new byte[100]);
if (testName.contains("/index") && accessor.layout.byteSize() > 1) {
assertThrows(IndexOutOfBoundsException.class, () -> accessor.get(segment, Long.MAX_VALUE));
assertThrows(IndexOutOfBoundsException.class, () -> accessor.set(segment, Long.MAX_VALUE, accessor.value));
}
}
static final ByteOrder NE = ByteOrder.nativeOrder();
@DataProvider(name = "segmentAccessors")
static Object[][] segmentAccessors() {
return new Object[][]{
{"byte", Accessor.ofSegment(ValueLayout.JAVA_BYTE, (byte) 42,
{"byte", Accessor.of(ValueLayout.JAVA_BYTE, (byte) 42,
MemorySegment::get, MemorySegment::set,
ByteBuffer::get, ByteBuffer::put)
},
{"boolean", Accessor.ofSegment(ValueLayout.JAVA_BOOLEAN, false,
{"boolean", Accessor.of(ValueLayout.JAVA_BOOLEAN, false,
MemorySegment::get, MemorySegment::set,
(bb, pos) -> bb.get(pos) != 0, (bb, pos, v) -> bb.put(pos, v ? (byte)1 : (byte)0))
},
{"char", Accessor.ofSegment(ValueLayout.JAVA_CHAR, (char) 42,
{"char", Accessor.of(ValueLayout.JAVA_CHAR, (char) 42,
MemorySegment::get, MemorySegment::set,
(bb, pos) -> bb.order(NE).getChar(pos), (bb, pos, v) -> bb.order(NE).putChar(pos, v))
},
{"short", Accessor.ofSegment(ValueLayout.JAVA_SHORT, (short) 42,
{"short", Accessor.of(ValueLayout.JAVA_SHORT, (short) 42,
MemorySegment::get, MemorySegment::set,
(bb, pos) -> bb.order(NE).getShort(pos), (bb, pos, v) -> bb.order(NE).putShort(pos, v))
},
{"int", Accessor.ofSegment(ValueLayout.JAVA_INT, 42,
{"int", Accessor.of(ValueLayout.JAVA_INT, 42,
MemorySegment::get, MemorySegment::set,
(bb, pos) -> bb.order(NE).getInt(pos), (bb, pos, v) -> bb.order(NE).putInt(pos, v))
},
{"float", Accessor.ofSegment(ValueLayout.JAVA_FLOAT, 42f,
{"float", Accessor.of(ValueLayout.JAVA_FLOAT, 42f,
MemorySegment::get, MemorySegment::set,
(bb, pos) -> bb.order(NE).getFloat(pos), (bb, pos, v) -> bb.order(NE).putFloat(pos, v))
},
{"long", Accessor.ofSegment(ValueLayout.JAVA_LONG, 42L,
{"long", Accessor.of(ValueLayout.JAVA_LONG, 42L,
MemorySegment::get, MemorySegment::set,
(bb, pos) -> bb.order(NE).getLong(pos), (bb, pos, v) -> bb.order(NE).putLong(pos, v))
},
{"double", Accessor.ofSegment(ValueLayout.JAVA_DOUBLE, 42d,
{"double", Accessor.of(ValueLayout.JAVA_DOUBLE, 42d,
MemorySegment::get, MemorySegment::set,
(bb, pos) -> bb.order(NE).getDouble(pos), (bb, pos, v) -> bb.order(NE).putDouble(pos, v))
},
{ "address", Accessor.ofSegment(ValueLayout.ADDRESS, MemorySegment.ofAddress(42),
{ "address", Accessor.of(ValueLayout.ADDRESS, MemorySegment.ofAddress(42),
MemorySegment::get, MemorySegment::set,
(bb, pos) -> {
ByteBuffer nb = bb.order(NE);
@ -208,39 +221,39 @@ public class TestMemoryAccessInstance {
})
},
{"byte/index", Accessor.ofSegment(ValueLayout.JAVA_BYTE, (byte) 42,
{"byte/index", Accessor.of(ValueLayout.JAVA_BYTE, (byte) 42,
MemorySegment::getAtIndex, MemorySegment::setAtIndex,
(bb, pos) -> bb.order(NE).get(pos), (bb, pos, v) -> bb.order(NE).put(pos, v))
},
{"boolean/index", Accessor.ofSegment(ValueLayout.JAVA_BOOLEAN, true,
{"boolean/index", Accessor.of(ValueLayout.JAVA_BOOLEAN, true,
MemorySegment::getAtIndex, MemorySegment::setAtIndex,
(bb, pos) -> bb.order(NE).get(pos) != 0, (bb, pos, v) -> bb.order(NE).put(pos, (byte) (v ? 1 : 0)))
},
{"char/index", Accessor.ofSegment(ValueLayout.JAVA_CHAR, (char) 42,
{"char/index", Accessor.of(ValueLayout.JAVA_CHAR, (char) 42,
MemorySegment::getAtIndex, MemorySegment::setAtIndex,
(bb, pos) -> bb.order(NE).getChar(pos * 2), (bb, pos, v) -> bb.order(NE).putChar(pos * 2, v))
},
{"short/index", Accessor.ofSegment(ValueLayout.JAVA_SHORT, (short) 42,
{"short/index", Accessor.of(ValueLayout.JAVA_SHORT, (short) 42,
MemorySegment::getAtIndex, MemorySegment::setAtIndex,
(bb, pos) -> bb.order(NE).getShort(pos * 2), (bb, pos, v) -> bb.order(NE).putShort(pos * 2, v))
},
{"int/index", Accessor.ofSegment(ValueLayout.JAVA_INT, 42,
{"int/index", Accessor.of(ValueLayout.JAVA_INT, 42,
MemorySegment::getAtIndex, MemorySegment::setAtIndex,
(bb, pos) -> bb.order(NE).getInt(pos * 4), (bb, pos, v) -> bb.order(NE).putInt(pos * 4, v))
},
{"float/index", Accessor.ofSegment(ValueLayout.JAVA_FLOAT, 42f,
{"float/index", Accessor.of(ValueLayout.JAVA_FLOAT, 42f,
MemorySegment::getAtIndex, MemorySegment::setAtIndex,
(bb, pos) -> bb.order(NE).getFloat(pos * 4), (bb, pos, v) -> bb.order(NE).putFloat(pos * 4, v))
},
{"long/index", Accessor.ofSegment(ValueLayout.JAVA_LONG, 42L,
{"long/index", Accessor.of(ValueLayout.JAVA_LONG, 42L,
MemorySegment::getAtIndex, MemorySegment::setAtIndex,
(bb, pos) -> bb.order(NE).getLong(pos * 8), (bb, pos, v) -> bb.order(NE).putLong(pos * 8, v))
},
{"double/index", Accessor.ofSegment(ValueLayout.JAVA_DOUBLE, 42d,
{"double/index", Accessor.of(ValueLayout.JAVA_DOUBLE, 42d,
MemorySegment::getAtIndex, MemorySegment::setAtIndex,
(bb, pos) -> bb.order(NE).getDouble(pos * 8), (bb, pos, v) -> bb.order(NE).putDouble(pos * 8, v))
},
{ "address/index", Accessor.ofSegment(ValueLayout.ADDRESS, MemorySegment.ofAddress(42),
{ "address/index", Accessor.of(ValueLayout.ADDRESS, MemorySegment.ofAddress(42),
MemorySegment::getAtIndex, MemorySegment::setAtIndex,
(bb, pos) -> {
ByteBuffer nb = bb.order(NE);

View File

@ -151,6 +151,11 @@ public class TestSegmentAllocators {
allocator.allocateArray(ValueLayout.JAVA_BYTE, -1);
}
@Test(dataProvider = "allocators", expectedExceptions = IllegalArgumentException.class)
public void testBadAllocationArrayOverflow(SegmentAllocator allocator) {
allocator.allocateArray(ValueLayout.JAVA_LONG, Long.MAX_VALUE);
}
@Test(expectedExceptions = OutOfMemoryError.class)
public void testBadArenaNullReturn() {
try (Arena arena = Arena.ofConfined()) {

View File

@ -35,9 +35,11 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.IntFunction;
import org.testng.SkipException;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@ -75,6 +77,24 @@ public class TestSegmentCopy {
}
}
@Test(expectedExceptions = UnsupportedOperationException.class, dataProvider = "segmentKinds")
public void testReadOnlyCopy(SegmentKind kind1, SegmentKind kind2) {
MemorySegment s1 = kind1.makeSegment(TEST_BYTE_SIZE);
MemorySegment s2 = kind2.makeSegment(TEST_BYTE_SIZE);
// check failure with read-only dest
MemorySegment.copy(s1, Type.BYTE.layout, 0, s2.asReadOnly(), Type.BYTE.layout, 0, 0);
}
@Test(expectedExceptions = IndexOutOfBoundsException.class, dataProvider = "types")
public void testBadOverflow(Type type) {
if (type.layout.byteSize() > 1) {
MemorySegment segment = MemorySegment.ofArray(new byte[100]);
MemorySegment.copy(segment, type.layout, 0, segment, type.layout, 0, Long.MAX_VALUE);
} else {
throw new SkipException("Byte layouts do not overflow");
}
}
@Test(dataProvider = "segmentKindsAndTypes")
public void testElementCopy(SegmentKind kind1, SegmentKind kind2, Type type1, Type type2) {
MemorySegment s1 = kind1.makeSegment(TEST_BYTE_SIZE);
@ -189,6 +209,13 @@ public class TestSegmentCopy {
return cases.toArray(Object[][]::new);
}
@DataProvider
static Object[][] types() {
return Arrays.stream(Type.values())
.map(t -> new Object[] { t })
.toArray(Object[][]::new);
}
@DataProvider
static Object[][] segmentKindsAndTypes() {
List<Object[]> cases = new ArrayList<>();

View File

@ -134,6 +134,22 @@ public class TestSlices {
}
}
@Test
public void testSliceAlignmentPowerOfTwo() {
try (Arena arena = Arena.ofConfined()) {
MemorySegment segment = arena.allocate(100, 4096);
for (int i = 8 ; i < 4096 ; i++) {
boolean badAlign = Long.bitCount(i) != 1; // not a power of two
try {
segment.asSlice(0, 100, i);
assertFalse(badAlign);
} catch (IllegalArgumentException iae) {
assertTrue(badAlign);
}
}
}
}
@DataProvider(name = "slices")
static Object[][] slices() {
return new Object[][] {