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; 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 * A value layout used to model the address of some region of memory. The carrier
* {@code MemorySegment.class}. The size and alignment of an address layout are platform-dependent * associated with an address layout is {@code MemorySegment.class}. The size and
* (e.g. on a 64-bit platform, the size and alignment of an address layout are set to 8 bytes). * 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> * <p>
* An address layout may optionally feature a {@linkplain #targetLayout() target layout}. An address layout with * An address layout may optionally feature a {@linkplain #targetLayout() target layout}.
* target layout {@code T} can be used to model the address of a region of memory whose layout is {@code T}. * An address layout with target layout {@code T} can be used to model the address of a
* For instance, an address layout with target layout {@link ValueLayout#JAVA_INT} can be used to model the address * region of memory whose layout is {@code T}. For instance, an address layout with
* of a region of memory that is 4 bytes long. Specifying a target layout can be useful in the following situations: * 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> * <ul>
* <li>When accessing a memory segment that has been obtained by reading an address from another * <li>When accessing a memory segment that has been obtained by reading an address from
* memory segment, e.g. using {@link MemorySegment#getAtIndex(AddressLayout, long)};</li> * 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 a downcall method handle, using {@link Linker#downcallHandle(FunctionDescriptor, Option...)};
* <li>When creating an upcall stub, using {@link Linker#upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...)}. * <li>When creating an upcall stub, using {@link Linker#upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...)}.
* </ul> * </ul>
* *
* @implSpec * @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
* @see #ADDRESS_UNALIGNED * @see #ADDRESS_UNALIGNED
@ -84,24 +88,28 @@ public sealed interface AddressLayout extends ValueLayout permits ValueLayouts.O
AddressLayout withOrder(ByteOrder order); AddressLayout withOrder(ByteOrder order);
/** /**
* Returns an address layout with the same carrier, alignment constraint, name and order as this address layout, * Returns an address layout with the same carrier, alignment constraint, name and
* but associated with the specified target layout. The returned address layout allows raw addresses to be accessed * order as this address layout, but associated with the specified target layout.
* as {@linkplain MemorySegment memory segments} whose size is set to the size of the specified layout. Moreover, * The returned address layout allows raw addresses to be accessed as
* if the accessed raw address is not compatible with the alignment constraint in the provided layout, * {@linkplain MemorySegment memory segments} whose size is set to the size of the
* {@linkplain IllegalArgumentException} will be thrown. * 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 * @apiNote
* This method can also be used to create an address layout which, when used, creates native memory * This method can also be used to create an address layout which, when used, creates
* segments with maximal size (e.g. {@linkplain Long#MAX_VALUE}). This can be done by using a target sequence * native memory segments with maximal size (e.g. {@linkplain Long#MAX_VALUE}). This
* layout with unspecified size, as follows: * can be done by using a target sequence layout with unspecified size, as follows:
* {@snippet lang = java: * {@snippet lang = java:
* AddressLayout addressLayout = ... * AddressLayout addressLayout = ...
* AddressLayout unboundedLayout = addressLayout.withTargetLayout( * AddressLayout unboundedLayout = addressLayout.withTargetLayout(
* MemoryLayout.sequenceLayout(Long.MAX_VALUE, ValueLayout.JAVA_BYTE)); * MemoryLayout.sequenceLayout(Long.MAX_VALUE, ValueLayout.JAVA_BYTE));
*} *}
* *
* @param layout the target layout. * @param layout the target layout
* @return an address layout with the same characteristics as this layout, but with the provided target layout. * @return an address layout with same characteristics as this layout, but with the
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled * provided target layout
* @throws IllegalCallerException If the caller is in a module that does not have
* native access enabled
* @see #targetLayout() * @see #targetLayout()
*/ */
@CallerSensitive @CallerSensitive
@ -109,18 +117,20 @@ public sealed interface AddressLayout extends ValueLayout permits ValueLayouts.O
AddressLayout withTargetLayout(MemoryLayout layout); AddressLayout withTargetLayout(MemoryLayout layout);
/** /**
* Returns an address layout with the same carrier, alignment constraint, name and order as this address layout, * Returns an address layout with the same carrier, alignment constraint, name and
* but with no target layout. * 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() * @see #targetLayout()
*/ */
AddressLayout withoutTargetLayout(); 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(); Optional<MemoryLayout> targetLayout();

View file

@ -31,47 +31,53 @@ import jdk.internal.ref.CleanerFactory;
import java.lang.foreign.MemorySegment.Scope; 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> * <p>
* An arena has a {@linkplain MemorySegment.Scope scope} - the <em>arena scope</em>. All the segments allocated * An arena has a {@linkplain MemorySegment.Scope scope} - the <em>arena scope</em>.
* by the arena are associated with the arena scope. As such, the arena determines the temporal bounds * All the segments allocated by the arena are associated with the arena scope. As such,
* of all the memory segments allocated by it. * the arena determines the temporal bounds of all the memory segments allocated by it.
* <p> * <p>
* Moreover, an arena also determines whether access to memory segments allocated by it should be * Moreover, an arena also determines whether access to memory segments allocated by it
* {@linkplain MemorySegment#isAccessibleBy(Thread) restricted} to specific threads. * should be {@linkplain MemorySegment#isAccessibleBy(Thread) restricted} to specific
* An arena is a {@link SegmentAllocator} and features several allocation methods that can be used by clients * threads. An arena is a {@link SegmentAllocator} and features several allocation
* to obtain native segments. * methods that can be used by clients to obtain native segments.
* <p> * <p>
* The simplest arena is the {@linkplain Arena#global() global arena}. The global arena * 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. * features an <em>unbounded lifetime</em>. The scope of the global arena is the global
* As such, native segments allocated with the global arena are always accessible and their backing regions * scope. As such, native segments allocated with the global arena are always accessible
* of memory are never deallocated. * and their backing regions of memory are never deallocated. Moreover, memory segments
* Moreover, memory segments allocated with the global arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread. * allocated with the global arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed}
* from any thread.
* {@snippet lang = java: * {@snippet lang = java:
* MemorySegment segment = Arena.global().allocate(100, 1); // @highlight regex='global()' * MemorySegment segment = Arena.global().allocate(100, 1); // @highlight regex='global()'
* ... * ...
* // segment is never deallocated! * // segment is never deallocated!
*} *}
* <p> * <p>
* Alternatively, clients can obtain an {@linkplain Arena#ofAuto() automatic arena}, that is an arena * Alternatively, clients can obtain an {@linkplain Arena#ofAuto() automatic arena}, that
* which features a <em>bounded lifetime</em> that is managed, automatically, by the garbage collector. The scope * is an arena which features a <em>bounded lifetime</em> that is managed, automatically,
* of an automatic arena is an automatic scope. As such, the regions * by the garbage collector. The scope of an automatic arena is an automatic scope. As
* of memory backing memory segments allocated with the automatic arena are deallocated at some unspecified time * such, the regions of memory backing memory segments allocated with the automatic arena
* <em>after</em> the automatic arena (and all the segments allocated by it) becomes * are deallocated at some unspecified time <em>after</em> the automatic arena (and all
* <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>, as shown below: * the segments allocated by it) becomes <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>,
* as shown below:
* {@snippet lang = java: * {@snippet lang = java:
* MemorySegment segment = Arena.ofAuto().allocate(100, 1); // @highlight regex='ofAuto()' * MemorySegment segment = Arena.ofAuto().allocate(100, 1); // @highlight regex='ofAuto()'
* ... * ...
* segment = null; // the segment region becomes available for deallocation after this point * 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> * <p>
* Rather than leaving deallocation in the hands of the Java runtime, clients will often wish to exercise control over * Rather than leaving deallocation in the hands of the Java runtime, clients will often
* the timing of deallocation for regions of memory that back memory segments. Two kinds of arenas support this, * wish to exercise control over the timing of deallocation for regions of memory that
* namely {@linkplain #ofConfined() confined} and {@linkplain #ofShared() shared} arenas. They both feature * back memory segments. Two kinds of arenas support this, namely {@linkplain #ofConfined() confined}
* bounded lifetimes that are managed manually. For instance, when a confined arena is {@linkplain #close() closed} * and {@linkplain #ofShared() shared} arenas. They both feature bounded lifetimes that
* successfully, its scope is {@linkplain Scope#isAlive() invalidated}. As a result, all the memory segments allocated * are managed manually. For instance, when a confined arena is {@linkplain #close() closed}
* by the arena can no longer be accessed, and their regions of memory are deallocated: * 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: * {@snippet lang = java:
* MemorySegment segment = null; * MemorySegment segment = null;
@ -82,9 +88,10 @@ import java.lang.foreign.MemorySegment.Scope;
* segment.get(ValueLayout.JAVA_BYTE, 0); // throws IllegalStateException * 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 * Memory segments allocated with a {@linkplain #ofConfined() confined arena} can only be
* thread that created the arena. If access to a memory segment from multiple threads is required, clients can allocate * accessed (and closed) by the thread that created the arena. If access to a memory
* segments in a {@linkplain #ofShared() shared arena} instead. * segment from multiple threads is required, clients can allocate segments in a
* {@linkplain #ofShared() shared arena} instead.
* <p> * <p>
* The characteristics of the various arenas are summarized in the following table: * 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> * <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 * Arenas provide strong temporal safety guarantees: a memory segment allocated by an
* <em>after</em> the arena has been closed. The cost of providing this guarantee varies based on the * arena cannot be accessed <em>after</em> the arena has been closed. The cost of
* number of threads that have access to the memory segments allocated by the arena. For instance, if an arena * providing this guarantee varies based on the number of threads that have access to the
* is always created and closed by one thread, and the memory segments allocated by the arena are always * 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. * accessed by that same thread, then ensuring correctness is trivial.
* <p> * <p>
* Conversely, if an arena allocates segments that can be accessed by multiple threads, or if the arena can be closed * Conversely, if an arena allocates segments that can be accessed by multiple threads,
* by a thread other than the accessing thread, then ensuring correctness is much more complex. For example, a segment * or if the arena can be closed by a thread other than the accessing thread, then
* allocated with the arena might be accessed <em>while</em> another thread attempts, concurrently, to close the arena. * ensuring correctness is much more complex. For example, a segment allocated with the
* To provide the strong temporal safety guarantee without forcing every client, even simple ones, to incur a performance * arena might be accessed <em>while</em> another thread attempts, concurrently, to close
* impact, arenas are divided into <em>thread-confined</em> arenas, and <em>shared</em> arenas. * 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> * <p>
* Confined arenas, support strong thread-confinement guarantees. Upon creation, they are assigned an * Confined arenas, support strong thread-confinement guarantees. Upon creation, they are
* <em>owner thread</em>, typically the thread which initiated the creation operation. * assigned an <em>owner thread</em>, typically the thread which initiated the creation
* The segments created by a confined arena can only be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} * operation. The segments created by a confined arena can only be
* by the owner thread. Moreover, any attempt to close the confined arena from a thread other than the owner thread will * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the owner thread.
* fail with {@link WrongThreadException}. * Moreover, any attempt to close the confined arena from a thread other than the owner
* thread will fail with a {@link WrongThreadException}.
* <p> * <p>
* Shared arenas, on the other hand, have no owner thread. The segments created by a shared arena * Shared arenas, on the other hand, have no owner thread. The segments created by a
* can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. This might be useful when * shared arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by
* multiple threads need to access the same memory segment concurrently (e.g. in the case of parallel processing). * any thread. This might be useful when multiple threads need to access the same memory
* Moreover, a shared arena can be closed by any thread. * 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> * <h2 id = "custom-arenas">Custom arenas</h2>
* *
* Clients can define custom arenas to implement more efficient allocation strategies, or to have better control over * Clients can define custom arenas to implement more efficient allocation strategies,
* when (and by whom) an arena can be closed. As an example, the following code defines a <em>slicing arena</em> that behaves * or to have better control over when (and by whom) an arena can be closed. As an
* like a confined arena (i.e., single-threaded access), but internally uses a * example, the following code defines a <em>slicing arena</em> that behaves like a
* {@linkplain SegmentAllocator#slicingAllocator(MemorySegment) slicing allocator} to respond to allocation requests. * confined arena (i.e., single-threaded access), but internally uses a
* When the slicing arena is closed, the underlying confined arena is also closed; this will invalidate all segments * {@linkplain SegmentAllocator#slicingAllocator(MemorySegment) slicing allocator} to
* allocated with the slicing arena (since the scope of the slicing arena is the same as that of the underlying * respond to allocation requests.
* confined arena): * 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: * {@snippet lang = java:
* class SlicingArena implements Arena { * 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 * In other words, a slicing arena provides a vastly more efficient and scalable
* the timely deallocation guarantee provided by the underlying confined arena: * allocation strategy, while still retaining the timely deallocation guarantee provided
* by the underlying confined arena:
* *
* {@snippet lang = java: * {@snippet lang = java:
* try (Arena slicingArena = new SlicingArena(1000)) { * try (Arena slicingArena = new SlicingArena(1000)) {
@ -204,18 +219,17 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
* {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
* Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}. * 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() { static Arena ofAuto() {
return MemorySessionImpl.createImplicit(CleanerFactory.cleaner()).asArena(); return MemorySessionImpl.createImplicit(CleanerFactory.cleaner()).asArena();
} }
/** /**
* Obtains the global arena. Segments allocated with the global arena can be * {@return the global 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.
* Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}. * Calling {@link #close()} on the returned arena will result in
* * an {@link UnsupportedOperationException}.
* @return the global arena.
*/ */
static Arena global() { static Arena global() {
class Holder { 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 * {@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, * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the thread
* the arena's <em>owner thread</em>. * that created the arena, the arena's <em>owner thread</em>.
*/ */
static Arena ofConfined() { static Arena ofConfined() {
return MemorySessionImpl.createConfined(Thread.currentThread()).asArena(); 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 * {@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() { static Arena ofShared() {
return MemorySessionImpl.createShared().asArena(); 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 returned segment is associated with this {@linkplain #scope() arena scope}.
* The segment's {@link MemorySegment#address() address} is the starting address of the * The segment's {@link MemorySegment#address() address} is the starting address of
* allocated off-heap region of memory backing the segment, and the address is * the allocated off-heap region of memory backing the segment, and the address is
* aligned according to the provided alignment constraint. * aligned according the provided alignment constraint.
* *
* @implSpec * @implSpec
* Implementations of this method must return a native segment featuring the requested size, * Implementations of this method must return a native segment featuring the
* and that is compatible with the provided alignment constraint. Furthermore, for any two segments * requested size, and that is compatible with the provided alignment constraint.
* {@code S1, S2} returned by this method, the following invariant must hold: * Furthermore, for any two segments {@code S1, S2} returned by this method, the
* following invariant must hold:
* *
* {@snippet lang = java: * {@snippet lang = java:
* S1.asOverlappingSlice(S2).isEmpty() == true * S1.asOverlappingSlice(S2).isEmpty() == true
* } * }
* *
* @param byteSize the size (in bytes) of the off-heap region of memory backing the native memory segment. * @param byteSize the size (in bytes) of the off-heap region of memory backing
* @param byteAlignment the alignment constraint (in bytes) of the off-heap region of memory backing the native memory segment. * the native memory segment
* @return a new 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}, * @throws IllegalArgumentException if {@code bytesSize < 0}, {@code byteAlignment <= 0},
* or if {@code byteAlignment} is not a power of 2 * or if {@code byteAlignment} is not a power of 2
* @throws IllegalStateException if this arena has already been {@linkplain #close() closed} * @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 * @throws WrongThreadException if this arena is confined, and this method is called
* other than the arena's owner thread * from a thread other than the arena's owner thread
*/ */
@Override @Override
MemorySegment allocate(long byteSize, long byteAlignment); MemorySegment allocate(long byteSize, long byteAlignment);
@ -275,25 +293,29 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
Scope scope(); Scope scope();
/** /**
* Closes this arena. If this method completes normally, the arena scope is no longer {@linkplain Scope#isAlive() alive}, * Closes this arena. If this method completes normally, the arena scope is no longer
* and all the memory segments associated with it can no longer be accessed. Furthermore, any off-heap region of memory backing the * {@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. * 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 * @apiNote This operation is not idempotent; that is, closing an already closed arena
* exception being thrown. This reflects a deliberate design choice: failure to close an arena might reveal a bug * <em>always</em> results in an exception being thrown. This reflects a
* in the underlying application logic. * 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}. * @implSpec If this method completes normally, then
* Implementations are allowed to throw {@link UnsupportedOperationException} if an explicit close operation is * {@code this.scope().isAlive() == false}.
* not supported. * Implementations are allowed to throw {@link UnsupportedOperationException}
* if an explicit close operation is not supported.
* *
* @see Scope#isAlive() * @see Scope#isAlive()
* *
* @throws IllegalStateException if the arena has already been closed * @throws IllegalStateException if the arena has already been closed
* @throws IllegalStateException if a segment associated with this arena is being accessed concurrently, e.g. * @throws IllegalStateException if a segment associated with this arena is being
* by a {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle} * accessed concurrently, e.g. by a
* @throws WrongThreadException if this arena is confined, and this method is called from a thread * {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle}
* 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
* @throws UnsupportedOperationException if this arena cannot be closed explicitly * @throws UnsupportedOperationException if this arena cannot be closed explicitly
*/ */
@Override @Override

View file

@ -34,13 +34,16 @@ import java.util.List;
import jdk.internal.foreign.FunctionDescriptorImpl; 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 * A function descriptor models the signature of a foreign function. A function
* argument layouts, and zero or one return layout. A function descriptor is used to create * descriptor is made up of zero or more argument layouts, and zero or one return layout.
* {@linkplain Linker#downcallHandle(MemorySegment, FunctionDescriptor, Linker.Option...) downcall method handles} and * 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}. * {@linkplain Linker#upcallStub(MethodHandle, FunctionDescriptor, Arena, Linker.Option...) upcall stubs}.
* *
* @implSpec * @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 * @see MemoryLayout
* @since 22 * @since 22
@ -53,35 +56,39 @@ public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
Optional<MemoryLayout> returnLayout(); 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(); List<MemoryLayout> argumentLayouts();
/** /**
* Returns a function descriptor with the given argument layouts appended to the argument layouts * Returns a function descriptor with the given argument layouts appended to the
* of this function descriptor. * 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 * @param addedLayouts the argument layouts to append
* @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
* @return a new function descriptor, with the provided additional argument layouts
*/ */
FunctionDescriptor appendArgumentLayouts(MemoryLayout... addedLayouts); FunctionDescriptor appendArgumentLayouts(MemoryLayout... addedLayouts);
/** /**
* Returns a function descriptor with the given argument layouts inserted at the given index, into the argument * Returns a function descriptor with the given argument layouts inserted at the
* layout array of this function descriptor. * given index, into the argument layout array of this function descriptor.
*
* @param index the index at which to insert the arguments * @param index the index at which to insert the arguments
* @param addedLayouts the argument layouts to insert at the given index. * @param addedLayouts the argument layouts to insert at given index
* @return a new function descriptor, with the provided additional argument layouts. * @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 one of the layouts in {@code addedLayouts}
* is a padding layout
* @throws IllegalArgumentException if {@code index < 0 || index > argumentLayouts().size()} * @throws IllegalArgumentException if {@code index < 0 || index > argumentLayouts().size()}
*/ */
FunctionDescriptor insertArgumentLayouts(int index, MemoryLayout... addedLayouts); FunctionDescriptor insertArgumentLayouts(int index, MemoryLayout... addedLayouts);
/** /**
* Returns a function descriptor with the provided return layout. * 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 * @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); FunctionDescriptor changeReturnLayout(MemoryLayout newReturn);
@ -91,28 +98,35 @@ public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
FunctionDescriptor dropReturnLayout(); 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> * <p>
* The carrier type of a layout {@code L} is determined as follows: * The carrier type of a layout {@code L} is determined as follows:
* <ul> * <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 ValueLayout} the carrier type is
* <li>If {@code L} is a {@link GroupLayout} or a {@link SequenceLayout}, the carrier type is {@link MemorySegment}.</li> * 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> * </ul>
* *
* @apiNote A function descriptor cannot, by construction, contain any padding layouts. As such, it is not * @apiNote A function descriptor cannot, by construction, contain any padding
* necessary to specify how padding layouts should be mapped to carrier types. * 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(); MethodType toMethodType();
/** /**
* Creates a function descriptor with the given return and argument layouts. * 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 {@code resLayout} is a padding layout
* @throws IllegalArgumentException if one of the layouts in {@code argLayouts} is a padding layout * @throws IllegalArgumentException if one of the layouts in {@code argLayouts}
* @return a new function descriptor with the provided return and argument layouts. * is a padding layout
* @return a new function descriptor with the provided return and argument layouts
*/ */
static FunctionDescriptor of(MemoryLayout resLayout, MemoryLayout... argLayouts) { static FunctionDescriptor of(MemoryLayout resLayout, MemoryLayout... argLayouts) {
Objects.requireNonNull(resLayout); 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 * Creates a function descriptor with the given argument layouts and no return
* that return no values. * 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 * @param argLayouts the argument layouts
* @return a new function descriptor with the provided 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) { static FunctionDescriptor ofVoid(MemoryLayout... argLayouts) {
// Null checks are implicit in List.of(argLayouts) // Null checks are implicit in List.of(argLayouts)

View file

@ -28,13 +28,16 @@ package java.lang.foreign;
import java.util.List; 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 * A compound layout that is an aggregation of multiple, heterogeneous
* can be combined: if member layouts are laid out one after the other, the resulting group layout is a * <em>member layouts</em>. There are two ways in which member layouts can be combined:
* {@linkplain StructLayout struct layout}; conversely, if all member layouts are laid out at the same starting offset, * if member layouts are laid out one after the other, the resulting group layout is a
* the resulting group layout is a {@linkplain UnionLayout union layout}. * {@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 * @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 * @sealedGraph
* @since 22 * @since 22
@ -44,9 +47,10 @@ public sealed interface GroupLayout extends MemoryLayout permits StructLayout, U
/** /**
* {@return the member layouts of this group layout} * {@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 * @apiNote the order in which member layouts are returned is the same order in which
* been passed to one of the group layout factory methods (see {@link MemoryLayout#structLayout(MemoryLayout...)}, * member layouts have been passed to one of the group layout factory methods
* {@link MemoryLayout#unionLayout(MemoryLayout...)}). * (see {@link MemoryLayout#structLayout(MemoryLayout...)} and
* {@link MemoryLayout#unionLayout(MemoryLayout...)}).
*/ */
List<MemoryLayout> memberLayouts(); List<MemoryLayout> memberLayouts();
@ -65,8 +69,9 @@ public sealed interface GroupLayout extends MemoryLayout permits StructLayout, U
/** /**
* {@inheritDoc} * {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc}
* @throws IllegalArgumentException if {@code byteAlignment} is less than {@code M}, where {@code M} is * @throws IllegalArgumentException if {@code byteAlignment} is less than {@code M},
* the maximum alignment constraint in any of the member layouts associated with this group layout * where {@code M} is the maximum alignment constraint in any of the
* member layouts associated with this group layout
*/ */
@Override @Override
GroupLayout withByteAlignment(long byteAlignment); GroupLayout withByteAlignment(long byteAlignment);

View file

@ -41,42 +41,49 @@ import java.util.stream.Collectors;
import java.util.stream.Stream; 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> * <p>
* Foreign functions typically reside in libraries that can be loaded on demand. Each library conforms to * Foreign functions typically reside in libraries that can be loaded on demand. Each
* a specific ABI (Application Binary Interface). An ABI is a set of calling conventions and data types associated with * library conforms to a specific ABI (Application Binary Interface). An ABI is a set of
* the compiler, OS, and processor where the library was built. For example, a C compiler on Linux/x64 usually * calling conventions and data types associated with the compiler, OS, and processor where
* builds libraries that conform to the SystemV ABI. * the library was built. For example, a C compiler on Linux/x64 usually builds libraries
* that conform to the SystemV ABI.
* <p> * <p>
* A linker has detailed knowledge of the calling conventions and data types used by a specific ABI. * A linker has detailed knowledge of the calling conventions and data types used by a
* For any library that conforms to that ABI, the linker can mediate between Java code running * specific ABI. For any library that conforms to that ABI, the linker can mediate
* in the JVM and foreign functions in the library. In particular: * between Java code running in the JVM and foreign functions in the library. In
* particular:
* <ul> * <ul>
* <li>A linker allows Java code to link against foreign functions, via * <li>A linker allows Java code to link against foreign functions, via
* {@linkplain #downcallHandle(MemorySegment, FunctionDescriptor, Option...) downcall method handles}; and</li> * {@linkplain #downcallHandle(MemorySegment, FunctionDescriptor, Option...) downcall method handles};
* <li>A linker allows foreign functions to call Java method handles, * and</li>
* via the generation of {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...) upcall stubs}.</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> * </ul>
* A linker provides a way to look up the <em>canonical layouts</em> associated with the data types used by the ABI. * A linker provides a way to look up the <em>canonical layouts</em> associated with the
* For example, a linker implementing the C ABI might choose to provide a canonical layout for the C {@code size_t} * data types used by the ABI. For example, a linker implementing the C ABI might choose
* type. On 64-bit platforms, this canonical layout might be equal to {@link ValueLayout#JAVA_LONG}. The canonical * to provide a canonical layout for the C {@code size_t} type. On 64-bit platforms,
* layouts supported by a linker are exposed via the {@link #canonicalLayouts()} method, which returns a map from * this canonical layout might be equal to {@link ValueLayout#JAVA_LONG}. The canonical
* type names to canonical layouts. * layouts supported by a linker are exposed via the {@link #canonicalLayouts()} method,
* which returns a map from type names to canonical layouts.
* <p> * <p>
* In addition, a linker provides a way to look up foreign functions in libraries that conform to the ABI. Each linker * In addition, a linker provides a way to look up foreign functions in libraries that
* chooses a set of libraries that are commonly used on the OS and processor combination associated with the ABI. * conform to the ABI. Each linker chooses a set of libraries that are commonly used on
* For example, a linker for Linux/x64 might choose two libraries: {@code libc} and {@code libm}. The functions in these * the OS and processor combination associated with the ABI. For example, a linker for
* libraries are exposed via a {@linkplain #defaultLookup() symbol lookup}. * 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> * <h2 id="native-linker">Calling native functions</h2>
* *
* The {@linkplain #nativeLinker() native linker} can be used to link against functions * The {@linkplain #nativeLinker() native linker} can be used to link against functions
* defined in C libraries (native functions). Suppose we wish to downcall from Java to the {@code strlen} function * defined in C libraries (native functions). Suppose we wish to downcall from Java to
* defined in the standard C library: * the {@code strlen} function defined in the standard C library:
* {@snippet lang = c: * {@snippet lang = c:
* size_t strlen(const char *s); * 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: * {@snippet lang = java:
* Linker linker = Linker.nativeLinker(); * 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}, * 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 * to the native functions defined by the C libraries loaded with the Java runtime.
* is used to search the address of the {@code strlen} native function. That address is then passed, along with * Above, the default lookup is used to search the address of the {@code strlen} native
* a <em>platform-dependent description</em> of the signature of the function expressed as a * function. That address is then passed, along with a <em>platform-dependent description</em>
* {@link FunctionDescriptor} (more on that below) to the native linker's * of the signature of the function expressed as a {@link FunctionDescriptor} (more on
* {@link #downcallHandle(MemorySegment, FunctionDescriptor, Option...)} method. * that below) to the native linker's {@link #downcallHandle(MemorySegment, FunctionDescriptor, Option...)}
* The obtained downcall method handle is then invoked as follows: * method. The obtained downcall method handle is then invoked as follows:
* *
* {@snippet lang = java: * {@snippet lang = java:
* try (Arena arena = Arena.ofConfined()) { * try (Arena arena = Arena.ofConfined()) {
@ -102,28 +109,34 @@ import java.util.stream.Stream;
*} *}
* <h3 id="describing-c-sigs">Describing C signatures</h3> * <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 * When interacting with the native linker, clients must provide a platform-dependent
* of the C function they wish to link against. This description, a {@link FunctionDescriptor function descriptor}, * description of the signature of the C function they wish to link against. This
* defines the layouts associated with the parameter types and return type (if any) of the C function. * description, a {@link FunctionDescriptor function descriptor}, defines the layouts
* associated with the parameter types and return type (if any) of the C function.
* <p> * <p>
* Scalar C types such as {@code bool}, {@code int} are modeled as {@linkplain ValueLayout value layouts} * Scalar C types such as {@code bool}, {@code int} are modeled as
* of a suitable carrier. The {@linkplain #canonicalLayouts() mapping} between a scalar type and its corresponding * {@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). * canonical layout is dependent on the ABI implemented by the native linker (see below).
* <p> * <p>
* Composite types are modeled as {@linkplain GroupLayout group layouts}. More specifically, a C {@code struct} type * Composite types are modeled as {@linkplain GroupLayout group layouts}. More
* maps to a {@linkplain StructLayout struct layout}, whereas a C {@code union} type maps to a {@link UnionLayout union * specifically, a C {@code struct} type maps to a {@linkplain StructLayout struct layout},
* layout}. When defining a struct or union layout, clients must pay attention to the size and alignment constraint * whereas a C {@code union} type maps to a {@link UnionLayout union layout}. When defining
* of the corresponding composite type definition in C. For instance, padding between two struct fields * a struct or union layout, clients must pay attention to the size and alignment constraint
* must be modeled explicitly, by adding an adequately sized {@linkplain PaddingLayout padding layout} member * of the corresponding composite type definition in C. For instance, padding between two
* to the resulting struct layout. * struct fields must be modeled explicitly, by adding an adequately sized
* {@linkplain PaddingLayout padding layout} member to the resulting struct layout.
* <p> * <p>
* Finally, pointer types such as {@code int**} and {@code int(*)(size_t*, size_t*)} are modeled as * Finally, pointer types such as {@code int**} and {@code int(*)(size_t*, size_t*)}
* {@linkplain AddressLayout address layouts}. When the spatial bounds of the pointer type are known statically, * are modeled as {@linkplain AddressLayout address layouts}. When the spatial bounds of
* the address layout can be associated with a {@linkplain AddressLayout#targetLayout() target layout}. For instance, * the pointer type are known statically, the address layout can be associated with a
* a pointer that is known to point to a C {@code int[2]} array can be modeled as an address layout whose * {@linkplain AddressLayout#targetLayout() target layout}. For instance, a pointer that
* target layout is a sequence layout whose element count is 2, and whose element type is {@link ValueLayout#JAVA_INT}. * 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> * <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> * <ul>
* <li>{@code bool}</li> * <li>{@code bool}</li>
* <li>{@code char}</li> * <li>{@code char}</li>
@ -137,19 +150,23 @@ import java.util.stream.Stream;
* <li>{@code wchar_t}</li> * <li>{@code wchar_t}</li>
* <li>{@code void*}</li> * <li>{@code void*}</li>
* </ul> * </ul>
* As noted above, the specific canonical layout associated with each type can vary, depending on the data model * As noted above, the specific canonical layout associated with each type can vary,
* supported by a given ABI. For instance, the C type {@code long} maps to the layout constant {@link ValueLayout#JAVA_LONG} * depending on the data model supported by a given ABI. For instance, the C type
* on Linux/x64, but maps to the layout constant {@link ValueLayout#JAVA_INT} on Windows/x64. Similarly, the C type * {@code long} maps to the layout constant {@link ValueLayout#JAVA_LONG} on Linux/x64,
* {@code size_t} maps to the layout constant {@link ValueLayout#JAVA_LONG} on 64-bit platforms, but maps to the layout * but maps to the layout constant {@link ValueLayout#JAVA_INT} on Windows/x64.
* constant {@link ValueLayout#JAVA_INT} on 32-bit platforms. * 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> * <p>
* A native linker typically does not provide canonical layouts for C's unsigned integral types. Instead, they are * A native linker typically does not provide canonical layouts for C's unsigned integral
* modeled using the canonical layouts associated with their corresponding signed integral types. For instance, * types. Instead, they are modeled using the canonical layouts associated with their
* the C type {@code unsigned long} maps to the layout constant {@link ValueLayout#JAVA_LONG} on Linux/x64, but maps to * corresponding signed integral types. For instance, the C type {@code unsigned long}
* maps to the layout constant {@link ValueLayout#JAVA_LONG} on Linux/x64, but maps to
* the layout constant {@link ValueLayout#JAVA_INT} on Windows/x64. * the layout constant {@link ValueLayout#JAVA_INT} on Windows/x64.
* <p> * <p>
* The following table shows some examples of how C types are modeled in Linux/x64 according to the * The following table shows some examples of how C types are modeled in Linux/x64
* "System V Application Binary Interface" (all the examples provided here will assume these platform-dependent mappings): * according to the "System V Application Binary Interface"
* (all the examples provided here will assume these platform-dependent mappings):
* *
* <blockquote><table class="plain"> * <blockquote><table class="plain">
* <caption style="display:none">Mapping C types</caption> * <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 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: * <li>{@code L} is a sequence layout {@code S} and all the following conditions hold:
* <ol> * <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> * <li>{@code S.elementLayout()} is a layout supported by {@code NL}.</li>
* </ol> * </ol>
* </li> * </li>
* <li>{@code L} is a group layout {@code G} and all the following conditions hold: * <li>{@code L} is a group layout {@code G} and all the following conditions hold:
* <ol> * <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>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>each member layout in {@code G.memberLayouts()} is either a padding layout or
* <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> * 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> * </ol>
* </li> * </li>
* </ul> * </ul>
* *
* Linker implementations may optionally support additional layouts, such as <em>packed</em> struct layouts. * Linker implementations may optionally support additional layouts, such as
* A packed struct is a struct in which there is at least one member layout {@code L} that has an alignment * <em>packed</em> struct layouts. A packed struct is a struct in which there is
* constraint less strict than its natural alignment. This allows to avoid padding between member layouts, * 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: * as well as avoiding padding at the end of the struct layout. For example:
* {@snippet lang = java: * {@snippet lang = java:
* // No padding between the 2 element layouts: * // No padding between the 2 element layouts:
* MemoryLayout noFieldPadding = MemoryLayout.structLayout( * MemoryLayout noFieldPadding = MemoryLayout.structLayout(
@ -260,23 +283,25 @@ import java.util.stream.Stream;
* ValueLayout.JAVA_INT); * ValueLayout.JAVA_INT);
* } * }
* <p> * <p>
* A native linker only supports function descriptors whose argument/return layouts are layouts supported by that linker * A native linker only supports function descriptors whose argument/return layouts are
* and are not sequence layouts. * layouts supported by that linker and are not sequence layouts.
* *
* <h3 id="function-pointers">Function pointers</h3> * <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 * Sometimes, it is useful to pass Java code as a function pointer to some native
* an {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...) upcall stub}. To demonstrate this, * function; this is achieved by using an
* let's consider the following function from the C standard library: * {@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: * {@snippet lang = c:
* void qsort(void *base, size_t nmemb, size_t size, * void qsort(void *base, size_t nmemb, size_t size,
* int (*compar)(const void *, const void *)); * 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 * The {@code qsort} function can be used to sort the contents of an array, using a
* passed as a function pointer (the {@code compar} parameter). To be able to call the {@code qsort} function from Java, * custom comparator function which is passed as a function pointer
* we must first create a downcall method handle for it, as follows: * (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: * {@snippet lang = java:
* Linker linker = Linker.nativeLinker(); * 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} * As before, we use {@link ValueLayout#JAVA_LONG} to map the C type {@code size_t} type,
* for both the first pointer parameter (the array pointer) and the last parameter (the function pointer). * and {@link ValueLayout#ADDRESS} for both the first pointer parameter (the array
* pointer) and the last parameter (the function pointer).
* <p> * <p>
* To invoke the {@code qsort} downcall handle obtained above, we need a function pointer to be passed as the last * To invoke the {@code qsort} downcall handle obtained above, we need a function pointer
* parameter. That is, we need to create a function pointer out of an existing method handle. First, let's write a * to be passed as the last parameter. That is, we need to create a function pointer out
* Java method that can compare two int elements passed as pointers (i.e. as {@linkplain MemorySegment memory segments}): * 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: * {@snippet lang = java:
* class Qsort { * class Qsort {
@ -312,13 +339,16 @@ import java.util.stream.Stream;
* comparDesc.toMethodType()); * comparDesc.toMethodType());
* } * }
* *
* First, we create a function descriptor for the function pointer type. Since we know that the parameters passed to * First, we create a function descriptor for the function pointer type. Since we know
* the comparator method will be pointers to elements of a C {@code int[]} array, we can specify {@link ValueLayout#JAVA_INT} * that the parameters passed to the comparator method will be pointers to elements of
* as the target layout for the address layouts of both parameters. This will allow the comparator method to access * a C {@code int[]} array, we can specify {@link ValueLayout#JAVA_INT} as the target
* the contents of the array elements to be compared. We then {@linkplain FunctionDescriptor#toMethodType() turn} * layout for the address layouts of both parameters. This will allow the comparator
* that function descriptor into a suitable {@linkplain java.lang.invoke.MethodType method type} which we then use to look up * method to access the contents of the array elements to be compared. We then
* the comparator method handle. We can now create an upcall stub that points to that method, and pass it, as a function * {@linkplain FunctionDescriptor#toMethodType() turn} that function descriptor into
* pointer, to the {@code qsort} downcall handle, as follows: * 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: * {@snippet lang = java:
* try (Arena arena = Arena.ofConfined()) { * 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 * This code creates an off-heap array, copies the contents of a Java array into it, and
* {@code qsort} method handle along with the comparator function we obtained from the native linker. After the invocation, the contents * then passes the array to the {@code qsort} method handle along with the comparator
* of the off-heap array will be sorted according to our comparator function, written in Java. We then extract a * function we obtained from the native linker. After the invocation, the contents
* new Java array from the segment, which contains the sorted elements. * 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> * <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 * When interacting with native functions, it is common for those functions to allocate
* a pointer to that region. Let's consider the following function from the C standard library: * 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: * {@snippet lang = c:
* void *malloc(size_t size); * void *malloc(size_t size);
* } * }
* *
* The {@code malloc} function allocates a region of memory with the given 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 * and returns a pointer to that region of memory, which is later deallocated using
* the C standard library: * another function from the C standard library:
* *
* {@snippet lang = c: * {@snippet lang = c:
* void free(void *ptr); * void free(void *ptr);
* } * }
* *
* The {@code free} function takes a pointer to a region of memory and deallocates that region. In this section we * The {@code free} function takes a pointer to a region of memory and deallocates that
* will show how to interact with these native functions, with the aim of providing a <em>safe</em> allocation * region. In this section we will show how to interact with these native functions,
* API (the approach outlined below can of course be generalized to allocation functions other than {@code malloc} * with the aim of providing a <em>safe</em> allocation API (the approach outlined below
* and {@code free}). * can of course be generalized to allocation functions other than {@code malloc} and
* {@code free}).
* <p> * <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: * {@snippet lang = java:
* Linker linker = Linker.nativeLinker(); * 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, * When a native function returning a pointer (such as {@code malloc}) is invoked using
* the Java runtime has no insight into the size or the lifetime of the returned pointer. Consider the following code: * 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: * {@snippet lang = java:
* MemorySegment segment = (MemorySegment)malloc.invokeExact(100); * 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 * 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 * <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, * 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 * unsafely, resize the segment to the desired size (100, in this case). It might also
* attach the segment to some existing {@linkplain Arena arena}, so that the lifetime of the region of memory * be desirable to attach the segment to some existing {@linkplain Arena arena}, so that
* backing the segment can be managed automatically, as for any other native segment created directly from Java code. * the lifetime of the region of memory backing the segment can be managed automatically,
* Both of these operations are accomplished using the restricted method {@link MemorySegment#reinterpret(long, Arena, Consumer)}, * as for any other native segment created directly from Java code. Both of these
* as follows: * operations are accomplished using the restricted method
* {@link MemorySegment#reinterpret(long, Arena, Consumer)}, as follows:
* *
* {@snippet lang = java: * {@snippet lang = java:
* MemorySegment allocateMemory(long byteSize, Arena arena) throws Throwable { * 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 * The {@code allocateMemory} method defined above accepts two parameters: a size and an
* {@code malloc} downcall method handle, and unsafely reinterprets the returned segment, by giving it a new size * arena. The method calls the {@code malloc} downcall method handle, and unsafely
* (the size passed to the {@code allocateMemory} method) and a new scope (the scope of the provided arena). * reinterprets the returned segment, by giving it a new size (the size passed to the
* The method also specifies a <em>cleanup action</em> to be executed when the provided arena is closed. Unsurprisingly, * {@code allocateMemory} method) and a new scope (the scope of the provided arena).
* the cleanup action passes the segment to the {@code free} downcall method handle, to deallocate the underlying * The method also specifies a <em>cleanup action</em> to be executed when the provided
* region of memory. We can use the {@code allocateMemory} method as follows: * 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: * {@snippet lang = java:
* try (Arena arena = Arena.ofConfined()) { * try (Arena arena = Arena.ofConfined()) {
@ -414,65 +453,79 @@ import java.util.stream.Stream;
* } // 'free' called here * } // 'free' called here
* } * }
* *
* Note how the segment obtained from {@code allocateMemory} acts as any other segment managed by the confined arena. More * Note how the segment obtained from {@code allocateMemory} acts as any other segment
* specifically, the obtained segment has the desired size, can only be accessed by a single thread (the thread that created * managed by the confined arena. More specifically, the obtained segment has the desired
* the confined arena), and its lifetime is tied to the surrounding <em>try-with-resources</em> block. * 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> * <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 * Variadic functions are C functions that can accept a variable number and type of
* trailing ellipsis ({@code ...}) at the end of the formal parameter list, such as: {@code void foo(int x, ...);} * arguments. They are declared with a trailing ellipsis ({@code ...}) at the end of the
* The arguments passed in place of the ellipsis are called <em>variadic arguments</em>. Variadic functions are, * formal parameter list, such as: {@code void foo(int x, ...);}
* essentially, templates that can be <em>specialized</em> into multiple non-variadic functions by replacing the * The arguments passed in place of the ellipsis are called <em>variadic arguments</em>.
* {@code ...} with a list of <em>variadic parameters</em> of a fixed number and type. * 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> * <p>
* It should be noted that values passed as variadic arguments undergo default argument promotion in C. For instance, the * It should be noted that values passed as variadic arguments undergo default argument
* following argument promotions are applied: * promotion in C. For instance, the following argument promotions are applied:
* <ul> * <ul>
* <li>{@code _Bool} -> {@code unsigned int}</li> * <li>{@code _Bool} -> {@code unsigned int}</li>
* <li>{@code [signed] char} -> {@code [signed] int}</li> * <li>{@code [signed] char} -> {@code [signed] int}</li>
* <li>{@code [signed] short} -> {@code [signed] int}</li> * <li>{@code [signed] short} -> {@code [signed] int}</li>
* <li>{@code float} -> {@code double}</li> * <li>{@code float} -> {@code double}</li>
* </ul> * </ul>
* whereby the signed-ness of the source type corresponds to the signed-ness of the promoted type. The complete process * whereby the signed-ness of the source type corresponds to the signed-ness of the
* of default argument promotion is described in the C specification. In effect, these promotions place limits on the * promoted type. The complete process of default argument promotion is described in the
* types that can be used to replace the {@code ...}, as the variadic parameters of the specialized form of a variadic * C specification. In effect, these promotions place limits on the types that can be
* function will always have a promoted type. * used to replace the {@code ...}, as the variadic parameters of the specialized form
* of a variadic function will always have a promoted type.
* <p> * <p>
* The native linker only supports linking the specialized form of a variadic function. A variadic function in its specialized * The native linker only supports linking the specialized form of a variadic function.
* form can be linked using a function descriptor describing the specialized form. Additionally, the * A variadic function in its specialized form can be linked using a function descriptor
* {@link Linker.Option#firstVariadicArg(int)} linker option must be provided to indicate the first variadic parameter in * describing the specialized form. Additionally, the {@link Linker.Option#firstVariadicArg(int)}
* the parameter list. The corresponding argument layout (if any), and all following argument layouts in the specialized * linker option must be provided to indicate the first variadic parameter in the
* function descriptor, are called <em>variadic argument layouts</em>. * 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> * <p>
* The native linker does not automatically perform default argument promotions. However, since passing an argument of a * The native linker does not automatically perform default argument promotions. However,
* non-promoted type as a variadic argument is not supported in C, the native linker will reject an attempt to link a * since passing an argument of a non-promoted type as a variadic argument is not
* specialized function descriptor with any variadic argument value layouts corresponding to a non-promoted C type. * supported in C, the native linker will reject an attempt to link a specialized
* Since the size of the C {@code int} type is platform-specific, exactly which layouts will be rejected is * function descriptor with any variadic argument value layouts corresponding to a
* platform-specific as well. As an example: on Linux/x64 the layouts corresponding to the C types {@code _Bool}, * non-promoted C type. Since the size of the C {@code int} type is platform-specific,
* {@code (unsigned) char}, {@code (unsigned) short}, and {@code float} (among others), will be rejected by the linker. * exactly which layouts will be rejected is platform-specific as well. As an example:
* The {@link #canonicalLayouts()} method can be used to find which layout corresponds to a particular C type. * 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> * <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: * {@snippet lang = c:
* int printf(const char *format, ...); * int printf(const char *format, ...);
* } * }
* *
* This function takes a format string, and a number of additional arguments (the number of such arguments is * This function takes a format string, and a number of additional arguments (the number
* dictated by the format string). Consider the following variadic call: * of such arguments is dictated by the format string). Consider the following
* variadic call:
* *
* {@snippet lang = c: * {@snippet lang = c:
* printf("%d plus %d equals %d", 2, 2, 4); * 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 * To perform an equivalent call using a downcall method handle we must create a function
* describes the specialized signature of the C function we want to call. This descriptor must include an additional layout * descriptor which describes the specialized signature of the C function we want to
* for each variadic argument we intend to provide. In this case, the specialized signature of the C * call. This descriptor must include an additional layout for each variadic argument we
* function is {@code (char*, int, int, int)} as the format string accepts three integer parameters. We then need to use * intend to provide. In this case, the specialized signature of the C function is
* a {@linkplain Linker.Option#firstVariadicArg(int) linker option} to specify the position of the first variadic layout * {@code (char*, int, int, int)} as the format string accepts three integer parameters.
* in the provided function descriptor (starting from 0). In this case, since the first parameter is the format string * We then need to use a {@linkplain Linker.Option#firstVariadicArg(int) linker option}
* (a non-variadic argument), the first variadic index needs to be set to 1, as follows: * 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: * {@snippet lang = java:
* Linker linker = Linker.nativeLinker(); * Linker linker = Linker.nativeLinker();
@ -487,64 +540,81 @@ import java.util.stream.Stream;
* *
* {@snippet lang = java: * {@snippet lang = java:
* try (Arena arena = Arena.ofConfined()) { * 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> * <h2 id="safety">Safety considerations</h2>
* *
* Creating a downcall method handle is intrinsically unsafe. A symbol in a foreign library does not, in general, * Creating a downcall method handle is intrinsically unsafe. A symbol in a foreign
* contain enough signature information (e.g. arity and types of foreign function parameters). As a consequence, * library does not, in general, contain enough signature information (e.g. arity and
* the linker runtime cannot validate linkage requests. When a client interacts with a downcall method handle obtained * types of foreign function parameters). As a consequence, the linker runtime cannot
* through an invalid linkage request (e.g. by specifying a function descriptor featuring too many argument layouts), * validate linkage requests. When a client interacts with a downcall method handle
* the result of such interaction is unspecified and can lead to JVM crashes. * 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> * <p>
* When an upcall stub is passed to a foreign function, a JVM crash might occur, if the foreign code casts the function pointer * When an upcall stub is passed to a foreign function, a JVM crash might occur, if the
* associated with the upcall stub to a type that is incompatible with the type of the upcall stub, and then attempts to * foreign code casts the function pointer associated with the upcall stub to a type that
* invoke the function through the resulting function pointer. Moreover, if the method * is incompatible with the type of the upcall stub, and then attempts to invoke the
* handle associated with an upcall stub returns a {@linkplain MemorySegment memory segment}, clients must ensure * function through the resulting function pointer. Moreover, if the method handle
* that this address cannot become invalid after the upcall is completed. This can lead to unspecified behavior, * associated with an upcall stub returns a {@linkplain MemorySegment memory segment},
* and even JVM crashes, since an upcall is typically executed in the context of a downcall method handle invocation. * 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 * @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 * @since 22
*/ */
public sealed interface Linker permits AbstractLinker { public sealed interface Linker permits AbstractLinker {
/** /**
* {@return a linker for the ABI associated with the underlying native platform} The underlying native platform * {@return a linker for the ABI associated with the underlying native platform}
* is the combination of OS and processor where the Java runtime is currently executing. * <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. * @apiNote It is not currently possible to obtain a linker for a different
* @implSpec A native linker implementation is guaranteed to provide canonical layouts for * combination of OS and processor.
* <a href="#describing-c-sigs">basic C types</a>. * @implSpec A native linker implementation is guaranteed to provide canonical
* @implNote The libraries exposed by the {@linkplain #defaultLookup() default lookup} associated with the returned * layouts for <a href="#describing-c-sigs">basic C types</a>.
* linker are the native libraries loaded in the process where the Java runtime is currently executing. For example, * @implNote The libraries exposed by the {@linkplain #defaultLookup() default lookup}
* on Linux, these libraries typically include {@code libc}, {@code libm} and {@code libdl}. * 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() { static Linker nativeLinker() {
return SharedUtils.getSystemLinker(); 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> * <p>
* Calling this method is equivalent to the following code: * Calling this method is equivalent to the following code:
* {@snippet lang=java : * {@snippet lang=java :
* linker.downcallHandle(function).bindTo(symbol); * linker.downcallHandle(function).bindTo(symbol);
* } * }
* *
* @param address the native memory segment whose {@linkplain MemorySegment#address() base address} is the * @param address the native memory segment whose
* address of the target foreign function. * {@linkplain MemorySegment#address() base address} is the address
* @param function the function descriptor of the target foreign function. * of the target foreign function
* @param options the linker options associated with this linkage request. * @param function the function descriptor of the target foreign function
* @return a downcall method handle. * @param options the linker options associated with this linkage request
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker * @return a downcall method handle
* @throws IllegalArgumentException if {@code !address.isNative()}, or if {@code address.equals(MemorySegment.NULL)} * @throws IllegalArgumentException if the provided function descriptor is not
* @throws IllegalArgumentException if an invalid combination of linker options is given * supported by this linker
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled * @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 * @see SymbolLookup
*/ */
@ -555,87 +625,111 @@ public sealed interface Linker permits AbstractLinker {
Option... options); 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> * <p>
* The Java {@linkplain java.lang.invoke.MethodType method type} associated with the returned method handle is * The Java {@linkplain java.lang.invoke.MethodType method type} associated with the
* {@linkplain FunctionDescriptor#toMethodType() derived} from the argument and return layouts in the function descriptor, * returned method handle is {@linkplain FunctionDescriptor#toMethodType() derived}
* but features an additional leading parameter of type {@link MemorySegment}, from which the address of the target * from the argument and return layouts in the function descriptor, but features an
* foreign function is derived. Moreover, if the function descriptor's return layout is a group layout, the resulting * additional leading parameter of type {@link MemorySegment}, from which the address
* downcall method handle accepts an additional leading parameter of type {@link SegmentAllocator}, which is used by * of the target foreign function is derived. Moreover, if the function descriptor's
* the linker runtime to allocate the memory region associated with the struct returned by the downcall method handle. * 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> * <p>
* Upon invoking a downcall method handle, the linker provides the following guarantees for any argument * Upon invoking a downcall method handle, the linker provides the following
* {@code A} of type {@link MemorySegment} whose corresponding layout is an {@linkplain AddressLayout address layout}: * guarantees for any argument {@code A} of type {@link MemorySegment} whose
* corresponding layout is an {@linkplain AddressLayout address layout}:
* <ul> * <ul>
* <li>{@code A.scope().isAlive() == true}. Otherwise, the invocation throws {@link IllegalStateException};</li> * <li>{@code A.scope().isAlive() == true}. Otherwise, the invocation
* <li>The invocation occurs in a thread {@code T} such that {@code A.isAccessibleBy(T) == true}. * throws {@link IllegalStateException};</li>
* Otherwise, the invocation throws {@link WrongThreadException}; and</li> * <li>The invocation occurs in a thread {@code T} such that
* <li>{@code A} is kept alive during the invocation. For instance, if {@code A} has been obtained using a * {@code A.isAccessibleBy(T) == true}.
* {@linkplain Arena#ofShared() shared arena}, any attempt to {@linkplain Arena#close() close} * Otherwise, the invocation throws {@link WrongThreadException}; and</li>
* the arena while the downcall method handle is still executing will result in an {@link IllegalStateException}.</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> *</ul>
* <p> * <p>
* Moreover, if the provided function descriptor's return layout is an {@linkplain AddressLayout address layout}, * Moreover, if the provided function descriptor's return layout is an
* invoking the returned method handle will return a native segment associated with * {@linkplain AddressLayout address layout}, invoking the returned method handle
* the global scope. Under normal conditions, the size of the returned segment is {@code 0}. * will return a native segment associated with the global scope. Under normal
* However, if the function descriptor's return layout has a {@linkplain AddressLayout#targetLayout() target layout} * conditions, the size of the returned segment is {@code 0}. However, if the
* {@code T}, then the size of the returned segment is set to {@code T.byteSize()}. * 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> * <p>
* The returned method handle will throw an {@link IllegalArgumentException} if the {@link MemorySegment} * The returned method handle will throw an {@link IllegalArgumentException} if the
* representing the target address of the foreign function is the {@link MemorySegment#NULL} address. If an argument * {@link MemorySegment} representing the target address of the foreign function is
* is a {@link MemorySegment}, whose corresponding layout is a {@linkplain GroupLayout group layout}, the linker * the {@link MemorySegment#NULL} address. If an argument is a {@link MemorySegment},
* might attempt to access the contents of the segment. As such, one of the exceptions specified by the * whose corresponding layout is a {@linkplain GroupLayout group layout}, the linker
* {@link MemorySegment#get(ValueLayout.OfByte, long)} or the * might attempt to access the contents of the segment. As such, one of the
* {@link MemorySegment#copy(MemorySegment, long, MemorySegment, long, long)} methods may be thrown. * exceptions specified by the {@link MemorySegment#get(ValueLayout.OfByte, long)} or
* The returned method handle will additionally throw {@link NullPointerException} if any argument * the {@link MemorySegment#copy(MemorySegment, long, MemorySegment, long, long)}
* passed to it is {@code null}. * 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 function the function descriptor of the target foreign function
* @param options the linker options associated with this linkage request. * @param options the linker options associated with this linkage request
* @return a downcall method handle. * @return a downcall method handle
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker * @throws IllegalArgumentException if the provided function descriptor is not
* @throws IllegalArgumentException if an invalid combination of linker options is given * supported by this linker
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled * @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 @CallerSensitive
@Restricted @Restricted
MethodHandle downcallHandle(FunctionDescriptor function, Option... options); 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 * Creates an upcall stub which can be passed to other foreign functions as a
* arena. Calling such a function pointer from foreign code will result in the execution of the provided * function pointer, associated with the given arena. Calling such a function
* method handle. * pointer from foreign code will result in the execution of the provided method
* handle.
* <p> * <p>
* The returned memory segment's address points to the newly allocated upcall stub, and is associated with * The returned memory segment's address points to the newly allocated upcall stub,
* the provided arena. As such, the lifetime of the returned upcall stub segment is controlled by the * and is associated with the provided arena. As such, the lifetime of the returned
* provided arena. For instance, if the provided arena is a confined arena, the returned * upcall stub segment is controlled by the provided arena. For instance, if the
* upcall stub segment will be deallocated when the provided confined arena is {@linkplain Arena#close() closed}. * 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> * <p>
* An upcall stub argument whose corresponding layout is an {@linkplain AddressLayout address layout} * An upcall stub argument whose corresponding layout is an
* is a native segment associated with the global scope. * {@linkplain AddressLayout address layout} is a native segment associated with the
* Under normal conditions, the size of this segment argument is {@code 0}. * global scope. Under normal conditions, the size of this segment argument is
* However, if the address layout has a {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size of the * {@code 0}. However, if the address layout has a
* segment argument is set to {@code T.byteSize()}. * {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size
* of the segment argument is set to {@code T.byteSize()}.
* <p> * <p>
* The target method handle should not throw any exceptions. If the target method handle does throw an exception, * The target method handle should not throw any exceptions. If the target method
* the JVM will terminate abruptly. To avoid this, clients should wrap the code in the target method handle in a * handle does throw an exception, the JVM will terminate abruptly. To avoid this,
* try/catch block to catch any unexpected exceptions. This can be done using the * clients should wrap the code in the target method handle in a try/catch block to
* {@link java.lang.invoke.MethodHandles#catchException(MethodHandle, Class, MethodHandle)} method handle combinator, * catch any unexpected exceptions. This can be done using the
* and handle exceptions as desired in the corresponding catch block. * {@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 target the target method handle
* @param function the upcall stub function descriptor. * @param function the upcall stub function descriptor
* @param arena the arena associated with the returned upcall stub segment. * @param arena the arena associated with the returned upcall stub segment
* @param options the linker options associated with this linkage request. * @param options the linker options associated with this linkage request
* @return a zero-length segment whose address is the address of the upcall stub. * @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 provided function descriptor is not
* @throws IllegalArgumentException if the type of {@code target} is incompatible with the * supported by this linker
* type {@linkplain FunctionDescriptor#toMethodType() derived} from {@code function} * @throws IllegalArgumentException if the type of {@code target} is incompatible
* @throws IllegalArgumentException if it is determined that the target method handle can throw an exception * 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 IllegalStateException if {@code arena.scope().isAlive() == false}
* @throws WrongThreadException if {@code arena} is a confined arena, and this method is called from a * @throws WrongThreadException if {@code arena} is a confined arena, and this method
* thread {@code T}, other than the arena's owner thread * 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 IllegalCallerException If the caller is in a module that does not have
* native access enabled
*/ */
@CallerSensitive @CallerSensitive
@Restricted @Restricted
@ -647,31 +741,44 @@ public sealed interface Linker permits AbstractLinker {
/** /**
* Returns a symbol lookup for symbols in a set of commonly used libraries. * Returns a symbol lookup for symbols in a set of commonly used libraries.
* <p> * <p>
* Each {@link Linker} is responsible for choosing libraries that are widely recognized as useful on the OS * Each {@link Linker} is responsible for choosing libraries that are widely
* and processor combination supported by the {@link Linker}. Accordingly, the precise set of symbols exposed by the * recognized as useful on the OS and processor combination supported by the
* symbol lookup is unspecified; it varies from one {@link Linker} to another. * {@link Linker}. Accordingly, the precise set of symbols exposed by the symbol
* @implNote It is strongly recommended that the result of {@link #defaultLookup} exposes a set of symbols that is stable over time. * lookup is unspecified; it varies from one {@link Linker} to another.
* 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 * @implNote It is strongly recommended that the result of {@link #defaultLookup}
* recommended that the result of {@link #defaultLookup()} exposes, as much as possible, a consistent set of symbols * exposes a set of symbols that is stable over time. Clients of
* across all the OS and processor combinations. * {@link #defaultLookup()} are likely to fail if a symbol that was
* @return a symbol lookup for symbols in a set of commonly used libraries. * 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(); SymbolLookup defaultLookup();
/** /**
* {@return an unmodifiable mapping between the names of data types used by the ABI implemented by this linker and their * {@return an unmodifiable mapping between the names of data types used by the ABI
* <em>canonical layouts</em>} * implemented by this linker and their <em>canonical layouts</em>}
* <p> * <p>
* Each {@link Linker} is responsible for choosing the data types that are widely recognized as useful on the OS * Each {@link Linker} is responsible for choosing the data types that are widely
* and processor combination supported by the {@link Linker}. Accordingly, the precise set of data type names * recognized as useful on the OS and processor combination supported by the
* and canonical layouts exposed by the linker are unspecified; they vary from one {@link Linker} to another. * {@link Linker}. Accordingly, the precise set of data type names and canonical
* @implNote It is strongly recommended that the result of {@link #canonicalLayouts()} exposes a set of symbols that is stable over time. * layouts exposed by the linker are unspecified; they vary from one {@link Linker}
* Clients of {@link #canonicalLayouts()} are likely to fail if a data type that was previously exposed by the linker * to another.
* 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 * @implNote It is strongly recommended that the result of {@link #canonicalLayouts()}
* recommended that the result of {@link #canonicalLayouts()} exposes, as much as possible, a consistent set of symbols * exposes a set of symbols that is stable over time. Clients of
* across all the OS and processor combinations. * {@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(); Map<String, MemoryLayout> canonicalLayouts();
@ -683,49 +790,57 @@ public sealed interface Linker permits AbstractLinker {
permits LinkerOptions.LinkerOptionImpl { permits LinkerOptions.LinkerOptionImpl {
/** /**
* {@return a linker option used to denote the index indicating the start of the variadic arguments passed to the * {@return a linker option used to denote the index indicating the start of the
* function described by the function descriptor associated with a downcall linkage request} * variadic arguments passed to the function described by the function
* descriptor associated with a downcall linkage request}
* <p> * <p>
* The {@code index} value must conform to {@code 0 <= index <= N}, where {@code N} is the number of argument * The {@code index} value must conform to {@code 0 <= index <= N}, where
* layouts of the function descriptor used in conjunction with this linker option. When the {@code index} is: * {@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> * <ul>
* <li>{@code 0}, all arguments passed to the function are passed as variadic arguments</li> * <li>{@code 0}, all arguments passed to the function are passed as variadic
* <li>{@code N}, none of the arguments passed to the function are passed as variadic arguments</li> * arguments</li>
* <li>{@code n}, where {@code 0 < m < N}, the arguments {@code m..N} 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> * </ul>
* It is important to always use this linker option when linking a <a href=Linker.html#variadic-funcs>variadic * It is important to always use this linker option when linking a
* function</a>, even if no variadic argument is passed (the second case in the list * <a href=Linker.html#variadic-funcs>variadic function</a>, even if no variadic
* above), as this might still affect the calling convention on certain platforms. * 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 * @implNote The index value is validated when making a linkage request, which is
* against which the index is validated is available. * 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 * @param index the index of the first variadic argument layout in the function
* with a downcall linkage request. * descriptor associated with a downcall linkage request
*/ */
static Option firstVariadicArg(int index) { static Option firstVariadicArg(int index) {
return new LinkerOptions.FirstVariadicArg(index); return new LinkerOptions.FirstVariadicArg(index);
} }
/** /**
* {@return a linker option used to save portions of the execution state immediately after * {@return a linker option used to save portions of the execution state
* calling a foreign function associated with a downcall method handle, * immediately after calling a foreign function associated with a
* before it can be overwritten by the Java runtime, or read through conventional means} * downcall method handle, before it can be overwritten by the Java
* runtime, or read through conventional means}
* <p> * <p>
* Execution state is captured by a downcall method handle on invocation, by writing it * Execution state is captured by a downcall method handle on invocation, by
* to a native segment provided by the user to the downcall method handle. * writing it to a native segment provided by the user to the downcall method
* For this purpose, a downcall method handle linked with this * handle. For this purpose, a downcall method handle linked with this option
* option will feature an additional {@link MemorySegment} parameter directly * will feature an additional {@link MemorySegment} parameter directly following
* following the target address, and optional {@link SegmentAllocator} parameters. * the target address, and optional {@link SegmentAllocator} parameters. This
* This parameter, the <em>capture state segment</em>, represents the native segment into which * parameter, the <em>capture state segment</em>, represents the native segment
* the captured state is written. * into which the captured state is written.
* <p> * <p>
* The capture state segment must have size and alignment compatible with the layout returned by * The capture state segment must have size and alignment compatible with the
* {@linkplain #captureStateLayout}. This layout is a struct layout which has a named field for * layout returned by {@linkplain #captureStateLayout}. This layout is a struct
* each captured value. * layout which has a named field for each captured value.
* <p> * <p>
* Captured state can be retrieved from the capture state segment by constructing var handles * Captured state can be retrieved from the capture state segment by constructing
* from the {@linkplain #captureStateLayout capture state layout}. * var handles from the {@linkplain #captureStateLayout capture state layout}.
* <p> * <p>
* The following example demonstrates the use of this linker option: * The following example demonstrates the use of this linker option:
* {@snippet lang = "java": * {@snippet lang = "java":
@ -745,9 +860,9 @@ public sealed interface Linker permits AbstractLinker {
* <p> * <p>
* This linker option can not be combined with {@link #critical}. * This linker option can not be combined with {@link #critical}.
* *
* @param capturedState the names of the values to save. * @param capturedState the names of the values to save
* @throws IllegalArgumentException if at least one of the provided {@code capturedState} names * @throws IllegalArgumentException if at least one of the provided
* is unsupported on the current platform * {@code capturedState} names is unsupported on the current platform
* @see #captureStateLayout() * @see #captureStateLayout()
*/ */
static Option captureCallState(String... capturedState) { 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 * {@return a struct layout that represents the layout of the capture state
* to a downcall handle linked with {@link #captureCallState(String...)}} * segment that is passed to a downcall handle linked with
* {@link #captureCallState(String...)}}
* <p> * <p>
* The capture state layout is <em>platform-dependent</em> but is guaranteed to be * The capture state layout is <em>platform-dependent</em> but is guaranteed to be
* a {@linkplain StructLayout struct layout} containing only {@linkplain ValueLayout value layouts} * 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>} * {@return a linker option used to mark a foreign function as <em>critical</em>}
* <p> * <p>
* A critical function is a function that has an extremely short running time in all cases * A critical function is a function that has an extremely short running time in
* (similar to calling an empty function), and does not call back into Java (e.g. using an upcall stub). * all cases (similar to calling an empty function), and does not call back into
* Java (e.g. using an upcall stub).
* <p> * <p>
* Using this linker option is a hint that some implementations may use to apply * Using this linker option is a hint that some implementations may use to apply
* optimizations that are only valid for critical functions. * optimizations that are only valid for critical functions.
* <p> * <p>
* Using this linker option when linking non-critical functions is likely to have adverse effects, * Using this linker option when linking non-critical functions is likely to have
* such as loss of performance or JVM crashes. * adverse effects, such as loss of performance or JVM crashes.
*/ */
static Option critical() { static Option critical() {
return LinkerOptions.Critical.INSTANCE; return LinkerOptions.Critical.INSTANCE;

View file

@ -28,11 +28,13 @@ package java.lang.foreign;
import jdk.internal.foreign.layout.PaddingLayoutImpl; 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, * A padding layout. A padding layout specifies the size of extra space which is
* and is typically used for aligning member layouts around word boundaries. * typically not accessed by applications, and is typically used for aligning member
* layouts around word boundaries.
* *
* @implSpec * @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 * @since 22
*/ */

View file

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

View file

@ -28,10 +28,11 @@ package java.lang.foreign;
import jdk.internal.foreign.layout.SequenceLayoutImpl; import jdk.internal.foreign.layout.SequenceLayoutImpl;
/** /**
* A compound layout that denotes a homogeneous repetition of a given <em>element layout</em>. * A compound layout that denotes a homogeneous repetition of a given
* The repetition count is said to be the sequence layout's <em>element count</em>. A sequence layout can be thought of as a * <em>element layout</em>. The repetition count is said to be the sequence layout's
* struct layout where the sequence layout's element layout is repeated a number of times that is equal to the sequence * <em>element count</em>. A sequence layout can be thought of as a struct layout where
* layout's element count. In other words this layout: * 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 : * {@snippet lang=java :
* MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN)); * MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN));
@ -47,7 +48,8 @@ import jdk.internal.foreign.layout.SequenceLayoutImpl;
* } * }
* *
* @implSpec * @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 * @since 22
*/ */
@ -65,18 +67,21 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
long elementCount(); long elementCount();
/** /**
* {@return a sequence layout with the same characteristics of this layout, but with the given element count} * {@return a sequence layout with the same characteristics of this layout, but with
* @param elementCount the new element count. * the given element count}
* @param elementCount the new element count
* @throws IllegalArgumentException if {@code elementCount} is negative * @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); SequenceLayout withElementCount(long elementCount);
/** /**
* Rearranges the elements in this sequence layout into a multi-dimensional sequence layout. * Rearranges the elements in this sequence layout into a multidimensional sequence
* The resulting layout is a sequence layout where element layouts in the {@linkplain #flatten() flattened projection} * layout. The resulting layout is a sequence layout where element layouts in the
* of this sequence layout are rearranged into one or more nested sequence layouts * {@linkplain #flatten() flattened projection} of this sequence layout are
* according to the provided element counts. This transformation preserves the layout size; * 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 * that is, multiplying the provided element counts must yield the same element count
* as the flattened projection of this sequence layout. * as the flattened projection of this sequence layout.
* <p> * <p>
@ -89,27 +94,32 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
* var reshapeSeq = MemoryLayout.sequenceLayout(2, MemoryLayout.sequenceLayout(6, ValueLayout.JAVA_INT)); * var reshapeSeq = MemoryLayout.sequenceLayout(2, MemoryLayout.sequenceLayout(6, ValueLayout.JAVA_INT));
* } * }
* <p> * <p>
* If one of the provided element counts is the special value {@code -1}, then the element * If one of the provided element counts is the special value {@code -1}, then
* count in that position will be inferred from the remaining element counts and the * the element count in that position will be inferred from the remaining element
* element count of the flattened projection of this layout. For instance, a layout equivalent to * counts and the element count of the flattened projection of this layout.
* the above {@code reshapeSeq} can also be computed in the following ways: * For instance, a layout equivalent to the above {@code reshapeSeq} can also be
* computed in the following ways:
* {@snippet lang=java : * {@snippet lang=java :
* var reshapeSeqImplicit1 = seq.reshape(-1, 6); * var reshapeSeqImplicit1 = seq.reshape(-1, 6);
* var reshapeSeqImplicit2 = seq.reshape(2, -1); * var reshapeSeqImplicit2 = seq.reshape(2, -1);
* } * }
* @param elementCounts an array of element counts, of which at most one can be {@code -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 * @return a sequence layout where element layouts in the
* sequence layout (see {@link #flatten()}) are re-arranged into one or more nested sequence layouts. * {@linkplain #flatten() flattened projection} of this sequence layout
* @throws IllegalArgumentException if two or more element counts are set to {@code -1}, or if one * (see {@link #flatten()}) are re-arranged into one or more nested
* or more element count is {@code <= 0} (but other than {@code -1}) or, if, after any required inference, * sequence layouts
* multiplying the element counts does not yield the same element count as the flattened projection of this * @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 * sequence layout
*/ */
SequenceLayout reshape(long... elementCounts); SequenceLayout reshape(long... elementCounts);
/** /**
* Returns a flattened sequence layout. The element layout of the returned sequence layout * Returns a flattened sequence layout. The element layout of the returned
* is the first non-sequence layout found by inspecting (recursively, if needed) the element layout of this sequence layout: * sequence layout is the first non-sequence layout found by inspecting
* (recursively, if needed) the element layout of this sequence layout:
* {@snippet lang=java : * {@snippet lang=java :
* MemoryLayout flatElementLayout(SequenceLayout sequenceLayout) { * MemoryLayout flatElementLayout(SequenceLayout sequenceLayout) {
* return switch (sequenceLayout.elementLayout()) { * return switch (sequenceLayout.elementLayout()) {
@ -119,9 +129,10 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
* } * }
* } * }
* <p> * <p>
* This transformation preserves the layout size; nested sequence layout in this sequence layout will * This transformation preserves the layout size; nested sequence layout in this
* be dropped and their element counts will be incorporated into that of the returned sequence layout. * sequence layout will be dropped and their element counts will be incorporated
* For instance, given a sequence layout of the kind: * into that of the returned sequence layout. For instance, given a
* sequence layout of the kind:
* {@snippet lang=java : * {@snippet lang=java :
* var seq = MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT)); * 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 : * {@snippet lang=java :
* var flattenedSeq = MemoryLayout.sequenceLayout(12, ValueLayout.JAVA_INT); * var flattenedSeq = MemoryLayout.sequenceLayout(12, ValueLayout.JAVA_INT);
* } * }
* @return a sequence layout with the same size as this layout (but, possibly, with different * @return a sequence layout with the same size as this layout
* element count), whose element layout is not a sequence layout. * (but, possibly, with different element count), whose
* element layout is not a sequence layout
*/ */
SequenceLayout flatten(); SequenceLayout flatten();
@ -149,7 +161,8 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
/** /**
* {@inheritDoc} * {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc}
* @throws IllegalArgumentException if {@code byteAlignment < elementLayout().byteAlignment()} * @throws IllegalArgumentException if
* {@code byteAlignment < elementLayout().byteAlignment()}
*/ */
SequenceLayout withByteAlignment(long 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. * A group layout whose member layouts are laid out one after the other.
* *
* @implSpec * @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 * @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 <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. * A symbol is a named entity, such as a function or a global variable.
* <p> * <p>
* A symbol lookup is created with respect to a particular library (or libraries). Subsequently, the {@link SymbolLookup#find(String)} * A symbol lookup is created with respect to a particular library (or libraries).
* method takes the name of a symbol and returns the address of the symbol in that library. * Subsequently, the {@link SymbolLookup#find(String)} method takes the name of a symbol
* and returns the address of the symbol in that library.
* <p> * <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> * <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 a {@link Linker} to create a downcall method handle, which
* <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> * can then be used to call the foreign function at the segment's address.</li>
* <li>It can be {@linkplain MemorySegment#set(AddressLayout, long, MemorySegment) stored} inside another memory segment.</li> * <li>It can be passed to an existing
* <li>It can be used to access the region of memory backing a global variable (this requires * {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle},
* {@linkplain MemorySegment#reinterpret(long) resizing} the segment first).</li> * 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> * </ul>
* *
* <h2 id="obtaining">Obtaining a symbol lookup</h2> * <h2 id="obtaining">Obtaining a symbol lookup</h2>
* *
* The factory methods {@link #libraryLookup(String, Arena)} and {@link #libraryLookup(Path, Arena)} * The factory methods {@link #libraryLookup(String, Arena)} and
* create a symbol lookup for a library known to the operating system. The library is specified by either its name or a path. * {@link #libraryLookup(Path, Arena)} create a symbol lookup for a library known to
* The library is loaded if not already loaded. The symbol lookup, which is known as a <em>library lookup</em>, and its * the operating system. The library is specified by either its name or a path.
* lifetime is controlled by an {@linkplain Arena arena}. For instance, if the provided arena is a * The library is loaded if not already loaded. The symbol lookup, which is known as a
* confined arena, the library associated with the symbol lookup is unloaded when the confined arena * <em>library lookup</em>, and its lifetime is controlled by an {@linkplain Arena arena}.
* is {@linkplain Arena#close() closed}: * 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: * {@snippet lang = java:
* try (Arena arena = Arena.ofConfined()) { * try (Arena arena = Arena.ofConfined()) {
@ -76,8 +84,9 @@ import java.util.function.BiFunction;
*} *}
* <p> * <p>
* If a library was previously loaded through JNI, i.e., by {@link System#load(String)} * 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 * or {@link System#loadLibrary(String)}, then the library was also associated with
* method {@link #loaderLookup()} creates a symbol lookup for all the libraries associated with the caller's class loader: * 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 : * {@snippet lang=java :
* System.loadLibrary("GL"); // libGL.so loaded here * System.loadLibrary("GL"); // libGL.so loaded here
@ -86,21 +95,24 @@ import java.util.function.BiFunction;
* MemorySegment glGetString = libGL.find("glGetString").orElseThrow(); * 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 * This symbol lookup, which is known as a <em>loader lookup</em>, is dynamic with
* with the class loader. If other libraries are subsequently loaded through JNI and associated with the class loader, * respect to the libraries associated with the class loader. If other libraries are
* then the loader lookup will expose their symbols automatically. * subsequently loaded through JNI and associated with the class loader, then the loader
* lookup will expose their symbols automatically.
* <p> * <p>
* Note that a loader lookup only exposes symbols in libraries that were previously loaded through JNI, i.e., * Note that a loader lookup only exposes symbols in libraries that were previously
* by {@link System#load(String)} or {@link System#loadLibrary(String)}. A loader lookup does not expose symbols in libraries * loaded through JNI, i.e., by {@link System#load(String)} or {@link System#loadLibrary(String)}.
* that were loaded in the course of creating a library lookup: * A loader lookup does not expose symbols in libraries that were loaded in the course
* of creating a library lookup:
* *
* {@snippet lang = java: * {@snippet lang = java:
* libraryLookup("libGL.so", arena).find("glGetString").isPresent(); // true * libraryLookup("libGL.so", arena).find("glGetString").isPresent(); // true
* loaderLookup().find("glGetString").isPresent(); // false * 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 * Note also that a library lookup for library {@code L} exposes symbols in {@code L}
* through JNI (the association with a class loader is immaterial to the library lookup): * even if {@code L} was previously loaded through JNI (the association with
* a class loader is immaterial to the library lookup):
* *
* {@snippet lang = java: * {@snippet lang = java:
* System.loadLibrary("GL"); // libGL.so loaded here * System.loadLibrary("GL"); // libGL.so loaded here
@ -108,10 +120,11 @@ import java.util.function.BiFunction;
*} *}
* *
* <p> * <p>
* Finally, each {@link Linker} provides a symbol lookup for libraries that are commonly used on the OS and processor * Finally, each {@link Linker} provides a symbol lookup for libraries that are commonly
* combination supported by that {@link Linker}. This symbol lookup, which is known as a <em>default lookup</em>, * used on the OS and processor combination supported by that {@link Linker}. This
* helps clients to quickly find addresses of well-known symbols. For example, a {@link Linker} for Linux/x64 might choose to * symbol lookup, which is known as a <em>default lookup</em>, helps clients to quickly
* expose symbols in {@code libc} through the default lookup: * 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: * {@snippet lang = java:
* Linker nativeLinker = Linker.nativeLinker(); * Linker nativeLinker = Linker.nativeLinker();
@ -126,27 +139,33 @@ public interface SymbolLookup {
/** /**
* Returns the address of the symbol with the given name. * 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); Optional<MemorySegment> find(String name);
/** /**
* {@return a composed symbol lookup that returns the result of finding the symbol with this lookup if found, * {@return a composed symbol lookup that returns the result of finding the symbol
* otherwise returns the result of finding the symbol with the other lookup} * 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 * @apiNote This method could be used to chain multiple symbol lookups together,
* be retrieved, in order, from multiple libraries: * e.g. so that symbols could be retrieved, in order, from multiple
* libraries:
* {@snippet lang = java: * {@snippet lang = java:
* var lookup = SymbolLookup.libraryLookup("foo", arena) * var lookup = SymbolLookup.libraryLookup("foo", arena)
* .or(SymbolLookup.libraryLookup("bar", arena)) * .or(SymbolLookup.libraryLookup("bar", arena))
* .or(SymbolLookup.loaderLookup()); * .or(SymbolLookup.loaderLookup());
*} *}
* The above code creates a symbol lookup that first searches for symbols in the "foo" library. If no symbol is found * The above code creates a symbol lookup that first searches for symbols in
* in "foo" then "bar" is searched. Finally, if a symbol is neither found in "foo" nor in "bar", the {@linkplain * the "foo" library. If no symbol is found in "foo" then "bar" is searched.
* SymbolLookup#loaderLookup() loader lookup} is used. * 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) { default SymbolLookup or(SymbolLookup other) {
Objects.requireNonNull(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> * <p>
* A library is associated with a class loader {@code CL} when the library is loaded via an invocation of * A library is associated with a class loader {@code CL} when the library is loaded
* {@link System#load(String)} or {@link System#loadLibrary(String)} from code in a class defined by {@code CL}. * via an invocation of {@link System#load(String)} or
* If that code makes further invocations of {@link System#load(String)} or {@link System#loadLibrary(String)}, * {@link System#loadLibrary(String)} from code in a class defined by {@code CL}.
* then more libraries are loaded and associated with {@code CL}. The symbol lookup returned by this method is always * If that code makes further invocations of {@link System#load(String)} or
* current: it reflects all the libraries associated with the relevant class loader, even if they were loaded after * {@link System#loadLibrary(String)} then more libraries are loaded and associated
* this method returned. * 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> * <p>
* Libraries associated with a class loader are unloaded when the class loader becomes * 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 * <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>. The
* returned by this method is associated with an automatic {@linkplain MemorySegment.Scope scope} which keeps the caller's * symbol lookup returned by this method is associated with an automatic
* class loader reachable. Therefore, libraries associated with the caller's class loader are kept loaded * {@linkplain MemorySegment.Scope scope} which keeps the caller's class loader
* (and their symbols available) as long as a loader lookup for that class loader, or any of the segments * reachable. Therefore, libraries associated with the caller's class loader are
* obtained by it, is reachable. * 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> * <p>
* In cases where this method is called from a context where there is no caller frame on the stack * In cases where this method is called from a context where there is no caller
* (e.g. when called directly from a JNI attached thread), the caller's class loader defaults to the * 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}. * {@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#load(String)
* @see System#loadLibrary(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. * Loads a library with the given name (if not already loaded) and creates a symbol
* The lifetime of the returned library lookup is controlled by the provided arena. * lookup for symbols in that library. The lifetime of the returned library lookup
* For instance, if the provided arena is a confined arena, the library * is controlled by the provided arena. For instance, if the provided arena is a
* associated with the returned lookup will be unloaded when the provided confined arena is * confined arena, the library associated with the returned lookup will be unloaded
* {@linkplain Arena#close() closed}. * 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, * @implNote The process of resolving a library name is OS-specific. For instance,
* the library name is resolved according to the specification of the {@code dlopen} function for that OS. * in a POSIX-compliant OS, the library name is resolved according to the
* In Windows, the library name is resolved according to the specification of the {@code LoadLibrary} function. * 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 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. * @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. * @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 IllegalStateException if {@code arena.scope().isAlive() == false}
* @throws WrongThreadException if {@code arena} is a confined arena, and this method is called from a * @throws WrongThreadException if {@code arena} is a confined arena, and this method
* thread {@code T}, other than the arena's owner thread * 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 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 @CallerSensitive
@Restricted @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 * Loads a library from the given path (if not already loaded) and creates a symbol
* in that library. The lifetime of the returned library lookup is controlled by the provided arena. * lookup for symbols in that library. The lifetime of the returned library lookup
* For instance, if the provided arena is a confined arena, the library * is controlled by the provided arena. For instance, if the provided arena is a
* associated with the returned lookup will be unloaded when the provided confined arena is * confined arena, the library associated with the returned lookup will be unloaded
* {@linkplain Arena#close() closed}. * 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 * @implNote On Linux, the functionalities provided by this factory method and the
* implemented using the {@code dlopen}, {@code dlsym} and {@code dlclose} functions. * returned symbol lookup are implemented using the {@code dlopen},
* @param path the path of the library in which symbols should be looked up. * {@code dlsym} and {@code dlclose} functions.
* @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. * @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 IllegalStateException if {@code arena.scope().isAlive() == false}
* @throws WrongThreadException if {@code arena} is a confined arena, and this method is called from a * @throws WrongThreadException if {@code arena} is a confined arena, and this method
* thread {@code T}, other than the arena's owner thread * 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 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 @CallerSensitive
@Restricted @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. * A group layout whose member layouts are laid out at the same starting offset.
* *
* @implSpec * @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 * @since 22
*/ */

View file

@ -30,22 +30,29 @@ import java.nio.ByteOrder;
import jdk.internal.foreign.layout.ValueLayouts; import jdk.internal.foreign.layout.ValueLayouts;
/** /**
* A layout that models values of basic data types. Examples of values modeled by a value layout are * A layout that models values of basic data types. Examples of values modeled by
* <em>integral</em> values (either signed or unsigned), <em>floating-point</em> values and * a value layout are <em>integral</em> values (either signed or unsigned),
* <em>address</em> values. * <em>floating-point</em> values and <em>address</em> values.
* <p> * <p>
* Each value layout has a size, an alignment (both expressed in bytes), * 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 * a {@linkplain ByteOrder byte order}, and a <em>carrier</em>, that is, the Java type
* {@linkplain MemorySegment#get(OfInt, long) accessing} a region of memory using the value layout. * that should be used when {@linkplain MemorySegment#get(OfInt, long) accessing} a
* region of memory using the value layout.
* <p> * <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 * This class defines useful value layout constants for Java primitive types and
* these constants is set to the {@linkplain ByteOrder#nativeOrder() native byte order}, thus making it easy to work * addresses.
* 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.
* *
* @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 * @sealedGraph
* @since 22 * @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} * {@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); ValueLayout withOrder(ByteOrder order);
@ -93,21 +100,26 @@ public sealed interface ValueLayout extends MemoryLayout
ValueLayout withByteAlignment(long byteAlignment); 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> * <p>
* The returned var handle's {@linkplain VarHandle#varType() var type} is the {@linkplain ValueLayout#carrier() carrier type} of * The returned var handle's {@linkplain VarHandle#varType() var type} is the
* this value layout, and the list of coordinate types is {@code (MemorySegment, long)}, where the memory segment coordinate * {@linkplain ValueLayout#carrier() carrier type} of this value layout, and the
* corresponds to the memory segment to be accessed, and the {@code long} coordinate corresponds to the byte offset * list of coordinate types is {@code (MemorySegment, long)}, where the
* into the accessed memory segment at which the access occurs. * 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> * <p>
* The returned var handle checks that accesses are aligned according to this value layout's * The returned var handle checks that accesses are aligned according to
* {@linkplain MemoryLayout#byteAlignment() alignment constraint}. * this value layout's {@linkplain MemoryLayout#byteAlignment() alignment constraint}.
* *
* @apiNote This method is similar, but more efficient than calling {@code MemoryLayout#varHandle(PathElement...)} * @apiNote This method is similar, but more efficient than calling
* with an empty path element array, as it avoids the creation of the var args array. * {@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 * @apiNote The returned var handle features certain
* restrictions</a> common to all memory access var handles derived from memory layouts. * <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...) * @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}), * An address layout constant whose size is the same as that of a
* byte alignment set to {@code sizeof(size_t)}, byte order set to {@link ByteOrder#nativeOrder()}. * 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()); 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()); 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}), * An unaligned address layout constant whose size is the same as that of a
* and byte order set to {@link ByteOrder#nativeOrder()}. * machine address ({@code size_t}), and byte order set to
* {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code: * Equivalent to the following code:
* {@snippet lang=java : * {@snippet lang=java :
* ADDRESS.withByteAlignment(1); * ADDRESS.withByteAlignment(1);
* } * }
* @apiNote Care should be taken when using unaligned value layouts as they may induce * @apiNote Care should be taken when using unaligned value layouts as they may
* performance and portability issues. * induce performance and portability issues.
*/ */
AddressLayout ADDRESS_UNALIGNED = ADDRESS.withByteAlignment(1); AddressLayout ADDRESS_UNALIGNED = ADDRESS.withByteAlignment(1);
@ -473,8 +487,8 @@ public sealed interface ValueLayout extends MemoryLayout
* {@snippet lang=java : * {@snippet lang=java :
* JAVA_CHAR.withByteAlignment(1); * JAVA_CHAR.withByteAlignment(1);
* } * }
* @apiNote Care should be taken when using unaligned value layouts as they may induce * @apiNote Care should be taken when using unaligned value layouts as they may
* performance and portability issues. * induce performance and portability issues.
*/ */
OfChar JAVA_CHAR_UNALIGNED = JAVA_CHAR.withByteAlignment(1); OfChar JAVA_CHAR_UNALIGNED = JAVA_CHAR.withByteAlignment(1);
@ -485,8 +499,8 @@ public sealed interface ValueLayout extends MemoryLayout
* {@snippet lang=java : * {@snippet lang=java :
* JAVA_SHORT.withByteAlignment(1); * JAVA_SHORT.withByteAlignment(1);
* } * }
* @apiNote Care should be taken when using unaligned value layouts as they may induce * @apiNote Care should be taken when using unaligned value layouts as they may
* performance and portability issues. * induce performance and portability issues.
*/ */
OfShort JAVA_SHORT_UNALIGNED = JAVA_SHORT.withByteAlignment(1); OfShort JAVA_SHORT_UNALIGNED = JAVA_SHORT.withByteAlignment(1);
@ -497,8 +511,8 @@ public sealed interface ValueLayout extends MemoryLayout
* {@snippet lang=java : * {@snippet lang=java :
* JAVA_INT.withByteAlignment(1); * JAVA_INT.withByteAlignment(1);
* } * }
* @apiNote Care should be taken when using unaligned value layouts as they may induce * @apiNote Care should be taken when using unaligned value layouts as they may
* performance and portability issues. * induce performance and portability issues.
*/ */
OfInt JAVA_INT_UNALIGNED = JAVA_INT.withByteAlignment(1); OfInt JAVA_INT_UNALIGNED = JAVA_INT.withByteAlignment(1);
@ -509,8 +523,8 @@ public sealed interface ValueLayout extends MemoryLayout
* {@snippet lang=java : * {@snippet lang=java :
* JAVA_LONG.withByteAlignment(1); * JAVA_LONG.withByteAlignment(1);
* } * }
* @apiNote Care should be taken when using unaligned value layouts as they may induce * @apiNote Care should be taken when using unaligned value layouts as they may
* performance and portability issues. * induce performance and portability issues.
*/ */
OfLong JAVA_LONG_UNALIGNED = JAVA_LONG.withByteAlignment(1); OfLong JAVA_LONG_UNALIGNED = JAVA_LONG.withByteAlignment(1);
@ -521,8 +535,8 @@ public sealed interface ValueLayout extends MemoryLayout
* {@snippet lang=java : * {@snippet lang=java :
* JAVA_FLOAT.withByteAlignment(1); * JAVA_FLOAT.withByteAlignment(1);
* } * }
* @apiNote Care should be taken when using unaligned value layouts as they may induce * @apiNote Care should be taken when using unaligned value layouts as they may
* performance and portability issues. * induce performance and portability issues.
*/ */
OfFloat JAVA_FLOAT_UNALIGNED = JAVA_FLOAT.withByteAlignment(1); OfFloat JAVA_FLOAT_UNALIGNED = JAVA_FLOAT.withByteAlignment(1);
@ -533,8 +547,8 @@ public sealed interface ValueLayout extends MemoryLayout
* {@snippet lang=java : * {@snippet lang=java :
* JAVA_DOUBLE.withByteAlignment(1); * JAVA_DOUBLE.withByteAlignment(1);
* } * }
* @apiNote Care should be taken when using unaligned value layouts as they may induce * @apiNote Care should be taken when using unaligned value layouts as they may
* performance and portability issues. * induce performance and portability issues.
*/ */
OfDouble JAVA_DOUBLE_UNALIGNED = JAVA_DOUBLE.withByteAlignment(1); OfDouble JAVA_DOUBLE_UNALIGNED = JAVA_DOUBLE.withByteAlignment(1);

View file

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

View file

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