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 137152d78cc..49cab25a75f 100644
--- a/src/java.base/share/classes/java/lang/foreign/AddressLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/AddressLayout.java
@@ -35,23 +35,27 @@ import java.nio.ByteOrder;
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
- * (e.g. on a 64-bit platform, the size and alignment of an address layout are set to 8 bytes).
+ * 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 (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
- * target layout {@code T} can be used to model the address of a region of memory whose layout is {@code T}.
- * For instance, an address layout with target layout {@link ValueLayout#JAVA_INT} can be used to model the address
- * of a region of memory that is 4 bytes long. Specifying a target layout can be useful in the following situations:
+ * An address layout may optionally feature a {@linkplain #targetLayout() target layout}.
+ * An address layout with target layout {@code T} can be used to model the address of a
+ * region of memory whose layout is {@code T}. For instance, an address layout with
+ * target layout {@link ValueLayout#JAVA_INT} can be used to model the address of a
+ * region of memory that is 4 bytes long. Specifying a target layout can be useful in
+ * the following situations:
*
- *
When accessing a memory segment that has been obtained by reading an address from another
- * memory segment, e.g. using {@link MemorySegment#getAtIndex(AddressLayout, long)};
+ *
When accessing a memory segment that has been obtained by reading an address from
+ * another memory segment, e.g. using {@link MemorySegment#getAtIndex(AddressLayout, long)};
*
When creating a downcall method handle, using {@link Linker#downcallHandle(FunctionDescriptor, Option...)};
*
When creating an upcall stub, using {@link Linker#upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...)}.
*
*
* @implSpec
- * Implementations of this interface are immutable, thread-safe and value-based.
+ * Implementations of this interface are immutable, thread-safe and
+ * value-based.
*
* @see #ADDRESS
* @see #ADDRESS_UNALIGNED
@@ -84,24 +88,28 @@ public sealed interface AddressLayout extends ValueLayout permits ValueLayouts.O
AddressLayout withOrder(ByteOrder order);
/**
- * Returns an address layout with the same carrier, alignment constraint, name and order as this address layout,
- * but associated with the specified target layout. The returned address layout allows raw addresses to be accessed
- * as {@linkplain MemorySegment memory segments} whose size is set to the size of the specified layout. Moreover,
- * if the accessed raw address is not compatible with the alignment constraint in the provided layout,
- * {@linkplain IllegalArgumentException} will be thrown.
+ * Returns an address layout with the same carrier, alignment constraint, name and
+ * order as this address layout, but associated with the specified target layout.
+ * The returned address layout allows raw addresses to be accessed as
+ * {@linkplain MemorySegment memory segments} whose size is set to the size of the
+ * specified layout. Moreover, if the accessed raw address is not compatible with
+ * the alignment constraint in the provided layout, {@linkplain IllegalArgumentException}
+ * will be thrown.
* @apiNote
- * This method can also be used to create an address layout which, when used, creates native memory
- * segments with maximal size (e.g. {@linkplain Long#MAX_VALUE}). This can be done by using a target sequence
- * layout with unspecified size, as follows:
+ * This method can also be used to create an address layout which, when used, creates
+ * native memory segments with maximal size (e.g. {@linkplain Long#MAX_VALUE}). This
+ * can be done by using a target sequence layout with unspecified size, as follows:
* {@snippet lang = java:
* AddressLayout addressLayout = ...
* AddressLayout unboundedLayout = addressLayout.withTargetLayout(
* MemoryLayout.sequenceLayout(Long.MAX_VALUE, ValueLayout.JAVA_BYTE));
*}
*
- * @param layout the target layout.
- * @return an address layout with the same characteristics as this layout, but with the provided target layout.
- * @throws IllegalCallerException If the caller is in a module that does not have native access enabled
+ * @param layout the target layout
+ * @return an address layout with same characteristics as this layout, but with the
+ * provided target layout
+ * @throws IllegalCallerException If the caller is in a module that does not have
+ * native access enabled
* @see #targetLayout()
*/
@CallerSensitive
@@ -109,18 +117,20 @@ public sealed interface AddressLayout extends ValueLayout permits ValueLayouts.O
AddressLayout withTargetLayout(MemoryLayout layout);
/**
- * Returns an address layout with the same carrier, alignment constraint, name and order as this address layout,
- * but with no target layout.
+ * Returns an address layout with the same carrier, alignment constraint, name and
+ * order as this address layout, but with no target layout.
*
- * @apiNote This can be useful to compare two address layouts that have different target layouts, but are otherwise equal.
+ * @apiNote This can be useful to compare two address layouts that have different
+ * target layouts, but are otherwise equal.
*
- * @return an address layout with the same characteristics as this layout, but with no target layout.
+ * @return an address layout with same characteristics as this layout, but with no
+ * target layout
* @see #targetLayout()
*/
AddressLayout withoutTargetLayout();
/**
- * {@return the target layout associated with this address layout (if any)}.
+ * {@return the target layout associated with this address layout (if any)}
*/
Optional 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 cdd5019b53d..adfc3a1fe6b 100644
--- a/src/java.base/share/classes/java/lang/foreign/Arena.java
+++ b/src/java.base/share/classes/java/lang/foreign/Arena.java
@@ -31,47 +31,53 @@ import jdk.internal.ref.CleanerFactory;
import java.lang.foreign.MemorySegment.Scope;
/**
- * An arena controls the lifecycle of native memory segments, providing both flexible allocation and timely deallocation.
+ * An arena controls the lifecycle of native memory segments, providing both flexible
+ * allocation and timely deallocation.
*
- * An arena has a {@linkplain MemorySegment.Scope scope} - the arena scope. All the segments allocated
- * by the arena are associated with the arena scope. As such, the arena determines the temporal bounds
- * of all the memory segments allocated by it.
+ * An arena has a {@linkplain MemorySegment.Scope scope} - the arena scope.
+ * All the segments allocated by the arena are associated with the arena scope. As such,
+ * the arena determines the temporal bounds of all the memory segments allocated by it.
*
- * Moreover, an arena also determines whether access to memory segments allocated by it should be
- * {@linkplain MemorySegment#isAccessibleBy(Thread) restricted} to specific threads.
- * An arena is a {@link SegmentAllocator} and features several allocation methods that can be used by clients
- * to obtain native segments.
+ * Moreover, an arena also determines whether access to memory segments allocated by it
+ * should be {@linkplain MemorySegment#isAccessibleBy(Thread) restricted} to specific
+ * threads. An arena is a {@link SegmentAllocator} and features several allocation
+ * methods that can be used by clients to obtain native segments.
*
* The simplest arena is the {@linkplain Arena#global() global arena}. The global arena
- * features an unbounded lifetime. The scope of the global arena is the global scope.
- * As such, native segments allocated with the global arena are always accessible and their backing regions
- * of memory are never deallocated.
- * Moreover, memory segments allocated with the global arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread.
+ * features an unbounded lifetime. The scope of the global arena is the global
+ * scope. As such, native segments allocated with the global arena are always accessible
+ * and their backing regions of memory are never deallocated. Moreover, memory segments
+ * allocated with the global arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed}
+ * from any thread.
* {@snippet lang = java:
* MemorySegment segment = Arena.global().allocate(100, 1); // @highlight regex='global()'
* ...
* // segment is never deallocated!
*}
*
- * 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. The scope
- * of an automatic arena is an automatic scope. 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) becomes
- * unreachable, as shown below:
+ * 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. The scope of an automatic arena is an automatic scope. 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) becomes unreachable,
+ * as shown below:
* {@snippet lang = java:
* MemorySegment segment = Arena.ofAuto().allocate(100, 1); // @highlight regex='ofAuto()'
* ...
* segment = null; // the segment region becomes available for deallocation after this point
*}
- * Memory segments allocated with an automatic arena can also be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread.
+ * Memory segments allocated with an automatic arena can also be
+ * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread.
*
- * Rather than leaving deallocation in the hands of the Java runtime, clients will often wish to exercise control over
- * the timing of deallocation for regions of memory that back memory segments. Two kinds of arenas support this,
- * namely {@linkplain #ofConfined() confined} and {@linkplain #ofShared() shared} arenas. They both feature
- * bounded lifetimes that are managed manually. For instance, when a confined arena is {@linkplain #close() closed}
- * successfully, its scope is {@linkplain Scope#isAlive() invalidated}. As a result, all the memory segments allocated
- * by the arena can no longer be accessed, and their regions of memory are deallocated:
+ * Rather than leaving deallocation in the hands of the Java runtime, clients will often
+ * wish to exercise control over the timing of deallocation for regions of memory that
+ * back memory segments. Two kinds of arenas support this, namely {@linkplain #ofConfined() confined}
+ * and {@linkplain #ofShared() shared} arenas. They both feature bounded lifetimes that
+ * are managed manually. For instance, when a confined arena is {@linkplain #close() closed}
+ * successfully, its scope is {@linkplain Scope#isAlive() invalidated}. As a result, all
+ * the memory segments allocated by the arena can no longer be accessed, and their
+ * regions of memory are deallocated:
*
* {@snippet lang = java:
* MemorySegment segment = null;
@@ -82,9 +88,10 @@ import java.lang.foreign.MemorySegment.Scope;
* segment.get(ValueLayout.JAVA_BYTE, 0); // throws IllegalStateException
*}
*
- * Memory segments allocated with a {@linkplain #ofConfined() confined arena} can only be accessed (and closed) by the
- * thread that created the arena. If access to a memory segment from multiple threads is required, clients can allocate
- * segments in a {@linkplain #ofShared() shared arena} instead.
+ * Memory segments allocated with a {@linkplain #ofConfined() confined arena} can only be
+ * accessed (and closed) by the thread that created the arena. If access to a memory
+ * segment from multiple threads is required, clients can allocate segments in a
+ * {@linkplain #ofShared() shared arena} instead.
*
* The characteristics of the various arenas are summarized in the following table:
*
@@ -120,38 +127,45 @@ import java.lang.foreign.MemorySegment.Scope;
*
*
Safety and thread-confinement
*
- * Arenas provide strong temporal safety guarantees: a memory segment allocated by an arena cannot be accessed
- * after the arena has been closed. The cost of providing this guarantee varies based on the
- * number of threads that have access to the memory segments allocated by the arena. For instance, if an arena
- * is always created and closed by one thread, and the memory segments allocated by the arena are always
+ * Arenas provide strong temporal safety guarantees: a memory segment allocated by an
+ * arena cannot be accessed after the arena has been closed. The cost of
+ * providing this guarantee varies based on the number of threads that have access to the
+ * memory segments allocated by the arena. For instance, if an arena is always created
+ * and closed by one thread, and the memory segments allocated by the arena are always
* accessed by that same thread, then ensuring correctness is trivial.
*
- * Conversely, if an arena allocates segments that can be accessed by multiple threads, or if the arena can be closed
- * by a thread other than the accessing thread, then ensuring correctness is much more complex. For example, a segment
- * allocated with the arena might be accessed while another thread attempts, concurrently, to close the arena.
- * To provide the strong temporal safety guarantee without forcing every client, even simple ones, to incur a performance
- * impact, arenas are divided into thread-confined arenas, and shared arenas.
+ * Conversely, if an arena allocates segments that can be accessed by multiple threads,
+ * or if the arena can be closed by a thread other than the accessing thread, then
+ * ensuring correctness is much more complex. For example, a segment allocated with the
+ * arena might be accessed while another thread attempts, concurrently, to close
+ * the arena. To provide the strong temporal safety guarantee without forcing every
+ * client, even simple ones, to incur a performance impact, arenas are divided into
+ * thread-confined arenas, and shared arenas.
*
- * Confined arenas, support strong thread-confinement guarantees. Upon creation, they are assigned an
- * owner thread, typically the thread which initiated the creation operation.
- * The segments created by a confined arena can only be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed}
- * by the owner thread. Moreover, any attempt to close the confined arena from a thread other than the owner thread will
- * fail with {@link WrongThreadException}.
+ * Confined arenas, support strong thread-confinement guarantees. Upon creation, they are
+ * assigned an owner thread, typically the thread which initiated the creation
+ * operation. The segments created by a confined arena can only be
+ * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the owner thread.
+ * Moreover, any attempt to close the confined arena from a thread other than the owner
+ * thread will fail with a {@link WrongThreadException}.
*
- * Shared arenas, on the other hand, have no owner thread. The segments created by a shared arena
- * can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. This might be useful when
- * multiple threads need to access the same memory segment concurrently (e.g. in the case of parallel processing).
- * Moreover, a shared arena can be closed by any thread.
+ * Shared arenas, on the other hand, have no owner thread. The segments created by a
+ * shared arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by
+ * any thread. This might be useful when multiple threads need to access the same memory
+ * segment concurrently (e.g. in the case of parallel processing). Moreover, a shared
+ * arena can be closed by any thread.
*
*
Custom arenas
*
- * Clients can define custom arenas to implement more efficient allocation strategies, or to have better control over
- * when (and by whom) an arena can be closed. As an example, the following code defines a slicing arena that behaves
- * like a confined arena (i.e., single-threaded access), but internally uses a
- * {@linkplain SegmentAllocator#slicingAllocator(MemorySegment) slicing allocator} to respond to allocation requests.
- * When the slicing arena is closed, the underlying confined arena is also closed; this will invalidate all segments
- * allocated with the slicing arena (since the scope of the slicing arena is the same as that of the underlying
- * confined arena):
+ * Clients can define custom arenas to implement more efficient allocation strategies,
+ * or to have better control over when (and by whom) an arena can be closed. As an
+ * example, the following code defines a slicing arena that behaves like a
+ * confined arena (i.e., single-threaded access), but internally uses a
+ * {@linkplain SegmentAllocator#slicingAllocator(MemorySegment) slicing allocator} to
+ * respond to allocation requests.
+ * When the slicing arena is closed, the underlying confined arena is also closed; this
+ * will invalidate all segments allocated with the slicing arena (since the scope of the
+ * slicing arena is the same as that of the underlying confined arena):
*
* {@snippet lang = java:
* class SlicingArena implements Arena {
@@ -177,8 +191,9 @@ import java.lang.foreign.MemorySegment.Scope;
* }
* }
*
- * In other words, a slicing arena provides a vastly more efficient and scalable allocation strategy, while still retaining
- * the timely deallocation guarantee provided by the underlying confined arena:
+ * In other words, a slicing arena provides a vastly more efficient and scalable
+ * allocation strategy, while still retaining the timely deallocation guarantee provided
+ * by the underlying confined arena:
*
* {@snippet lang = java:
* try (Arena slicingArena = new SlicingArena(1000)) {
@@ -204,18 +219,17 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
* {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
* Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}.
*
- * @return a new arena that is managed, automatically, by the garbage collector.
+ * @return a new arena that is managed, automatically, by the garbage collector
*/
static Arena ofAuto() {
return MemorySessionImpl.createImplicit(CleanerFactory.cleaner()).asArena();
}
/**
- * 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}.
- *
- * @return the global arena.
+ * {@return 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}.
*/
static Arena global() {
class Holder {
@@ -226,8 +240,8 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
/**
* {@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.
+ * {@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();
@@ -235,36 +249,40 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
/**
* {@return a new shared arena} Segments allocated with the global arena can be
- * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
+ * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
*/
static Arena ofShared() {
return MemorySessionImpl.createShared().asArena();
}
/**
- * Returns a native memory segment with the given size (in bytes) and alignment constraint (in bytes).
+ * 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 region of memory backing the segment, and the address is
- * aligned according to the provided alignment constraint.
+ * The segment's {@link MemorySegment#address() address} is the starting address of
+ * the allocated off-heap region of memory backing the segment, and the address is
+ * aligned according the provided alignment constraint.
*
* @implSpec
- * Implementations of this method must return a native segment featuring the requested size,
- * and that is compatible with the provided alignment constraint. Furthermore, for any two segments
- * {@code S1, S2} returned by this method, the following invariant must hold:
+ * Implementations of this method must return a native segment featuring the
+ * requested size, and that is compatible with the provided alignment constraint.
+ * Furthermore, for any two segments {@code S1, S2} returned by this method, the
+ * following invariant must hold:
*
* {@snippet lang = java:
* S1.asOverlappingSlice(S2).isEmpty() == true
* }
*
- * @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.
+ * @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 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
- * other than the arena's 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
MemorySegment allocate(long byteSize, long byteAlignment);
@@ -275,25 +293,29 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
Scope scope();
/**
- * Closes this arena. If this method completes normally, the arena scope is no longer {@linkplain Scope#isAlive() alive},
- * and all the memory segments associated with it can no longer be accessed. Furthermore, any off-heap region of memory backing the
+ * Closes this arena. If this method completes normally, the arena scope is no longer
+ * {@linkplain Scope#isAlive() alive}, and all the memory segments associated with it
+ * can no longer be accessed. Furthermore, any off-heap region of memory backing the
* segments obtained from this arena are also released.
*
- * @apiNote This operation is not idempotent; that is, closing an already closed arena always results in an
- * exception being thrown. This reflects a deliberate design choice: failure to close an arena might reveal a bug
- * in the underlying application logic.
+ * @apiNote This operation is not idempotent; that is, closing an already closed arena
+ * always results in an exception being thrown. This reflects a
+ * deliberate design choice: failure to close an arena might reveal a bug
+ * in the underlying application logic.
*
- * @implSpec If this method completes normally, then {@code this.scope().isAlive() == false}.
- * Implementations are allowed to throw {@link UnsupportedOperationException} if an explicit close operation is
- * not supported.
+ * @implSpec If this method completes normally, then
+ * {@code this.scope().isAlive() == false}.
+ * Implementations are allowed to throw {@link UnsupportedOperationException}
+ * if an explicit close operation is not supported.
*
* @see Scope#isAlive()
*
* @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
- * other than the arena's owner thread
+ * @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 other than the arena's owner thread
* @throws UnsupportedOperationException if this arena cannot be closed explicitly
*/
@Override
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 ee42e991480..dd1ec8e1660 100644
--- a/src/java.base/share/classes/java/lang/foreign/FunctionDescriptor.java
+++ b/src/java.base/share/classes/java/lang/foreign/FunctionDescriptor.java
@@ -34,13 +34,16 @@ import java.util.List;
import jdk.internal.foreign.FunctionDescriptorImpl;
/**
- * 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
+ * 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
- * Implementing classes are immutable, thread-safe and value-based.
+ * Implementing classes are immutable, thread-safe and
+ * value-based.
*
* @see MemoryLayout
* @since 22
@@ -53,35 +56,39 @@ public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
Optional returnLayout();
/**
- * {@return the argument layouts of this function descriptor (as an unmodifiable list)}.
+ * {@return the argument layouts of this function descriptor (as an unmodifiable list)}
*/
List argumentLayouts();
/**
- * Returns a function descriptor with the given argument layouts appended to the argument layouts
- * of this function descriptor.
- * @param addedLayouts the argument layouts to append.
- * @throws IllegalArgumentException if one of the layouts in {@code addedLayouts} is a padding layout
- * @return a new function descriptor, with the provided additional argument layouts.
+ * Returns a function descriptor with the given argument layouts appended to the
+ * argument layouts of this function descriptor.
+ *
+ * @param addedLayouts the argument layouts to append
+ * @throws IllegalArgumentException if one of the layouts in {@code addedLayouts} is
+ * a padding layout
+ * @return a new function descriptor, with the provided additional argument layouts
*/
FunctionDescriptor appendArgumentLayouts(MemoryLayout... addedLayouts);
/**
- * Returns a function descriptor with the given argument layouts inserted at the given index, into the argument
- * layout array of this function descriptor.
+ * Returns a function descriptor with the given argument layouts inserted at the
+ * given index, into the argument layout array of this function descriptor.
+ *
* @param index the index at which to insert the arguments
- * @param addedLayouts the argument layouts to insert at the given index.
- * @return a new function descriptor, with the provided additional argument layouts.
- * @throws IllegalArgumentException if one of the layouts in {@code addedLayouts} is a padding layout
+ * @param addedLayouts the argument layouts to insert at given index
+ * @return a new function descriptor, with the provided additional argument layouts
+ * @throws IllegalArgumentException if one of the layouts in {@code addedLayouts}
+ * is a padding layout
* @throws IllegalArgumentException if {@code index < 0 || index > argumentLayouts().size()}
*/
FunctionDescriptor insertArgumentLayouts(int index, MemoryLayout... addedLayouts);
/**
* Returns a function descriptor with the provided return layout.
- * @param newReturn the new return layout.
+ * @param newReturn the new return layout
* @throws IllegalArgumentException if {@code newReturn} is a padding layout
- * @return a new function descriptor, with the provided return layout.
+ * @return a new function descriptor, with the provided return layout
*/
FunctionDescriptor changeReturnLayout(MemoryLayout newReturn);
@@ -91,28 +98,35 @@ public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
FunctionDescriptor dropReturnLayout();
/**
- * Returns the method type consisting of the carrier types of the layouts in this function descriptor.
+ * Returns the method type consisting of the carrier types of the layouts in this
+ * function descriptor.
*
* The carrier type of a layout {@code L} is determined as follows:
*
- *
If {@code L} is a {@link ValueLayout} the carrier type is determined through {@link ValueLayout#carrier()}.
- *
If {@code L} is a {@link GroupLayout} or a {@link SequenceLayout}, the carrier type is {@link MemorySegment}.
+ *
If {@code L} is a {@link ValueLayout} the carrier type is
+ * determined through {@link ValueLayout#carrier()}.
+ *
If {@code L} is a {@link GroupLayout} or a {@link SequenceLayout},
+ * the carrier type is {@link MemorySegment}.
*
*
- * @apiNote A function descriptor cannot, by construction, contain any padding layouts. As such, it is not
- * necessary to specify how padding layouts should be mapped to carrier types.
+ * @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.
+ * @return the method type consisting of the carrier types of the layouts in this
+ * function descriptor
*/
MethodType toMethodType();
/**
* Creates a function descriptor with the given return and argument layouts.
- * @param resLayout the return layout.
- * @param argLayouts the argument layouts.
+ *
+ * @param resLayout the return layout
+ * @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 a new function descriptor with the provided return and argument layouts.
+ * @throws IllegalArgumentException if one of the layouts in {@code argLayouts}
+ * is a padding layout
+ * @return a new function descriptor with the provided return and argument layouts
*/
static FunctionDescriptor of(MemoryLayout resLayout, MemoryLayout... argLayouts) {
Objects.requireNonNull(resLayout);
@@ -121,11 +135,13 @@ public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
}
/**
- * Creates a function descriptor with the given argument layouts and no return layout. This is useful for modeling 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 a new function descriptor with the provided argument layouts.
+ * 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 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 24bec8f0439..03eb33c1644 100644
--- a/src/java.base/share/classes/java/lang/foreign/GroupLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/GroupLayout.java
@@ -28,13 +28,16 @@ package java.lang.foreign;
import java.util.List;
/**
- * 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}.
+ * 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.
+ * This class is immutable, thread-safe and
+ * value-based.
*
* @sealedGraph
* @since 22
@@ -44,9 +47,10 @@ public sealed interface GroupLayout extends MemoryLayout permits StructLayout, U
/**
* {@return the member layouts of this group layout}
*
- * @apiNote the order in which member layouts are returned in 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...)}).
+ * @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...)} and
+ * {@link MemoryLayout#unionLayout(MemoryLayout...)}).
*/
List memberLayouts();
@@ -65,8 +69,9 @@ public sealed interface GroupLayout extends MemoryLayout permits StructLayout, U
/**
* {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
- * @throws IllegalArgumentException if {@code byteAlignment} is less than {@code M}, where {@code M} is
- * the maximum alignment constraint in any of the member layouts associated with this group layout
+ * @throws IllegalArgumentException if {@code byteAlignment} is less than {@code M},
+ * where {@code M} is the maximum alignment constraint in any of the
+ * member layouts associated with this group layout
*/
@Override
GroupLayout withByteAlignment(long byteAlignment);
diff --git a/src/java.base/share/classes/java/lang/foreign/Linker.java b/src/java.base/share/classes/java/lang/foreign/Linker.java
index 604b1489239..0ca3470c479 100644
--- a/src/java.base/share/classes/java/lang/foreign/Linker.java
+++ b/src/java.base/share/classes/java/lang/foreign/Linker.java
@@ -41,42 +41,49 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
- * A linker provides access to foreign functions from Java code, and access to Java code from foreign functions.
+ * A linker provides access to foreign functions from Java code, and access to Java code
+ * from foreign functions.
*
- * Foreign functions typically reside in libraries that can be loaded on demand. Each library conforms to
- * a specific ABI (Application Binary Interface). An ABI is a set of calling conventions and data types associated with
- * the compiler, OS, and processor where the library was built. For example, a C compiler on Linux/x64 usually
- * builds libraries that conform to the SystemV ABI.
+ * Foreign functions typically reside in libraries that can be loaded on demand. Each
+ * library conforms to a specific ABI (Application Binary Interface). An ABI is a set of
+ * calling conventions and data types associated with the compiler, OS, and processor where
+ * the library was built. For example, a C compiler on Linux/x64 usually builds libraries
+ * that conform to the SystemV ABI.
*
- * A linker has detailed knowledge of the calling conventions and data types used by a specific ABI.
- * For any library that conforms to that ABI, the linker can mediate between Java code running
- * in the JVM and foreign functions in the library. In particular:
+ * A linker has detailed knowledge of the calling conventions and data types used by a
+ * specific ABI. For any library that conforms to that ABI, the linker can mediate
+ * between Java code running in the JVM and foreign functions in the library. In
+ * particular:
*
*
A linker allows Java code to link against foreign functions, via
- * {@linkplain #downcallHandle(MemorySegment, FunctionDescriptor, Option...) downcall method handles}; and
- *
A linker allows foreign functions to call Java method handles,
- * via the generation of {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...) upcall stubs}.
A linker allows foreign functions to call Java method handles, via the generation
+ * of {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...) upcall stubs}.
*
- * A linker provides a way to look up the canonical layouts associated with the data types used by the ABI.
- * For example, a linker implementing the C ABI might choose to provide a canonical layout for the C {@code size_t}
- * type. On 64-bit platforms, this canonical layout might be equal to {@link ValueLayout#JAVA_LONG}. The canonical
- * layouts supported by a linker are exposed via the {@link #canonicalLayouts()} method, which returns a map from
- * type names to canonical layouts.
+ * A linker provides a way to look up the canonical layouts associated with the
+ * data types used by the ABI. For example, a linker implementing the C ABI might choose
+ * to provide a canonical layout for the C {@code size_t} type. On 64-bit platforms,
+ * this canonical layout might be equal to {@link ValueLayout#JAVA_LONG}. The canonical
+ * layouts supported by a linker are exposed via the {@link #canonicalLayouts()} method,
+ * which returns a map from type names to canonical layouts.
*
- * In addition, a linker provides a way to look up foreign functions in libraries that conform to the ABI. Each linker
- * chooses a set of libraries that are commonly used on the OS and processor combination associated with the ABI.
- * For example, a linker for Linux/x64 might choose two libraries: {@code libc} and {@code libm}. The functions in these
- * libraries are exposed via a {@linkplain #defaultLookup() symbol lookup}.
+ * In addition, a linker provides a way to look up foreign functions in libraries that
+ * conform to the ABI. Each linker chooses a set of libraries that are commonly used on
+ * the OS and processor combination associated with the ABI. For example, a linker for
+ * Linux/x64 might choose two libraries: {@code libc} and {@code libm}. The functions in
+ * these libraries are exposed via a {@linkplain #defaultLookup() symbol lookup}.
*
*
Calling native functions
*
* The {@linkplain #nativeLinker() native linker} can be used to link against functions
- * defined in C libraries (native functions). Suppose we wish to downcall from Java to the {@code strlen} function
- * defined in the standard C library:
+ * defined in C libraries (native functions). Suppose we wish to downcall from Java to
+ * the {@code strlen} function defined in the standard C library:
* {@snippet lang = c:
* size_t strlen(const char *s);
* }
- * A downcall method handle that exposes {@code strlen} is obtained, using the native linker, as follows:
+ * A downcall method handle that exposes {@code strlen} is obtained, using the native
+ * linker, as follows:
*
* {@snippet lang = java:
* Linker linker = Linker.nativeLinker();
@@ -87,12 +94,12 @@ import java.util.stream.Stream;
* }
*
* Note how the native linker also provides access, via its {@linkplain #defaultLookup() default lookup},
- * to the native functions defined by the C libraries loaded with the Java runtime. Above, the default lookup
- * is used to search the address of the {@code strlen} native function. That address is then passed, along with
- * a platform-dependent description of the signature of the function expressed as a
- * {@link FunctionDescriptor} (more on that below) to the native linker's
- * {@link #downcallHandle(MemorySegment, FunctionDescriptor, Option...)} method.
- * The obtained downcall method handle is then invoked as follows:
+ * to the native functions defined by the C libraries loaded with the Java runtime.
+ * Above, the default lookup is used to search the address of the {@code strlen} native
+ * function. That address is then passed, along with a platform-dependent description
+ * of the signature of the function expressed as a {@link FunctionDescriptor} (more on
+ * that below) to the native linker's {@link #downcallHandle(MemorySegment, FunctionDescriptor, Option...)}
+ * method. The obtained downcall method handle is then invoked as follows:
*
* {@snippet lang = java:
* try (Arena arena = Arena.ofConfined()) {
@@ -102,28 +109,34 @@ import java.util.stream.Stream;
*}
*
Describing C signatures
*
- * When interacting with the native linker, clients must provide a platform-dependent description of the signature
- * of the C function they wish to link against. This description, a {@link FunctionDescriptor function descriptor},
- * defines the layouts associated with the parameter types and return type (if any) of the C function.
+ * When interacting with the native linker, clients must provide a platform-dependent
+ * description of the signature of the C function they wish to link against. This
+ * description, a {@link FunctionDescriptor function descriptor}, defines the layouts
+ * associated with the parameter types and return type (if any) of the C function.
*
- * Scalar C types such as {@code bool}, {@code int} are modeled as {@linkplain ValueLayout value layouts}
- * of a suitable carrier. The {@linkplain #canonicalLayouts() mapping} between a scalar type and its corresponding
+ * Scalar C types such as {@code bool}, {@code int} are modeled as
+ * {@linkplain ValueLayout value layouts} of a suitable carrier. The
+ * {@linkplain #canonicalLayouts() mapping} between a scalar type and its corresponding
* canonical layout is dependent on the ABI implemented by the native linker (see below).
*
- * Composite types are modeled as {@linkplain GroupLayout group layouts}. More specifically, a C {@code struct} type
- * maps to a {@linkplain StructLayout struct layout}, whereas a C {@code union} type maps to a {@link UnionLayout union
- * layout}. When defining a struct or union layout, clients must pay attention to the size and alignment constraint
- * of the corresponding composite type definition in C. For instance, padding between two struct fields
- * must be modeled explicitly, by adding an adequately sized {@linkplain PaddingLayout padding layout} member
- * to the resulting struct layout.
+ * Composite types are modeled as {@linkplain GroupLayout group layouts}. More
+ * specifically, a C {@code struct} type maps to a {@linkplain StructLayout struct layout},
+ * whereas a C {@code union} type maps to a {@link UnionLayout union layout}. When defining
+ * a struct or union layout, clients must pay attention to the size and alignment constraint
+ * of the corresponding composite type definition in C. For instance, padding between two
+ * struct fields must be modeled explicitly, by adding an adequately sized
+ * {@linkplain PaddingLayout padding layout} member to the resulting struct layout.
*
- * Finally, pointer types such as {@code int**} and {@code int(*)(size_t*, size_t*)} are modeled as
- * {@linkplain AddressLayout address layouts}. When the spatial bounds of the pointer type are known statically,
- * the address layout can be associated with a {@linkplain AddressLayout#targetLayout() target layout}. For instance,
- * a pointer that is known to point to a C {@code int[2]} array can be modeled as an address layout whose
- * target layout is a sequence layout whose element count is 2, and whose element type is {@link ValueLayout#JAVA_INT}.
+ * Finally, pointer types such as {@code int**} and {@code int(*)(size_t*, size_t*)}
+ * are modeled as {@linkplain AddressLayout address layouts}. When the spatial bounds of
+ * the pointer type are known statically, the address layout can be associated with a
+ * {@linkplain AddressLayout#targetLayout() target layout}. For instance, a pointer that
+ * is known to point to a C {@code int[2]} array can be modeled as an address layout
+ * whose target layout is a sequence layout whose element count is 2, and whose
+ * element type is {@link ValueLayout#JAVA_INT}.
*
- * All native linker implementations are guaranteed to provide canonical layouts for the following set of types:
+ * All native linker implementations are guaranteed to provide canonical layouts for the
+ * following set of types:
*
- * As noted above, the specific canonical layout associated with each type can vary, depending on the data model
- * supported by a given ABI. For instance, the C type {@code long} maps to the layout constant {@link ValueLayout#JAVA_LONG}
- * on Linux/x64, but maps to the layout constant {@link ValueLayout#JAVA_INT} on Windows/x64. Similarly, the C type
- * {@code size_t} maps to the layout constant {@link ValueLayout#JAVA_LONG} on 64-bit platforms, but maps to the layout
- * constant {@link ValueLayout#JAVA_INT} on 32-bit platforms.
+ * As noted above, the specific canonical layout associated with each type can vary,
+ * depending on the data model supported by a given ABI. For instance, the C type
+ * {@code long} maps to the layout constant {@link ValueLayout#JAVA_LONG} on Linux/x64,
+ * but maps to the layout constant {@link ValueLayout#JAVA_INT} on Windows/x64.
+ * Similarly, the C type {@code size_t} maps to the layout constant
+ * {@link ValueLayout#JAVA_LONG} on 64-bit platforms, but maps to the layout constant
+ * {@link ValueLayout#JAVA_INT} on 32-bit platforms.
*
- * A native linker typically does not provide canonical layouts for C's unsigned integral types. Instead, they are
- * modeled using the canonical layouts associated with their corresponding signed integral types. For instance,
- * the C type {@code unsigned long} maps to the layout constant {@link ValueLayout#JAVA_LONG} on Linux/x64, but maps to
+ * A native linker typically does not provide canonical layouts for C's unsigned integral
+ * types. Instead, they are modeled using the canonical layouts associated with their
+ * corresponding signed integral types. For instance, the C type {@code unsigned long}
+ * maps to the layout constant {@link ValueLayout#JAVA_LONG} on Linux/x64, but maps to
* the layout constant {@link ValueLayout#JAVA_INT} on Windows/x64.
*
- * The following table shows some examples of how C types are modeled in Linux/x64 according to the
- * "System V Application Binary Interface" (all the examples provided here will assume these platform-dependent mappings):
+ * The following table shows some examples of how C types are modeled in Linux/x64
+ * according to the "System V Application Binary Interface"
+ * (all the examples provided here will assume these platform-dependent mappings):
*
*
{@code L} is a value layout {@code V} and {@code V.withoutName()} is a canonical layout
*
{@code L} is a sequence layout {@code S} and all the following conditions hold:
*
- *
the alignment constraint of {@code S} is set to its natural alignment, and
+ *
the alignment constraint of {@code S} is set to its
+ * natural alignment, and
*
{@code S.elementLayout()} is a layout supported by {@code NL}.
*
*
*
{@code L} is a group layout {@code G} and all the following conditions hold:
*
- *
the alignment constraint of {@code G} is set to its natural alignment;
+ *
the alignment constraint of {@code G} is set to its
+ * natural alignment;
*
the size of {@code G} is a multiple of its alignment constraint;
- *
each member layout in {@code G.memberLayouts()} is either a padding layout or a layout supported by {@code NL}, and
- *
{@code G} does not contain padding other than what is strictly required to align its non-padding layout elements, or to satisfy (2).
+ *
each member layout in {@code G.memberLayouts()} is either a padding layout or
+ * a layout supported by {@code NL}, and
+ *
{@code G} does not contain padding other than what is strictly required to align
+ * its non-padding layout elements, or to satisfy (2).
*
*
*
*
- * Linker implementations may optionally support additional layouts, such as packed struct layouts.
- * A packed struct is a struct in which there is at least one member layout {@code L} that has an alignment
- * constraint less strict than its natural alignment. This allows to avoid padding between member layouts,
+ * Linker implementations may optionally support additional layouts, such as
+ * packed struct layouts. A packed struct is a struct in which there is
+ * at least one member layout {@code L} that has an alignment constraint less strict
+ * than its natural alignment. This allows to avoid padding between member layouts,
* as well as avoiding padding at the end of the struct layout. For example:
+
* {@snippet lang = java:
* // No padding between the 2 element layouts:
* MemoryLayout noFieldPadding = MemoryLayout.structLayout(
@@ -260,23 +283,25 @@ import java.util.stream.Stream;
* ValueLayout.JAVA_INT);
* }
*
- * A native linker only supports function descriptors whose argument/return layouts are layouts supported by that linker
- * and are not sequence layouts.
+ * A native linker only supports function descriptors whose argument/return layouts are
+ * layouts supported by that linker and are not sequence layouts.
*
*
Function pointers
*
- * Sometimes, it is useful to pass Java code as a function pointer to some native function; this is achieved by using
- * an {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...) upcall stub}. To demonstrate this,
- * let's consider the following function from the C standard library:
+ * Sometimes, it is useful to pass Java code as a function pointer to some native
+ * function; this is achieved by using an
+ * {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...) upcall stub}.
+ * To demonstrate this, let's consider the following function from the C standard library:
*
* {@snippet lang = c:
* void qsort(void *base, size_t nmemb, size_t size,
* int (*compar)(const void *, const void *));
* }
*
- * The {@code qsort} function can be used to sort the contents of an array, using a custom comparator function which is
- * passed as a function pointer (the {@code compar} parameter). To be able to call the {@code qsort} function from Java,
- * we must first create a downcall method handle for it, as follows:
+ * The {@code qsort} function can be used to sort the contents of an array, using a
+ * custom comparator function which is passed as a function pointer
+ * (the {@code compar} parameter). To be able to call the {@code qsort} function from
+ * Java, we must first create a downcall method handle for it, as follows:
*
* {@snippet lang = java:
* Linker linker = Linker.nativeLinker();
@@ -286,12 +311,14 @@ import java.util.stream.Stream;
* );
* }
*
- * As before, we use {@link ValueLayout#JAVA_LONG} to map the C type {@code size_t} type, and {@link ValueLayout#ADDRESS}
- * for both the first pointer parameter (the array pointer) and the last parameter (the function pointer).
+ * As before, we use {@link ValueLayout#JAVA_LONG} to map the C type {@code size_t} type,
+ * and {@link ValueLayout#ADDRESS} for both the first pointer parameter (the array
+ * pointer) and the last parameter (the function pointer).
*
- * To invoke the {@code qsort} downcall handle obtained above, we need a function pointer to be passed as the last
- * parameter. That is, we need to create a function pointer out of an existing method handle. First, let's write a
- * Java method that can compare two int elements passed as pointers (i.e. as {@linkplain MemorySegment memory segments}):
+ * To invoke the {@code qsort} downcall handle obtained above, we need a function pointer
+ * to be passed as the last parameter. That is, we need to create a function pointer out
+ * of an existing method handle. First, let's write a Java method that can compare two
+ * int elements passed as pointers (i.e. as {@linkplain MemorySegment memory segments}):
*
* {@snippet lang = java:
* class Qsort {
@@ -312,13 +339,16 @@ import java.util.stream.Stream;
* comparDesc.toMethodType());
* }
*
- * First, we create a function descriptor for the function pointer type. Since we know that the parameters passed to
- * the comparator method will be pointers to elements of a C {@code int[]} array, we can specify {@link ValueLayout#JAVA_INT}
- * as the target layout for the address layouts of both parameters. This will allow the comparator method to access
- * the contents of the array elements to be compared. We then {@linkplain FunctionDescriptor#toMethodType() turn}
- * that function descriptor into a suitable {@linkplain java.lang.invoke.MethodType method type} which we then use to look up
- * the comparator method handle. We can now create an upcall stub that points to that method, and pass it, as a function
- * pointer, to the {@code qsort} downcall handle, as follows:
+ * First, we create a function descriptor for the function pointer type. Since we know
+ * that the parameters passed to the comparator method will be pointers to elements of
+ * a C {@code int[]} array, we can specify {@link ValueLayout#JAVA_INT} as the target
+ * layout for the address layouts of both parameters. This will allow the comparator
+ * method to access the contents of the array elements to be compared. We then
+ * {@linkplain FunctionDescriptor#toMethodType() turn} that function descriptor into
+ * a suitable {@linkplain java.lang.invoke.MethodType method type} which we then use to
+ * look up the comparator method handle. We can now create an upcall stub that points to
+ * that method, and pass it, as a function pointer, to the {@code qsort} downcall handle,
+ * as follows:
*
* {@snippet lang = java:
* try (Arena arena = Arena.ofConfined()) {
@@ -329,34 +359,39 @@ import java.util.stream.Stream;
* }
* }
*
- * This code creates an off-heap array, copies the contents of a Java array into it, and then passes the array to the
- * {@code qsort} method handle along with the comparator function we obtained from the native linker. After the invocation, the contents
- * of the off-heap array will be sorted according to our comparator function, written in Java. We then extract a
- * new Java array from the segment, which contains the sorted elements.
+ * This code creates an off-heap array, copies the contents of a Java array into it, and
+ * then passes the array to the {@code qsort} method handle along with the comparator
+ * function we obtained from the native linker. After the invocation, the contents
+ * of the off-heap array will be sorted according to our comparator function, written in
+ * Java. We then extract a new Java array from the segment, which contains the sorted
+ * elements.
*
*
Functions returning pointers
*
- * When interacting with native functions, it is common for those functions to allocate a region of memory and return
- * a pointer to that region. Let's consider the following function from the C standard library:
+ * When interacting with native functions, it is common for those functions to allocate
+ * a region of memory and return a pointer to that region. Let's consider the following
+ * function from the C standard library:
*
* {@snippet lang = c:
* void *malloc(size_t size);
* }
*
* The {@code malloc} function allocates a region of memory with the given size,
- * and returns a pointer to that region of memory, which is later deallocated using another function from
- * the C standard library:
+ * and returns a pointer to that region of memory, which is later deallocated using
+ * another function from the C standard library:
*
* {@snippet lang = c:
* void free(void *ptr);
* }
*
- * The {@code free} function takes a pointer to a region of memory and deallocates that region. In this section we
- * will show how to interact with these native functions, with the aim of providing a safe allocation
- * API (the approach outlined below can of course be generalized to allocation functions other than {@code malloc}
- * and {@code free}).
+ * The {@code free} function takes a pointer to a region of memory and deallocates that
+ * region. In this section we will show how to interact with these native functions,
+ * with the aim of providing a safe allocation API (the approach outlined below
+ * can of course be generalized to allocation functions other than {@code malloc} and
+ * {@code free}).
*
- * First, we need to create the downcall method handles for {@code malloc} and {@code free}, as follows:
+ * First, we need to create the downcall method handles for {@code malloc} and
+ * {@code free}, as follows:
*
* {@snippet lang = java:
* Linker linker = Linker.nativeLinker();
@@ -372,8 +407,9 @@ import java.util.stream.Stream;
* );
* }
*
- * 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:
+ * 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);
@@ -382,11 +418,12 @@ import java.util.stream.Stream;
* The size of the segment returned by the {@code malloc} downcall method handle is
* zero. Moreover, the scope of the
* returned segment is the global scope. To provide safe access to the segment, we must,
- * 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 of these operations are accomplished using the restricted method {@link MemorySegment#reinterpret(long, Arena, Consumer)},
- * as follows:
+ * 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 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 {
@@ -401,12 +438,14 @@ import java.util.stream.Stream;
* }
* }
*
- * The {@code allocateMemory} method defined above accepts two parameters: a size and an arena. The method calls the
- * {@code malloc} downcall method handle, and unsafely reinterprets the returned segment, by giving it a new size
- * (the size passed to the {@code allocateMemory} method) and a new scope (the scope of the provided arena).
- * The method also specifies a cleanup action to be executed when the provided arena is closed. Unsurprisingly,
- * the cleanup action passes the segment to the {@code free} downcall method handle, to deallocate the underlying
- * region of memory. We can use the {@code allocateMemory} method as follows:
+ * The {@code allocateMemory} method defined above accepts two parameters: a size and an
+ * arena. The method calls the {@code malloc} downcall method handle, and unsafely
+ * reinterprets the returned segment, by giving it a new size (the size passed to the
+ * {@code allocateMemory} method) and a new scope (the scope of the provided arena).
+ * The method also specifies a cleanup action to be executed when the provided
+ * arena is closed. Unsurprisingly, the cleanup action passes the segment to the
+ * {@code free} downcall method handle, to deallocate the underlying region of memory.
+ * We can use the {@code allocateMemory} method as follows:
*
* {@snippet lang = java:
* try (Arena arena = Arena.ofConfined()) {
@@ -414,65 +453,79 @@ import java.util.stream.Stream;
* } // 'free' called here
* }
*
- * Note how the segment obtained from {@code allocateMemory} acts as any other segment managed by the confined arena. More
- * specifically, the obtained segment has the desired size, can only be accessed by a single thread (the thread that created
- * the confined arena), and its lifetime is tied to the surrounding try-with-resources block.
+ * Note how the segment obtained from {@code allocateMemory} acts as any other segment
+ * managed by the confined arena. More specifically, the obtained segment has the desired
+ * size, can only be accessed by a single thread (the thread that created the confined
+ * arena), and its lifetime is tied to the surrounding try-with-resources block.
*
*
Variadic functions
*
- * Variadic functions are C functions that can accept a variable number and type of arguments. They are declared with a
- * trailing ellipsis ({@code ...}) at the end of the formal parameter list, such as: {@code void foo(int x, ...);}
- * The arguments passed in place of the ellipsis are called variadic arguments. Variadic functions are,
- * essentially, templates that can be specialized into multiple non-variadic functions by replacing the
- * {@code ...} with a list of variadic parameters of a fixed number and type.
+ * Variadic functions are C functions that can accept a variable number and type of
+ * arguments. They are declared with a trailing ellipsis ({@code ...}) at the end of the
+ * formal parameter list, such as: {@code void foo(int x, ...);}
+ * The arguments passed in place of the ellipsis are called variadic arguments.
+ * Variadic functions are, essentially, templates that can be specialized into
+ * multiple non-variadic functions by replacing the {@code ...} with a list of
+ * variadic parameters of a fixed number and type.
*
- * It should be noted that values passed as variadic arguments undergo default argument promotion in C. For instance, the
- * following argument promotions are applied:
+ * It should be noted that values passed as variadic arguments undergo default argument
+ * promotion in C. For instance, the following argument promotions are applied:
*
*
{@code _Bool} -> {@code unsigned int}
*
{@code [signed] char} -> {@code [signed] int}
*
{@code [signed] short} -> {@code [signed] int}
*
{@code float} -> {@code double}
*
- * whereby the signed-ness of the source type corresponds to the signed-ness of the promoted type. The complete process
- * of default argument promotion is described in the C specification. In effect, these promotions place limits on the
- * types that can be used to replace the {@code ...}, as the variadic parameters of the specialized form of a variadic
- * function will always have a promoted type.
+ * whereby the signed-ness of the source type corresponds to the signed-ness of the
+ * promoted type. The complete process of default argument promotion is described in the
+ * C specification. In effect, these promotions place limits on the types that can be
+ * used to replace the {@code ...}, as the variadic parameters of the specialized form
+ * of a variadic function will always have a promoted type.
*
- * The native linker only supports linking the specialized form of a variadic function. A variadic function in its specialized
- * form can be linked using a function descriptor describing the specialized form. Additionally, the
- * {@link Linker.Option#firstVariadicArg(int)} linker option must be provided to indicate the first variadic parameter in
- * the parameter list. The corresponding argument layout (if any), and all following argument layouts in the specialized
- * function descriptor, are called variadic argument layouts.
+ * The native linker only supports linking the specialized form of a variadic function.
+ * A variadic function in its specialized form can be linked using a function descriptor
+ * describing the specialized form. Additionally, the {@link Linker.Option#firstVariadicArg(int)}
+ * linker option must be provided to indicate the first variadic parameter in the
+ * parameter list. The corresponding argument layout (if any), and all following
+ * argument layouts in the specialized function descriptor, are called
+ * variadic argument layouts.
*
- * The native linker does not automatically perform default argument promotions. However, since passing an argument of a
- * non-promoted type as a variadic argument is not supported in C, the native linker will reject an attempt to link a
- * specialized function descriptor with any variadic argument value layouts corresponding to a non-promoted C type.
- * Since the size of the C {@code int} type is platform-specific, exactly which layouts will be rejected is
- * platform-specific as well. As an example: on Linux/x64 the layouts corresponding to the C types {@code _Bool},
- * {@code (unsigned) char}, {@code (unsigned) short}, and {@code float} (among others), will be rejected by the linker.
- * The {@link #canonicalLayouts()} method can be used to find which layout corresponds to a particular C type.
+ * The native linker does not automatically perform default argument promotions. However,
+ * since passing an argument of a non-promoted type as a variadic argument is not
+ * supported in C, the native linker will reject an attempt to link a specialized
+ * function descriptor with any variadic argument value layouts corresponding to a
+ * non-promoted C type. Since the size of the C {@code int} type is platform-specific,
+ * exactly which layouts will be rejected is platform-specific as well. As an example:
+ * on Linux/x64 the layouts corresponding to the C types {@code _Bool},
+ * {@code (unsigned) char}, {@code (unsigned) short}, and {@code float} (among others),
+ * will be rejected by the linker. The {@link #canonicalLayouts()} method can be used to
+ * find which layout corresponds to a particular C type.
*
- * A well-known variadic function is the {@code printf} function, defined in the C standard library:
+ * A well-known variadic function is the {@code printf} function, defined in the
+ * C standard library:
*
* {@snippet lang = c:
* int printf(const char *format, ...);
* }
*
- * This function takes a format string, and a number of additional arguments (the number of such arguments is
- * dictated by the format string). Consider the following variadic call:
+ * This function takes a format string, and a number of additional arguments (the number
+ * of such arguments is dictated by the format string). Consider the following
+ * variadic call:
*
* {@snippet lang = c:
* printf("%d plus %d equals %d", 2, 2, 4);
* }
*
- * 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 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:
+ * 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 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();
@@ -487,64 +540,81 @@ import java.util.stream.Stream;
*
* {@snippet lang = java:
* try (Arena arena = Arena.ofConfined()) {
- * int res = (int)printf.invokeExact(arena.allocateFrom("%d plus %d equals %d"), 2, 2, 4); //prints "2 plus 2 equals 4"
+ * //prints "2 plus 2 equals 4"
+ * int res = (int)printf.invokeExact(arena.allocateFrom("%d plus %d equals %d"), 2, 2, 4);
* }
*}
*
*
Safety considerations
*
- * Creating a downcall method handle is intrinsically unsafe. A symbol in a foreign library does not, in general,
- * contain enough signature information (e.g. arity and types of foreign function parameters). As a consequence,
- * the linker runtime cannot validate linkage requests. When a client interacts with a downcall method handle obtained
- * 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.
+ * Creating a downcall method handle is intrinsically unsafe. A symbol in a foreign
+ * library does not, in general, contain enough signature information (e.g. arity and
+ * types of foreign function parameters). As a consequence, the linker runtime cannot
+ * validate linkage requests. When a client interacts with a downcall method handle
+ * obtained 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.
*
- * 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 is completed. 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.
+ * 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 is
+ * completed. 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.
*
* @implSpec
- * Implementations of this interface are immutable, thread-safe and value-based.
+ * Implementations of this interface are immutable, thread-safe and
+ * value-based.
*
* @since 22
*/
public sealed interface Linker permits AbstractLinker {
/**
- * {@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.
+ * {@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.
- * @implSpec A native linker implementation is guaranteed to provide canonical layouts for
- * basic C types.
- * @implNote The libraries exposed by the {@linkplain #defaultLookup() default lookup} associated with the returned
- * 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}.
+ * @apiNote It is not currently possible to obtain a linker for a different
+ * combination of OS and processor.
+ * @implSpec A native linker implementation is guaranteed to provide canonical
+ * layouts for basic C types.
+ * @implNote The libraries exposed by the {@linkplain #defaultLookup() default lookup}
+ * associated with the returned 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}.
*/
static Linker nativeLinker() {
return SharedUtils.getSystemLinker();
}
/**
- * Creates a method handle that is used to call a foreign function with the given signature and address.
+ * Creates a method handle that is used to call a foreign function with
+ * the given signature and address.
*
* Calling this method is equivalent to the following code:
* {@snippet lang=java :
* linker.downcallHandle(function).bindTo(symbol);
* }
*
- * @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
- * @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
+ * @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
+ * @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
*/
@@ -555,87 +625,111 @@ public sealed interface Linker permits AbstractLinker {
Option... options);
/**
- * Creates a method handle that is used to call a foreign function with the given signature.
+ * Creates a method handle that is used to call a foreign function with
+ * the given signature.
*
- * The Java {@linkplain java.lang.invoke.MethodType method type} associated with the returned method handle is
- * {@linkplain FunctionDescriptor#toMethodType() derived} from the argument and return layouts in the function descriptor,
- * but features an additional leading parameter of type {@link MemorySegment}, from which the address of the target
- * foreign function is derived. Moreover, if the function descriptor's return layout is a group layout, the resulting
- * 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.
+ * The Java {@linkplain java.lang.invoke.MethodType method type} associated with the
+ * returned method handle is {@linkplain FunctionDescriptor#toMethodType() derived}
+ * from the argument and return layouts in the function descriptor, but features an
+ * additional leading parameter of type {@link MemorySegment}, from which the address
+ * of the target foreign function is derived. Moreover, if the function descriptor's
+ * return layout is a group layout, the resulting 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 provides the following guarantees for any argument
- * {@code A} of type {@link MemorySegment} whose corresponding layout is an {@linkplain AddressLayout address layout}:
+ * 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}:
*
- *
{@code A.scope().isAlive() == true}. Otherwise, the invocation throws {@link IllegalStateException};
- *
The invocation occurs in a thread {@code T} such that {@code A.isAccessibleBy(T) == true}.
- * Otherwise, the invocation throws {@link WrongThreadException}; and
- *
{@code A} is kept alive during the invocation. For instance, if {@code A} has been obtained using a
- * {@linkplain Arena#ofShared() shared arena}, any attempt to {@linkplain Arena#close() close}
- * the arena while the downcall method handle is still executing will result in an {@link IllegalStateException}.
The invocation occurs in a thread {@code T} such that
+ * {@code A.isAccessibleBy(T) == true}.
+ * Otherwise, the invocation throws {@link WrongThreadException}; and
+ *
{@code A} is kept alive during the invocation. For instance,
+ * if {@code A} has been obtained using a {@linkplain Arena#ofShared() shared arena},
+ * any attempt to {@linkplain Arena#close() close} the arena while the
+ * downcall method handle is still executing will result in an
+ * {@link IllegalStateException}.
*
*
- * 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
- * the global scope. 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() target layout}
- * {@code T}, then the size of the returned segment is set to {@code T.byteSize()}.
+ * 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 the global scope. 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() 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. If an argument
- * is a {@link MemorySegment}, whose corresponding layout is a {@linkplain GroupLayout group layout}, the linker
- * might attempt to access the contents of the segment. As such, one of the exceptions specified by the
- * {@link MemorySegment#get(ValueLayout.OfByte, long)} or the
- * {@link MemorySegment#copy(MemorySegment, long, MemorySegment, long, long)} methods may be thrown.
- * The returned method handle will additionally throw {@link NullPointerException} if any argument
- * passed to it is {@code null}.
+ * 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. If an argument is a {@link MemorySegment},
+ * whose corresponding layout is a {@linkplain GroupLayout group layout}, the linker
+ * might attempt to access the contents of the segment. As such, one of the
+ * exceptions specified by the {@link MemorySegment#get(ValueLayout.OfByte, long)} or
+ * the {@link MemorySegment#copy(MemorySegment, long, MemorySegment, long, long)}
+ * methods may be thrown. The returned method handle will additionally throw
+ * {@link NullPointerException} if any argument passed to it is {@code null}.
*
- * @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
+ * @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
*/
@CallerSensitive
@Restricted
MethodHandle downcallHandle(FunctionDescriptor function, Option... options);
/**
- * 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.
+ * 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.
*
- * The returned memory segment's address points to the newly allocated upcall stub, and is associated with
- * the provided arena. As such, the lifetime of the returned upcall stub segment is controlled by the
- * provided arena. For instance, if the provided arena is a confined arena, the returned
- * upcall stub segment will be deallocated when the provided confined arena is {@linkplain Arena#close() closed}.
+ * The returned memory segment's address points to the newly allocated upcall stub,
+ * and is associated with the provided arena. As such, the lifetime of the returned
+ * upcall stub segment is controlled by the provided arena. For instance, if the
+ * provided arena is a confined arena, the returned upcall stub segment will be
+ * deallocated when the provided confined arena is {@linkplain Arena#close() closed}.
*
- * An upcall stub argument whose corresponding layout is an {@linkplain AddressLayout address layout}
- * is a native segment associated with the global scope.
- * Under normal conditions, the size of this segment argument is {@code 0}.
- * 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()}.
+ * An upcall stub argument whose corresponding layout is an
+ * {@linkplain AddressLayout address layout} is a native segment associated with the
+ * global scope. Under normal conditions, the size of this segment argument is
+ * {@code 0}. 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 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.
+ * The target method handle should not throw any exceptions. If the target method
+ * handle does throw an exception, 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.
*
- * @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 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 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
+ * @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 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 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
- * @throws IllegalCallerException If the caller is in a module that does not have native access enabled
+ * @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
+ * @throws IllegalCallerException If the caller is in a module that does not have
+ * native access enabled
*/
@CallerSensitive
@Restricted
@@ -647,31 +741,44 @@ public sealed interface Linker permits AbstractLinker {
/**
* Returns a symbol lookup for symbols in a set of commonly used libraries.
*
- * Each {@link Linker} is responsible for choosing libraries that are widely recognized as useful on the OS
- * and processor combination supported by the {@link Linker}. Accordingly, the precise set of symbols exposed by the
- * symbol lookup is unspecified; it varies from one {@link Linker} to another.
- * @implNote It is strongly recommended that the result of {@link #defaultLookup} exposes a set of symbols that is stable over time.
- * Clients of {@link #defaultLookup()} are likely to fail if a symbol that was previously exposed by the symbol lookup is no longer exposed.
- *
If an implementer provides {@link Linker} implementations for multiple OS and processor combinations, then it is strongly
- * recommended that the result of {@link #defaultLookup()} exposes, as much as possible, a consistent set of symbols
- * across all the OS and processor combinations.
- * @return a symbol lookup for symbols in a set of commonly used libraries.
+ * Each {@link Linker} is responsible for choosing libraries that are widely
+ * recognized as useful on the OS and processor combination supported by the
+ * {@link Linker}. Accordingly, the precise set of symbols exposed by the symbol
+ * lookup is unspecified; it varies from one {@link Linker} to another.
+ *
+ * @implNote It is strongly recommended that the result of {@link #defaultLookup}
+ * exposes a set of symbols that is stable over time. Clients of
+ * {@link #defaultLookup()} are likely to fail if a symbol that was
+ * previously exposed by the symbol lookup is no longer exposed.
+ *
If an implementer provides {@link Linker} implementations for
+ * multiple OS and processor combinations, then it is strongly
+ * recommended that the result of {@link #defaultLookup()} exposes, as much
+ * as possible, a consistent set of symbols across all the OS and processor
+ * combinations.
+ *
+ * @return a symbol lookup for symbols in a set of commonly used libraries
*/
SymbolLookup defaultLookup();
/**
- * {@return an unmodifiable mapping between the names of data types used by the ABI implemented by this linker and their
- * canonical layouts}
+ * {@return an unmodifiable mapping between the names of data types used by the ABI
+ * implemented by this linker and their canonical layouts}
*
- * Each {@link Linker} is responsible for choosing the data types that are widely recognized as useful on the OS
- * and processor combination supported by the {@link Linker}. Accordingly, the precise set of data type names
- * and canonical layouts exposed by the linker are unspecified; they vary from one {@link Linker} to another.
- * @implNote It is strongly recommended that the result of {@link #canonicalLayouts()} exposes a set of symbols that is stable over time.
- * Clients of {@link #canonicalLayouts()} are likely to fail if a data type that was previously exposed by the linker
- * is no longer exposed, or if its canonical layout is updated.
- *
If an implementer provides {@link Linker} implementations for multiple OS and processor combinations, then it is strongly
- * recommended that the result of {@link #canonicalLayouts()} exposes, as much as possible, a consistent set of symbols
- * across all the OS and processor combinations.
+ * Each {@link Linker} is responsible for choosing the data types that are widely
+ * recognized as useful on the OS and processor combination supported by the
+ * {@link Linker}. Accordingly, the precise set of data type names and canonical
+ * layouts exposed by the linker are unspecified; they vary from one {@link Linker}
+ * to another.
+ *
+ * @implNote It is strongly recommended that the result of {@link #canonicalLayouts()}
+ * exposes a set of symbols that is stable over time. Clients of
+ * {@link #canonicalLayouts()} are likely to fail if a data type that was
+ * previously exposed by the linker is no longer exposed, or if its
+ * canonical layout is updated.
+ *
If an implementer provides {@link Linker} implementations for multiple
+ * OS and processor combinations, then it is strongly recommended that the
+ * result of {@link #canonicalLayouts()} exposes, as much as possible,
+ * a consistent set of symbols across all the OS and processor combinations.
*/
Map canonicalLayouts();
@@ -683,49 +790,57 @@ public sealed interface Linker permits AbstractLinker {
permits LinkerOptions.LinkerOptionImpl {
/**
- * {@return a linker option used to denote the index indicating the start of the variadic arguments passed to the
- * function described by the function descriptor associated with a downcall linkage request}
+ * {@return a linker option used to denote the index indicating the start of the
+ * variadic arguments passed to the function described by the function
+ * descriptor associated with a downcall linkage request}
*
- * The {@code index} value must conform to {@code 0 <= index <= N}, where {@code N} is the number of argument
- * layouts of the function descriptor used in conjunction with this linker option. When the {@code index} is:
+ * The {@code index} value must conform to {@code 0 <= index <= N}, where
+ * {@code N} is the number of argument layouts of the function descriptor used in
+ * conjunction with this linker option. When the {@code index} is:
*
- *
{@code 0}, all arguments passed to the function are passed as variadic arguments
- *
{@code N}, none of the arguments passed to the function are passed as variadic arguments
- *
{@code n}, where {@code 0 < m < N}, the arguments {@code m..N} are passed as variadic arguments
+ *
{@code 0}, all arguments passed to the function are passed as variadic
+ * arguments
+ *
{@code N}, none of the arguments passed to the function are passed as
+ * variadic arguments
+ *
{@code n}, where {@code 0 < m < N}, the arguments {@code m..N} are passed
+ * as variadic arguments
*
- * It is important to always use this linker option when linking a variadic
- * function, even if no variadic argument is passed (the second case in the list
- * above), as this might still affect the calling convention on certain platforms.
+ * It is important to always use this linker option when linking a
+ * variadic function, even if no variadic
+ * argument is passed (the second case in the list above), as this might still
+ * affect the calling convention on certain platforms.
*
- * @implNote The index value is validated when making a linkage request, which is when the function descriptor
- * against which the index is validated is available.
+ * @implNote The index value is validated when making a linkage request, which is
+ * when the function descriptor against which the index is validated is
+ * available.
*
- * @param index 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);
}
/**
- * {@return a linker option used to save portions of the execution state immediately after
- * calling a foreign function associated with a downcall method handle,
- * before it can be overwritten by the Java runtime, or read through conventional means}
+ * {@return a linker option used to save portions of the execution state
+ * immediately after calling a foreign function associated with a
+ * downcall method handle, before it can be overwritten by the Java
+ * runtime, or read through conventional means}
*
- * Execution state is captured by a downcall method handle on invocation, by writing it
- * to a native segment provided by the user to the downcall method handle.
- * 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, the capture state segment, represents the native segment into which
- * the captured state is written.
+ * Execution state is captured by a downcall method handle on invocation, by
+ * writing it to a native segment provided by the user to the downcall method
+ * handle. 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, the capture state segment, represents the native segment
+ * into which the captured state is written.
*
- * 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.
+ * 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}.
+ * Captured state can be retrieved from the capture state segment by constructing
+ * var handles from the {@linkplain #captureStateLayout capture state layout}.
*
* The following example demonstrates the use of this linker option:
* {@snippet lang = "java":
@@ -745,9 +860,9 @@ public sealed interface Linker permits AbstractLinker {
*
* This linker option can not be combined with {@link #critical}.
*
- * @param capturedState the names of the values to save.
- * @throws IllegalArgumentException if at least one of the provided {@code capturedState} names
- * is unsupported on the current platform
+ * @param capturedState the names of the values to save
+ * @throws IllegalArgumentException if at least one of the provided
+ * {@code capturedState} names is unsupported on the current platform
* @see #captureStateLayout()
*/
static Option captureCallState(String... capturedState) {
@@ -759,8 +874,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...)}}
+ * {@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...)}}
*
* The capture state layout is platform-dependent but is guaranteed to be
* a {@linkplain StructLayout struct layout} containing only {@linkplain ValueLayout value layouts}
@@ -789,14 +905,15 @@ public sealed interface Linker permits AbstractLinker {
/**
* {@return a linker option used to mark a foreign function as critical}
*
- * A critical function is a function that has an extremely short running time in all cases
- * (similar to calling an empty function), and does not call back into Java (e.g. using an upcall stub).
+ * A critical function is a function that has an extremely short running time in
+ * all cases (similar to calling an empty function), and does not call back into
+ * Java (e.g. using an upcall stub).
*
* Using this linker option is a hint that some implementations may use to apply
* optimizations that are only valid for critical functions.
*
- * Using this linker option when linking non-critical functions is likely to have adverse effects,
- * such as loss of performance or JVM crashes.
+ * Using this linker option when linking non-critical functions is likely to have
+ * adverse effects, such as loss of performance or JVM crashes.
*/
static Option critical() {
return LinkerOptions.Critical.INSTANCE;
diff --git a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
index 71193a02212..0933c637acb 100644
--- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
@@ -43,21 +43,26 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
/**
* A memory layout describes the contents of a memory segment.
*
- * There are two leaves in the layout hierarchy, {@linkplain ValueLayout value layouts}, which are used to represent values of given size and kind
- * 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.
+ * There are two leaves in the layout hierarchy, {@linkplain ValueLayout value layouts},
+ * which are used to represent values of given size and kind 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.
+ * 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.
+ * Layouts can be optionally associated with a name. A layout name can be
+ * referred to when constructing layout paths.
*
* Consider the following struct declaration in C:
*
@@ -85,46 +90,58 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
* All layouts have a size (expressed in bytes), which is defined as follows:
*
*
The size of a value layout is determined by the {@linkplain ValueLayout#carrier()}
- * associated with the value layout. That is, the constant {@link ValueLayout#JAVA_INT} has carrier {@code int}, and
- * size of 4 bytes;
- *
The size of an address layout is platform-dependent. That is, the constant {@link ValueLayout#ADDRESS}
- * has a size of 8 bytes on a 64-bit platform;
- *
The size of a padding layout is always provided explicitly, on {@linkplain MemoryLayout#paddingLayout(long) construction};
- *
The size of a sequence layout whose element layout is E and element count is L,
- * is the size of E, multiplied by L;
- *
The size of a struct layout with member layouts M1, M2, ... Mn whose sizes are
- * S1, S2, ... Sn, respectively, is S1 + S2 + ... + Sn;
- *
The size of a union layout U with member layouts M1, M2, ... Mn whose sizes are
+ * associated with the value layout. That is, the constant {@link ValueLayout#JAVA_INT}
+ * has carrier {@code int}, and size of 4 bytes;
+ *
The size of an address layout is platform-dependent. That is, the constant
+ * {@link ValueLayout#ADDRESS} has a size of 8 bytes on a 64-bit platform;
+ *
The size of a padding layout is always provided explicitly, on
+ * {@linkplain MemoryLayout#paddingLayout(long) construction};
+ *
The size of a sequence layout whose element layout is E
+ * and element count is L, is the size of E,
+ * multiplied by L;
+ *
The size of a struct layout with member layouts M1, M2, ... Mn
+ * whose sizes are S1, S2, ... Sn, respectively,
+ * is S1 + S2 + ... + Sn;
+ *
The size of a union layout U with member layouts
+ * M1, M2, ... Mn whose sizes are
* S1, S2, ... Sn, respectively, is max(S1, S2, ... Sn).
*
*
- * Furthermore, all layouts have a natural alignment (expressed in bytes) which is defined as follows:
+ * Furthermore, all layouts have a natural alignment (expressed in bytes) which
+ * is defined as follows:
*
*
The natural alignment of a padding layout is 1;
- *
The natural alignment of a value layout whose size is N is N;
- *
The natural alignment of a sequence layout whose element layout is E is the alignment of E;
- *
The natural alignment of a group layout with member layouts M1, M2, ... Mn whose
- * alignments are A1, A2, ... An, respectively, is max(A1, A2 ... An).
+ *
The natural alignment of a value layout whose size is N is
+ * N;
+ *
The natural alignment of a sequence layout whose element layout is
+ * E is the alignment of E;
+ *
The natural alignment of a group layout with member layouts
+ * M1, M2, ... Mn whose alignments are
+ * A1, A2, ... An, respectively, is max(A1, A2 ... An).
*
- * A layout's alignment can be overridden if needed (see {@link MemoryLayout#withByteAlignment(long)}), which can be useful to describe
+ * 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
*
- * 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).
+ * 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).
*
* Layout paths can be used to:
*
- *
obtain {@linkplain MemoryLayout#byteOffset(PathElement...) offsets} of arbitrarily nested layouts;
- *
obtain a {@linkplain #varHandle(PathElement...) var handle} that can be used to access the value corresponding
- * to the selected layout;
+ *
obtain {@linkplain MemoryLayout#byteOffset(PathElement...) offsets} of
+ * arbitrarily nested layouts;
+ *
obtain a {@linkplain #varHandle(PathElement...) var handle} that can be used
+ * to access the value corresponding to the selected layout;
*
{@linkplain #select(PathElement...) select} an arbitrarily nested layout.
*
*
- * For instance, given the {@code taggedValues} sequence layout constructed above, we can obtain the offset,
- * in bytes, of the member layout named value in the first sequence element, as follows:
+ * For instance, given the {@code taggedValues} sequence layout constructed above, we can
+ * obtain the offset, in bytes, of the member layout named value in the
+ * first sequence element, as follows:
* {@snippet lang=java :
* long valueOffset = TAGGED_VALUES.byteOffset(PathElement.sequenceElement(0),
* PathElement.groupElement("value")); // yields 4
@@ -138,11 +155,13 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
*
*
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:
+ * 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 = TAGGED_VALUES.varHandle(PathElement.sequenceElement(),
@@ -156,9 +175,10 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
*
*
* Open path elements also affect 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:
+ * {@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 = TAGGED_VALUES.byteOffsetHandle(PathElement.sequenceElement(),
@@ -169,8 +189,8 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
*
*
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:
+ * 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(
@@ -185,10 +205,12 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
* );
* }
*
- * This layout is a struct layout describing 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.
+ * This layout is a struct layout describing 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.
*
* With dereference path elements, we can obtain a var handle that accesses the {@code y} coordinate of one of the
* point in the rectangle, as follows:
@@ -210,40 +232,50 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
*
*
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 that 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.
+ * 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 that 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.
*
- * 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:
+ * 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:
*
- *
{@code L} is a sequence layout and {@code E} is a sequence path element (one of {@link PathElement#sequenceElement(long)},
- * {@link PathElement#sequenceElement(long, long)} or {@link PathElement#sequenceElement()}). Moreover, if {@code E}
- * contains one or more sequence indices, such indices have to be compatible with the sequence layout's element count;
- *
{@code L} is a group layout and {@code E} is a group path element (one of {@link PathElement#groupElement(String)}
- * or {@link PathElement#groupElement(long)}). Moreover, the group path element must refer to a valid member layout in
+ *
{@code L} is a sequence layout and {@code E} is a sequence path element
+ * (one of {@link PathElement#sequenceElement(long)}, {@link PathElement#sequenceElement(long, long)}
+ * or {@link PathElement#sequenceElement()}). Moreover, if {@code E} contains one or
+ * more sequence indices, such indices have to be compatible with the sequence layout's
+ * element count;
+ *
{@code L} is a group layout and {@code E} is a group path element (one of
+ * {@link PathElement#groupElement(String)} or {@link PathElement#groupElement(long)}).
+ * Moreover, the group path element must refer to a valid member layout in
* {@code L}, either by name, or index;
- *
{@code L} is an address layout and {@code E} is a {@linkplain PathElement#dereferenceElement() dereference path element}.
+ *
{@code L} is an address layout and {@code E} is a {@linkplain PathElement#dereferenceElement()
+ * dereference path element}.
* Moreover, {@code L} must define some {@linkplain AddressLayout#targetLayout() target layout}.
*
- * 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}.
+ * 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}.
*
*
Access mode restrictions
*
- * A var handle returned by {@link #varHandle(PathElement...)} or {@link ValueLayout#varHandle()} features certain
- * access characteristics, which are derived from the selected layout {@code L}:
+ * A var handle returned by {@link #varHandle(PathElement...)} or
+ * {@link ValueLayout#varHandle()} features certain access characteristics, which are
+ * derived from the selected layout {@code L}:
*
*
A carrier type {@code T}, derived from {@code L.carrier()}
*
An alignment constraint {@code A}, derived from {@code L.byteAlignment()}
*
An access size {@code S}, derived from {@code L.byteSize()}
*
- * Depending on the above characteristics, the returned var handle might feature certain access mode restrictions.
- * We say that a var handle is aligned if its alignment constraint {@code A} is compatible with the access size
- * {@code S}, that is if {@code A >= S}. An aligned var handle is guaranteed to support the following access modes:
+ * Depending on the above characteristics, the returned var handle might feature certain
+ * access mode restrictions. We say that a var handle is aligned if its
+ * alignment constraint {@code A} is compatible with the access size {@code S}, that is
+ * if {@code A >= S}. An aligned var handle is guaranteed to support the following
+ * access modes:
*
*
read write access modes for all {@code T}. On 32-bit platforms, access modes
* {@code get} and {@code set} for {@code long}, {@code double} and {@code MemorySegment}
@@ -260,26 +292,33 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
* (Future major platform releases of the JDK may support additional
* numeric types for certain currently unsupported access modes.)
*
- * If {@code T} is {@code float}, {@code double} or {@link MemorySegment} then atomic update access modes compare
- * values using their bitwise representation (see {@link Float#floatToRawIntBits}, {@link Double#doubleToRawLongBits}
+ * If {@code T} is {@code float}, {@code double} or {@link MemorySegment} then atomic
+ * update access modes compare values using their bitwise representation
+ * (see {@link Float#floatToRawIntBits}, {@link Double#doubleToRawLongBits}
* and {@link MemorySegment#address()}, respectively).
*
- * Alternatively, a var handle is unaligned if its alignment constraint {@code A} is incompatible with the
- * access size {@code S}, that is, if {@code A < S}. An unaligned var handle only supports the {@code get} and {@code set}
- * access modes. All other access modes will result in {@link UnsupportedOperationException} being thrown. Moreover,
- * while supported, access modes {@code get} and {@code set} might lead to word tearing.
+ * Alternatively, a var handle is unaligned if its alignment constraint {@code A}
+ * is incompatible with the access size {@code S}, that is, if {@code A < S}. An
+ * unaligned var handle only supports the {@code get} and {@code set} access modes. All
+ * other access modes will result in {@link UnsupportedOperationException} being thrown.
+ * Moreover, while supported, access modes {@code get} and {@code set} might lead to
+ * word tearing.
*
*
Working with variable-length arrays
*
- * We have seen how sequence layouts are used to describe the contents of an array whose size is known statically.
- * There are cases, however, where the array size is only known dynamically. We call such arrays variable-length arrays.
+ * We have seen how sequence layouts are used to describe the contents of an array whose
+ * size is known statically. There are cases, however, where the array size is
+ * only known dynamically. We call such arrays variable-length arrays.
* There are two common kinds of variable-length arrays:
*
- *
a toplevel variable-length array whose size depends on the value of some unrelated variable, or parameter;
- *
an variable-length array nested in a struct, whose size depends on the value of some other field in the enclosing struct.
+ *
a toplevel variable-length array whose size depends on the value of
+ * some unrelated variable, or parameter;
+ *
an variable-length array nested in a struct, whose size depends on
+ * the value of some other field in the enclosing struct.
*
- * While variable-length arrays cannot be modeled directly using sequence layouts, clients can still enjoy structured
- * access to elements of variable-length arrays using var handles as demonstrated in the following sections.
+ * While variable-length arrays cannot be modeled directly using sequence layouts,
+ * clients can still enjoy structured access to elements of variable-length arrays
+ * using var handles as demonstrated in the following sections.
*
*
Toplevel variable-length arrays
*
@@ -292,8 +331,8 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
* } Point;
* }
*
- * In the above code, a point is modeled as two coordinates ({@code x} and {@code y} respectively). Now consider
- * the following snippet of C code:
+ * In the above code, a point is modeled as two coordinates ({@code x} and
+ * {@code y} respectively). Now consider the following snippet of C code:
*
* {@snippet lang=c :
* int size = ...
@@ -303,10 +342,12 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
* }
* }
*
- * Here, we allocate an array of points ({@code points}). Crucially, the size of the array is dynamically bound to the value
- * of the {@code size} variable. Inside the loop, the {@code x} coordinate of all the points in the array is accessed.
+ * Here, we allocate an array of points ({@code points}). Crucially, the size of
+ * the array is dynamically bound to the value of the {@code size} variable. Inside
+ * the loop, the {@code x} coordinate of all the points in the array is accessed.
*
- * To model this code in Java, let's start by defining a layout for the {@code Point} struct, as follows:
+ * To model this code in Java, let's start by defining a layout for the {@code Point}
+ * struct, as follows:
*
* {@snippet lang=java :
* StructLayout POINT = MemoryLayout.structLayout(
@@ -315,10 +356,12 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
* );
* }
*
- * Since we know we need to create and access an array of points, it would be tempting to create a sequence layout modelling
- * the variable-length array, and then derive the necessary access var handles from the sequence layout. But this approach
- * is problematic, as the size of the variable-length array is not known. Instead, a var handle that provides structured
- * access to the elements of a variable-length array can be obtained directly from the layout describing the array elements
+ * Since we know we need to create and access an array of points, it would be tempting to
+ * create a sequence layout modelling the variable-length array, and then derive the
+ * necessary access var handles from the sequence layout. But this approach is
+ * problematic, as the size of the variable-length array is not known. Instead, a
+ * var handle that provides structured access to the elements of a variable-length array
+ * can be obtained directly from the layout describing the array elements
* (e.g. the point layout), as demonstrated below:
*
* {@snippet lang=java :
@@ -331,15 +374,19 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
* }
* }
*
- * Here, the coordinate {@code x} of subsequent point in the array is accessed using the {@code POINT_ARR_X} var
- * handle, which is obtained using the {@link #arrayElementVarHandle(PathElement...)} method. This var handle
- * features two {@code long} coordinates: the first is a base offset (set to {@code 0L}), while the
- * second is a logical index that can be used to stride over all the elements of the point array.
+ * Here, the coordinate {@code x} of subsequent point in the array is accessed using the
+ * {@code POINT_ARR_X} var handle, which is obtained using the
+ * {@link #arrayElementVarHandle(PathElement...)} method. This var handle features two
+ * {@code long} coordinates: the first is a base offset (set to {@code 0L}), while the
+ * second is a logical index that can be used to stride over all the elements of the
+ * point array.
*
- * The base offset coordinate allows clients to express complex access operations, by injecting additional offset
- * computation into the var handle (we will see an example of that below). In cases where the base offset is constant
- * (as in the previous example) clients can, if desired, drop the base offset parameter and make the access expression
- * simpler. This is achieved using the {@link java.lang.invoke.MethodHandles#insertCoordinates(VarHandle, int, Object...)}
+ * The base offset coordinate allows clients to express complex access operations, by
+ * injecting additional offset computation into the var handle (we will see an example
+ * of that below). In cases where the base offset is constant (as in the previous
+ * example) clients can, if desired, drop the base offset parameter and make the access
+ * expression simpler. This is achieved using the
+ * {@link java.lang.invoke.MethodHandles#insertCoordinates(VarHandle, int, Object...)}
* var handle adapter.
*
*
Nested variable-length arrays
@@ -353,13 +400,15 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
* } Polygon;
* }
*
- * In the above code, a polygon is modeled as a size (the number of edges in the polygon) and an array of points
- * (one for each vertex in the polygon). The number of vertices depends on the number of edges in the polygon. As such,
- * the size of the {@code points} array is left unspecified in the C declaration, using a Flexible Array Member
- * (a feature standardized in C99).
+ * In the above code, a polygon is modeled as a size (the number of edges in the polygon)
+ * and an array of points (one for each vertex in the polygon). The number of vertices
+ * depends on the number of edges in the polygon. As such, the size of the {@code points}
+ * array is left unspecified in the C declaration, using a
+ * Flexible Array Member (a feature standardized in C99).
*
- * Again, clients can perform structured access to elements in the nested variable-length array using the
- * {@link #arrayElementVarHandle(PathElement...)} method, as demonstrated below:
+ * Again, clients can perform structured access to elements in the nested variable-length
+ * array using the {@link #arrayElementVarHandle(PathElement...)} method, as demonstrated
+ * below:
*
* {@snippet lang=java :
* StructLayout POLYGON = MemoryLayout.structLayout(
@@ -371,12 +420,14 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
* long POINTS_OFFSET = POLYGON.byteOffset(PathElement.groupElement("points"));
* }
*
- * The {@code POLYGON} layout contains a sequence layout of size zero. The element layout of the sequence layout
- * is the {@code POINT} layout, shown previously. The polygon layout is used to obtain a var handle
- * that provides access to the polygon size, as well as an offset ({@code POINTS_OFFSET}) to the start of the
- * variable-length {@code points} array.
+ * The {@code POLYGON} layout contains a sequence layout of size zero. The
+ * element layout of the sequence layout is the {@code POINT} layout, shown previously.
+ * The polygon layout is used to obtain a var handle that provides access to the polygon
+ * size, as well as an offset ({@code POINTS_OFFSET}) to the start of the variable-length
+ * {@code points} array.
*
- * The {@code x} coordinates of all the points in a polygon can then be accessed as follows:
+ * The {@code x} coordinates of all the points in a polygon can then be accessed as
+ * follows:
* {@snippet lang=java :
* MemorySegment polygon = ...
* int size = POLYGON_SIZE.get(polygon, 0L);
@@ -384,14 +435,16 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
* ... POINT_ARR_X.get(polygon, POINTS_OFFSET, (long)i) ...
* }
* }
- * Here, we first obtain the polygon size, using the {@code POLYGON_SIZE} var handle. Then, in a loop, we read
- * the {@code x} coordinates of all the points in the polygon. This is done by providing a custom offset
- * (namely, {@code POINTS_OFFSET}) to the offset coordinate of the {@code POINT_ARR_X} var handle. As before,
- * the loop induction variable {@code i} is passed as the index of the {@code POINT_ARR_X} var handle,
- * to stride over all the elements of the variable-length array.
+ * Here, we first obtain the polygon size, using the {@code POLYGON_SIZE} var handle.
+ * Then, in a loop, we read the {@code x} coordinates of all the points in the polygon.
+ * This is done by providing a custom offset (namely, {@code POINTS_OFFSET}) to the
+ * offset coordinate of the {@code POINT_ARR_X} var handle. As before, the loop
+ * induction variable {@code i} is passed as the index of the {@code POINT_ARR_X}
+ * var handle, to stride over all the elements of the variable-length array.
*
* @implSpec
- * Implementations of this interface are immutable, thread-safe and value-based.
+ * Implementations of this interface are immutable, thread-safe and
+ * value-based.
*
* @sealedGraph
* @since 22
@@ -411,42 +464,51 @@ public sealed interface MemoryLayout
Optional name();
/**
- * {@return a memory layout with the same characteristics as this layout, but with the given name}
+ * {@return a memory layout with the same characteristics as this layout, but with
+ * the given name}
*
- * @param name the layout name.
+ * @param name the layout name
* @see MemoryLayout#name()
*/
MemoryLayout withName(String name);
/**
- * {@return a memory layout with the same characteristics as this layout, but with no name}
+ * {@return a memory layout with the same characteristics as this layout, but with
+ * no name}
*
- * @apiNote This can be useful to compare two layouts that have different names, but are otherwise equal.
+ * @apiNote This can be useful to compare two layouts that have different names, but
+ * are otherwise equal.
* @see MemoryLayout#name()
*/
MemoryLayout withoutName();
/**
- * {@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:
+ * {@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:
*
*
*
{@code A=1} means unaligned (in the usual sense), which is common in packets.
- *
{@code A=8} means word aligned (on LP64), {@code A=4} int aligned, {@code A=2} short aligned, etc.
- *
{@code A=64} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).
+ *
{@code A=8} means word aligned (on LP64), {@code A=4} int aligned,
+ * {@code A=2} short aligned, etc.
+ *
{@code A=64} is the most strict alignment required by the x86/SV ABI
+ * (for AVX-512 data).
*
*
- * 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.
+ * 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.
*/
long byteAlignment();
/**
- * {@return a memory layout with the same characteristics as this layout, but with the given
- * 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.
+ * @param byteAlignment the layout alignment constraint, expressed in bytes
* @throws IllegalArgumentException if {@code byteAlignment} is not a power of two
*/
MemoryLayout withByteAlignment(long byteAlignment);
@@ -462,19 +524,24 @@ public sealed interface MemoryLayout
long scale(long offset, long index);
/**
- *{@return a method handle that can be used to invoke {@link #scale(long, long)} on this layout}
+ *{@return a method handle that can be used to invoke {@link #scale(long, long)}
+ * on this layout}
*/
MethodHandle scaleHandle();
/**
- * Computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the
- * path is 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 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
+ * @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 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
*/
long byteOffset(PathElement... elements);
@@ -486,9 +553,10 @@ public sealed interface MemoryLayout
*
*
its return type is {@code long};
*
it has one leading {@code long} parameter representing the base offset;
- *
it has as zero or more trailing parameters of type {@code long}, one for each open path element
- * in the provided layout path. The order of these parameters corresponds to the order in which the open path
- * elements occur in the provided layout path.
+ *
it has as zero or more trailing parameters of type {@code long}, one for
+ * each open path element in the provided layout
+ * path. The order of these parameters corresponds to the order in which the
+ * open path elements occur in the provided layout path.
*
*
* The final offset returned by the method handle is computed as follows:
@@ -497,79 +565,99 @@ public sealed interface MemoryLayout
* offset = b + c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
* }
*
- * where {@code b} represents the base offset provided as a dynamic {@code long} argument, {@code x_1}, {@code x_2},
- * ... {@code x_n} represent indices into sequences provided as dynamic {@code long} arguments, whereas
- * {@code s_1}, {@code s_2}, ... {@code s_n} are static stride constants derived from the size of the element
- * layout of a sequence, and {@code c_1}, {@code c_2}, ... {@code c_m} are other static offset constants
- * (such as field offsets) which are derived from the layout path.
+ * where {@code b} represents the base offset provided as a dynamic
+ * {@code long} argument, {@code x_1}, {@code x_2}, ... {@code x_n} represent indices
+ * into sequences provided as dynamic {@code long} arguments, whereas
+ * {@code s_1}, {@code s_2}, ... {@code s_n} are static stride constants
+ * derived from the size of the element layout of a sequence, and
+ * {@code c_1}, {@code c_2}, ... {@code c_m} are other static offset
+ * constants (such as field offsets) 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.
+ * @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 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
+ * @param elements the layout path elements
+ * @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
*/
MethodHandle byteOffsetHandle(PathElement... elements);
/**
- * 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.
+ * 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.
*
* The returned var handle has the following characteristics:
*
*
its type is derived from the {@linkplain ValueLayout#carrier() carrier} of the
* selected value layout;
- *
it has a leading parameter of type {@code MemorySegment} representing the accessed segment
- *
a following {@code long} parameter, corresponding to the base offset, denoted as {@code B};
- *
it has zero or more trailing access coordinates of type {@code long}, one for each
- * open path element in the provided layout path, denoted as
- * {@code I1, I2, ... In}, respectively. The order of these access coordinates corresponds to the order
- * in which the open path elements occur in the provided layout path.
+ *
it has a leading parameter of type {@code MemorySegment} representing the
+ * accessed segment
+ *
a following {@code long} parameter, corresponding to the base offset,
+ * denoted as {@code B};
+ *
it has zero or more trailing access coordinates of type {@code long},
+ * one for each open path element in the provided
+ * layout path, denoted as {@code I1, I2, ... In}, respectively. The order of
+ * these access coordinates corresponds to the order in which the open path
+ * elements occur in the provided layout path.
*
*
- * If the provided layout path {@code P} contains no dereference elements, then the offset {@code O} of the access
- * operation is computed as follows:
+ * If the provided layout path {@code P} contains no dereference elements, then the
+ * offset {@code O} of the access operation is computed as follows:
*
* {@snippet lang = "java":
* O = this.offsetHandle(P).invokeExact(B, I1, I2, ... In);
* }
*
- * Accessing a memory segment using the var handle returned by this method is subject to the following checks:
+ * Accessing a memory segment using the var handle returned by this method is subject
+ * to the following checks:
*
- *
The physical address of the accessed memory segment must be aligned
- * according to the {@linkplain #byteAlignment() alignment constraint} of the root layout (this layout), or
- * an {@link IllegalArgumentException} will be issued. Note that the alignment constraint of the root layout
- * can be more strict (but not less) than the alignment constraint of the selected value layout.
- *
The offset of the access operation (computed as above) must fall inside the spatial bounds of the
- * accessed memory segment, or an {@link IndexOutOfBoundsException} is thrown. This is the case when {@code O + A <= S},
- * where {@code O} is the accessed offset (computed as above), {@code A} is the size of the selected layout and {@code S}
- * is the size of the accessed memory segment.
- *
The accessed memory segment must be {@link MemorySegment#isAccessibleBy(Thread) accessible} from the
- * thread performing the access operation, or a {@link WrongThreadException} is thrown.
- *
The {@linkplain MemorySegment#scope() scope} associated with the accessed segment must be
- * {@linkplain MemorySegment.Scope#isAlive() alive}, or an {@link IllegalStateException} is thrown.
+ *
The physical address of the accessed memory segment must be
+ * aligned according to the
+ * {@linkplain #byteAlignment() alignment constraint} of the root layout
+ * (this layout), or an {@link IllegalArgumentException} is thrown. Note
+ * that the alignment constraint of the root layout can be more strict
+ * (but not less) than the alignment constraint of the selected value layout.
+ *
The offset of the access operation (computed as above) must fall inside
+ * the spatial bounds of the accessed memory segment, or an
+ * {@link IndexOutOfBoundsException} is thrown. This is the case when
+ * {@code O + A <= S}, where {@code O} is the accessed offset (computed as above),
+ * {@code A} is the size of the selected layout and {@code S} is the size of the
+ * accessed memory segment.
+ *
The accessed memory segment must be
+ * {@link MemorySegment#isAccessibleBy(Thread) accessible} from the thread
+ * performing the access operation, or a {@link WrongThreadException} is thrown.
+ *
The {@linkplain MemorySegment#scope() scope} associated with the accessed
+ * segment must be {@linkplain MemorySegment.Scope#isAlive() alive}, or an
+ * {@link IllegalStateException} is thrown.
*
*
- * If the selected layout is an {@linkplain AddressLayout address layout}, calling {@link VarHandle#get(Object...)}
- * on the returned var handle will return a new memory segment. The segment is associated with the global scope.
- * Moreover, the size of the segment depends on whether the address layout has a
+ * If the selected layout is an {@linkplain AddressLayout address layout}, calling
+ * {@link VarHandle#get(Object...)} on the returned var handle will return a new
+ * memory segment. The segment is associated with the global scope. Moreover, the
+ * size of the segment depends on whether the address layout has a
* {@linkplain AddressLayout#targetLayout() target layout}. More specifically:
*
- *
If the address layout has a target layout {@code T}, then the size of the returned segment
- * is {@code T.byteSize()};
- *
Otherwise, the address layout has no target layout and the size of the returned segment
+ *
If the address layout has a target layout {@code T}, then the size
+ * of the returned segment is {@code T.byteSize()};
+ *
Otherwise, the address layout has no target layout and the size
+ * of the returned segment
* is zero.
*
- * Moreover, if the selected layout is an {@linkplain AddressLayout address layout}, calling {@link VarHandle#set(Object...)}
- * can throw {@link IllegalArgumentException} if the memory segment representing the address to be written is not a
+ * Moreover, if the selected layout is an {@linkplain AddressLayout address layout},
+ * calling {@link VarHandle#set(Object...)} can throw {@link IllegalArgumentException}
+ * if the memory segment representing the address to be written is not a
* {@linkplain MemorySegment#isNative() native} memory segment.
*
- * If the provided layout path has size {@code m} and contains a dereference path element in position {@code k}
- * (where {@code k <= m}) then two layout paths {@code P} and {@code P'} are derived, where P contains all the path
- * elements from 0 to {@code k - 1} and {@code P'} contains all the path elements from {@code k + 1} to
- * {@code m} (if any). Then, the returned var handle is computed as follows:
+ * If the provided layout path has size {@code m} and contains a dereference path
+ * element in position {@code k} (where {@code k <= m}) then two layout paths
+ * {@code P} and {@code P'} are derived, where P contains all the path elements from
+ * 0 to {@code k - 1} and {@code P'} contains all the path elements from {@code k + 1}
+ * to {@code m} (if any). Then, the returned var handle is computed as follows:
*
* {@snippet lang = "java":
* VarHandle baseHandle = this.varHandle(P);
@@ -580,153 +668,195 @@ public sealed interface MemoryLayout
* baseHandle.toMethodHandle(VarHandle.AccessMode.GET));
* }
*
- * (The above can be trivially generalized to cases where the provided layout path contains more than one dereference
- * path elements).
+ * (The above can be trivially generalized to cases where the provided layout path
+ * contains more than one dereference path elements).
*
- * As an example, consider the memory layout expressed by a {@link GroupLayout} instance constructed as follows:
+ * As an example, consider the memory layout expressed by a {@link GroupLayout}
+ * instance constructed as follows:
* {@snippet lang = "java":
* GroupLayout grp = java.lang.foreign.MemoryLayout.structLayout(
* MemoryLayout.paddingLayout(4),
* ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value")
* );
* }
- * To access the member layout named {@code value}, we can construct a var handle as follows:
+ * To access the member layout named {@code value}, we can construct a var handle as
+ * follows:
* {@snippet lang = "java":
* VarHandle handle = grp.varHandle(PathElement.groupElement("value")); //(MemorySegment, long) -> int
* }
*
- * @apiNote The resulting var handle features certain access mode restrictions,
- * which are common to all var handles derived from memory layouts.
+ * @apiNote The resulting var handle features certain
+ * access mode restrictions, which
+ * are common to all var handles derived from memory layouts.
*
- * @param elements the layout path elements.
- * @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}
+ * @param elements the layout path elements
+ * @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}
*/
VarHandle varHandle(PathElement... elements);
/**
- * Creates a var handle that accesses adjacent elements in a memory segment at offsets selected by the given layout path,
- * where the accessed elements have this layout, and where the initial layout in the path is this layout.
+ * Creates a var handle that accesses adjacent elements in a memory segment at
+ * offsets selected by the given layout path, where the accessed elements have this
+ * layout, and where the initial layout in the path is this layout.
*
* The returned var handle has the following characteristics:
*
*
its type is derived from the {@linkplain ValueLayout#carrier() carrier} of the
* selected value layout;
- *
it has a leading parameter of type {@code MemorySegment} representing the accessed segment
- *
a following {@code long} parameter, corresponding to the base offset, denoted as {@code B};
- *
a following {@code long} parameter, corresponding to the array index, denoted as {@code I0}. The array
- * index is used to scale the accessed offset by this layout size;
- *
it has zero or more trailing access coordinates of type {@code long}, one for each
- * open path element in the provided layout path, denoted as
- * {@code I1, I2, ... In}, respectively. The order of these access coordinates corresponds to the order
- * in which the open path elements occur in the provided layout path.
+ *
it has a leading parameter of type {@code MemorySegment} representing
+ * the accessed segment
+ *
a following {@code long} parameter, corresponding to the base offset,
+ * denoted as {@code B};
+ *
a following {@code long} parameter, corresponding to the array index,
+ * denoted as {@code I0}. The array index is used to scale the accessed offset
+ * by this layout size;
+ *
it has zero or more trailing access coordinates of type {@code long},
+ * one for each open path element in the provided
+ * layout path, denoted as {@code I1, I2, ... In}, respectively. The order of
+ * these access coordinates corresponds to the order in which the open path
+ * elements occur in the provided layout path.
*
*
- * If the provided layout path {@code P} contains no dereference elements, then the offset {@code O} of the access
- * operation is computed as follows:
+ * If the provided layout path {@code P} contains no dereference elements, then the
+ * offset {@code O} of the access operation is computed as follows:
*
* {@snippet lang = "java":
* O = this.offsetHandle(P).invokeExact(this.scale(B, I0), I1, I2, ... In);
* }
*
- * More formally, this method can be obtained from the {@link #varHandle(PathElement...)}, as follows:
+ * More formally, this method can be obtained from the {@link #varHandle(PathElement...)},
+ * as follows:
* {@snippet lang = "java":
* MethodHandles.collectCoordinates(varHandle(elements), 1, scaleHandle())
* }
*
* @apiNote
- * As the leading index coordinate {@code I0} is not bound by any sequence layout, it can assume any non-negative
- * value - provided that the resulting offset computation does not overflow, or that the computed offset does not fall
- * outside the spatial bound of the accessed memory segment. As such, the var handles returned from this method can
- * be especially useful when accessing variable-length arrays.
+ * As the leading index coordinate {@code I0} is not bound by any sequence layout, it
+ * can assume any non-negative value - provided that the resulting offset
+ * computation does not overflow, or that the computed offset does not fall outside
+ * the spatial bound of the accessed memory segment. As such, the var handles
+ * returned from this method can be especially useful when accessing
+ * variable-length arrays.
*
- * @param elements the layout path elements.
- * @return a var handle that accesses adjacent elements in a memory segment at offsets 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}
+ * @param elements the layout path elements
+ * @return a var handle that accesses adjacent elements in a memory segment at
+ * offsets 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}
*/
VarHandle arrayElementVarHandle(PathElement... elements);
/**
- * 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 initial layout in the path is this layout.
+ * 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 initial layout in
+ * the path is this layout.
*
* The returned method handle has the following characteristics:
*
*
its return type is {@code MemorySegment};
- *
it has a leading parameter of type {@code MemorySegment} corresponding to the memory segment to be sliced
+ *
it has a leading parameter of type {@code MemorySegment} corresponding to
+ * the memory segment to be sliced
*
a following {@code long} parameter, corresponding to the base offset
- *
it has as zero or more trailing parameters of type {@code long}, one for each open path element
- * in the provided layout path. The order of these parameters corresponds to the order in which the open path
- * elements occur in the provided layout path.
+ *
it has as zero or more trailing parameters of type {@code long}, one for
+ * each open path element in the provided
+ * layout path. The order of these parameters corresponds to the order in which
+ * the open path elements occur in the provided layout path.
*
*
* The offset {@code O} of the returned segment is computed as if by a call to a
- * {@linkplain #byteOffsetHandle(PathElement...) byte offset handle} constructed using the given path elements.
+ * {@linkplain #byteOffsetHandle(PathElement...) byte offset handle} constructed
+ * using the given path elements.
*
- * Computing a slice of a memory segment using the method handle returned by this method is subject to the following checks:
+ * Computing a slice of a memory segment using the method handle returned by this
+ * method is subject to the following checks:
*
- *
The physical address of the accessed memory segment must be aligned
- * according to the {@linkplain #byteAlignment() alignment constraint} of the root layout (this layout), or
- * an {@link IllegalArgumentException} will be issued. Note that the alignment constraint of the root layout
- * can be more strict (but not less) than the alignment constraint of the selected layout.
- *
The start offset of the slicing operation (computed as above) must fall inside the spatial bounds of the
- * accessed memory segment, or an {@link IndexOutOfBoundsException} is thrown. This is the case when {@code O + A <= S},
- * where {@code O} is the start offset of the slicing operation (computed as above), {@code A} is the size of the
- * selected layout and {@code S} is the size of the accessed memory segment.
+ *
The physical address of the accessed memory segment must be
+ * aligned according to the
+ * {@linkplain #byteAlignment() alignment constraint} of the root layout
+ * (this layout), or an {@link IllegalArgumentException} will be issued. Note
+ * that the alignment constraint of the root layout can be more strict
+ * (but not less) than the alignment constraint of the selected layout.
+ *
The start offset of the slicing operation (computed as above) must fall
+ * inside the spatial bounds of the accessed memory segment, or an
+ * {@link IndexOutOfBoundsException} is thrown. This is the case when
+ * {@code O + A <= S}, where {@code O} is the start offset of
+ * the slicing operation (computed as above), {@code A} is the size of the
+ * selected layout and {@code S} is the size of the accessed memory segment.
*
*
- * @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.
+ * @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 that 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
+ * @param elements the layout path elements
+ * @return a method handle that 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
*/
MethodHandle sliceHandle(PathElement... elements);
/**
- * Returns the layout selected from the provided path, where the initial layout in the path is 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 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)})
+ * @param elements the layout path elements
+ * @return the layout selected by the layout path in {@code elements}
+ * @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)})
*/
MemoryLayout select(PathElement... elements);
/**
- * An element in a layout path. There
- * are three kinds of path elements:
+ * An element in a layout path.
+ * There are three kinds of path elements:
*
- *
group path elements, used to select a member layout within a {@link GroupLayout}, either by name or by index;
- *
sequence path elements, used to select one or more sequence element layouts within a {@link SequenceLayout}; and
- *
dereference path elements, used to dereference
- * an address layout as its target layout.
+ *
group path elements, used to select a member layout within a
+ * {@link GroupLayout}, either by name or by index;
+ *
sequence path elements, used to select one or more
+ * sequence element layouts within a {@link SequenceLayout}; and
+ *
dereference path elements, used to
+ * dereference an address
+ * layout as its target layout.
*
* 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.
+ * Implementations of this interface are immutable, thread-safe and
+ * value-based.
*
* @since 22
*/
sealed interface PathElement permits LayoutPath.PathElementImpl {
/**
- * Returns a path element that selects a member layout with the given name in a group layout.
+ * {@return a path element which selects a member layout with the given name in a
+ * group layout}
*
- * @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 the current path is selected.
- * In such cases, using {@link #groupElement(long)} might be preferable.
+ * @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 the current path is
+ * selected. In such cases, using {@link #groupElement(long)} might be
+ * preferable.
*
- * @param name the name of the member layout to be selected.
- * @return a path element that selects the group member layout with the given name.
+ * @param name the name of the member layout to be selected
*/
static PathElement groupElement(String name) {
Objects.requireNonNull(name);
@@ -735,10 +865,10 @@ public sealed interface MemoryLayout
}
/**
- * Returns a path element that selects a member layout with the given index in a group layout.
+ * {@return a path element that selects a member layout with the given index in a
+ * group layout}
*
- * @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.
+ * @param index the index of the member layout element to be selected
* @throws IllegalArgumentException if {@code index < 0}
*/
static PathElement groupElement(long index) {
@@ -750,10 +880,10 @@ public sealed interface MemoryLayout
}
/**
- * Returns a path element that selects the element layout at the specified position in a sequence layout.
+ * {@return a path element which selects the element layout at the specified
+ * index in a sequence layout}
*
- * @param index the index of the sequence element to be selected.
- * @return a path element that selects the sequence element layout with the given index.
+ * @param index the index of the sequence element to be selected
* @throws IllegalArgumentException if {@code index < 0}
*/
static PathElement sequenceElement(long index) {
@@ -765,20 +895,25 @@ public sealed interface MemoryLayout
}
/**
- * Returns an open path element that 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
+ * that 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}.
*
- * 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:
+ * 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 {@code F > 0}, then {@code B = ceilDiv(C - S, F)}
*
if {@code F < 0}, then {@code B = ceilDiv(-(S + 1), -F)}
*
*
- * @param start the index of the first sequence element to be selected.
- * @param step the step factor at which subsequence sequence elements are to be selected.
- * @return a path element that selects the sequence element layout with the given index.
+ * @param start the index of the first sequence element to be selected
+ * @param step the step factor at which subsequence sequence elements are to be
+ * selected
+ * @return a path element that selects the sequence element layout with the
+ * given index.
* @throws IllegalArgumentException if {@code start < 0}, or {@code step == 0}
*/
static PathElement sequenceElement(long start, long step) {
@@ -793,13 +928,12 @@ public sealed interface MemoryLayout
}
/**
- * Returns an open path element that selects an unspecified
- * element layout in a sequence layout.
+ * {@return an open path element
+ * that selects an unspecified element layout in a sequence layout}
*
- * 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.
+ * 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}.
*/
static PathElement sequenceElement() {
return new LayoutPath.PathElementImpl(PathKind.SEQUENCE_ELEMENT,
@@ -807,10 +941,8 @@ public sealed interface MemoryLayout
}
/**
- * Returns a path element that dereferences an address layout as its
- * {@linkplain AddressLayout#targetLayout() target layout} (where set).
- *
- * @return a path element that dereferences an address layout.
+ * {@return a path element that dereferences an address layout as its
+ * {@linkplain AddressLayout#targetLayout() target layout} (where set)}
*/
static PathElement dereferenceElement() {
return new LayoutPath.PathElementImpl(PathKind.DEREF_ELEMENT,
@@ -819,22 +951,27 @@ public sealed interface MemoryLayout
}
/**
- * Compares the specified object with this layout for equality. Returns {@code true} if and only if the specified
- * object is also a layout, and it is equal to this layout. Two layouts are considered equal if they are of
- * the same kind, have the same size, name and alignment constraint. Furthermore, depending on the layout kind, additional
- * conditions must be satisfied:
+ * Compares the specified object with this layout for equality. Returns {@code true}
+ * if and only if the specified object is also a layout, and it is equal to this
+ * layout. Two layouts are considered equal if they are of the same kind, have the
+ * same size, name and alignment constraint. Furthermore, depending on the
+ * layout kind, additional conditions must be satisfied:
*
- *
two value layouts are considered equal if they have the same {@linkplain ValueLayout#order() order},
- * and {@linkplain ValueLayout#carrier() carrier}. Additionally, two address layouts are considered equal if they
- * also have the same {@linkplain AddressLayout#targetLayout() target layout};
- *
two sequence layouts are considered equal if they have the same element count (see {@link SequenceLayout#elementCount()}), and
- * if their element layouts (see {@link SequenceLayout#elementLayout()}) are also equal;
- *
two group layouts are considered equal if they are of the same type (see {@link StructLayout},
- * {@link UnionLayout}) and if their member layouts (see {@link GroupLayout#memberLayouts()}) are also equal.
+ *
two value layouts are considered equal if they have the same
+ * {@linkplain ValueLayout#order() order}, and
+ * {@linkplain ValueLayout#carrier() carrier}. Additionally, two address
+ * layouts are considered equal if they also have the same
+ * {@linkplain AddressLayout#targetLayout() target layout};
+ *
two sequence layouts are considered equal if they have the same element
+ * count (see {@link SequenceLayout#elementCount()}), and if their element
+ * layouts (see {@link SequenceLayout#elementLayout()}) are also equal;
+ *
two group layouts are considered equal if they are of the same type
+ * (see {@link StructLayout}, {@link UnionLayout}) and if their member layouts
+ * (see {@link GroupLayout#memberLayouts()}) are also equal.
*
*
- * @param other the object to be compared for equality with this layout.
- * @return {@code true} if the specified object is equal to this layout.
+ * @param other the object to be compared for equality with this layout
+ * @return {@code true} if the specified object is equal to this layout
*/
boolean equals(Object other);
@@ -850,13 +987,14 @@ public sealed interface MemoryLayout
String toString();
/**
- * 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.
+ * 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.
+ * @param byteSize the padding size (expressed in bytes)
+ * @return the new selector layout
* @throws IllegalArgumentException if {@code byteSize <= 0}
*/
static PaddingLayout paddingLayout(long byteSize) {
@@ -866,11 +1004,12 @@ public sealed interface MemoryLayout
/**
* Creates a sequence layout with the given element layout and element count.
*
- * @param elementCount the sequence element count.
- * @param elementLayout the sequence element layout.
- * @return the new sequence layout with the given element layout and size.
+ * @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 elementLayout.byteSize() * elementCount} overflows
+ * @throws IllegalArgumentException if {@code elementLayout.byteSize() * elementCount}
+ * overflows
* @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}
*/
static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) {
@@ -885,28 +1024,31 @@ public sealed interface MemoryLayout
/**
* Creates a struct layout with the given member layouts.
*
- * @param elements The member layouts of the struct layout.
- * @return a struct layout with the given member layouts.
- * @throws IllegalArgumentException if the sum of the {@linkplain #byteSize() byte sizes} of the member
- * layouts overflows
- * @throws IllegalArgumentException if a member layout in {@code elements} occurs at an offset
- * (relative to the start of the struct layout) which is not compatible with its alignment constraint
+ * @param elements The member layouts of the struct layout
+ * @return a struct layout with the given member layouts
+ * @throws IllegalArgumentException if the sum of the {@linkplain #byteSize() byte sizes}
+ * of the member layouts overflows
+ * @throws IllegalArgumentException if a member layout in {@code elements} occurs at
+ * an offset (relative to the start of the struct layout) which is not
+ * compatible with its alignment constraint
*
- * @apiNote This factory does not automatically align element layouts, by inserting additional {@linkplain PaddingLayout
- * padding layout} elements. As such, the following struct layout creation will fail with an exception:
+ * @apiNote This factory does not automatically align element layouts, by inserting
+ * additional {@linkplain PaddingLayout padding layout} elements. As such,
+ * the following struct layout creation will fail with an exception:
*
* {@snippet lang = java:
* structLayout(JAVA_SHORT, JAVA_INT);
* }
*
- * To avoid the exception, clients can either insert additional padding layout elements:
+ * To avoid the exception, clients can either insert additional padding layout
+ * elements:
*
* {@snippet lang = java:
* structLayout(JAVA_SHORT, MemoryLayout.paddingLayout(2), JAVA_INT);
* }
*
- * Or, alternatively, they can use a member layout that features a smaller alignment constraint. This will result
- * in a packed struct layout:
+ * Or, alternatively, they can use a member layout that features a smaller alignment
+ * constraint. This will result in a packed struct layout:
*
* {@snippet lang = java:
* structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2));
@@ -923,8 +1065,8 @@ public sealed interface MemoryLayout
/**
* Creates a union layout with the given member layouts.
*
- * @param elements The member layouts of the union layout.
- * @return a union layout with the given member layouts.
+ * @param elements The member layouts of the union layout
+ * @return a union layout with the given member layouts
*/
static UnionLayout unionLayout(MemoryLayout... elements) {
Objects.requireNonNull(elements);
diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java
index ad00dbe11b1..0b0a2e136cb 100644
--- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java
+++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java
@@ -53,85 +53,101 @@ import jdk.internal.vm.annotation.ForceInline;
*
* There are two kinds of memory segments:
*
- *
A heap segment is backed by, and provides access to, a region of memory inside the Java heap (an "on-heap" region).
- *
A native segment is backed by, and provides access to, a region of memory outside the Java heap (an "off-heap" region).
+ *
A heap segment is backed by, and provides access to, a region of
+ * memory inside the Java heap (an "on-heap" region).
+ *
A native segment is backed by, and provides access to, a region of
+ * memory outside the Java heap (an "off-heap" region).
*
- * Heap segments can be obtained by calling one of the {@link MemorySegment#ofArray(int[])} factory methods.
- * These methods return a memory segment backed by the on-heap region that holds the specified Java array.
+ * Heap segments can be obtained by calling one of the {@link MemorySegment#ofArray(int[])}
+ * factory methods. These methods return a memory segment backed by the on-heap region
+ * that holds the specified Java array.
*
* Native segments can be obtained by calling one of the {@link Arena#allocate(long, long)}
- * factory methods, which return a memory segment backed by a newly allocated off-heap region with the given size
- * and aligned to the given alignment constraint. Alternatively, native segments can be obtained by
- * {@link FileChannel#map(MapMode, long, long, Arena) mapping} a file into a new off-heap region
- * (in some systems, this operation is sometimes referred to as {@code mmap}).
- * Segments obtained in this way are called mapped segments, and their contents can be {@linkplain #force() persisted} and
- * {@linkplain #load() loaded} to and from the underlying memory-mapped file.
+ * factory methods, which return a memory segment backed by a newly allocated off-heap
+ * region with the given size and aligned to the given alignment constraint.
+ * Alternatively, native segments can be obtained by
+ * {@link FileChannel#map(MapMode, long, long, Arena) mapping} a file into a new off-heap
+ * region (in some systems, this operation is sometimes referred to as {@code mmap}).
+ * Segments obtained in this way are called mapped segments, and their contents
+ * can be {@linkplain #force() persisted} and {@linkplain #load() loaded} to and from the
+ * underlying memory-mapped file.
*
- * Both kinds of segments are read and written using the same methods, known as access operations.
- * An access operation on a memory segment always and only provides access to the region for which the segment was obtained.
+ * Both kinds of segments are read and written using the same methods, known as
+ * access operations. An access operation on a memory
+ * segment always and only provides access to the region for which the segment was
+ * obtained.
*
*
Characteristics of memory segments
*
- * Every memory segment has an {@linkplain #address() address}, expressed as a {@code long} value.
- * The nature of a segment's address depends on the kind of the segment:
+ * Every memory segment has an {@linkplain #address() address}, expressed as a
+ * {@code long} value. The nature of a segment's address depends on the kind of the
+ * segment:
*
- *
The address of a heap segment is not a physical address, but rather an offset within the region of memory
- * which backs the segment. The region is inside the Java heap, so garbage collection might cause the region to be
- * relocated in physical memory over time, but this is not exposed to clients of the {@code MemorySegment} API who
+ *
The address of a heap segment is not a physical address, but rather an offset
+ * within the region of memory which backs the segment. The region is inside the Java
+ * heap, so garbage collection might cause the region to be relocated in physical memory
+ * over time, but this is not exposed to clients of the {@code MemorySegment} API who
* see a stable virtualized address for a heap segment backed by the region.
- * A heap segment obtained from one of the {@link #ofArray(int[])} factory methods has an address of zero.
- *
The address of a native segment (including mapped segments) denotes the physical address of the region of
- * memory which backs the segment.
+ * A heap segment obtained from one of the {@link #ofArray(int[])} factory methods has
+ * an address of zero.
+ *
The address of a native segment (including mapped segments) denotes the physical
+ * address of the region of memory which backs the segment.
*
*
- * Every memory segment has a {@linkplain #byteSize() size}. The size of a heap segment is derived from the Java array
- * from which it is obtained. This size is predictable across Java runtimes.
- * The size of a native segment is either passed explicitly
+ * Every memory segment has a {@linkplain #byteSize() size}. The size of a heap segment
+ * is derived from the Java array from which it is obtained. This size is predictable
+ * across Java runtimes. The size of a native segment is either passed explicitly
* (as in {@link Arena#allocate(long, long)}) or derived from a {@link MemoryLayout}
* (as in {@link Arena#allocate(MemoryLayout)}). The size of a memory segment is typically
* a positive number but may be zero, but never negative.
*
- * The address and size of a memory segment jointly ensure that access operations on the segment cannot fall
- * outside the boundaries of the region of memory that backs the segment.
- * That is, a memory segment has spatial bounds.
+ * The address and size of a memory segment jointly ensure that access operations on the
+ * segment cannot fall outside the boundaries of the region of memory that backs
+ * the segment. That is, a memory segment has spatial bounds.
*
- * Every memory segment is associated with a {@linkplain Scope scope}. This ensures that access operations
- * on a memory segment cannot occur when the region of memory that backs the memory segment is no longer available
- * (e.g., after the scope associated with the accessed memory segment is no longer {@linkplain Scope#isAlive() alive}).
+ * Every memory segment is associated with a {@linkplain Scope scope}. This ensures that
+ * access operations on a memory segment cannot occur when the region of memory that
+ * backs the memory segment is no longer available (e.g., after the scope associated
+ * with the accessed memory segment is no longer {@linkplain Scope#isAlive() alive}).
* That is, a memory segment has temporal bounds.
*
- * 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.
+ * 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.
*
*
Accessing memory segments
*
- * A memory segment can be read or written using various access operations provided in this class (e.g. {@link #get(ValueLayout.OfInt, long)}).
- * Each access operation takes a {@linkplain ValueLayout value layout}, which specifies the size and shape of the value,
- * and an offset, expressed in bytes.
- * For instance, to read an int from a segment, using {@linkplain ByteOrder#nativeOrder() default endianness}, the following code can be used:
+ * A memory segment can be read or written using various access operations provided in
+ * this class (e.g. {@link #get(ValueLayout.OfInt, long)}). Each access operation takes
+ * a {@linkplain ValueLayout value layout}, which specifies the size and shape of the
+ * value, and an offset, expressed in bytes. For instance, to read an {@code int} from
+ * a segment, using {@linkplain ByteOrder#nativeOrder() default endianness}, the
+ * following code can be used:
* {@snippet lang=java :
* MemorySegment segment = ...
* int value = segment.get(ValueLayout.JAVA_INT, 0);
* }
*
- * If the value to be read is stored in memory using {@linkplain ByteOrder#BIG_ENDIAN big-endian} encoding, the access operation
- * can be expressed as follows:
+ * If the value to be read is stored in memory using {@linkplain ByteOrder#BIG_ENDIAN big-endian}
+ * encoding, the access operation can be expressed as follows:
* {@snippet lang=java :
* int value = segment.get(ValueLayout.JAVA_INT.withOrder(BIG_ENDIAN), 0);
* }
*
- * Access operations on memory segments are implemented using var handles. The {@link ValueLayout#varHandle()}
- * method can be used to obtain a var handle that can be used to get/set values represented by the given value layout
- * on a memory segment at the given offset:
+ * Access operations on memory segments are implemented using var handles. The
+ * {@link ValueLayout#varHandle()} method can be used to obtain a var handle that can be
+ * used to get/set values represented by the given value layout on a memory segment at
+ * the given offset:
*
* {@snippet lang=java:
* VarHandle intAtOffsetHandle = ValueLayout.JAVA_INT.varHandle(); // (MemorySegment, long)
* int value = (int) intAtOffsetHandle.get(segment, 10L); // segment.get(ValueLayout.JAVA_INT, 10L)
* }
*
- * Alternatively, a var handle that can be used to access an element of an {@code int} array at a given logical
- * index can be created as follows:
+ * Alternatively, a var handle that can be used to access an element of an {@code int}
+ * array at a given logical index can be created as follows:
*
* {@snippet lang=java:
* VarHandle intAtOffsetAndIndexHandle =
@@ -140,8 +156,9 @@ import jdk.internal.vm.annotation.ForceInline;
* }
*
*
- * Clients can also drop the base offset parameter, in order to make the access expression simpler. This can be used to
- * implement access operations such as {@link #getAtIndex(OfInt, long)}:
+ * Clients can also drop the base offset parameter, in order to make the access
+ * expression simpler. This can be used to implement access operations such as
+ * {@link #getAtIndex(OfInt, long)}:
*
* {@snippet lang=java:
* VarHandle intAtIndexHandle =
@@ -149,16 +166,20 @@ import jdk.internal.vm.annotation.ForceInline;
* int value = (int) intAtIndexHandle.get(segment, 3L); // segment.getAtIndex(ValueLayout.JAVA_INT, 3L);
* }
*
- * Var handles for more complex access expressions (e.g. struct field access, pointer dereference) can be created directly
- * from memory layouts, using layout paths.
+ * Var handles for more complex access expressions (e.g. struct field access, pointer
+ * dereference) can be created directly from memory layouts, using
+ * layout paths.
*
*
Slicing memory segments
*
- * Memory segments support {@linkplain MemorySegment#asSlice(long, long) slicing}. Slicing a memory segment
- * returns a new memory segment that is backed by the same region of memory as the original. The address of the sliced
- * segment is derived from the address of the original segment, by adding an offset (expressed in bytes). The size of
- * the sliced segment is either derived implicitly (by subtracting the specified offset from the size of the original segment),
- * or provided explicitly. In other words, a sliced segment has stricter spatial bounds than those of the original segment:
+ * Memory segments support {@linkplain MemorySegment#asSlice(long, long) slicing}.
+ * Slicing a memory segment returns a new memory segment that is backed by the same
+ * region of memory as the original. The address of the sliced segment is derived from
+ * the address of the original segment, by adding an offset (expressed in bytes). The
+ * size of the sliced segment is either derived implicitly (by subtracting the specified
+ * offset from the size of the original segment), or provided explicitly. In other words,
+ * a sliced segment has stricter spatial bounds than those of the original
+ * segment:
* {@snippet lang = java:
* Arena arena = ...
* MemorySegment segment = arena.allocate(100);
@@ -167,17 +188,20 @@ import jdk.internal.vm.annotation.ForceInline;
* arena.close();
* slice.get(ValueLayout.JAVA_INT, 0); // Already closed!
*}
- * The above code creates a native segment that is 100 bytes long; then, it creates a slice that starts at offset 50
- * of {@code segment}, and is 10 bytes long. That is, the address of the {@code slice} is {@code segment.address() + 50},
- * and its size is 10. As a result, attempting to read an int value at offset 20 of the
- * {@code slice} segment will result in an exception. The {@linkplain Arena temporal bounds} of the original segment
- * is inherited by its slices; that is, when the scope associated with {@code segment} is no longer {@linkplain Scope#isAlive() alive},
- * {@code slice} will also become inaccessible.
+ * The above code creates a native segment that is 100 bytes long; then, it creates a
+ * slice that starts at offset 50 of {@code segment}, and is 10 bytes long. That is, the
+ * address of the {@code slice} is {@code segment.address() + 50}, and its size is 10.
+ * As a result, attempting to read an int value at offset 20 of the {@code slice} segment
+ * will result in an exception. The {@linkplain Arena temporal bounds} of the original
+ * segment is inherited by its slices; that is, when the scope associated with
+ * {@code segment} is no longer {@linkplain Scope#isAlive() alive}, {@code slice} will
+ * also become inaccessible.
*
- * A client might obtain a {@link Stream} from a segment, which can then be used to slice the segment (according to a given
- * element layout) and even allow multiple threads to work in parallel on disjoint segment slices
- * (to do this, the segment has to be {@linkplain MemorySegment#isAccessibleBy(Thread) accessible}
- * from multiple threads). The following code can be used to sum all int values in a memory segment in parallel:
+ * A client might obtain a {@link Stream} from a segment, which can then be used to slice
+ * the segment (according to a given element layout) and even allow multiple threads to
+ * work in parallel on disjoint segment slices (to do this, the segment has to be
+ * {@linkplain MemorySegment#isAccessibleBy(Thread) accessible} from multiple threads).
+ * The following code can be used to sum all int values in a memory segment in parallel:
*
* {@snippet lang = java:
* try (Arena arena = Arena.ofShared()) {
@@ -191,22 +215,29 @@ import jdk.internal.vm.annotation.ForceInline;
*
*
Alignment
*
- * Access operations on a memory segment are constrained not only by the spatial and temporal bounds of the segment,
- * but also by the alignment constraint of the value layout specified to the operation. An access operation can
- * access only those offsets in the segment that denote addresses in physical memory that are aligned according
- * to the layout. An address in physical memory is aligned according to a layout if the address is an integer
- * multiple of the layout's alignment constraint. For example, the address 1000 is aligned according to an 8-byte alignment
- * constraint (because 1000 is an integer multiple of 8), and to a 4-byte alignment constraint, and to a 2-byte alignment
- * constraint; in contrast, the address 1004 is aligned according to a 4-byte alignment constraint, and to a 2-byte alignment
- * constraint, but not to an 8-byte alignment constraint.
- * Access operations are required to respect alignment because it can impact the performance of access operations, and
- * can also determine which access operations are available at a given physical address. For instance,
- * {@linkplain java.lang.invoke.VarHandle#compareAndSet(Object...) atomic access operations} operations using
- * {@link java.lang.invoke.VarHandle} are only permitted at aligned addresses. In addition, alignment
- * applies to an access operation whether the segment being accessed is a native segment or a heap segment.
+ * Access operations on a memory segment are constrained not only by the spatial and
+ * temporal bounds of the segment, but also by the alignment constraint of the
+ * value layout specified to the operation. An access operation can access only those
+ * offsets in the segment that denote addresses in physical memory that are
+ * aligned according to the layout. An address in physical memory is
+ * aligned according to a layout if the address is an integer multiple of
+ * the layout's alignment constraint. For example, the address 1000 is aligned according
+ * to an 8-byte alignment constraint (because 1000 is an integer multiple of 8), and to
+ * a 4-byte alignment constraint, and to a 2-byte alignment constraint; in contrast,
+ * the address 1004 is aligned according to a 4-byte alignment constraint, and to
+ * a 2-byte alignment constraint, but not to an 8-byte alignment constraint.
+ * Access operations are required to respect alignment because it can impact
+ * the performance of access operations, and can also determine which access operations
+ * are available at a given physical address. For instance,
+ * {@linkplain java.lang.invoke.VarHandle#compareAndSet(Object...) atomic access operations}
+ * operations using {@link java.lang.invoke.VarHandle} are only permitted at aligned
+ * addresses. In addition, alignment applies to an access operation whether the segment
+ * being accessed is a native segment or a heap segment.
*
- * If the segment being accessed is a native segment, then its {@linkplain #address() address} in physical memory can be
- * combined with the offset to obtain the target address in physical memory. The pseudo-function below demonstrates this:
+ * If the segment being accessed is a native segment, then its
+ * {@linkplain #address() address} in physical memory can be combined with the offset to
+ * obtain the target address in physical memory. The pseudo-function below
+ * demonstrates this:
*
* {@snippet lang = java:
* boolean isAligned(MemorySegment segment, long offset, MemoryLayout layout) {
@@ -216,76 +247,105 @@ import jdk.internal.vm.annotation.ForceInline;
*
* For example:
*
- *
A native segment with address 1000 can be accessed at offsets 0, 8, 16, 24, etc under an 8-byte alignment constraint,
- * because the target addresses (1000, 1008, 1016, 1024) are 8-byte aligned.
- * Access at offsets 1-7 or 9-15 or 17-23 is disallowed because the target addresses would not be 8-byte aligned.
- *
A native segment with address 1000 can be accessed at offsets 0, 4, 8, 12, etc under a 4-byte alignment constraint,
- * because the target addresses (1000, 1004, 1008, 1012) are 4-byte aligned.
- * Access at offsets 1-3 or 5-7 or 9-11 is disallowed because the target addresses would not be 4-byte aligned.
- *
A native segment with address 1000 can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint,
- * because the target addresses (1000, 1002, 1004, 1006) are 2-byte aligned.
- * Access at offsets 1 or 3 or 5 is disallowed because the target addresses would not be 2-byte aligned.
- *
A native segment with address 1004 can be accessed at offsets 0, 4, 8, 12, etc under a 4-byte alignment constraint,
- * and at offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint.
- * Under an 8-byte alignment constraint, it can be accessed at offsets 4, 12, 20, 28, etc.
- *
A native segment with address 1006 can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint.
- * Under a 4-byte alignment constraint, it can be accessed at offsets 2, 6, 10, 14, etc.
- * Under an 8-byte alignment constraint, it can be accessed at offsets 2, 10, 18, 26, etc.
- *
A native segment with address 1007 can be accessed at offsets 0, 1, 2, 3, etc under a 1-byte alignment constraint.
- * Under a 2-byte alignment constraint, it can be accessed at offsets 1, 3, 5, 7, etc.
- * Under a 4-byte alignment constraint, it can be accessed at offsets 1, 5, 9, 13, etc.
- * Under an 8-byte alignment constraint, it can be accessed at offsets 1, 9, 17, 25, etc.
+ *
A native segment with address 1000 can be accessed at offsets 0, 8, 16, 24, etc
+ * under an 8-byte alignment constraint, because the target addresses
+ * (1000, 1008, 1016, 1024) are 8-byte aligned.
+ * Access at offsets 1-7 or 9-15 or 17-23 is disallowed because the target addresses
+ * would not be 8-byte aligned.
+ *
A native segment with address 1000 can be accessed at offsets 0, 4, 8, 12, etc
+ * under a 4-byte alignment constraint, because the target addresses
+ * (1000, 1004, 1008, 1012) are 4-byte aligned.
+ * Access at offsets 1-3 or 5-7 or 9-11 is disallowed because the target addresses
+ * would not be 4-byte aligned.
+ *
A native segment with address 1000 can be accessed at offsets 0, 2, 4, 6, etc
+ * under a 2-byte alignment constraint, because the target addresses
+ * (1000, 1002, 1004, 1006) are 2-byte aligned.
+ * Access at offsets 1 or 3 or 5 is disallowed because the target addresses would
+ * not be 2-byte aligned.
+ *
A native segment with address 1004 can be accessed at offsets 0, 4, 8, 12, etc
+ * under a 4-byte alignment constraint, and at offsets 0, 2, 4, 6, etc
+ * under a 2-byte alignment constraint. Under an 8-byte alignment constraint,
+ * it can be accessed at offsets 4, 12, 20, 28, etc.
+ *
A native segment with address 1006 can be accessed at offsets 0, 2, 4, 6, etc
+ * under a 2-byte alignment constraint.
+ * Under a 4-byte alignment constraint, it can be accessed at offsets 2, 6, 10, 14, etc.
+ * Under an 8-byte alignment constraint, it can be accessed at offsets 2, 10, 18, 26, etc.
+ *
A native segment with address 1007 can be accessed at offsets 0, 1, 2, 3, etc
+ * under a 1-byte alignment constraint.
+ * Under a 2-byte alignment constraint, it can be accessed at offsets 1, 3, 5, 7, etc.
+ * Under a 4-byte alignment constraint, it can be accessed at offsets 1, 5, 9, 13, etc.
+ * Under an 8-byte alignment constraint, it can be accessed at offsets 1, 9, 17, 25, etc.
*
*
- * The alignment constraint used to access a segment is typically dictated by the shape of the data structure stored
- * in the segment. For example, if the programmer wishes to store a sequence of 8-byte values in a native segment, then
- * the segment should be allocated by specifying an 8-byte alignment constraint, either via {@link Arena#allocate(long, long)}
- * or {@link Arena#allocate(MemoryLayout)}. These factories ensure that the off-heap region of memory backing
- * the returned segment has a starting address that is 8-byte aligned. Subsequently, the programmer can access the
- * segment at the offsets of interest -- 0, 8, 16, 24, etc -- in the knowledge that every such access is aligned.
+ * The alignment constraint used to access a segment is typically dictated by the shape
+ * of the data structure stored in the segment. For example, if the programmer wishes to
+ * store a sequence of 8-byte values in a native segment, then the segment should be
+ * allocated by specifying an 8-byte alignment constraint, either via
+ * {@link Arena#allocate(long, long)} or {@link Arena#allocate(MemoryLayout)}. These
+ * factories ensure that the off-heap region of memory backing the returned segment
+ * has a starting address that is 8-byte aligned. Subsequently, the programmer can access
+ * the segment at the offsets of interest -- 0, 8, 16, 24, etc -- in the knowledge that
+ * every such access is aligned.
*
- * If the segment being accessed is a heap segment, then determining whether access is aligned is more complex.
- * The address of the segment in physical memory is not known and is not even fixed (it may change when the segment
- * is relocated during garbage collection). This means that the address cannot be combined with the specified offset to
- * determine a target address in physical memory. Since the alignment constraint always refers to alignment of
- * addresses in physical memory, it is not possible in principle to determine if any offset in a heap segment is aligned.
+ * If the segment being accessed is a heap segment, then determining whether access is
+ * aligned is more complex. The address of the segment in physical memory is not known
+ * and is not even fixed (it may change when the segment is relocated during garbage
+ * collection). This means that the address cannot be combined with the specified offset
+ * to determine a target address in physical memory. Since the alignment constraint
+ * always refers to alignment of addresses in physical memory, it is not
+ * possible in principle to determine if any offset in a heap segment is aligned.
* For example, suppose the programmer chooses an 8-byte alignment constraint and tries
- * to access offset 16 in a heap segment. If the heap segment's address 0 corresponds to physical address 1000,
- * then the target address (1016) would be aligned, but if address 0 corresponds to physical address 1004,
- * then the target address (1020) would not be aligned. It is undesirable to allow access to target addresses that are
- * aligned according to the programmer's chosen alignment constraint, but might not be predictably aligned in physical memory
- * (e.g. because of platform considerations and/or garbage collection behavior).
+ * to access offset 16 in a heap segment. If the heap segment's address 0 corresponds to
+ * physical address 1000, then the target address (1016) would be aligned, but if
+ * address 0 corresponds to physical address 1004, then the target address (1020) would
+ * not be aligned. It is undesirable to allow access to target addresses that are
+ * aligned according to the programmer's chosen alignment constraint, but might not be
+ * predictably aligned in physical memory (e.g. because of platform considerations
+ * and/or garbage collection behavior).
*
- * In practice, the Java runtime lays out arrays in memory so that each n-byte element occurs at an n-byte
- * 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:
+ * In practice, the Java runtime lays out arrays in memory so that each n-byte element
+ * occurs at an n-byte 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:
*
- *
The starting physical address of a {@code short[]} array will be 2-byte aligned (e.g. 1006) so that successive
- * short elements occur at 2-byte aligned addresses (e.g. 1006, 1008, 1010, 1012, etc). A heap segment backed by a
- * {@code short[]} array can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint. The segment cannot
- * be accessed at any offset under a 4-byte alignment constraint, because there is no guarantee that the target
- * address would be 4-byte aligned, e.g., offset 0 would correspond to physical address 1006 while offset 1 would correspond
- * to physical address 1007. Similarly, the segment cannot be accessed at any offset under an 8-byte alignment constraint,
- * because there is no guarantee that the target address would be 8-byte aligned, e.g., offset 2 would correspond
- * to physical address 1008 but offset 4 would correspond to physical address 1010.
- *
The starting physical address of a {@code long[]} array will be 8-byte aligned (e.g. 1000) on 64-bit platforms,
- * so that successive long elements occur at 8-byte aligned addresses (e.g., 1000, 1008, 1016, 1024, etc.) On 64-bit platforms,
- * a heap segment backed by a {@code long[]} array can be accessed at offsets 0, 8, 16, 24, etc under an 8-byte alignment
- * constraint. In addition, the segment can be accessed at offsets 0, 4, 8, 12, etc under a 4-byte alignment constraint,
- * because the target addresses (1000, 1004, 1008, 1012) are 4-byte aligned. And, the segment can be accessed at offsets
- * 0, 2, 4, 6, etc under a 2-byte alignment constraint, because the target addresses (e.g. 1000, 1002, 1004, 1006) are 2-byte aligned.
- *
The starting physical address of a {@code long[]} array will be 4-byte aligned (e.g. 1004) on 32-bit platforms,
- * so that successive long elements occur at 4-byte aligned addresses (e.g., 1004, 1008, 1012, 1016, etc.) On 32-bit
- * platforms, a heap segment backed by a {@code long[]} array can be accessed at offsets 0, 4, 8, 12, etc under a 4-byte
- * alignment constraint, because the target addresses (1004, 1008, 1012, 1016) are 4-byte aligned. And, the segment
- * can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint, because the target addresses
- * (e.g. 1000, 1002, 1004, 1006) are 2-byte aligned.
+ *
The starting physical address of a {@code short[]} array will be 2-byte aligned
+ * (e.g. 1006) so that successive short elements occur at 2-byte aligned addresses
+ * (e.g. 1006, 1008, 1010, 1012, etc). A heap segment backed by a {@code short[]}
+ * array can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment
+ * constraint. The segment cannot be accessed at any offset under a 4-byte
+ * alignment constraint, because there is no guarantee that the target address would
+ * be 4-byte aligned, e.g., offset 0 would correspond to physical address 1006 while
+ * offset 1 would correspond to physical address 1007. Similarly, the segment cannot
+ * be accessed at any offset under an 8-byte alignment constraint, because there is
+ * no guarantee that the target address would be 8-byte aligned, e.g., offset 2
+ * would correspond to physical address 1008 but offset 4 would correspond to
+ * physical address 1010.
+ *
The starting physical address of a {@code long[]} array will be 8-byte aligned
+ * (e.g. 1000) on 64-bit platforms, so that successive long elements occur at
+ * 8-byte aligned addresses (e.g., 1000, 1008, 1016, 1024, etc.) On 64-bit platforms,
+ * a heap segment backed by a {@code long[]} array can be accessed at offsets
+ * 0, 8, 16, 24, etc under an 8-byte alignment constraint. In addition, the segment
+ * can be accessed at offsets 0, 4, 8, 12, etc under a 4-byte alignment constraint,
+ * because the target addresses (1000, 1004, 1008, 1012) are 4-byte aligned. And,
+ * the segment can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment
+ * constraint, because the target addresses (e.g. 1000, 1002, 1004, 1006) are
+ * 2-byte aligned.
+ *
The starting physical address of a {@code long[]} array will be 4-byte aligned
+ * (e.g. 1004) on 32-bit platforms, so that successive long elements occur at 4-byte
+ * aligned addresses (e.g., 1004, 1008, 1012, 1016, etc.) On 32-bit platforms, a heap
+ * segment backed by a {@code long[]} array can be accessed at offsets
+ * 0, 4, 8, 12, etc under a 4-byte alignment constraint, because the target addresses
+ * (1004, 1008, 1012, 1016) are 4-byte aligned. And, the segment can be accessed at
+ * offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint, because the target
+ * addresses (e.g. 1000, 1002, 1004, 1006) are 2-byte aligned.
*
*
- * In other words, heap segments feature a (platform-dependent) maximum alignment which is derived from the
- * size of the elements of the Java array backing the segment, as shown in the following table:
+ * In other words, heap segments feature a (platform-dependent) maximum
+ * alignment which is derived from the size of the elements of the Java array backing the
+ * segment, as shown in the following table:
*
*
*
- * Heap segments can only be accessed using a layout whose alignment is smaller or equal to the
- * maximum alignment associated with the heap segment. Attempting to access a heap segment using a layout
- * whose alignment is greater than the maximum alignment associated with the heap segment will fail,
- * as demonstrated in the following example:
+ * Heap segments can only be accessed using a layout whose alignment is smaller or equal
+ * to the maximum alignment associated with the heap segment. Attempting to access a
+ * heap segment using a layout whose alignment is greater than the maximum alignment
+ * associated with the heap segment will fail, as demonstrated in the following example:
*
* {@snippet lang=java :
* MemorySegment byteSegment = MemorySegment.ofArray(new byte[10]);
* byteSegment.get(ValueLayout.JAVA_INT, 0); // fails: ValueLayout.JAVA_INT.byteAlignment() > ValueLayout.JAVA_BYTE.byteAlignment()
* }
*
- * In such circumstances, clients have two options. They can use a heap segment backed by a different array
- * type (e.g. {@code long[]}), capable of supporting greater maximum alignment. More specifically, the maximum alignment
- * associated with {@code long[]} is set to {@code ValueLayout.JAVA_LONG.byteAlignment()} which is a platform-dependent
- * value (set to {@code ValueLayout.ADDRESS.byteSize()}). That is, {@code long[]}) is guaranteed to provide at least
- * 8-byte alignment in 64-bit platforms, but only 4-byte alignment in 32-bit platforms:
+ * In such circumstances, clients have two options. They can use a heap segment backed
+ * by a different array type (e.g. {@code long[]}), capable of supporting greater maximum
+ * alignment. More specifically, the maximum alignment associated with {@code long[]} is
+ * set to {@code ValueLayout.JAVA_LONG.byteAlignment()} which is a platform-dependent
+ * value (set to {@code ValueLayout.ADDRESS.byteSize()}). That is, {@code long[]}) is
+ * guaranteed to provide at least 8-byte alignment in 64-bit platforms, but only 4-byte
+ * alignment in 32-bit platforms:
*
* {@snippet lang=java :
* MemorySegment longSegment = MemorySegment.ofArray(new long[10]);
@@ -337,7 +399,8 @@ import jdk.internal.vm.annotation.ForceInline;
* }
*
* Alternatively, they can invoke the access operation with an unaligned layout.
- * All unaligned layout constants (e.g. {@link ValueLayout#JAVA_INT_UNALIGNED}) have their alignment constraint set to 1:
+ * All unaligned layout constants (e.g. {@link ValueLayout#JAVA_INT_UNALIGNED}) have
+ * their alignment constraint set to 1:
* {@snippet lang=java :
* MemorySegment byteSegment = MemorySegment.ofArray(new byte[10]);
* byteSegment.get(ValueLayout.JAVA_INT_UNALIGNED, 0); // ok: ValueLayout.JAVA_INT_UNALIGNED.byteAlignment() == ValueLayout.JAVA_BYTE.byteAlignment()
@@ -345,46 +408,56 @@ import jdk.internal.vm.annotation.ForceInline;
*
*
Zero-length memory segments
*
- * When interacting with foreign functions, it is common for those functions
- * to allocate a region of memory and return a pointer to that region. Modeling the region of memory with a memory segment
- * is challenging because the Java runtime has no insight into the size of the region. Only the address of the start of
- * the region, stored in the pointer, is available. For example, a C function with return type {@code char*} might return
- * a pointer to a region containing a single {@code char} value, or to a region containing an array of {@code char} values,
- * where the size of the array might be provided in a separate parameter. The size of the array is not readily apparent
- * to the code calling the foreign function and hoping to use its result. In addition to having no insight
- * into the size of the region of memory backing a pointer returned from a foreign function, it also has no insight
- * into the lifetime intended for said region of memory by the foreign function that allocated it.
+ * When interacting with foreign functions, it is
+ * common for those functions to allocate a region of memory and return a pointer to that
+ * region. Modeling the region of memory with a memory segment is challenging because
+ * the Java runtime has no insight into the size of the region. Only the address of the
+ * start of the region, stored in the pointer, is available. For example, a C function
+ * with return type {@code char*} might return a pointer to a region containing a single
+ * {@code char} value, or to a region containing an array of {@code char} values, where
+ * the size of the array might be provided in a separate parameter. The size of the
+ * array is not readily apparent to the code calling the foreign function and hoping to
+ * use its result. In addition to having no insight into the size of the region of
+ * memory backing a pointer returned from a foreign function, it also has no insight
+ * into the lifetime intended for said region of memory by the foreign function that
+ * allocated it.
*
* The {@code MemorySegment} API uses zero-length memory segments to represent:
*
pointers read from a memory segment (more on that below).
*
- * The address of the zero-length segment is the address stored in the pointer. The spatial and temporal bounds of the
- * zero-length segment are as follows:
+ * The address of the zero-length segment is the address stored in the pointer.
+ * The spatial and temporal bounds of the zero-length segment are as follows:
*
- *
The size of the segment is zero. any attempt to access these segments will fail with {@link IndexOutOfBoundsException}.
- * This is a crucial safety feature: as these segments are associated with a region
- * of memory whose size is not known, any access operations involving these segments cannot be validated.
- * In effect, a zero-length memory segment wraps an address, and it cannot be used without explicit intent
- * (see below);
+ *
The size of the segment is zero. Any attempt to access these segments will
+ * fail with {@link IndexOutOfBoundsException}. This is a crucial safety feature: as
+ * these segments are associated with a region of memory whose size is not known, any
+ * access operations involving these segments cannot be validated. In effect, a
+ * zero-length memory segment wraps an address, and it cannot be used
+ * without explicit intent (see below);
*
The segment is associated with the global scope. Thus, while zero-length
- * memory segments cannot be accessed directly, they can be passed, opaquely, to other pointer-accepting foreign functions.
+ * memory segments cannot be accessed directly, they can be passed, opaquely, to
+ * other pointer-accepting foreign functions.
*
*
- * To demonstrate how clients can work with zero-length memory segments, consider the case of a client that wants
- * to read a pointer from some memory segment. This can be done via the
- * {@linkplain MemorySegment#get(AddressLayout, long)} access method. This method accepts an
- * {@linkplain AddressLayout address layout} (e.g. {@link ValueLayout#ADDRESS}), the layout of the pointer
- * to be read. For instance, on a 64-bit platform, the size of an address layout is 8 bytes. The access operation
- * also accepts an offset, expressed in bytes, which indicates the position (relative to the start of the memory segment)
- * at which the pointer is stored. The access operation returns a zero-length native memory segment, backed by a region
+ * To demonstrate how clients can work with zero-length memory segments, consider the
+ * case of a client that wants to read a pointer from some memory segment. This can be
+ * done via the {@linkplain MemorySegment#get(AddressLayout, long)} access method. This
+ * method accepts an {@linkplain AddressLayout address layout}
+ * (e.g. {@link ValueLayout#ADDRESS}), the layout of the pointer to be read. For instance,
+ * on a 64-bit platform, the size of an address layout is 8 bytes. The access operation
+ * also accepts an offset, expressed in bytes, which indicates the position (relative to
+ * the start of the memory segment) at which the pointer is stored. The access operation
+ * returns a zero-length native memory segment, backed by a region
* of memory whose starting address is the 64-bit value read at the specified offset.
*
- * The returned zero-length memory segment cannot be accessed directly by the client: since the size of the segment
- * is zero, any access operation would result in out-of-bounds access. Instead, the client must, unsafely,
- * assign new spatial bounds to the zero-length memory segment. This can be done via the
+ * The returned zero-length memory segment cannot be accessed directly by the client:
+ * since the size of the segment is zero, any access operation would result in
+ * out-of-bounds access. Instead, the client must, unsafely, assign new spatial
+ * bounds to the zero-length memory segment. This can be done via the
* {@link #reinterpret(long)} method, as follows:
*
* {@snippet lang = java:
@@ -393,9 +466,10 @@ import jdk.internal.vm.annotation.ForceInline;
* int x = ptr.getAtIndex(ValueLayout.JAVA_INT, 3); // ok
*}
*
- * In some cases, the client might additionally want to assign new temporal bounds to a zero-length memory segment.
- * This can be done via the {@link #reinterpret(long, Arena, Consumer)} method, which returns a
- * new native segment with the desired size and the same temporal bounds as those of the provided arena:
+ * In some cases, the client might additionally want to assign new temporal bounds to a
+ * zero-length memory segment. This can be done via the
+ * {@link #reinterpret(long, Arena, Consumer)} method, which returns a new native segment
+ * with the desired size and the same temporal bounds as those of the provided arena:
*
* {@snippet lang = java:
* MemorySegment ptr = null;
@@ -407,12 +481,14 @@ import jdk.internal.vm.annotation.ForceInline;
* int x = ptr.getAtIndex(ValueLayout.JAVA_INT, 3); // throws IllegalStateException
*}
*
- * Alternatively, if the size of the region of memory backing the zero-length memory segment is known statically,
- * the client can overlay a {@linkplain AddressLayout#withTargetLayout(MemoryLayout) target layout} on the address
+ * Alternatively, if the size of the region of memory backing the zero-length memory
+ * segment is known statically, the client can overlay a
+ * {@linkplain AddressLayout#withTargetLayout(MemoryLayout) target layout} on the address
* layout used when reading a pointer. The target layout is then used to dynamically
- * expand the size of the native memory segment returned by the access operation, so that the size
- * of the segment is the same as the size of the target layout. In other words, the returned segment is no
- * longer a zero-length memory segment, and the pointer it represents can be dereferenced directly:
+ * expand the size of the native memory segment returned by the access operation
+ * so that the size of the segment is the same as the size of the target layout . In other
+ * words, the returned segment is no longer a zero-length memory segment, and the pointer
+ * it represents can be dereferenced directly:
*
* {@snippet lang = java:
* AddressLayout intArrPtrLayout = ValueLayout.ADDRESS.withTargetLayout(
@@ -424,12 +500,13 @@ import jdk.internal.vm.annotation.ForceInline;
* All the methods that can be used to manipulate zero-length memory segments
* ({@link #reinterpret(long)}, {@link #reinterpret(Arena, Consumer)}, {@link #reinterpret(long, Arena, Consumer)} and
* {@link AddressLayout#withTargetLayout(MemoryLayout)}) are
- * restricted methods, and should be used with caution:
- * assigning a segment incorrect spatial and/or temporal bounds could result in a VM crash when attempting to access
- * the memory segment.
+ * restricted methods, and should
+ * be used with caution: assigning a segment incorrect spatial and/or temporal bounds
+ * could result in a VM crash when attempting to access the memory segment.
*
* @implSpec
- * Implementations of this interface are immutable, thread-safe and value-based.
+ * Implementations of this interface are immutable, thread-safe and
+ * value-based.
*
* @since 22
*/
@@ -438,61 +515,73 @@ 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}.
+ * @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 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}.
- * @return the Java object associated with this memory segment, if any.
+ * 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}.
+ *
+ * @return the Java object associated with this memory segment, if any
*/
Optional