diff --git a/src/java.base/share/classes/java/lang/foreign/AddressLayout.java b/src/java.base/share/classes/java/lang/foreign/AddressLayout.java index 9819cc84cc9..877a6432961 100644 --- a/src/java.base/share/classes/java/lang/foreign/AddressLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/AddressLayout.java @@ -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). *
* 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. - *
- * 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()
diff --git a/src/java.base/share/classes/java/lang/foreign/Arena.java b/src/java.base/share/classes/java/lang/foreign/Arena.java
index f111368d7d5..1f3c1adc16d 100644
--- a/src/java.base/share/classes/java/lang/foreign/Arena.java
+++ b/src/java.base/share/classes/java/lang/foreign/Arena.java
@@ -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 bounded lifetime 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
- * after the automatic arena (and all the segments allocated by it) become
+ * after the automatic arena (and all the segments allocated by it) becomes
* unreachable, 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 owner thread.
*/
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();
diff --git a/src/java.base/share/classes/java/lang/foreign/FunctionDescriptor.java b/src/java.base/share/classes/java/lang/foreign/FunctionDescriptor.java
index ab2fa82b10e..f536f6fdcf9 100644
--- a/src/java.base/share/classes/java/lang/foreign/FunctionDescriptor.java
+++ b/src/java.base/share/classes/java/lang/foreign/FunctionDescriptor.java
@@ -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
- * The carrier type of a layout is determined as follows:
+ * The carrier type of a layout {@code L} is determined as follows:
*
- * All the native linker implementations limit the function descriptors that they support to those that contain
- * only so-called canonical 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:
+ *
- * 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 inferred
+ * @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.
*
- * 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}:
*
* 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()}.
*
* 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 inferred
- * 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.
*
@@ -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()}.
*
* 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.
*
* This method is restricted.
* 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 inferred type.
+ * @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 capture state segment, represents the native segment into which
* the captured state is written.
*
- * 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.
*
* 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...)}}
*
- * The capture state layout is platform dependent but is guaranteed to be
+ * The capture state layout is platform-dependent 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 {
*
+ * Clients can obtain the names of the supported captured value layouts as follows:
* {@snippet lang = java:
- * String capturedNames = Linker.Option.captureStateLayout().memberLayouts().stream()
+ * List
- * More complex layouts can be derived from simpler ones: a sequence layout denotes a repetition of one or more
- * element layout (see {@link SequenceLayout}); a group layout 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.
+ *
+ * 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.
*
* Layouts can be optionally associated with a name. A layout name can be referred to when
* constructing layout paths.
@@ -81,47 +85,50 @@ import jdk.internal.javac.PreviewFeature;
* ).withName("TaggedValues");
* }
*
- *
- * Furthermore, all layouts feature a natural alignment which can be inferred as follows:
+ * Furthermore, all layouts have a natural alignment (expressed in bytes) which is defined as follows:
*
- * All value layouts have an explicit 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.
*
*
- * 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:
+ *
- * Such layout paths 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 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:
+ *
+ * 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
* }
*
+ *
+ * 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
+ * }
+ *
+ *
+ * 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:
+ *
- * 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 natural alignment 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 well-formed for this layout.
+ * @throws IllegalArgumentException if the layout path contains one or more open path elements.
+ * @throws IllegalArgumentException if the layout path contains one or more dereference path elements.
*/
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.
- *
- * 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.
- *
- * 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.
+ *
+ * The returned method handle has the following characteristics:
+ *
+ * The final offset returned by the method handle is computed as follows:
*
*
+ * The returned var handle has the following characteristics:
+ *
* 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:
*
*
- * 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.
*
- * 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 dereference path elements.
+ * 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:
*
* 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.
- *
- * The offset of the returned segment is computed as follows:
- *
- * 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.
+ *
+ * The returned method handle has the following characteristics:
+ *
+ * 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 well-formed for this layout.
+ * @throws IllegalArgumentException if the layout path contains one or more dereference path elements.
*/
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 well-formed for this layout.
+ * @throws IllegalArgumentException if the layout path contains one or more dereference path elements.
+ * @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 layout path. There
- * are two kinds of path elements: group path elements and sequence path elements. 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 explicit (see {@link PathElement#sequenceElement(long)}) or
- * implicit (see {@link PathElement#sequenceElement()}). When a path uses one or more implicit
- * sequence path elements, it acquires additional free dimensions.
+ * are three kinds of path elements:
+ *
- * 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:
- *
- *
- * 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:
*
- * 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:
- *
- *
- * 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:
*
* 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
- * confinement characteristics of the arena used to obtain them.
+ * confinement characteristics of the arena used to obtain them.
*
*
* 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:
*
* 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.
*
- * 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.
*
- * 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 immutable
- * (e.g. the segment is a read-only segment, see {@link #isReadOnly()}), then the resulting buffer is read-only
- * (see {@link ByteBuffer#isReadOnly()}). Additionally, if this is a native segment, the resulting buffer is
- * direct (see {@link ByteBuffer#isDirect()}).
+ * the properties of this segment. More specifically, the resulting buffer has the following characteristics:
+ *
- * 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}.
- *
- * 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}.
*
- * 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)}.
*
@@ -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).
*
- * 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.
*
@@ -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.
*
* 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in {@code T}.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in {@code T}.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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
* incompatible with the alignment constraint in the provided layout,
* or if the layout alignment is greater than its size.
- * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds 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:
*
- * 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);
+ * }
+ *
+ * This interface defines factories for commonly used allocators:
*
@@ -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.
+ *
+ * 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.
*
- * 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 thread-safe.
*
* @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);
* }
- *
- * 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.
- *
- * While the allocator returned by this method is thread-safe, concurrent access on the same recycling
+ * @implNote While a prefix allocator is thread-safe, 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.
diff --git a/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java b/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java
index 95bde61f0bd..8259e766b15 100644
--- a/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java
@@ -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 element layout.
- * The repetition count is said to be the sequence layout's element count. 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 element layout.
+ * The repetition count is said to be the sequence layout's element count. 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;
+ * };
+ * }
+ * }
+ *
* 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:
diff --git a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java
index f6ef8b23725..7db7302b28d 100644
--- a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java
+++ b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java
@@ -55,7 +55,7 @@ import java.util.function.BiFunction;
*
* This method is restricted.
* 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.
diff --git a/src/java.base/share/classes/java/lang/foreign/ValueLayout.java b/src/java.base/share/classes/java/lang/foreign/ValueLayout.java
index 88163d61054..24f5b641991 100644
--- a/src/java.base/share/classes/java/lang/foreign/ValueLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/ValueLayout.java
@@ -42,9 +42,11 @@ import jdk.internal.javac.PreviewFeature;
* {@linkplain MemorySegment#get(OfInt, long) accessing} a region of memory using the value layout.
*
* 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 value-based.
*
@@ -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 strided 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.
- *
- * 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}.
*
* 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:
*
@@ -116,7 +116,7 @@
*
diff --git a/src/java.base/share/classes/java/lang/foreign/snippet-files/Snippets.java b/src/java.base/share/classes/java/lang/foreign/snippet-files/Snippets.java
index b2143fe3c55..c1e18f27c02 100644
--- a/src/java.base/share/classes/java/lang/foreign/snippet-files/Snippets.java
+++ b/src/java.base/share/classes/java/lang/foreign/snippet-files/Snippets.java
@@ -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
}
diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
index 3b2313228b1..7d86f747827 100644
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
@@ -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.
*
* 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.
*
- * 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}.
+ * 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.
*
* 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
diff --git a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java
index 54042c842b7..ad533280388 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java
@@ -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");
}
diff --git a/src/java.base/share/classes/jdk/internal/foreign/Utils.java b/src/java.base/share/classes/jdk/internal/foreign/Utils.java
index bb990540942..ca1a6941530 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/Utils.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/Utils.java
@@ -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
- *
*
* @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)
diff --git a/src/java.base/share/classes/java/lang/foreign/GroupLayout.java b/src/java.base/share/classes/java/lang/foreign/GroupLayout.java
index 20f6f29fd30..895678f6fd3 100644
--- a/src/java.base/share/classes/java/lang/foreign/GroupLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/GroupLayout.java
@@ -29,10 +29,10 @@ import java.util.List;
import jdk.internal.javac.PreviewFeature;
/**
- * A compound layout that aggregates multiple member layouts. 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 struct layout
- * (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 union layout (see {@link MemoryLayout#unionLayout(MemoryLayout...)}).
+ * A compound layout that is an aggregation of multiple, heterogeneous member layouts. 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 value-based.
@@ -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
+ *
+ *
+ * A native linker only supports function descriptors whose argument/return layouts are layouts supported by that linker
+ * and are not sequence layouts.
*
*
+ *
- *
+ *
+ *
+ * Function pointers
*
@@ -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.
*
*
* Size, alignment and byte order
+ * Characteristics of memory layouts
*
- * 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 size (expressed in bytes), which is defined as follows:
*
- *
*
- *
- * A layout's natural alignment can be overridden if needed (see {@link MemoryLayout#withByteAlignment(long)}), which can be useful to describe
- * hyper-aligned layouts.
- * Layout paths
*
- * A layout path originates from a root layout (typically a group or a sequence layout) and terminates
- * at a layout nested within the root layout - this is the layout selected by the layout path.
- * Layout paths are typically expressed as a sequence of one or more {@link PathElement} instances.
+ * A layout path 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 below).
*
+ *
* value
in the first 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 free dimensions. 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:
+ * Open path elements
+ *
+ * Some layout path elements, said open path elements, 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 bind
+ * 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
- * which member layout named {@code value} should be selected from the enclosing sequence layout),
- * it follows that the var handle {@code valueHandle} will feature an additional {@code long}
- * access coordinate.
- *
- * Dereference path elements
+ *
+ * A special kind of path element, called dereference path element, 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.
+ * Layout path well-formedness
+ *
+ * A layout path is applied to a layout {@code C_0}, also called the initial layout. 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 selected layout.
+ *
+ *
+ * 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 value-based.
*
@@ -184,28 +252,23 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
Optional
+ *
+ *
*
* where {@code x_1}, {@code x_2}, ... {@code x_n} are dynamic 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 static 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 well-formed for this layout.
+ * @throws IllegalArgumentException if the layout path contains one or more dereference path elements.
*/
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.
+ * {@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)
* }
+ *
* {@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 static stride constants which are derived from
* the layout path.
*
{@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 access mode restrictions, which are common to all memory segment view handles.
+ * @apiNote The resulting var handle features certain access mode restrictions, 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 well-formed 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.
- *
- *
- *
- * where {@code x_1}, {@code x_2}, ... {@code x_n} are dynamic values provided as {@code long}
- * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are static offset constants
- * and {@code s_1}, {@code s_2}, ... {@code s_n} are static stride constants which are derived from
- * the layout path.
- *
- * {@code
- * byteOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
- * }
+ *
+ *
+ *
+ * Sequence path elements selecting more than one sequence element layout are called
+ * open path elements.
*
* @implSpec
* Implementations of this interface are immutable, thread-safe and value-based.
@@ -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 range 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 open path element which selects the element
+ * layout in a range 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}.
*
- *
- * where {@code E} is the size (in bytes) of the sequence element layout.
- * {@code
- * E * (S + I * F)
- * }
*
*
*
- *
- * where {@code E} is the size (in bytes) of the sequence element layout.
- * {@code
- * E * I
- * }
*
*
* @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 Accessing memory segments
*
@@ -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).
*
*
@@ -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 reachable
+ * 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 {
*
+ *
*
- *
* @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 not 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 incompatible with the alignment constraint 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 incompatible
+ * with the alignment constraint 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 incompatible with the alignment constraint 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 incompatible
+ * with the alignment constraint 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(
diff --git a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java
index 54c070001cc..cd7ae75329e 100644
--- a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java
+++ b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java
@@ -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.
*
*
* Obtaining a symbol lookup
@@ -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 library lookup, 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.
*
- *
@@ -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 :
diff --git a/src/java.base/share/classes/java/lang/foreign/package-info.java b/src/java.base/share/classes/java/lang/foreign/package-info.java
index c905be4c249..95485943a19 100644
--- a/src/java.base/share/classes/java/lang/foreign/package-info.java
+++ b/src/java.base/share/classes/java/lang/foreign/package-info.java
@@ -77,8 +77,8 @@
* Foreign function access
* 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 Java Native Interface (JNI)).
* Restricted methods
* Some methods in this package are considered restricted. 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.
*