8319324: FFM: Reformat javadocs

Reviewed-by: mcimadamore
This commit is contained in:
Per Minborg 2023-11-09 15:18:43 +00:00
parent a3f1b33b9b
commit f939542104
16 changed files with 3001 additions and 2166 deletions

View File

@ -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).
* <p>
* 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:
* <ul>
* <li>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)};</li>
* <li>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)};</li>
* <li>When creating a downcall method handle, using {@link Linker#downcallHandle(FunctionDescriptor, Option...)};
* <li>When creating an upcall stub, using {@link Linker#upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...)}.
* </ul>
*
* @implSpec
* Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
* Implementations of this interface are immutable, thread-safe and
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @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<MemoryLayout> targetLayout();

View File

@ -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.
* <p>
* An arena has a {@linkplain MemorySegment.Scope scope} - the <em>arena scope</em>. 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 <em>arena scope</em>.
* 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.
* <p>
* 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.
* <p>
* The simplest arena is the {@linkplain Arena#global() global arena}. The global arena
* features an <em>unbounded lifetime</em>. 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 <em>unbounded lifetime</em>. 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!
*}
* <p>
* Alternatively, clients can obtain an {@linkplain Arena#ofAuto() automatic arena}, that is an arena
* which features a <em>bounded lifetime</em> that is managed, automatically, by the garbage collector. 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
* <em>after</em> the automatic arena (and all the segments allocated by it) becomes
* <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>, as shown below:
* Alternatively, clients can obtain an {@linkplain Arena#ofAuto() automatic arena}, that
* is an arena which features a <em>bounded lifetime</em> that is managed, automatically,
* by the garbage collector. 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 <em>after</em> the automatic arena (and all
* the segments allocated by it) becomes <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>,
* as shown below:
* {@snippet lang = java:
* MemorySegment segment = Arena.ofAuto().allocate(100, 1); // @highlight regex='ofAuto()'
* ...
* 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.
* <p>
* 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.
* <p>
* The characteristics of the various arenas are summarized in the following table:
*
@ -120,38 +127,45 @@ import java.lang.foreign.MemorySegment.Scope;
*
* <h2 id = "thread-confinement">Safety and thread-confinement</h2>
*
* Arenas provide strong temporal safety guarantees: a memory segment allocated by an arena cannot be accessed
* <em>after</em> 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 <em>after</em> 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.
* <p>
* 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 <em>while</em> 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 <em>thread-confined</em> arenas, and <em>shared</em> 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 <em>while</em> 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
* <em>thread-confined</em> arenas, and <em>shared</em> arenas.
* <p>
* Confined arenas, support strong thread-confinement guarantees. Upon creation, they are assigned an
* <em>owner thread</em>, 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 <em>owner thread</em>, 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}.
* <p>
* 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.
*
* <h2 id = "custom-arenas">Custom arenas</h2>
*
* 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 <em>slicing arena</em> 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 <em>slicing arena</em> 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 <em>owner thread</em>.
* {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the thread
* that created the arena, the arena's <em>owner thread</em>.
*/
static Arena ofConfined() {
return MemorySessionImpl.createConfined(Thread.currentThread()).asArena();
@ -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 <em>always</em> 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
* <em>always</em> 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

View File

@ -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 <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
* Implementing classes are immutable, thread-safe and
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @see MemoryLayout
* @since 22
@ -53,35 +56,39 @@ public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
Optional<MemoryLayout> 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<MemoryLayout> 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.
* <p>
* The carrier type of a layout {@code L} is determined as follows:
* <ul>
* <li>If {@code L} is a {@link ValueLayout} the carrier type is determined through {@link ValueLayout#carrier()}.</li>
* <li>If {@code L} is a {@link GroupLayout} or a {@link SequenceLayout}, the carrier type is {@link MemorySegment}.</li>
* <li>If {@code L} is a {@link ValueLayout} the carrier type is
* determined through {@link ValueLayout#carrier()}.</li>
* <li>If {@code L} is a {@link GroupLayout} or a {@link SequenceLayout},
* the carrier type is {@link MemorySegment}.</li>
* </ul>
*
* @apiNote A function descriptor cannot, by construction, contain any padding layouts. As such, it is not
* necessary to specify how padding 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)

View File

@ -28,13 +28,16 @@ package java.lang.foreign;
import java.util.List;
/**
* A compound layout that is an aggregation of multiple, heterogeneous <em>member layouts</em>. There are two ways in which member layouts
* can be combined: if member layouts are laid out one after the other, the resulting group layout is a
* {@linkplain StructLayout struct layout}; conversely, if all member layouts are laid out at the same starting offset,
* the resulting group layout is a {@linkplain UnionLayout union layout}.
* A compound layout that is an aggregation of multiple, heterogeneous
* <em>member layouts</em>. There are two ways in which member layouts can be combined:
* if member layouts are laid out one after the other, the resulting group layout is a
* {@linkplain StructLayout struct layout}; conversely, if all member layouts are laid
* out at the same starting offset, the resulting group layout is a
* {@linkplain UnionLayout union layout}.
*
* @implSpec
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
* This class is immutable, thread-safe and
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @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<MemoryLayout> 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);

View File

@ -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.
* <p>
* 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.
* <p>
* 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:
* <ul>
* <li>A linker allows Java code to link against foreign functions, via
* {@linkplain #downcallHandle(MemorySegment, FunctionDescriptor, Option...) downcall method handles}; and</li>
* <li>A linker allows foreign functions to call Java method handles,
* via the generation of {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...) upcall stubs}.</li>
* {@linkplain #downcallHandle(MemorySegment, FunctionDescriptor, Option...) downcall method handles};
* and</li>
* <li>A linker allows foreign functions to call Java method handles, via the generation
* of {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...) upcall stubs}.</li>
* </ul>
* A linker provides a way to look up the <em>canonical layouts</em> 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 <em>canonical layouts</em> 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.
* <p>
* 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}.
*
* <h2 id="native-linker">Calling native functions</h2>
*
* 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 <em>platform-dependent description</em> 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 <em>platform-dependent description</em>
* 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;
*}
* <h3 id="describing-c-sigs">Describing C signatures</h3>
*
* 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.
* <p>
* 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).
* <p>
* 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.
* <p>
* 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}.
* <p>
* 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:
* <ul>
* <li>{@code bool}</li>
* <li>{@code char}</li>
@ -137,19 +150,23 @@ import java.util.stream.Stream;
* <li>{@code wchar_t}</li>
* <li>{@code void*}</li>
* </ul>
* 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.
* <p>
* 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.
* <p>
* 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):
*
* <blockquote><table class="plain">
* <caption style="display:none">Mapping C types</caption>
@ -230,24 +247,30 @@ import java.util.stream.Stream;
* <li>{@code L} is a value layout {@code V} and {@code V.withoutName()} is a canonical layout</li>
* <li>{@code L} is a sequence layout {@code S} and all the following conditions hold:
* <ol>
* <li>the alignment constraint of {@code S} is set to its <a href="MemoryLayout.html#layout-align">natural alignment</a>, and</li>
* <li>the alignment constraint of {@code S} is set to its
* <a href="MemoryLayout.html#layout-align">natural alignment</a>, and</li>
* <li>{@code S.elementLayout()} is a layout supported by {@code NL}.</li>
* </ol>
* </li>
* <li>{@code L} is a group layout {@code G} and all the following conditions hold:
* <ol>
* <li>the alignment constraint of {@code G} is set to its <a href="MemoryLayout.html#layout-align">natural alignment</a>;</li>
* <li>the alignment constraint of {@code G} is set to its
* <a href="MemoryLayout.html#layout-align">natural alignment</a>;</li>
* <li>the size of {@code G} is a multiple of its alignment constraint;</li>
* <li>each member layout in {@code G.memberLayouts()} is either a padding layout or a layout supported by {@code NL}, and</li>
* <li>{@code G} does not contain padding other than what is strictly required to align its non-padding layout elements, or to satisfy (2).</li>
* <li>each member layout in {@code G.memberLayouts()} is either a padding layout or
* a layout supported by {@code NL}, and</li>
* <li>{@code G} does not contain padding other than what is strictly required to align
* its non-padding layout elements, or to satisfy (2).</li>
* </ol>
* </li>
* </ul>
*
* Linker implementations may optionally support additional layouts, such as <em>packed</em> 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
* <em>packed</em> 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);
* }
* <p>
* 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.
*
* <h3 id="function-pointers">Function pointers</h3>
*
* 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).
* <p>
* 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.
*
* <h3 id="by-ref">Functions returning pointers</h3>
*
* 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 <em>safe</em> 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 <em>safe</em> allocation API (the approach outlined below
* can of course be generalized to allocation functions other than {@code malloc} and
* {@code free}).
* <p>
* 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
* <a href="MemorySegment.html#wrapping-addresses">zero</a>. 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 <em>cleanup action</em> 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 <em>cleanup action</em> 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 <em>try-with-resources</em> 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 <em>try-with-resources</em> block.
*
* <h3 id="variadic-funcs">Variadic functions</h3>
*
* 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 <em>variadic arguments</em>. Variadic functions are,
* essentially, templates that can be <em>specialized</em> into multiple non-variadic functions by replacing the
* {@code ...} with a list of <em>variadic parameters</em> 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 <em>variadic arguments</em>.
* Variadic functions are, essentially, templates that can be <em>specialized</em> into
* multiple non-variadic functions by replacing the {@code ...} with a list of
* <em>variadic parameters</em> of a fixed number and type.
* <p>
* 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:
* <ul>
* <li>{@code _Bool} -> {@code unsigned int}</li>
* <li>{@code [signed] char} -> {@code [signed] int}</li>
* <li>{@code [signed] short} -> {@code [signed] int}</li>
* <li>{@code float} -> {@code double}</li>
* </ul>
* 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.
* <p>
* 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 <em>variadic argument layouts</em>.
* 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
* <em>variadic argument layouts</em>.
* <p>
* 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.
* <p>
* 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);
* }
*}
*
* <h2 id="safety">Safety considerations</h2>
*
* 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.
* <p>
* 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 <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
* Implementations of this interface are immutable, thread-safe and
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @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}
* <p>
* 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
* <a href="#describing-c-sigs">basic C types</a>.
* @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 <a href="#describing-c-sigs">basic C types</a>.
* @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.
* <p>
* 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.
* <p>
* 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.
* <p>
* 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}:
* <ul>
* <li>{@code A.scope().isAlive() == true}. Otherwise, the invocation throws {@link IllegalStateException};</li>
* <li>The invocation occurs in a thread {@code T} such that {@code A.isAccessibleBy(T) == true}.
* Otherwise, the invocation throws {@link WrongThreadException}; and</li>
* <li>{@code A} is kept alive during the invocation. For instance, if {@code A} has been obtained using a
* {@linkplain Arena#ofShared() shared arena}, any attempt to {@linkplain Arena#close() close}
* the arena while the downcall method handle is still executing will result in an {@link IllegalStateException}.</li>
* <li>{@code A.scope().isAlive() == true}. Otherwise, the invocation
* throws {@link IllegalStateException};</li>
* <li>The invocation occurs in a thread {@code T} such that
* {@code A.isAccessibleBy(T) == true}.
* Otherwise, the invocation throws {@link WrongThreadException}; and</li>
* <li>{@code A} is kept alive during the invocation. For instance,
* if {@code A} has been obtained using a {@linkplain Arena#ofShared() shared arena},
* any attempt to {@linkplain Arena#close() close} the arena while the
* downcall method handle is still executing will result in an
* {@link IllegalStateException}.</li>
*</ul>
* <p>
* Moreover, if the provided function descriptor's return layout is an {@linkplain AddressLayout address layout},
* invoking the returned method handle will return a native segment associated with
* 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()}.
* <p>
* The returned method handle will throw an {@link IllegalArgumentException} if the {@link MemorySegment}
* representing the target address of the foreign function is the {@link MemorySegment#NULL} address. 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.
* <p>
* 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}.
* <p>
* 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()}.
* <p>
* 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.
* <p>
* 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.
* <p>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.
* <p>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
* <em>canonical layouts</em>}
* {@return an unmodifiable mapping between the names of data types used by the ABI
* implemented by this linker and their <em>canonical layouts</em>}
* <p>
* 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.
* <p>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.
* <p>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<String, MemoryLayout> 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}
* <p>
* 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:
* <ul>
* <li>{@code 0}, all arguments passed to the function are passed as variadic arguments</li>
* <li>{@code N}, none of the arguments passed to the function are passed as variadic arguments</li>
* <li>{@code n}, where {@code 0 < m < N}, the arguments {@code m..N} are passed as variadic arguments</li>
* <li>{@code 0}, all arguments passed to the function are passed as variadic
* arguments</li>
* <li>{@code N}, none of the arguments passed to the function are passed as
* variadic arguments</li>
* <li>{@code n}, where {@code 0 < m < N}, the arguments {@code m..N} are passed
* as variadic arguments</li>
* </ul>
* It is important to always use this linker option when linking a <a href=Linker.html#variadic-funcs>variadic
* function</a>, 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
* <a href=Linker.html#variadic-funcs>variadic function</a>, 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}
* <p>
* 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 <em>capture state segment</em>, 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 <em>capture state segment</em>, represents the native segment
* into which the captured state is written.
* <p>
* 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.
* <p>
* 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}.
* <p>
* The following example demonstrates the use of this linker option:
* {@snippet lang = "java":
@ -745,9 +860,9 @@ public sealed interface Linker permits AbstractLinker {
* <p>
* 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...)}}
* <p>
* The capture state layout is <em>platform-dependent</em> but is guaranteed to be
* a {@linkplain StructLayout struct layout} containing only {@linkplain ValueLayout value layouts}
@ -789,14 +905,15 @@ public sealed interface Linker permits AbstractLinker {
/**
* {@return a linker option used to mark a foreign function as <em>critical</em>}
* <p>
* 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).
* <p>
* Using this linker option is a hint that some implementations may use to apply
* optimizations that are only valid for critical functions.
* <p>
* 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;

View File

@ -28,11 +28,13 @@ package java.lang.foreign;
import jdk.internal.foreign.layout.PaddingLayoutImpl;
/**
* A padding layout. A padding layout specifies the size of extra space which is typically not accessed by applications,
* and is typically used for aligning member layouts around word boundaries.
* A padding layout. A padding layout specifies the size of extra space which is
* typically not accessed by applications, and is typically used for aligning member
* layouts around word boundaries.
*
* @implSpec
* Implementing classes are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
* Implementing classes are immutable, thread-safe and
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @since 22
*/

View File

@ -36,12 +36,14 @@ import jdk.internal.foreign.StringSupport;
import jdk.internal.vm.annotation.ForceInline;
/**
* An object that may be used to allocate {@linkplain MemorySegment memory segments}. Clients implementing this interface
* must implement the {@link #allocate(long, long)} method. A segment allocator defines several methods
* which can be useful to create segments from several kinds of Java values such as primitives and arrays.
* An object that may be used to allocate {@linkplain MemorySegment memory segments}.
* Clients implementing this interface must implement the {@link #allocate(long, long)}
* method. A segment allocator defines several methods which can be useful to create
* segments from several kinds of Java values such as primitives and arrays.
* <p>
* {@code SegmentAllocator} is a {@linkplain FunctionalInterface functional interface}. Clients can easily obtain a new
* segment allocator by using either a lambda expression or a method reference:
* {@code SegmentAllocator} is a {@linkplain FunctionalInterface functional interface}.
* Clients can easily obtain a new segment allocator by using either a lambda expression
* or a method reference:
*
* {@snippet lang=java :
* SegmentAllocator autoAllocator = (byteSize, byteAlignment) -> Arena.ofAuto().allocate(byteSize, byteAlignment);
@ -49,25 +51,29 @@ import jdk.internal.vm.annotation.ForceInline;
* <p>
* This interface defines factories for commonly used allocators:
* <ul>
* <li>{@link #slicingAllocator(MemorySegment)} obtains an efficient slicing allocator, where memory
* is allocated by repeatedly slicing the provided memory segment;</li>
* <li>{@link #prefixAllocator(MemorySegment)} obtains an allocator which wraps a segment
* and recycles its content upon each new allocation request.</li>
* <li>{@link #slicingAllocator(MemorySegment)} obtains an efficient slicing
* allocator, where memory is allocated by repeatedly slicing the provided
* memory segment;</li>
* <li>{@link #prefixAllocator(MemorySegment)} obtains an allocator which wraps a
* segment and recycles its content upon each new allocation request.</li>
* </ul>
* <p>
* Passing a segment allocator to an API can be especially useful in circumstances where a client wants to communicate <em>where</em>
* the results of a certain operation (performed by the API) should be stored, as a memory segment. For instance,
* {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handles} can accept an additional
* {@link SegmentAllocator} parameter if the underlying foreign function is known to return a struct by-value. Effectively,
* the allocator parameter tells the linker where to store the return value of the foreign function.
* Passing a segment allocator to an API can be especially useful in circumstances where
* a client wants to communicate <em>where</em> the results of a certain operation
* (performed by the API) should be stored, as a memory segment. For instance,
* {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handles}
* can accept an additional {@link SegmentAllocator} parameter if the underlying
* foreign function is known to return a struct by-value. Effectively, the allocator
* parameter tells the linker where to store the return value of the foreign function.
*
* @apiNote Unless otherwise specified, the {@link #allocate(long, long)} method is not thread-safe.
* Furthermore, memory segments allocated by a segment allocator can be associated with different
* lifetimes, and can even be backed by overlapping regions of memory. For these reasons, clients should generally
* only interact with a segment allocator they own.
* @apiNote Unless otherwise specified, the {@link #allocate(long, long)} method is
* not thread-safe. Furthermore, memory segments allocated by a segment
* allocator can be associated with different lifetimes, and can even be backed
* by overlapping regions of memory. For these reasons, clients should
* generally only interact with a segment allocator they own.
* <p>
* Clients should consider using an {@linkplain Arena arena} instead, which, provides strong thread-safety,
* lifetime and non-overlapping guarantees.
* Clients should consider using an {@linkplain Arena arena} instead, which, provides
* strong thread-safety, lifetime and non-overlapping guarantees.
*
* @since 22
*/
@ -75,16 +81,17 @@ import jdk.internal.vm.annotation.ForceInline;
public interface SegmentAllocator {
/**
* Converts a Java string into a null-terminated C string using the {@linkplain StandardCharsets#UTF_8 UTF-8} charset,
* storing the result into a memory segment.
* Converts a Java string into a null-terminated C string using the
* {@linkplain StandardCharsets#UTF_8 UTF-8} charset, storing the result into a
* memory segment.
* <p>
* Calling this method is equivalent to the following code:
* {@snippet lang = java:
* allocateFrom(str, StandardCharsets.UTF_8);
*}
*
* @param str the Java string to be converted into a C string.
* @return a new native segment containing the converted C string.
* @param str the Java string to be converted into a C string
* @return a new native segment containing the converted C string
*/
@ForceInline
default MemorySegment allocateFrom(String str) {
@ -97,7 +104,7 @@ public interface SegmentAllocator {
* and storing the result into a memory segment.
* <p>
* This method always replaces malformed-input and unmappable-character
* sequences with this charset's default replacement byte array. The
* sequences with this charset's default replacement byte array. The
* {@link java.nio.charset.CharsetEncoder} class should be used when more
* control over the encoding process is required.
* <p>
@ -106,17 +113,21 @@ public interface SegmentAllocator {
* the string, such as {@link MemorySegment#getString(long)}, the string
* will appear truncated when read again.
*
* @param str the Java string to be converted into a C string.
* @param charset the charset used to {@linkplain Charset#newEncoder() encode} the string bytes.
* @return a new native segment containing the converted C string.
* @throws IllegalArgumentException if {@code charset} is not a {@linkplain StandardCharsets standard charset}
* @implSpec The default implementation for this method copies the contents of the provided Java string
* into a new memory segment obtained by calling {@code this.allocate(B + N)}, where:
* @param str the Java string to be converted into a C string
* @param charset the charset used to {@linkplain Charset#newEncoder() encode} the
* string bytes
* @return a new native segment containing the converted C string
* @throws IllegalArgumentException if {@code charset} is not a
* {@linkplain StandardCharsets standard charset}
* @implSpec The default implementation for this method copies the contents of the
* provided Java string into a new memory segment obtained by calling
* {@code this.allocate(B + N)}, where:
* <ul>
* <li>{@code B} is the size, in bytes, of the string encoded using the provided charset
* (e.g. {@code str.getBytes(charset).length});</li>
* <li>{@code N} is the size (in bytes) of the terminator char according to the provided charset. For instance,
* this is 1 for {@link StandardCharsets#US_ASCII} and 2 for {@link StandardCharsets#UTF_16}.</li>
* <li>{@code B} is the size, in bytes, of the string encoded using the
* provided charset (e.g. {@code str.getBytes(charset).length});</li>
* <li>{@code N} is the size (in bytes) of the terminator char according to the
* provided charset. For instance, this is 1 for {@link StandardCharsets#US_ASCII}
* and 2 for {@link StandardCharsets#UTF_16}.</li>
* </ul>
*/
@ForceInline
@ -143,11 +154,12 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment initialized with the provided byte value.}
* {@return a new memory segment initialized with the provided byte value}
* <p>
* The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout.
* The given value is written into the segment according to the byte order and alignment constraint of the
* given layout.
* The size of the allocated memory segment is the
* {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is
* written into the segment according to the byte order and alignment constraint of
* the given layout.
*
* @implSpec The default implementation is equivalent to:
* {@snippet lang=java :
@ -156,8 +168,8 @@ public interface SegmentAllocator {
* return seg;
* }
*
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set in the newly allocated memory segment.
* @param layout the layout of the block of memory to be allocated
* @param value the value to be set in the newly allocated memory segment
*/
default MemorySegment allocateFrom(ValueLayout.OfByte layout, byte value) {
Objects.requireNonNull(layout);
@ -167,11 +179,12 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment initialized with the provided char value.}
* {@return a new memory segment initialized with the provided char value}
* <p>
* The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout.
* The given value is written into the segment according to the byte order and alignment constraint of the
* given layout.
* The size of the allocated memory segment is the
* {@linkplain MemoryLayout#byteSize() size} of the given layout.
* The given value is written into the segment according to the byte order and
* alignment constraint of the given layout.
*
* @implSpec The default implementation is equivalent to:
* {@snippet lang=java :
@ -180,8 +193,8 @@ public interface SegmentAllocator {
* return seg;
* }
*
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set in the newly allocated memory segment.
* @param layout the layout of the block of memory to be allocated
* @param value the value to be set in the newly allocated memory segment
*/
default MemorySegment allocateFrom(ValueLayout.OfChar layout, char value) {
Objects.requireNonNull(layout);
@ -191,11 +204,12 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment initialized with the provided short value.}
* {@return a new memory segment initialized with the provided short value}
* <p>
* The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout.
* The given value is written into the segment according to the byte order and alignment constraint of the
* given layout.
* The size of the allocated memory segment is the
* {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is
* written into the segment according to the byte order and alignment constraint of
* the given layout.
*
* @implSpec The default implementation is equivalent to:
* {@snippet lang=java :
@ -204,8 +218,8 @@ public interface SegmentAllocator {
* return seg;
* }
*
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set in the newly allocated memory segment.
* @param layout the layout of the block of memory to be allocated
* @param value the value to be set in the newly allocated memory segment
*/
default MemorySegment allocateFrom(ValueLayout.OfShort layout, short value) {
Objects.requireNonNull(layout);
@ -215,11 +229,12 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment initialized with the provided int value.}
* {@return a new memory segment initialized with the provided int value}
* <p>
* The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout.
* The given value is written into the segment according to the byte order and alignment constraint of the
* given layout.
* The size of the allocated memory segment is the
* {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is
* written into the segment according to the byte order and alignment constraint of
* the given layout.
*
* @implSpec The default implementation is equivalent to:
* {@snippet lang=java :
@ -228,8 +243,8 @@ public interface SegmentAllocator {
* return seg;
* }
*
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set in the newly allocated memory segment.
* @param layout the layout of the block of memory to be allocated
* @param value the value to be set in the newly allocated memory segment
*/
default MemorySegment allocateFrom(ValueLayout.OfInt layout, int value) {
Objects.requireNonNull(layout);
@ -239,11 +254,12 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment initialized with the provided float value.}
* {@return a new memory segment initialized with the provided float value}
* <p>
* The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout.
* The given value is written into the segment according to the byte order and alignment constraint of the
* given layout.
* The size of the allocated memory segment is the
* {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is
* written into the segment according to the byte order and alignment constraint of
* the given layout.
*
* @implSpec The default implementation is equivalent to:
* {@snippet lang=java :
@ -252,8 +268,8 @@ public interface SegmentAllocator {
* return seg;
* }
*
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set in the newly allocated memory segment.
* @param layout the layout of the block of memory to be allocated
* @param value the value to be set in the newly allocated memory segment
*/
default MemorySegment allocateFrom(ValueLayout.OfFloat layout, float value) {
Objects.requireNonNull(layout);
@ -263,11 +279,12 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment initialized with the provided long value.}
* {@return a new memory segment initialized with the provided long value}
* <p>
* The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout.
* The given value is written into the segment according to the byte order and alignment constraint of the
* given layout.
* The size of the allocated memory segment is the
* {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is
* written into the segment according to the byte order and alignment constraint of
* the given layout.
*
* @implSpec The default implementation is equivalent to:
* {@snippet lang=java :
@ -276,8 +293,8 @@ public interface SegmentAllocator {
* return seg;
* }
*
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set in the newly allocated memory segment.
* @param layout the layout of the block of memory to be allocated
* @param value the value to be set in the newly allocated memory segment
*/
default MemorySegment allocateFrom(ValueLayout.OfLong layout, long value) {
Objects.requireNonNull(layout);
@ -287,11 +304,12 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment initialized with the provided double value.}
* {@return a new memory segment initialized with the provided double value}
* <p>
* The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout.
* The given value is written into the segment according to the byte order and alignment constraint of the
* given layout.
* The size of the allocated memory segment is the
* {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is
* written into the segment according to the byte order and alignment constraint of
* the given layout.
*
* @implSpec The default implementation is equivalent to:
* {@snippet lang=java :
@ -300,8 +318,8 @@ public interface SegmentAllocator {
* return seg;
* }
*
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set in the newly allocated memory segment.
* @param layout the layout of the block of memory to be allocated
* @param value the value to be set in the newly allocated memory segment
*/
default MemorySegment allocateFrom(ValueLayout.OfDouble layout, double value) {
Objects.requireNonNull(layout);
@ -311,13 +329,16 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment initialized with the {@linkplain MemorySegment#address() address} of the provided memory segment.}
* {@return a new memory segment initialized with the
* {@linkplain MemorySegment#address() address} of the provided memory segment}
* <p>
* The address value might be narrowed according to the platform address size (see {@link ValueLayout#ADDRESS}).
* The address value might be narrowed according to the platform address size
* (see {@link ValueLayout#ADDRESS}).
* <p>
* The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout.
* The given value is written into the segment according to the byte order and alignment constraint of the
* given layout.
* The size of the allocated memory segment is the
* {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is
* written into the segment according to the byte order and alignment constraint of
* the given layout.
*
* @implSpec The default implementation is equivalent to:
* {@snippet lang=java :
@ -327,9 +348,10 @@ public interface SegmentAllocator {
* return seg;
* }
*
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set in the newly allocated memory segment.
* @throws UnsupportedOperationException if {@code value} is not a {@linkplain MemorySegment#isNative() native} segment
* @param layout the layout of the block of memory to be allocated
* @param value the value to be set in the newly allocated memory segment
* @throws UnsupportedOperationException if {@code value} is not
* a {@linkplain MemorySegment#isNative() native} segment
*/
default MemorySegment allocateFrom(AddressLayout layout, MemorySegment value) {
Objects.requireNonNull(value);
@ -340,11 +362,12 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment initialized with the contents of the provided segment.}
* {@return a new memory segment initialized with the contents of the provided segment}
* <p>
* The size of the allocated memory segment is the {@code elementLayout.byteSize() * elementCount}.
* The contents of the source segment is copied into the result segment element by element, according to the byte
* order and alignment constraint of the given element layout.
* The size of the allocated memory segment is the
* {@code elementLayout.byteSize() * elementCount}. The contents of the
* source segment is copied into the result segment element by element, according
* to the byte order and alignment constraint of the given element layout.
*
* @implSpec The default implementation for this method is equivalent to the following code:
* {@snippet lang = java:
@ -352,19 +375,19 @@ public interface SegmentAllocator {
* MemorySegment.copy(source, sourceElementLayout, sourceOffset, dest, elementLayout, 0, elementCount);
* return dest;
* }
* @param elementLayout the element layout of the allocated array.
* @param source the source segment.
* @param sourceElementLayout the element layout of the source segment.
* @param sourceOffset the starting offset, in bytes, of the source segment.
* @param elementCount the number of elements in the source segment to be copied.
* @param elementLayout the element layout of the allocated array
* @param source the source segment
* @param sourceElementLayout the element layout of the source segment
* @param sourceOffset the starting offset, in bytes, of the source segment
* @param elementCount the number of elements in the source segment to be copied
* @throws IllegalArgumentException if {@code elementLayout.byteSize() != sourceElementLayout.byteSize()}
* @throws IllegalArgumentException if the source segment/offset
* are <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
* in the source element layout.
* in the source element layout
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
* @throws IllegalArgumentException if {@code sourceElementLayout.byteAlignment() > sourceElementLayout.byteSize()}
* @throws IllegalStateException if the {@linkplain MemorySegment#scope() scope} associated with {@code source} is not
* {@linkplain MemorySegment.Scope#isAlive() alive}
* @throws IllegalStateException if the {@linkplain MemorySegment#scope() scope} associated
* with {@code source} is not {@linkplain MemorySegment.Scope#isAlive() alive}
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code source.isAccessibleBy(T) == false}
* @throws IndexOutOfBoundsException if {@code elementCount * sourceElementLayout.byteSize()} overflows
@ -386,20 +409,25 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment initialized with the elements in the provided byte array.}
* {@return a new memory segment initialized with the elements in the provided
* byte array}
* <p>
* The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}.
* The contents of the source array is copied into the result segment element by element, according to the byte
* order and alignment constraint of the given element layout.
* The size of the allocated memory segment is
* {@code elementLayout.byteSize() * elements.length}. The contents of the
* source array is copied into the result segment element by element, according
* to the byte order and alignment constraint of the given element layout.
*
* @implSpec The default implementation for this method is equivalent to the following code:
* @implSpec The default implementation for this method is equivalent to the
* following code:
* {@snippet lang = java:
* this.allocateFrom(layout, MemorySegment.ofArray(array),
* ValueLayout.JAVA_BYTE, 0, array.length)
*}
* @param elementLayout the element layout of the array to be allocated.
* @param elements the byte elements to be copied to the newly allocated memory block.
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
* @param elementLayout the element layout of the array to be allocated
* @param elements the byte elements to be copied to the newly allocated
* memory block
* @throws IllegalArgumentException if
* {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
*/
@ForceInline
default MemorySegment allocateFrom(ValueLayout.OfByte elementLayout, byte... elements) {
@ -408,20 +436,25 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment initialized with the elements in the provided short array.}
* {@return a new memory segment initialized with the elements in the provided
* short array}
* <p>
* The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}.
* The contents of the source array are copied into the result segment element by element, according to the byte
* order and alignment constraint of the given element layout.
* The size of the allocated memory segment is
* {@code elementLayout.byteSize() * elements.length}. The contents of the
* source array are copied into the result segment element by element, according
* to the byte order and alignment constraint of the given element layout.
*
* @implSpec The default implementation for this method is equivalent to the following code:
* @implSpec The default implementation for this method is equivalent to the
* following code:
* {@snippet lang = java:
* this.allocateFrom(layout, MemorySegment.ofArray(array),
* ValueLayout.JAVA_SHORT, 0, array.length)
*}
* @param elementLayout the element layout of the array to be allocated.
* @param elements the short elements to be copied to the newly allocated memory block.
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
* @param elementLayout the element layout of the array to be allocated
* @param elements the short elements to be copied to the newly allocated
* memory block
* @throws IllegalArgumentException if
* {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
*/
@ForceInline
default MemorySegment allocateFrom(ValueLayout.OfShort elementLayout, short... elements) {
@ -430,20 +463,25 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment initialized with the elements in the provided char array.}
* {@return a new memory segment initialized with the elements in the provided
* char array}
* <p>
* The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}.
* The contents of the source array is copied into the result segment element by element, according to the byte
* order and alignment constraint of the given element layout.
* The size of the allocated memory segment is
* {@code elementLayout.byteSize() * elements.length}. The contents of the
* source array is copied into the result segment element by element, according
* to the byte order and alignment constraint of the given element layout.
*
* @implSpec The default implementation for this method is equivalent to the following code:
* @implSpec The default implementation for this method is equivalent to the
* following code:
* {@snippet lang = java:
* this.allocateFrom(layout, MemorySegment.ofArray(array),
* ValueLayout.JAVA_CHAR, 0, array.length)
*}
* @param elementLayout the element layout of the array to be allocated.
* @param elements the char elements to be copied to the newly allocated memory block.
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
* @param elementLayout the element layout of the array to be allocated
* @param elements the char elements to be copied to the newly allocated
* memory block
* @throws IllegalArgumentException if
* {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
*/
@ForceInline
default MemorySegment allocateFrom(ValueLayout.OfChar elementLayout, char... elements) {
@ -452,20 +490,25 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment initialized with the elements in the provided int array.}
* {@return a new memory segment initialized with the elements in the provided
* int array}
* <p>
* The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}.
* The contents of the source array is copied into the result segment element by element, according to the byte
* order and alignment constraint of the given element layout.
* The size of the allocated memory segment is
* {@code elementLayout.byteSize() * elements.length}. The contents of the
* source array is copied into the result segment element by element, according
* to the byte order and alignment constraint of the given element layout.
*
* @implSpec The default implementation for this method is equivalent to the following code:
* @implSpec The default implementation for this method is equivalent to the
* following code:
* {@snippet lang = java:
* this.allocateFrom(layout, MemorySegment.ofArray(array),
* ValueLayout.JAVA_INT, 0, array.length)
*}
* @param elementLayout the element layout of the array to be allocated.
* @param elements the int elements to be copied to the newly allocated memory block.
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
* @param elementLayout the element layout of the array to be allocated
* @param elements the int elements to be copied to the newly allocated
* memory block
* @throws IllegalArgumentException if
* {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
*/
@ForceInline
default MemorySegment allocateFrom(ValueLayout.OfInt elementLayout, int... elements) {
@ -474,20 +517,25 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment initialized with the elements in the provided float array.}
* {@return a new memory segment initialized with the elements in the provided
* float array}
* <p>
* The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}.
* The contents of the source array is copied into the result segment element by element, according to the byte
* order and alignment constraint of the given element layout.
* The size of the allocated memory segment is
* {@code elementLayout.byteSize() * elements.length}. The contents of
* the source array is copied into the result segment element by element, according
* to the byte order and alignment constraint of the given element layout.
*
* @implSpec The default implementation for this method is equivalent to the following code:
* @implSpec The default implementation for this method is equivalent to the
* following code:
* {@snippet lang = java:
* this.allocateFrom(layout, MemorySegment.ofArray(array),
* ValueLayout.JAVA_FLOAT, 0, array.length)
*}
* @param elementLayout the element layout of the array to be allocated.
* @param elements the float elements to be copied to the newly allocated memory block.
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
* @param elementLayout the element layout of the array to be allocated
* @param elements the float elements to be copied to the newly allocated
* memory block
* @throws IllegalArgumentException if
* {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
*/
@ForceInline
default MemorySegment allocateFrom(ValueLayout.OfFloat elementLayout, float... elements) {
@ -496,20 +544,25 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment initialized with the elements in the provided long array.}
* {@return a new memory segment initialized with the elements in the provided
* long array}
* <p>
* The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}.
* The contents of the source array is copied into the result segment element by element, according to the byte
* order and alignment constraint of the given element layout.
* The size of the allocated memory segment is
* {@code elementLayout.byteSize() * elements.length}. The contents of
* the source array is copied into the result segment element by element, according
* to the byte order and alignment constraint of the given element layout.
*
* @implSpec The default implementation for this method is equivalent to the following code:
* @implSpec The default implementation for this method is equivalent to the
* following code:
* {@snippet lang = java:
* this.allocateFrom(layout, MemorySegment.ofArray(array),
* ValueLayout.JAVA_LONG, 0, array.length)
*}
* @param elementLayout the element layout of the array to be allocated.
* @param elements the long elements to be copied to the newly allocated memory block.
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
* @param elementLayout the element layout of the array to be allocated
* @param elements the long elements to be copied to the newly allocated
* memory block
* @throws IllegalArgumentException if
* {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
*/
@ForceInline
default MemorySegment allocateFrom(ValueLayout.OfLong elementLayout, long... elements) {
@ -518,20 +571,25 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment initialized with the elements in the provided double array.}
* {@return a new memory segment initialized with the elements in the provided
* double array}
* <p>
* The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}.
* The contents of the source array is copied into the result segment element by element, according to the byte
* order and alignment constraint of the given element layout.
* The size of the allocated memory segment is
* {@code elementLayout.byteSize() * elements.length}. The contents of
* the source array is copied into the result segment element by element, according
* to the byte order and alignment constraint of the given element layout.
*
* @implSpec The default implementation for this method is equivalent to the following code:
* @implSpec The default implementation for this method is equivalent to the
* following code:
* {@snippet lang = java:
* this.allocateFrom(layout, MemorySegment.ofArray(array),
* ValueLayout.JAVA_DOUBLE, 0, array.length)
*}
* @param elementLayout the element layout of the array to be allocated.
* @param elements the double elements to be copied to the newly allocated memory block.
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
* @param elementLayout the element layout of the array to be allocated
* @param elements the double elements to be copied to the newly allocated
* memory block
* @throws IllegalArgumentException if
* {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
*/
@ForceInline
default MemorySegment allocateFrom(ValueLayout.OfDouble elementLayout, double... elements) {
@ -543,9 +601,9 @@ public interface SegmentAllocator {
* {@return a new memory segment with the given layout}
*
* @implSpec The default implementation for this method calls
* {@code this.allocate(layout.byteSize(), layout.byteAlignment())}.
* {@code this.allocate(layout.byteSize(), layout.byteAlignment())}.
*
* @param layout the layout of the block of memory to be allocated.
* @param layout the layout of the block of memory to be allocated
*/
default MemorySegment allocate(MemoryLayout layout) {
Objects.requireNonNull(layout);
@ -556,11 +614,12 @@ public interface SegmentAllocator {
* {@return a new memory segment with the given {@code elementLayout} and {@code count}}
*
* @implSpec The default implementation for this method calls
* {@code this.allocate(MemoryLayout.sequenceLayout(count, elementLayout))}.
* {@code this.allocate(MemoryLayout.sequenceLayout(count, elementLayout))}.
*
* @param elementLayout the array element layout.
* @param count the array element count.
* @throws IllegalArgumentException if {@code elementLayout.byteSize() * count} overflows
* @param elementLayout the array element layout
* @param count the array element count
* @throws IllegalArgumentException if {@code elementLayout.byteSize() * count}
* overflows
* @throws IllegalArgumentException if {@code count < 0}
*/
default MemorySegment allocate(MemoryLayout elementLayout, long count) {
@ -575,9 +634,9 @@ public interface SegmentAllocator {
* {@return a new memory segment with the given {@code byteSize}}
*
* @implSpec The default implementation for this method calls
* {@code this.allocate(byteSize, 1)}.
* {@code this.allocate(byteSize, 1)}.
*
* @param byteSize the size (in bytes) of the block of memory to be allocated.
* @param byteSize the size (in bytes) of the block of memory to be allocated
* @throws IllegalArgumentException if {@code byteSize < 0}
*/
default MemorySegment allocate(long byteSize) {
@ -585,26 +644,31 @@ public interface SegmentAllocator {
}
/**
* {@return a new memory segment with the given {@code byteSize} and {@code byteAlignment}}
* {@return a new memory segment with the given {@code byteSize} and
* {@code byteAlignment}}
*
* @param byteSize the size (in bytes) of the block of memory to be allocated.
* @param byteAlignment the alignment (in bytes) of the block of memory to be allocated.
* @throws IllegalArgumentException if {@code byteSize < 0}, {@code byteAlignment <= 0},
* @param byteSize the size (in bytes) of the block of memory
* to be allocated
* @param byteAlignment the alignment (in bytes) of the block of memory
* to be allocated
* @throws IllegalArgumentException if {@code byteSize < 0},
* {@code byteAlignment <= 0},
* or if {@code byteAlignment} is not a power of 2
*/
MemorySegment allocate(long byteSize, long byteAlignment);
/**
* Returns a segment allocator that responds to allocation requests by returning consecutive slices
* obtained from the provided segment. Each new allocation request will return a new slice starting at the
* current offset (modulo additional padding to satisfy alignment constraint), with given size.
* Returns a segment allocator that responds to allocation requests by returning
* consecutive slices obtained from the provided segment. Each new allocation
* request will return a new slice starting at the current offset (modulo additional
* padding to satisfy alignment constraint), with given size.
* <p>
* The returned allocator throws {@link IndexOutOfBoundsException} when a slice of the provided
* segment with the requested size and alignment cannot be found.
* The returned allocator throws {@link IndexOutOfBoundsException} when a slice of
* the provided segment with the requested size and alignment cannot be found.
*
* @implNote A slicing allocator is not <em>thread-safe</em>.
*
* @param segment the segment from which the returned allocator should slice from.
* @param segment the segment from which the returned allocator should slice from
* @return a new slicing allocator
*/
static SegmentAllocator slicingAllocator(MemorySegment segment) {
@ -613,25 +677,29 @@ public interface SegmentAllocator {
}
/**
* Returns a segment allocator that responds to allocation requests by recycling a single segment. Each
* new allocation request will return a new slice starting at the segment offset {@code 0}, hence the name
* <em>prefix allocator</em>.
* Returns a segment allocator that responds to allocation requests by recycling a
* single segment. Each new allocation request will return a new slice starting at
* the segment offset {@code 0}, hence the name <em>prefix allocator</em>.
* <p>
* Equivalent to (but likely more efficient than) the following code:
* {@snippet lang=java :
* MemorySegment segment = ...
* SegmentAllocator prefixAllocator = (size, align) -> segment.asSlice(0, size, align);
* }
* The returned allocator throws {@link IndexOutOfBoundsException} when a slice of the provided
* segment with the requested size and alignment cannot be found.
* The returned allocator throws {@link IndexOutOfBoundsException} when a slice of
* the provided segment with the requested size and alignment cannot be found.
*
* @apiNote A prefix allocator can be useful to limit allocation requests in case a client
* knows that they have fully processed the contents of the allocated segment before the subsequent allocation request
* takes place.
* @implNote While a prefix allocator is <em>thread-safe</em>, concurrent access on the same recycling
* allocator might cause a thread to overwrite contents written to the underlying segment by a different thread.
* @apiNote A prefix allocator can be useful to limit allocation requests in case a
* client knows that they have fully processed the contents of the allocated
* segment before the subsequent allocation request takes place.
*
* @param segment the memory segment to be recycled by the returned allocator.
* @return an allocator that recycles an existing segment upon each new allocation request.
* @implNote While a prefix allocator is <em>thread-safe</em>, concurrent access on
* the same recycling allocator might cause a thread to overwrite contents
* written to the underlying segment by a different thread.
*
* @param segment the memory segment to be recycled by the returned allocator
* @return an allocator that recycles an existing segment upon each new
* allocation request
*/
static SegmentAllocator prefixAllocator(MemorySegment segment) {
return (AbstractMemorySegmentImpl)Objects.requireNonNull(segment);

View File

@ -28,10 +28,11 @@ package java.lang.foreign;
import jdk.internal.foreign.layout.SequenceLayoutImpl;
/**
* A compound layout that denotes a homogeneous repetition of a given <em>element layout</em>.
* The repetition count is said to be the sequence layout's <em>element count</em>. A sequence layout can be thought of as a
* struct layout where the sequence layout's element layout is repeated a number of times that is equal to the sequence
* layout's element count. In other words this layout:
* A compound layout that denotes a homogeneous repetition of a given
* <em>element layout</em>. The repetition count is said to be the sequence layout's
* <em>element count</em>. A sequence layout can be thought of as a struct layout where
* the sequence layout's element layout is repeated a number of times that is equal to
* the sequence layout's element count. In other words this layout:
*
* {@snippet lang=java :
* MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN));
@ -47,7 +48,8 @@ import jdk.internal.foreign.layout.SequenceLayoutImpl;
* }
*
* @implSpec
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
* This class is immutable, thread-safe and
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @since 22
*/
@ -65,18 +67,21 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
long elementCount();
/**
* {@return a sequence layout with the same characteristics of this layout, but with the given element count}
* @param elementCount the new element count.
* {@return a sequence layout with the same characteristics of this layout, but with
* the given element count}
* @param elementCount the new element count
* @throws IllegalArgumentException if {@code elementCount} is negative
* @throws IllegalArgumentException if {@code elementLayout.bitSize() * elementCount} overflows
* @throws IllegalArgumentException if {@code elementLayout.bitSize() * elementCount}
* overflows
*/
SequenceLayout withElementCount(long elementCount);
/**
* Rearranges the elements in this sequence layout into a multi-dimensional sequence layout.
* The resulting layout is a sequence layout where element layouts in the {@linkplain #flatten() flattened projection}
* of this sequence layout are rearranged into one or more nested sequence layouts
* according to the provided element counts. This transformation preserves the layout size;
* Rearranges the elements in this sequence layout into a multidimensional sequence
* layout. The resulting layout is a sequence layout where element layouts in the
* {@linkplain #flatten() flattened projection} of this sequence layout are
* rearranged into one or more nested sequence layouts according to the provided
* element counts. This transformation preserves the layout size;
* that is, multiplying the provided element counts must yield the same element count
* as the flattened projection of this sequence layout.
* <p>
@ -89,27 +94,32 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
* var reshapeSeq = MemoryLayout.sequenceLayout(2, MemoryLayout.sequenceLayout(6, ValueLayout.JAVA_INT));
* }
* <p>
* If one of the provided element counts is the special value {@code -1}, then the element
* count in that position will be inferred from the remaining element counts and the
* element count of the flattened projection of this layout. For instance, a layout equivalent to
* the above {@code reshapeSeq} can also be computed in the following ways:
* If one of the provided element counts is the special value {@code -1}, then
* the element count in that position will be inferred from the remaining element
* counts and the element count of the flattened projection of this layout.
* For instance, a layout equivalent to the above {@code reshapeSeq} can also be
* computed in the following ways:
* {@snippet lang=java :
* var reshapeSeqImplicit1 = seq.reshape(-1, 6);
* var reshapeSeqImplicit2 = seq.reshape(2, -1);
* }
* @param elementCounts an array of element counts, of which at most one can be {@code -1}.
* @return a sequence layout where element layouts in the {@linkplain #flatten() flattened projection} of this
* sequence layout (see {@link #flatten()}) are re-arranged into one or more nested sequence layouts.
* @throws IllegalArgumentException if two or more element counts are set to {@code -1}, or if one
* or more element count is {@code <= 0} (but other than {@code -1}) or, if, after any required inference,
* multiplying the element counts does not yield the same element count as the flattened projection of this
* @param elementCounts an array of element counts, of which at most one can be {@code -1}
* @return a sequence layout where element layouts in the
* {@linkplain #flatten() flattened projection} of this sequence layout
* (see {@link #flatten()}) are re-arranged into one or more nested
* sequence layouts
* @throws IllegalArgumentException if two or more element counts are set to {@code -1},
* or if one or more element count is {@code <= 0} (but other than {@code -1}) or,
* if, after any required inference, multiplying the element counts does not
* yield the same element count as the flattened projection of this
* sequence layout
*/
SequenceLayout reshape(long... elementCounts);
/**
* Returns a flattened sequence layout. The element layout of the returned sequence layout
* is the first non-sequence layout found by inspecting (recursively, if needed) the element layout of this sequence layout:
* Returns a flattened sequence layout. The element layout of the returned
* sequence layout is the first non-sequence layout found by inspecting
* (recursively, if needed) the element layout of this sequence layout:
* {@snippet lang=java :
* MemoryLayout flatElementLayout(SequenceLayout sequenceLayout) {
* return switch (sequenceLayout.elementLayout()) {
@ -119,9 +129,10 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
* }
* }
* <p>
* This transformation preserves the layout size; nested sequence layout in this sequence layout will
* be dropped and their element counts will be incorporated into that of the returned sequence layout.
* For instance, given a sequence layout of the kind:
* This transformation preserves the layout size; nested sequence layout in this
* sequence layout will be dropped and their element counts will be incorporated
* into that of the returned sequence layout. For instance, given a
* sequence layout of the kind:
* {@snippet lang=java :
* var seq = MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT));
* }
@ -129,8 +140,9 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
* {@snippet lang=java :
* var flattenedSeq = MemoryLayout.sequenceLayout(12, ValueLayout.JAVA_INT);
* }
* @return a sequence layout with the same size as this layout (but, possibly, with different
* element count), whose element layout is not a sequence layout.
* @return a sequence layout with the same size as this layout
* (but, possibly, with different element count), whose
* element layout is not a sequence layout
*/
SequenceLayout flatten();
@ -149,7 +161,8 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
/**
* {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
* @throws IllegalArgumentException if {@code byteAlignment < elementLayout().byteAlignment()}
* @throws IllegalArgumentException if
* {@code byteAlignment < elementLayout().byteAlignment()}
*/
SequenceLayout withByteAlignment(long byteAlignment);
}

View File

@ -31,7 +31,8 @@ import jdk.internal.foreign.layout.StructLayoutImpl;
* A group layout whose member layouts are laid out one after the other.
*
* @implSpec
* Implementing classes are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
* Implementing classes are immutable, thread-safe and
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @since 22
*/

View File

@ -46,26 +46,34 @@ import java.util.function.BiFunction;
* A <em>symbol lookup</em> retrieves the address of a symbol in one or more libraries.
* A symbol is a named entity, such as a function or a global variable.
* <p>
* A symbol lookup is created with respect to a particular library (or libraries). Subsequently, the {@link SymbolLookup#find(String)}
* method takes the name of a symbol and returns the address of the symbol in that library.
* A symbol lookup is created with respect to a particular library (or libraries).
* Subsequently, the {@link SymbolLookup#find(String)} method takes the name of a symbol
* and returns the address of the symbol in that library.
* <p>
* The address of a symbol is modeled as a zero-length {@linkplain MemorySegment memory segment}. The segment can be used in different ways:
* The address of a symbol is modeled as a zero-length
* {@linkplain MemorySegment memory segment}. The segment can be used in different ways:
* <ul>
* <li>It can be passed to a {@link Linker} to create a downcall method handle, which can then be used to call the foreign function at the segment's address.</li>
* <li>It can be passed to an existing {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle}, as an argument to the underlying foreign function.</li>
* <li>It can be {@linkplain MemorySegment#set(AddressLayout, long, MemorySegment) stored} inside another memory segment.</li>
* <li>It can be used to access the region of memory backing a global variable (this requires
* {@linkplain MemorySegment#reinterpret(long) resizing} the segment first).</li>
* <li>It can be passed to a {@link Linker} to create a downcall method handle, which
* can then be used to call the foreign function at the segment's address.</li>
* <li>It can be passed to an existing
* {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle},
* as an argument to the underlying foreign function.</li>
* <li>It can be {@linkplain MemorySegment#set(AddressLayout, long, MemorySegment) stored}
* inside another memory segment.</li>
* <li>It can be used to access the region of memory backing a global variable
* (this requires {@linkplain MemorySegment#reinterpret(long) resizing}
* the segment first).</li>
* </ul>
*
* <h2 id="obtaining">Obtaining a symbol lookup</h2>
*
* The factory methods {@link #libraryLookup(String, Arena)} and {@link #libraryLookup(Path, Arena)}
* create a symbol lookup for a library known to the operating system. The library is specified by either its name or a path.
* The library is loaded if not already loaded. The symbol lookup, which is known as a <em>library lookup</em>, and its
* lifetime is controlled by an {@linkplain Arena arena}. For instance, if the provided arena is a
* confined arena, the library associated with the symbol lookup is unloaded when the confined arena
* is {@linkplain Arena#close() closed}:
* The factory methods {@link #libraryLookup(String, Arena)} and
* {@link #libraryLookup(Path, Arena)} create a symbol lookup for a library known to
* the operating system. The library is specified by either its name or a path.
* The library is loaded if not already loaded. The symbol lookup, which is known as a
* <em>library lookup</em>, and its lifetime is controlled by an {@linkplain Arena arena}.
* For instance, if the provided arena is a confined arena, the library associated with
* the symbol lookup is unloaded when the confined arena is {@linkplain Arena#close() closed}:
*
* {@snippet lang = java:
* try (Arena arena = Arena.ofConfined()) {
@ -76,8 +84,9 @@ import java.util.function.BiFunction;
*}
* <p>
* If a library was previously loaded through JNI, i.e., by {@link System#load(String)}
* or {@link System#loadLibrary(String)}, then the library was also associated with a particular class loader. The factory
* method {@link #loaderLookup()} creates a symbol lookup for all the libraries associated with the caller's class loader:
* or {@link System#loadLibrary(String)}, then the library was also associated with
* a particular class loader. The factory method {@link #loaderLookup()} creates
* a symbol lookup for all the libraries associated with the caller's class loader:
*
* {@snippet lang=java :
* System.loadLibrary("GL"); // libGL.so loaded here
@ -86,21 +95,24 @@ import java.util.function.BiFunction;
* MemorySegment glGetString = libGL.find("glGetString").orElseThrow();
* }
*
* This symbol lookup, which is known as a <em>loader lookup</em>, is dynamic with respect to the libraries associated
* with the class loader. If other libraries are subsequently loaded through JNI and associated with the class loader,
* then the loader lookup will expose their symbols automatically.
* This symbol lookup, which is known as a <em>loader lookup</em>, is dynamic with
* respect to the libraries associated with the class loader. If other libraries are
* subsequently loaded through JNI and associated with the class loader, then the loader
* lookup will expose their symbols automatically.
* <p>
* Note that a loader lookup only exposes symbols in libraries that were previously loaded through JNI, i.e.,
* by {@link System#load(String)} or {@link System#loadLibrary(String)}. A loader lookup does not expose symbols in libraries
* that were loaded in the course of creating a library lookup:
* Note that a loader lookup only exposes symbols in libraries that were previously
* loaded through JNI, i.e., by {@link System#load(String)} or {@link System#loadLibrary(String)}.
* A loader lookup does not expose symbols in libraries that were loaded in the course
* of creating a library lookup:
*
* {@snippet lang = java:
* libraryLookup("libGL.so", arena).find("glGetString").isPresent(); // true
* loaderLookup().find("glGetString").isPresent(); // false
*}
*
* Note also that a library lookup for library {@code L} exposes symbols in {@code L} even if {@code L} was previously loaded
* through JNI (the association with a class loader is immaterial to the library lookup):
* Note also that a library lookup for library {@code L} exposes symbols in {@code L}
* even if {@code L} was previously loaded through JNI (the association with
* a class loader is immaterial to the library lookup):
*
* {@snippet lang = java:
* System.loadLibrary("GL"); // libGL.so loaded here
@ -108,10 +120,11 @@ import java.util.function.BiFunction;
*}
*
* <p>
* Finally, each {@link Linker} provides a symbol lookup for libraries that are commonly used on the OS and processor
* combination supported by that {@link Linker}. This symbol lookup, which is known as a <em>default lookup</em>,
* helps clients to quickly find addresses of well-known symbols. For example, a {@link Linker} for Linux/x64 might choose to
* expose symbols in {@code libc} through the default lookup:
* Finally, each {@link Linker} provides a symbol lookup for libraries that are commonly
* used on the OS and processor combination supported by that {@link Linker}. This
* symbol lookup, which is known as a <em>default lookup</em>, helps clients to quickly
* find addresses of well-known symbols. For example, a {@link Linker} for Linux/x64
* might choose to expose symbols in {@code libc} through the default lookup:
*
* {@snippet lang = java:
* Linker nativeLinker = Linker.nativeLinker();
@ -126,27 +139,33 @@ public interface SymbolLookup {
/**
* Returns the address of the symbol with the given name.
* @param name the symbol name.
* @return a zero-length memory segment whose address indicates the address of the symbol, if found.
*
* @param name the symbol name
* @return a zero-length memory segment whose address indicates the address of
* the symbol, if found
*/
Optional<MemorySegment> find(String name);
/**
* {@return a composed symbol lookup that returns the result of finding the symbol with this lookup if found,
* otherwise returns the result of finding the symbol with the other lookup}
* {@return a composed symbol lookup that returns the result of finding the symbol
* with this lookup if found, otherwise returns the result of finding
* the symbol with the other lookup}
*
* @apiNote This method could be used to chain multiple symbol lookups together, e.g. so that symbols could
* be retrieved, in order, from multiple libraries:
* @apiNote This method could be used to chain multiple symbol lookups together,
* e.g. so that symbols could be retrieved, in order, from multiple
* libraries:
* {@snippet lang = java:
* var lookup = SymbolLookup.libraryLookup("foo", arena)
* .or(SymbolLookup.libraryLookup("bar", arena))
* .or(SymbolLookup.loaderLookup());
*}
* The above code creates a symbol lookup that first searches for symbols in the "foo" library. If no symbol is found
* in "foo" then "bar" is searched. Finally, if a symbol is neither found in "foo" nor in "bar", the {@linkplain
* SymbolLookup#loaderLookup() loader lookup} is used.
* The above code creates a symbol lookup that first searches for symbols in
* the "foo" library. If no symbol is found in "foo" then "bar" is searched.
* Finally, if a symbol is neither found in "foo" nor in "bar", the
* {@linkplain SymbolLookup#loaderLookup() loader lookup} is used.
*
* @param other the symbol lookup that should be used to look for symbols not found in this lookup.
* @param other the symbol lookup that should be used to look for symbols not found
* in this lookup
*/
default SymbolLookup or(SymbolLookup other) {
Objects.requireNonNull(other);
@ -154,27 +173,33 @@ public interface SymbolLookup {
}
/**
* Returns a symbol lookup for symbols in the libraries associated with the caller's class loader.
* Returns a symbol lookup for symbols in the libraries associated with the caller's
* class loader.
* <p>
* A library is associated with a class loader {@code CL} when the library is loaded via an invocation of
* {@link System#load(String)} or {@link System#loadLibrary(String)} from code in a class defined by {@code CL}.
* If that code makes further invocations of {@link System#load(String)} or {@link System#loadLibrary(String)},
* then more libraries are loaded and associated with {@code CL}. The symbol lookup returned by this method is always
* current: it reflects all the libraries associated with the relevant class loader, even if they were loaded after
* this method returned.
* A library is associated with a class loader {@code CL} when the library is loaded
* via an invocation of {@link System#load(String)} or
* {@link System#loadLibrary(String)} from code in a class defined by {@code CL}.
* If that code makes further invocations of {@link System#load(String)} or
* {@link System#loadLibrary(String)} then more libraries are loaded and associated
* with {@code CL}. The symbol lookup returned by this method is always current: it
* reflects all the libraries associated with the relevant class loader, even if they
* were loaded after this method returned.
* <p>
* Libraries associated with a class loader are unloaded when the class loader becomes
* <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>. The symbol lookup
* returned by this method is associated with an automatic {@linkplain MemorySegment.Scope scope} which keeps the caller's
* class loader reachable. Therefore, libraries associated with the caller's class loader are kept loaded
* (and their symbols available) as long as a loader lookup for that class loader, or any of the segments
* obtained by it, is reachable.
* <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>. The
* symbol lookup returned by this method is associated with an automatic
* {@linkplain MemorySegment.Scope scope} which keeps the caller's class loader
* reachable. Therefore, libraries associated with the caller's class loader are
* kept loaded (and their symbols available) as long as a loader lookup for that
* class loader, or any of the segments obtained by it, is reachable.
* <p>
* In cases where this method is called from a context where there is no caller frame on the stack
* (e.g. when called directly from a JNI attached thread), the caller's class loader defaults to the
* In cases where this method is called from a context where there is no caller
* frame on the stack (e.g. when called directly from a JNI attached thread), the
* caller's class loader defaults to the
* {@linkplain ClassLoader#getSystemClassLoader system class loader}.
*
* @return a symbol lookup for symbols in the libraries associated with the caller's class loader.
* @return a symbol lookup for symbols in the libraries associated with
* the caller's class loader
* @see System#load(String)
* @see System#loadLibrary(String)
*/
@ -206,24 +231,28 @@ public interface SymbolLookup {
}
/**
* Loads a library with the given name (if not already loaded) and creates a symbol lookup for symbols in that library.
* The lifetime of the returned library lookup is controlled by the provided arena.
* For instance, if the provided arena is a confined arena, the library
* associated with the returned lookup will be unloaded when the provided confined arena is
* {@linkplain Arena#close() closed}.
* Loads a library with the given name (if not already loaded) and creates a symbol
* lookup for symbols in that library. The lifetime of the returned library lookup
* is controlled by the provided arena. For instance, if the provided arena is a
* confined arena, the library associated with the returned lookup will be unloaded
* when the provided confined arena is {@linkplain Arena#close() closed}.
*
* @implNote The process of resolving a library name is OS-specific. For instance, in a POSIX-compliant OS,
* the library name is resolved according to the specification of the {@code dlopen} function for that OS.
* In Windows, the library name is resolved according to the specification of the {@code LoadLibrary} function.
* @implNote The process of resolving a library name is OS-specific. For instance,
* in a POSIX-compliant OS, the library name is resolved according to the
* specification of the {@code dlopen} function for that OS. In Windows,
* the library name is resolved according to the specification of the
* {@code LoadLibrary} function.
*
* @param name the name of the library in which symbols should be looked up.
* @param arena the arena associated with symbols obtained from the returned lookup.
* @return a new symbol lookup suitable to find symbols in a library with the given name.
* @param name the name of the library in which symbols should be looked up
* @param arena the arena associated with symbols obtained from the returned lookup
* @return a new symbol lookup suitable to find symbols in a library with the
* given name
* @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 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 IllegalArgumentException if {@code name} does not identify a valid library
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled
* @throws IllegalCallerException If the caller is in a module that does not have
* native access enabled
*/
@CallerSensitive
@Restricted
@ -237,22 +266,26 @@ public interface SymbolLookup {
}
/**
* Loads a library from the given path (if not already loaded) and creates a symbol lookup for symbols
* in that library. The lifetime of the returned library lookup is controlled by the provided arena.
* For instance, if the provided arena is a confined arena, the library
* associated with the returned lookup will be unloaded when the provided confined arena is
* {@linkplain Arena#close() closed}.
* Loads a library from the given path (if not already loaded) and creates a symbol
* lookup for symbols in that library. The lifetime of the returned library lookup
* is controlled by the provided arena. For instance, if the provided arena is a
* confined arena, the library associated with the returned lookup will be unloaded
* when the provided confined arena is {@linkplain Arena#close() closed}.
*
* @implNote On Linux, the functionalities provided by this factory method and the returned symbol lookup are
* implemented using the {@code dlopen}, {@code dlsym} and {@code dlclose} functions.
* @param path the path of the library in which symbols should be looked up.
* @param arena the arena associated with symbols obtained from the returned lookup.
* @return a new symbol lookup suitable to find symbols in a library with the given path.
* @implNote On Linux, the functionalities provided by this factory method and the
* returned symbol lookup are implemented using the {@code dlopen},
* {@code dlsym} and {@code dlclose} functions.
*
* @param path the path of the library in which symbols should be looked up
* @param arena the arena associated with symbols obtained from the returned lookup
* @return a new symbol lookup suitable to find symbols in a library with the given
* path
* @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 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 IllegalArgumentException if {@code path} does not point to a valid library
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled
* @throws IllegalCallerException If the caller is in a module that does not have
* native access enabled
*/
@CallerSensitive
@Restricted

View File

@ -31,7 +31,8 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
* A group layout whose member layouts are laid out at the same starting offset.
*
* @implSpec
* Implementing classes are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
* Implementing classes are immutable, thread-safe and
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @since 22
*/

View File

@ -30,22 +30,29 @@ import java.nio.ByteOrder;
import jdk.internal.foreign.layout.ValueLayouts;
/**
* A layout that models values of basic data types. Examples of values modeled by a value layout are
* <em>integral</em> values (either signed or unsigned), <em>floating-point</em> values and
* <em>address</em> values.
* A layout that models values of basic data types. Examples of values modeled by
* a value layout are <em>integral</em> values (either signed or unsigned),
* <em>floating-point</em> values and <em>address</em> values.
* <p>
* Each value layout has a size, an alignment (both expressed in bytes),
* a {@linkplain ByteOrder byte order}, and a <em>carrier</em>, that is, the Java type that should be used when
* {@linkplain MemorySegment#get(OfInt, long) accessing} a region of memory using the value layout.
* a {@linkplain ByteOrder byte order}, and a <em>carrier</em>, that is, the Java type
* that should be used when {@linkplain MemorySegment#get(OfInt, long) accessing} a
* region of memory using the value layout.
* <p>
* This class defines useful value layout constants for Java primitive types and addresses.
* @apiNote Some characteristics of the Java layout constants are platform-dependent. For instance, the byte order of
* these constants is set to the {@linkplain ByteOrder#nativeOrder() native byte order}, thus making it easy to work
* with other APIs, such as arrays and {@link java.nio.ByteBuffer}. Moreover, the alignment constraint of
* {@link ValueLayout#JAVA_LONG} and {@link ValueLayout#JAVA_DOUBLE} are set to 8 bytes on 64-bit platforms, but only to
* 4 bytes on 32-bit platforms.
* This class defines useful value layout constants for Java primitive types and
* addresses.
*
* @implSpec implementing classes and subclasses are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
* @apiNote Some characteristics of the Java layout constants are platform-dependent.
* For instance, the byte order of these constants is set to the
* {@linkplain ByteOrder#nativeOrder() native byte order}, thus making it easy
* to work with other APIs, such as arrays and {@link java.nio.ByteBuffer}.
* Moreover, the alignment constraint of {@link ValueLayout#JAVA_LONG} and
* {@link ValueLayout#JAVA_DOUBLE} is set to 8 bytes on 64-bit platforms,
* but only to 4 bytes on 32-bit platforms.
*
* @implSpec implementing classes and subclasses are immutable, thread-safe and
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @sealedGraph
* @since 22
@ -63,7 +70,7 @@ public sealed interface ValueLayout extends MemoryLayout
/**
* {@return a value layout with the same characteristics as this layout, but with the given byte order}
*
* @param order the desired byte order.
* @param order the desired byte order
*/
ValueLayout withOrder(ByteOrder order);
@ -93,21 +100,26 @@ public sealed interface ValueLayout extends MemoryLayout
ValueLayout withByteAlignment(long byteAlignment);
/**
* {@return a var handle which can be used to access values described by this value layout, in a given memory segment.}
* {@return a var handle which can be used to access values described by this value
* layout, in a given memory segment}
* <p>
* The returned var handle's {@linkplain VarHandle#varType() var type} is the {@linkplain ValueLayout#carrier() carrier type} of
* this value layout, and the list of coordinate types is {@code (MemorySegment, long)}, where the memory segment coordinate
* corresponds to the memory segment to be accessed, and the {@code long} coordinate corresponds to the byte offset
* into the accessed memory segment at which the access occurs.
* The returned var handle's {@linkplain VarHandle#varType() var type} is the
* {@linkplain ValueLayout#carrier() carrier type} of this value layout, and the
* list of coordinate types is {@code (MemorySegment, long)}, where the
* memory segment coordinate corresponds to the memory segment to be accessed, and
* the {@code long} coordinate corresponds to the byte offset into the accessed
* memory segment at which the access occurs.
* <p>
* The returned var handle checks that accesses are aligned according to this value layout's
* {@linkplain MemoryLayout#byteAlignment() alignment constraint}.
* The returned var handle checks that accesses are aligned according to
* this value layout's {@linkplain MemoryLayout#byteAlignment() alignment constraint}.
*
* @apiNote This method is similar, but more efficient than calling {@code MemoryLayout#varHandle(PathElement...)}
* with an empty path element array, as it avoids the creation of the var args array.
* @apiNote This method is similar, but more efficient than calling
* {@code MemoryLayout#varHandle(PathElement...)} with an empty path
* element array, as it avoids the creation of the var args array.
*
* @apiNote The returned var handle features certain <a href="MemoryLayout.html#access-mode-restrictions">access mode
* restrictions</a> common to all memory access var handles derived from memory layouts.
* @apiNote The returned var handle features certain
* <a href="MemoryLayout.html#access-mode-restrictions">access mode restrictions</a>
* common to all memory access var handles derived from memory layouts.
*
* @see MemoryLayout#varHandle(PathElement...)
*/
@ -399,8 +411,9 @@ public sealed interface ValueLayout extends MemoryLayout
}
/**
* An address layout constant whose size is the same as that of a machine address ({@code size_t}),
* byte alignment set to {@code sizeof(size_t)}, byte order set to {@link ByteOrder#nativeOrder()}.
* An address layout constant whose size is the same as that of a
* machine address ({@code size_t}), byte alignment set to {@code sizeof(size_t)},
* byte order set to {@link ByteOrder#nativeOrder()}.
*/
AddressLayout ADDRESS = ValueLayouts.OfAddressImpl.of(ByteOrder.nativeOrder());
@ -455,14 +468,15 @@ public sealed interface ValueLayout extends MemoryLayout
OfDouble JAVA_DOUBLE = ValueLayouts.OfDoubleImpl.of(ByteOrder.nativeOrder());
/**
* An unaligned address layout constant whose size is the same as that of a machine address ({@code size_t}),
* and byte order set to {@link ByteOrder#nativeOrder()}.
* An unaligned address layout constant whose size is the same as that of a
* machine address ({@code size_t}), and byte order set to
* {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* ADDRESS.withByteAlignment(1);
* }
* @apiNote Care should be taken when using unaligned value layouts as they may induce
* performance and portability issues.
* @apiNote Care should be taken when using unaligned value layouts as they may
* induce performance and portability issues.
*/
AddressLayout ADDRESS_UNALIGNED = ADDRESS.withByteAlignment(1);
@ -473,8 +487,8 @@ public sealed interface ValueLayout extends MemoryLayout
* {@snippet lang=java :
* JAVA_CHAR.withByteAlignment(1);
* }
* @apiNote Care should be taken when using unaligned value layouts as they may induce
* performance and portability issues.
* @apiNote Care should be taken when using unaligned value layouts as they may
* induce performance and portability issues.
*/
OfChar JAVA_CHAR_UNALIGNED = JAVA_CHAR.withByteAlignment(1);
@ -485,8 +499,8 @@ public sealed interface ValueLayout extends MemoryLayout
* {@snippet lang=java :
* JAVA_SHORT.withByteAlignment(1);
* }
* @apiNote Care should be taken when using unaligned value layouts as they may induce
* performance and portability issues.
* @apiNote Care should be taken when using unaligned value layouts as they may
* induce performance and portability issues.
*/
OfShort JAVA_SHORT_UNALIGNED = JAVA_SHORT.withByteAlignment(1);
@ -497,8 +511,8 @@ public sealed interface ValueLayout extends MemoryLayout
* {@snippet lang=java :
* JAVA_INT.withByteAlignment(1);
* }
* @apiNote Care should be taken when using unaligned value layouts as they may induce
* performance and portability issues.
* @apiNote Care should be taken when using unaligned value layouts as they may
* induce performance and portability issues.
*/
OfInt JAVA_INT_UNALIGNED = JAVA_INT.withByteAlignment(1);
@ -509,8 +523,8 @@ public sealed interface ValueLayout extends MemoryLayout
* {@snippet lang=java :
* JAVA_LONG.withByteAlignment(1);
* }
* @apiNote Care should be taken when using unaligned value layouts as they may induce
* performance and portability issues.
* @apiNote Care should be taken when using unaligned value layouts as they may
* induce performance and portability issues.
*/
OfLong JAVA_LONG_UNALIGNED = JAVA_LONG.withByteAlignment(1);
@ -521,8 +535,8 @@ public sealed interface ValueLayout extends MemoryLayout
* {@snippet lang=java :
* JAVA_FLOAT.withByteAlignment(1);
* }
* @apiNote Care should be taken when using unaligned value layouts as they may induce
* performance and portability issues.
* @apiNote Care should be taken when using unaligned value layouts as they may
* induce performance and portability issues.
*/
OfFloat JAVA_FLOAT_UNALIGNED = JAVA_FLOAT.withByteAlignment(1);
@ -533,8 +547,8 @@ public sealed interface ValueLayout extends MemoryLayout
* {@snippet lang=java :
* JAVA_DOUBLE.withByteAlignment(1);
* }
* @apiNote Care should be taken when using unaligned value layouts as they may induce
* performance and portability issues.
* @apiNote Care should be taken when using unaligned value layouts as they may
* induce performance and portability issues.
*/
OfDouble JAVA_DOUBLE_UNALIGNED = JAVA_DOUBLE.withByteAlignment(1);

View File

@ -29,18 +29,21 @@
* <h2 id="fma">Foreign memory access</h2>
*
* <p>
* The main abstraction introduced to support foreign memory access is {@link java.lang.foreign.MemorySegment}, which
* models a contiguous region of memory, residing either inside or outside the Java heap. Memory segments are
* typically allocated using an {@link java.lang.foreign.Arena}, which controls the lifetime of the regions of memory
* backing the segments it allocates. The contents of a memory segment can be described using a
* {@link java.lang.foreign.MemoryLayout memory layout}, which provides basic operations to query sizes, offsets, and
* alignment constraints. Memory layouts also provide an alternate, more abstract way, to
* The main abstraction introduced to support foreign memory access is
* {@link java.lang.foreign.MemorySegment}, that models a contiguous region of memory,
* residing either inside or outside the Java heap. Memory segments are typically
* allocated using an {@link java.lang.foreign.Arena}, which controls the lifetime of
* the regions of memory backing the segments it allocates. The contents of a
* memory segment can be described using a {@link java.lang.foreign.MemoryLayout memory layout},
* which provides basic operations to query sizes, offsets, and alignment constraints.
* Memory layouts also provide an alternate, more abstract way, to
* <a href=MemorySegment.html#segment-deref>access memory segments</a> using
* {@linkplain java.lang.foreign.MemoryLayout#varHandle(java.lang.foreign.MemoryLayout.PathElement...) var handles},
* which can be computed using <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>.
*
* For example, to allocate an off-heap region of memory big enough to hold 10 values of the primitive type {@code int},
* and fill it with values ranging from {@code 0} to {@code 9}, we can use the following code:
* <p>
* For example, to allocate an off-heap region of memory big enough to hold 10 values of
* the primitive type {@code int}, and fill it with values ranging from {@code 0} to
* {@code 9}, we can use the following code:
*
* {@snippet lang = java:
* try (Arena arena = Arena.ofConfined()) {
@ -51,38 +54,47 @@
* }
* }
*
* This code creates a <em>native</em> memory segment, that is, a memory segment backed by
* off-heap memory; the size of the segment is 40 bytes, enough to store 10 values of the primitive type {@code int}.
* The native segment is allocated using a {@linkplain java.lang.foreign.Arena#ofConfined() confined arena}.
* As such, access to the native segment is restricted to the current thread (the thread that created the arena).
* Moreover, when the arena is closed, the native segment is invalidated, and its backing region of memory is
* deallocated. Note the use of the <em>try-with-resources</em> construct: this idiom ensures that the off-heap region
* of memory backing the native segment will be released at the end of the block, according to the semantics described
* This code creates a <em>native</em> memory segment, that is, a memory segment backed
* by off-heap memory; the size of the segment is 40 bytes, enough to store 10 values of
* the primitive type {@code int}. The native segment is allocated using a
* {@linkplain java.lang.foreign.Arena#ofConfined() confined arena}. As such, access to
* the native segment is restricted to the current thread (the thread that created the
* arena). Moreover, when the arena is closed, the native segment is invalidated, and
* its backing region of memory is deallocated. Note the use of the <em>try-with-resources</em>
* construct: this idiom ensures that the off-heap region of memory backing the native
* segment will be released at the end of the block, according to the semantics described
* in Section {@jls 14.20.3} of <cite>The Java Language Specification</cite>.
* <p>
* Memory segments provide strong safety guarantees when it comes to memory access. First, when accessing a memory segment,
* the access coordinates are validated (upon access), to make sure that access does not occur at any address that resides
* <em>outside</em> the boundaries of the memory segment used by the access operation. We call this guarantee <em>spatial safety</em>;
* in other words, access to memory segments is bounds-checked, in the same way as array access is, as described in
* Memory segments provide strong safety guarantees when it comes to memory access.
* First, when accessing a memory segment, the access coordinates are validated
* (upon access), to make sure that access does not occur at any address that resides
* <em>outside</em> the boundaries of the memory segment used by the access operation.
* We call this guarantee <em>spatial safety</em>; in other words, access to
* memory segments is bounds-checked, in the same way as array access is, as described in
* Section {@jls 15.10.4} of <cite>The Java Language Specification</cite>.
* <p>
* Additionally, to prevent a region of memory from being accessed <em>after</em> it has been deallocated
* (i.e. <em>use-after-free</em>), a segment is also validated (upon access) to make sure that the arena from which it
* has been obtained has not been closed. We call this guarantee <em>temporal safety</em>.
* Additionally, to prevent a region of memory from being accessed <em>after</em> it has
* been deallocated (i.e. <em>use-after-free</em>), a segment is also validated
* (upon access) to make sure that the arena from which it has been obtained has not
* been closed. We call this guarantee <em>temporal safety</em>.
* <p>
* Together, spatial and temporal safety ensure that each memory access operation either succeeds - and accesses a valid
* location within the region of memory backing the memory segment - or fails.
* Together, spatial and temporal safety ensure that each memory access operation either
* succeeds - and accesses a valid location within the region of memory backing the
* memory segment - or fails.
*
* <h2 id="ffa">Foreign function access</h2>
* The key abstractions introduced to support foreign function access are {@link java.lang.foreign.SymbolLookup},
* {@link java.lang.foreign.FunctionDescriptor} and {@link java.lang.foreign.Linker}. The first is used to look up symbols
* inside libraries; the second is used to model the signature of foreign functions, while the third is used
* to link foreign functions as {@link java.lang.invoke.MethodHandle} instances,
* so that clients can perform foreign function calls directly in Java, without the need for intermediate layers of C/C++
* code (as is the case with the <a href="{@docRoot}/../specs/jni/index.html">Java Native Interface (JNI)</a>).
*
* The key abstractions introduced to support foreign function access are
* {@link java.lang.foreign.SymbolLookup}, {@link java.lang.foreign.FunctionDescriptor} and
* {@link java.lang.foreign.Linker}. The first is used to look up symbols inside
* libraries; the second is used to model the signature of foreign functions, while the
* third is used to link foreign functions as {@link java.lang.invoke.MethodHandle}
* instances, so that clients can perform foreign function calls directly in Java,
* without the need for intermediate layers of C/C++ code (as is the case with the
* <a href="{@docRoot}/../specs/jni/index.html">Java Native Interface (JNI)</a>).
* <p>
* For example, to compute the length of a string using the C standard library function {@code strlen} on a Linux/x64 platform,
* we can use the following code:
* For example, to compute the length of a string using the C standard library function
* {@code strlen} on a Linux/x64 platform, we can use the following code:
*
* {@snippet lang = java:
* Linker linker = Linker.nativeLinker();
@ -98,52 +110,65 @@
* }
*}
*
* Here, we obtain a {@linkplain java.lang.foreign.Linker#nativeLinker() native linker} and we use it
* to {@linkplain java.lang.foreign.SymbolLookup#find(java.lang.String) look up} the {@code strlen} function in the
* standard C library; a <em>downcall method handle</em> targeting said function is subsequently
* Here, we obtain a {@linkplain java.lang.foreign.Linker#nativeLinker() native linker}
* and we use it to {@linkplain java.lang.foreign.SymbolLookup#find(java.lang.String) look up}
* the {@code strlen} function in the standard C library; a <em>downcall method handle</em>
* targeting said function is subsequently
* {@linkplain java.lang.foreign.Linker#downcallHandle(FunctionDescriptor, Linker.Option...) obtained}.
* To complete the linking successfully, we must provide a {@link java.lang.foreign.FunctionDescriptor} instance,
* describing the signature of the {@code strlen} function.
* From this information, the linker will uniquely determine the sequence of steps which will turn
* the method handle invocation (here performed using {@link java.lang.invoke.MethodHandle#invokeExact(java.lang.Object...)})
* into a foreign function call, according to the rules specified by the ABI of the underlying platform.
* To complete the linking successfully, we must provide a
* {@link java.lang.foreign.FunctionDescriptor} instance, describing the signature of the
* {@code strlen} function. From this information, the linker will uniquely determine
* the sequence of steps which will turn the method handle invocation (here performed
* using {@link java.lang.invoke.MethodHandle#invokeExact(java.lang.Object...)})
* into a foreign function call, according to the rules specified by the ABI of the
* underlying platform.
* <p>
* The {@link java.lang.foreign.Arena} class also provides many useful methods for
* interacting with foreign code, such as
* {@linkplain java.lang.foreign.SegmentAllocator#allocateFrom(java.lang.String) converting} Java strings into
* zero-terminated, UTF-8 strings, as demonstrated in the above example.
* {@linkplain java.lang.foreign.SegmentAllocator#allocateFrom(java.lang.String) converting}
* Java strings into zero-terminated, UTF-8 strings, as demonstrated in the above example.
*
* <h2 id="restricted">Restricted methods</h2>
* Some methods in this package are considered <em>restricted</em>. Restricted methods are typically used to bind native
* foreign data and/or functions to first-class Java API elements which can then be used directly by clients. For instance
* the restricted method {@link java.lang.foreign.MemorySegment#reinterpret(long)}
* can be used to create a fresh segment with the same address and temporal bounds,
* but with the provided size. This can be useful to resize memory segments obtained when interacting with native functions.
* <p>
* Binding foreign data and/or functions is generally unsafe and, if done incorrectly, can result in VM crashes,
* or memory corruption when the bound Java API element is accessed. For instance, incorrectly resizing a native
* memory segment using {@link java.lang.foreign.MemorySegment#reinterpret(long)} can lead to a JVM crash, or, worse,
* lead to silent memory corruption when attempting to access the resized segment. For these reasons, it is crucial for
* code that calls a restricted method to never pass arguments that might cause incorrect binding of foreign data and/or
* functions to a Java API.
* <p>
* Given the potential danger of restricted methods, the Java runtime issues a warning on the standard error stream
* every time a restricted method is invoked. Such warnings can be disabled by granting access to restricted methods
* to selected modules. This can be done either via implementation-specific command line options or programmatically, e.g. by calling
* {@link java.lang.ModuleLayer.Controller#enableNativeAccess(java.lang.Module)}.
* <p>
* For every class in this package, unless specified otherwise, any method arguments of reference
* type must not be null, and any null argument will elicit a {@code NullPointerException}. This fact is not individually
* documented for methods of this API.
*
* @apiNote Usual memory model guarantees (see {@jls 17.4}) do not apply when accessing native memory segments as
* these segments are backed by off-heap regions of memory.
* Some methods in this package are considered <em>restricted</em>. Restricted methods
* are typically used to bind native foreign data and/or functions to first-class
* Java API elements which can then be used directly by clients. For instance the
* restricted method {@link java.lang.foreign.MemorySegment#reinterpret(long)} can be
* used to create a fresh segment with the same address and temporal bounds, but with
* the provided size. This can be useful to resize memory segments obtained when
* interacting with native functions.
* <p>
* Binding foreign data and/or functions is generally unsafe and, if done incorrectly,
* can result in VM crashes, or memory corruption when the bound Java API element
* is accessed. For instance, incorrectly resizing a native memory segment using
* {@link java.lang.foreign.MemorySegment#reinterpret(long)} can lead to a JVM crash, or,
* worse, lead to silent memory corruption when attempting to access the resized segment.
* For these reasons, it is crucial for code that calls a restricted method to never pass
* arguments that might cause incorrect binding of foreign data and/or functions to
* a Java API.
* <p>
* Given the potential danger of restricted methods, the Java runtime issues a warning on
* the standard error stream every time a restricted method is invoked. Such warnings can
* be disabled by granting access to restricted methods to selected modules. This can be
* done either via implementation-specific command line options or programmatically, e.g.
* by calling {@link java.lang.ModuleLayer.Controller#enableNativeAccess(java.lang.Module)}.
* <p>
* For every class in this package, unless specified otherwise, any method arguments of
* reference type must not be {@code null}, and any null argument will elicit a
* {@code NullPointerException}. This fact is not individually documented for methods of
* this API.
*
* @apiNote Usual memory model guarantees (see {@jls 17.4}) do not apply when accessing
* native memory segments as these segments are backed by off-heap regions of memory.
*
* @implNote
* In the reference implementation, access to restricted methods can be granted to specific modules using the command line option
* {@code --enable-native-access=M1,M2, ... Mn}, where {@code M1}, {@code M2}, {@code ... Mn} are module names
* (for the unnamed module, the special value {@code ALL-UNNAMED} can be used). If this option is specified, access to
* restricted methods are only granted to the modules listed by that option. If this option is not specified,
* access to restricted methods is enabled for all modules, but access to restricted methods will result in runtime warnings.
* In the reference implementation, access to restricted methods can be granted to
* specific modules using the command line option {@code --enable-native-access=M1,M2, ... Mn},
* where {@code M1}, {@code M2}, {@code ... Mn} are module names (for the unnamed module,
* the special value {@code ALL-UNNAMED} can be used). If this option is specified,
* access to restricted methods are only granted to the modules listed by that option.
* If this option is not specified, access to restricted methods is enabled for all
* modules, but access to restricted methods will result in runtime warnings.
*
* @spec jni/index.html Java Native Interface Specification
*

View File

@ -1045,48 +1045,48 @@ public abstract class FileChannel
* The file mapping mode, see
* {@link FileChannel#map(FileChannel.MapMode, long, long)};
* the mapping mode might affect the behavior of the returned
* memory mapped segment (see {@link MemorySegment#force()}).
* memory mapped segment (see {@link MemorySegment#force()})
*
* @param offset
* The offset (expressed in bytes) within the file at which the
* mapped segment is to start.
* mapped segment is to start
*
* @param size
* The size (in bytes) of the mapped memory backing the memory
* segment.
* segment
*
* @param arena
* The segment arena.
* The segment arena
*
* @return A new mapped memory segment.
* @return A new mapped memory segment
*
* @throws IllegalArgumentException
* If {@code offset < 0}, {@code size < 0} or
* {@code offset + size} overflows the range of {@code long}.
* {@code offset + size} overflows the range of {@code long}
*
* @throws IllegalStateException
* If {@code arena.isAlive() == false}.
* If {@code arena.isAlive() == false}
*
* @throws WrongThreadException
* If {@code arena} is a confined scoped arena, and this method is called from a
* thread {@code T}, other than the scoped arena's owner thread.
* If {@code arena} is a confined scoped arena, and this method is called
* from a thread {@code T}, other than the scoped arena's owner thread
*
* @throws NonReadableChannelException
* If the {@code mode} is {@link MapMode#READ_ONLY READ_ONLY} or
* an implementation specific map mode requiring read access,
* but this channel was not opened for reading.
* but this channel was not opened for reading
*
* @throws NonWritableChannelException
* If the {@code mode} is {@link MapMode#READ_WRITE READ_WRITE},
* {@link MapMode#PRIVATE PRIVATE} or an implementation specific
* map mode requiring write access, but this channel was not
* opened for both reading and writing.
* opened for both reading and writing
*
* @throws IOException
* If some other I/O error occurs.
* If some other I/O error occurs
*
* @throws UnsupportedOperationException
* If an unsupported map mode is specified.
* If an unsupported map mode is specified
*
* @since 22
*/