8319324: FFM: Reformat javadocs
Reviewed-by: mcimadamore
This commit is contained in:
parent
a3f1b33b9b
commit
f939542104
@ -35,23 +35,27 @@ import java.nio.ByteOrder;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* A value layout used to model the address of some region of memory. The carrier associated with an address layout is
|
||||
* {@code MemorySegment.class}. The size and alignment of an address layout are platform-dependent
|
||||
* (e.g. on a 64-bit platform, the size and alignment of an address layout are set to 8 bytes).
|
||||
* A value layout used to model the address of some region of memory. The carrier
|
||||
* associated with an address layout is {@code MemorySegment.class}. The size and
|
||||
* alignment of an address layout are platform-dependent (e.g. on a 64-bit platform,
|
||||
* the size and alignment of an address layout are set to 8 bytes).
|
||||
* <p>
|
||||
* An address layout may optionally feature a {@linkplain #targetLayout() target layout}. An address layout with
|
||||
* target layout {@code T} can be used to model the address of a region of memory whose layout is {@code T}.
|
||||
* For instance, an address layout with target layout {@link ValueLayout#JAVA_INT} can be used to model the address
|
||||
* of a region of memory that is 4 bytes long. Specifying a target layout can be useful in the following situations:
|
||||
* An address layout may optionally feature a {@linkplain #targetLayout() target layout}.
|
||||
* An address layout with target layout {@code T} can be used to model the address of a
|
||||
* region of memory whose layout is {@code T}. For instance, an address layout with
|
||||
* target layout {@link ValueLayout#JAVA_INT} can be used to model the address of a
|
||||
* region of memory that is 4 bytes long. Specifying a target layout can be useful in
|
||||
* the following situations:
|
||||
* <ul>
|
||||
* <li>When accessing a memory segment that has been obtained by reading an address from another
|
||||
* memory segment, e.g. using {@link MemorySegment#getAtIndex(AddressLayout, long)};</li>
|
||||
* <li>When accessing a memory segment that has been obtained by reading an address from
|
||||
* another memory segment, e.g. using {@link MemorySegment#getAtIndex(AddressLayout, long)};</li>
|
||||
* <li>When creating a downcall method handle, using {@link Linker#downcallHandle(FunctionDescriptor, Option...)};
|
||||
* <li>When creating an upcall stub, using {@link Linker#upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...)}.
|
||||
* </ul>
|
||||
*
|
||||
* @implSpec
|
||||
* Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
* Implementations of this interface are immutable, thread-safe and
|
||||
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @see #ADDRESS
|
||||
* @see #ADDRESS_UNALIGNED
|
||||
@ -84,24 +88,28 @@ public sealed interface AddressLayout extends ValueLayout permits ValueLayouts.O
|
||||
AddressLayout withOrder(ByteOrder order);
|
||||
|
||||
/**
|
||||
* Returns an address layout with the same carrier, alignment constraint, name and order as this address layout,
|
||||
* but associated with the specified target layout. The returned address layout allows raw addresses to be accessed
|
||||
* as {@linkplain MemorySegment memory segments} whose size is set to the size of the specified layout. Moreover,
|
||||
* if the accessed raw address is not compatible with the alignment constraint in the provided layout,
|
||||
* {@linkplain IllegalArgumentException} will be thrown.
|
||||
* Returns an address layout with the same carrier, alignment constraint, name and
|
||||
* order as this address layout, but associated with the specified target layout.
|
||||
* The returned address layout allows raw addresses to be accessed as
|
||||
* {@linkplain MemorySegment memory segments} whose size is set to the size of the
|
||||
* specified layout. Moreover, if the accessed raw address is not compatible with
|
||||
* the alignment constraint in the provided layout, {@linkplain IllegalArgumentException}
|
||||
* will be thrown.
|
||||
* @apiNote
|
||||
* This method can also be used to create an address layout which, when used, creates native memory
|
||||
* segments with maximal size (e.g. {@linkplain Long#MAX_VALUE}). This can be done by using a target sequence
|
||||
* layout with unspecified size, as follows:
|
||||
* This method can also be used to create an address layout which, when used, creates
|
||||
* native memory segments with maximal size (e.g. {@linkplain Long#MAX_VALUE}). This
|
||||
* can be done by using a target sequence layout with unspecified size, as follows:
|
||||
* {@snippet lang = java:
|
||||
* AddressLayout addressLayout = ...
|
||||
* AddressLayout unboundedLayout = addressLayout.withTargetLayout(
|
||||
* MemoryLayout.sequenceLayout(Long.MAX_VALUE, ValueLayout.JAVA_BYTE));
|
||||
*}
|
||||
*
|
||||
* @param layout the target layout.
|
||||
* @return an address layout with the same characteristics as this layout, but with the provided target layout.
|
||||
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled
|
||||
* @param layout the target layout
|
||||
* @return an address layout with same characteristics as this layout, but with the
|
||||
* provided target layout
|
||||
* @throws IllegalCallerException If the caller is in a module that does not have
|
||||
* native access enabled
|
||||
* @see #targetLayout()
|
||||
*/
|
||||
@CallerSensitive
|
||||
@ -109,18 +117,20 @@ public sealed interface AddressLayout extends ValueLayout permits ValueLayouts.O
|
||||
AddressLayout withTargetLayout(MemoryLayout layout);
|
||||
|
||||
/**
|
||||
* Returns an address layout with the same carrier, alignment constraint, name and order as this address layout,
|
||||
* but with no target layout.
|
||||
* Returns an address layout with the same carrier, alignment constraint, name and
|
||||
* order as this address layout, but with no target layout.
|
||||
*
|
||||
* @apiNote This can be useful to compare two address layouts that have different target layouts, but are otherwise equal.
|
||||
* @apiNote This can be useful to compare two address layouts that have different
|
||||
* target layouts, but are otherwise equal.
|
||||
*
|
||||
* @return an address layout with the same characteristics as this layout, but with no target layout.
|
||||
* @return an address layout with same characteristics as this layout, but with no
|
||||
* target layout
|
||||
* @see #targetLayout()
|
||||
*/
|
||||
AddressLayout withoutTargetLayout();
|
||||
|
||||
/**
|
||||
* {@return the target layout associated with this address layout (if any)}.
|
||||
* {@return the target layout associated with this address layout (if any)}
|
||||
*/
|
||||
Optional<MemoryLayout> targetLayout();
|
||||
|
||||
|
@ -31,47 +31,53 @@ import jdk.internal.ref.CleanerFactory;
|
||||
import java.lang.foreign.MemorySegment.Scope;
|
||||
|
||||
/**
|
||||
* An arena controls the lifecycle of native memory segments, providing both flexible allocation and timely deallocation.
|
||||
* An arena controls the lifecycle of native memory segments, providing both flexible
|
||||
* allocation and timely deallocation.
|
||||
* <p>
|
||||
* An arena has a {@linkplain MemorySegment.Scope scope} - the <em>arena scope</em>. All the segments allocated
|
||||
* by the arena are associated with the arena scope. As such, the arena determines the temporal bounds
|
||||
* of all the memory segments allocated by it.
|
||||
* An arena has a {@linkplain MemorySegment.Scope scope} - the <em>arena scope</em>.
|
||||
* All the segments allocated by the arena are associated with the arena scope. As such,
|
||||
* the arena determines the temporal bounds of all the memory segments allocated by it.
|
||||
* <p>
|
||||
* Moreover, an arena also determines whether access to memory segments allocated by it should be
|
||||
* {@linkplain MemorySegment#isAccessibleBy(Thread) restricted} to specific threads.
|
||||
* An arena is a {@link SegmentAllocator} and features several allocation methods that can be used by clients
|
||||
* to obtain native segments.
|
||||
* Moreover, an arena also determines whether access to memory segments allocated by it
|
||||
* should be {@linkplain MemorySegment#isAccessibleBy(Thread) restricted} to specific
|
||||
* threads. An arena is a {@link SegmentAllocator} and features several allocation
|
||||
* methods that can be used by clients to obtain native segments.
|
||||
* <p>
|
||||
* The simplest arena is the {@linkplain Arena#global() global arena}. The global arena
|
||||
* features an <em>unbounded lifetime</em>. The scope of the global arena is the global scope.
|
||||
* As such, native segments allocated with the global arena are always accessible and their backing regions
|
||||
* of memory are never deallocated.
|
||||
* Moreover, memory segments allocated with the global arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread.
|
||||
* features an <em>unbounded lifetime</em>. The scope of the global arena is the global
|
||||
* scope. As such, native segments allocated with the global arena are always accessible
|
||||
* and their backing regions of memory are never deallocated. Moreover, memory segments
|
||||
* allocated with the global arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed}
|
||||
* from any thread.
|
||||
* {@snippet lang = java:
|
||||
* MemorySegment segment = Arena.global().allocate(100, 1); // @highlight regex='global()'
|
||||
* ...
|
||||
* // segment is never deallocated!
|
||||
*}
|
||||
* <p>
|
||||
* Alternatively, clients can obtain an {@linkplain Arena#ofAuto() automatic arena}, that is an arena
|
||||
* which features a <em>bounded lifetime</em> that is managed, automatically, by the garbage collector. The scope
|
||||
* of an automatic arena is an automatic scope. As such, the regions
|
||||
* of memory backing memory segments allocated with the automatic arena are deallocated at some unspecified time
|
||||
* <em>after</em> the automatic arena (and all the segments allocated by it) becomes
|
||||
* <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>, as shown below:
|
||||
* Alternatively, clients can obtain an {@linkplain Arena#ofAuto() automatic arena}, that
|
||||
* is an arena which features a <em>bounded lifetime</em> that is managed, automatically,
|
||||
* by the garbage collector. The scope of an automatic arena is an automatic scope. As
|
||||
* such, the regions of memory backing memory segments allocated with the automatic arena
|
||||
* are deallocated at some unspecified time <em>after</em> the automatic arena (and all
|
||||
* the segments allocated by it) becomes <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>,
|
||||
* as shown below:
|
||||
* {@snippet lang = java:
|
||||
* MemorySegment segment = Arena.ofAuto().allocate(100, 1); // @highlight regex='ofAuto()'
|
||||
* ...
|
||||
* segment = null; // the segment region becomes available for deallocation after this point
|
||||
*}
|
||||
* Memory segments allocated with an automatic arena can also be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread.
|
||||
* Memory segments allocated with an automatic arena can also be
|
||||
* {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread.
|
||||
* <p>
|
||||
* Rather than leaving deallocation in the hands of the Java runtime, clients will often wish to exercise control over
|
||||
* the timing of deallocation for regions of memory that back memory segments. Two kinds of arenas support this,
|
||||
* namely {@linkplain #ofConfined() confined} and {@linkplain #ofShared() shared} arenas. They both feature
|
||||
* bounded lifetimes that are managed manually. For instance, when a confined arena is {@linkplain #close() closed}
|
||||
* successfully, its scope is {@linkplain Scope#isAlive() invalidated}. As a result, all the memory segments allocated
|
||||
* by the arena can no longer be accessed, and their regions of memory are deallocated:
|
||||
* Rather than leaving deallocation in the hands of the Java runtime, clients will often
|
||||
* wish to exercise control over the timing of deallocation for regions of memory that
|
||||
* back memory segments. Two kinds of arenas support this, namely {@linkplain #ofConfined() confined}
|
||||
* and {@linkplain #ofShared() shared} arenas. They both feature bounded lifetimes that
|
||||
* are managed manually. For instance, when a confined arena is {@linkplain #close() closed}
|
||||
* successfully, its scope is {@linkplain Scope#isAlive() invalidated}. As a result, all
|
||||
* the memory segments allocated by the arena can no longer be accessed, and their
|
||||
* regions of memory are deallocated:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* MemorySegment segment = null;
|
||||
@ -82,9 +88,10 @@ import java.lang.foreign.MemorySegment.Scope;
|
||||
* segment.get(ValueLayout.JAVA_BYTE, 0); // throws IllegalStateException
|
||||
*}
|
||||
*
|
||||
* Memory segments allocated with a {@linkplain #ofConfined() confined arena} can only be accessed (and closed) by the
|
||||
* thread that created the arena. If access to a memory segment from multiple threads is required, clients can allocate
|
||||
* segments in a {@linkplain #ofShared() shared arena} instead.
|
||||
* Memory segments allocated with a {@linkplain #ofConfined() confined arena} can only be
|
||||
* accessed (and closed) by the thread that created the arena. If access to a memory
|
||||
* segment from multiple threads is required, clients can allocate segments in a
|
||||
* {@linkplain #ofShared() shared arena} instead.
|
||||
* <p>
|
||||
* The characteristics of the various arenas are summarized in the following table:
|
||||
*
|
||||
@ -120,38 +127,45 @@ import java.lang.foreign.MemorySegment.Scope;
|
||||
*
|
||||
* <h2 id = "thread-confinement">Safety and thread-confinement</h2>
|
||||
*
|
||||
* Arenas provide strong temporal safety guarantees: a memory segment allocated by an arena cannot be accessed
|
||||
* <em>after</em> the arena has been closed. The cost of providing this guarantee varies based on the
|
||||
* number of threads that have access to the memory segments allocated by the arena. For instance, if an arena
|
||||
* is always created and closed by one thread, and the memory segments allocated by the arena are always
|
||||
* Arenas provide strong temporal safety guarantees: a memory segment allocated by an
|
||||
* arena cannot be accessed <em>after</em> the arena has been closed. The cost of
|
||||
* providing this guarantee varies based on the number of threads that have access to the
|
||||
* memory segments allocated by the arena. For instance, if an arena is always created
|
||||
* and closed by one thread, and the memory segments allocated by the arena are always
|
||||
* accessed by that same thread, then ensuring correctness is trivial.
|
||||
* <p>
|
||||
* Conversely, if an arena allocates segments that can be accessed by multiple threads, or if the arena can be closed
|
||||
* by a thread other than the accessing thread, then ensuring correctness is much more complex. For example, a segment
|
||||
* allocated with the arena might be accessed <em>while</em> another thread attempts, concurrently, to close the arena.
|
||||
* To provide the strong temporal safety guarantee without forcing every client, even simple ones, to incur a performance
|
||||
* impact, arenas are divided into <em>thread-confined</em> arenas, and <em>shared</em> arenas.
|
||||
* Conversely, if an arena allocates segments that can be accessed by multiple threads,
|
||||
* or if the arena can be closed by a thread other than the accessing thread, then
|
||||
* ensuring correctness is much more complex. For example, a segment allocated with the
|
||||
* arena might be accessed <em>while</em> another thread attempts, concurrently, to close
|
||||
* the arena. To provide the strong temporal safety guarantee without forcing every
|
||||
* client, even simple ones, to incur a performance impact, arenas are divided into
|
||||
* <em>thread-confined</em> arenas, and <em>shared</em> arenas.
|
||||
* <p>
|
||||
* Confined arenas, support strong thread-confinement guarantees. Upon creation, they are assigned an
|
||||
* <em>owner thread</em>, typically the thread which initiated the creation operation.
|
||||
* The segments created by a confined arena can only be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed}
|
||||
* by the owner thread. Moreover, any attempt to close the confined arena from a thread other than the owner thread will
|
||||
* fail with {@link WrongThreadException}.
|
||||
* Confined arenas, support strong thread-confinement guarantees. Upon creation, they are
|
||||
* assigned an <em>owner thread</em>, typically the thread which initiated the creation
|
||||
* operation. The segments created by a confined arena can only be
|
||||
* {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the owner thread.
|
||||
* Moreover, any attempt to close the confined arena from a thread other than the owner
|
||||
* thread will fail with a {@link WrongThreadException}.
|
||||
* <p>
|
||||
* Shared arenas, on the other hand, have no owner thread. The segments created by a shared arena
|
||||
* can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. This might be useful when
|
||||
* multiple threads need to access the same memory segment concurrently (e.g. in the case of parallel processing).
|
||||
* Moreover, a shared arena can be closed by any thread.
|
||||
* Shared arenas, on the other hand, have no owner thread. The segments created by a
|
||||
* shared arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by
|
||||
* any thread. This might be useful when multiple threads need to access the same memory
|
||||
* segment concurrently (e.g. in the case of parallel processing). Moreover, a shared
|
||||
* arena can be closed by any thread.
|
||||
*
|
||||
* <h2 id = "custom-arenas">Custom arenas</h2>
|
||||
*
|
||||
* Clients can define custom arenas to implement more efficient allocation strategies, or to have better control over
|
||||
* when (and by whom) an arena can be closed. As an example, the following code defines a <em>slicing arena</em> that behaves
|
||||
* like a confined arena (i.e., single-threaded access), but internally uses a
|
||||
* {@linkplain SegmentAllocator#slicingAllocator(MemorySegment) slicing allocator} to respond to allocation requests.
|
||||
* When the slicing arena is closed, the underlying confined arena is also closed; this will invalidate all segments
|
||||
* allocated with the slicing arena (since the scope of the slicing arena is the same as that of the underlying
|
||||
* confined arena):
|
||||
* Clients can define custom arenas to implement more efficient allocation strategies,
|
||||
* or to have better control over when (and by whom) an arena can be closed. As an
|
||||
* example, the following code defines a <em>slicing arena</em> that behaves like a
|
||||
* confined arena (i.e., single-threaded access), but internally uses a
|
||||
* {@linkplain SegmentAllocator#slicingAllocator(MemorySegment) slicing allocator} to
|
||||
* respond to allocation requests.
|
||||
* When the slicing arena is closed, the underlying confined arena is also closed; this
|
||||
* will invalidate all segments allocated with the slicing arena (since the scope of the
|
||||
* slicing arena is the same as that of the underlying confined arena):
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* class SlicingArena implements Arena {
|
||||
@ -177,8 +191,9 @@ import java.lang.foreign.MemorySegment.Scope;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* In other words, a slicing arena provides a vastly more efficient and scalable allocation strategy, while still retaining
|
||||
* the timely deallocation guarantee provided by the underlying confined arena:
|
||||
* In other words, a slicing arena provides a vastly more efficient and scalable
|
||||
* allocation strategy, while still retaining the timely deallocation guarantee provided
|
||||
* by the underlying confined arena:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* try (Arena slicingArena = new SlicingArena(1000)) {
|
||||
@ -204,18 +219,17 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
|
||||
* {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
|
||||
* Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}.
|
||||
*
|
||||
* @return a new arena that is managed, automatically, by the garbage collector.
|
||||
* @return a new arena that is managed, automatically, by the garbage collector
|
||||
*/
|
||||
static Arena ofAuto() {
|
||||
return MemorySessionImpl.createImplicit(CleanerFactory.cleaner()).asArena();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the global arena. Segments allocated with the global arena can be
|
||||
* {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
|
||||
* Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}.
|
||||
*
|
||||
* @return the global arena.
|
||||
* {@return the global arena} Segments allocated with the global arena can be
|
||||
* {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
|
||||
* Calling {@link #close()} on the returned arena will result in
|
||||
* an {@link UnsupportedOperationException}.
|
||||
*/
|
||||
static Arena global() {
|
||||
class Holder {
|
||||
@ -226,8 +240,8 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
|
||||
|
||||
/**
|
||||
* {@return a new confined arena} Segments allocated with the confined arena can be
|
||||
* {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the thread that created the arena,
|
||||
* the arena's <em>owner thread</em>.
|
||||
* {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the thread
|
||||
* that created the arena, the arena's <em>owner thread</em>.
|
||||
*/
|
||||
static Arena ofConfined() {
|
||||
return MemorySessionImpl.createConfined(Thread.currentThread()).asArena();
|
||||
@ -235,36 +249,40 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
|
||||
|
||||
/**
|
||||
* {@return a new shared arena} Segments allocated with the global arena can be
|
||||
* {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
|
||||
* {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread.
|
||||
*/
|
||||
static Arena ofShared() {
|
||||
return MemorySessionImpl.createShared().asArena();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a native memory segment with the given size (in bytes) and alignment constraint (in bytes).
|
||||
* Returns a native memory segment with the given size (in bytes) and alignment
|
||||
* constraint (in bytes).
|
||||
* The returned segment is associated with this {@linkplain #scope() arena scope}.
|
||||
* The segment's {@link MemorySegment#address() address} is the starting address of the
|
||||
* allocated off-heap region of memory backing the segment, and the address is
|
||||
* aligned according to the provided alignment constraint.
|
||||
* The segment's {@link MemorySegment#address() address} is the starting address of
|
||||
* the allocated off-heap region of memory backing the segment, and the address is
|
||||
* aligned according the provided alignment constraint.
|
||||
*
|
||||
* @implSpec
|
||||
* Implementations of this method must return a native segment featuring the requested size,
|
||||
* and that is compatible with the provided alignment constraint. Furthermore, for any two segments
|
||||
* {@code S1, S2} returned by this method, the following invariant must hold:
|
||||
* Implementations of this method must return a native segment featuring the
|
||||
* requested size, and that is compatible with the provided alignment constraint.
|
||||
* Furthermore, for any two segments {@code S1, S2} returned by this method, the
|
||||
* following invariant must hold:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* S1.asOverlappingSlice(S2).isEmpty() == true
|
||||
* }
|
||||
*
|
||||
* @param byteSize the size (in bytes) of the off-heap region of memory backing the native memory segment.
|
||||
* @param byteAlignment the alignment constraint (in bytes) of the off-heap region of memory backing the native memory segment.
|
||||
* @return a new native memory segment.
|
||||
* @param byteSize the size (in bytes) of the off-heap region of memory backing
|
||||
* the native memory segment
|
||||
* @param byteAlignment the alignment constraint (in bytes) of the off-heap region
|
||||
* of memory backing the native memory segment
|
||||
* @return a new native memory segment
|
||||
* @throws IllegalArgumentException if {@code bytesSize < 0}, {@code byteAlignment <= 0},
|
||||
* or if {@code byteAlignment} is not a power of 2
|
||||
* @throws IllegalStateException if this arena has already been {@linkplain #close() closed}
|
||||
* @throws WrongThreadException if this arena is confined, and this method is called from a thread
|
||||
* other than the arena's owner thread
|
||||
* @throws WrongThreadException if this arena is confined, and this method is called
|
||||
* from a thread other than the arena's owner thread
|
||||
*/
|
||||
@Override
|
||||
MemorySegment allocate(long byteSize, long byteAlignment);
|
||||
@ -275,25 +293,29 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
|
||||
Scope scope();
|
||||
|
||||
/**
|
||||
* Closes this arena. If this method completes normally, the arena scope is no longer {@linkplain Scope#isAlive() alive},
|
||||
* and all the memory segments associated with it can no longer be accessed. Furthermore, any off-heap region of memory backing the
|
||||
* Closes this arena. If this method completes normally, the arena scope is no longer
|
||||
* {@linkplain Scope#isAlive() alive}, and all the memory segments associated with it
|
||||
* can no longer be accessed. Furthermore, any off-heap region of memory backing the
|
||||
* segments obtained from this arena are also released.
|
||||
*
|
||||
* @apiNote This operation is not idempotent; that is, closing an already closed arena <em>always</em> results in an
|
||||
* exception being thrown. This reflects a deliberate design choice: failure to close an arena might reveal a bug
|
||||
* in the underlying application logic.
|
||||
* @apiNote This operation is not idempotent; that is, closing an already closed arena
|
||||
* <em>always</em> results in an exception being thrown. This reflects a
|
||||
* deliberate design choice: failure to close an arena might reveal a bug
|
||||
* in the underlying application logic.
|
||||
*
|
||||
* @implSpec If this method completes normally, then {@code this.scope().isAlive() == false}.
|
||||
* Implementations are allowed to throw {@link UnsupportedOperationException} if an explicit close operation is
|
||||
* not supported.
|
||||
* @implSpec If this method completes normally, then
|
||||
* {@code this.scope().isAlive() == false}.
|
||||
* Implementations are allowed to throw {@link UnsupportedOperationException}
|
||||
* if an explicit close operation is not supported.
|
||||
*
|
||||
* @see Scope#isAlive()
|
||||
*
|
||||
* @throws IllegalStateException if the arena has already been closed
|
||||
* @throws IllegalStateException if a segment associated with this arena is being accessed concurrently, e.g.
|
||||
* by a {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle}
|
||||
* @throws WrongThreadException if this arena is confined, and this method is called from a thread
|
||||
* other than the arena's owner thread
|
||||
* @throws IllegalStateException if a segment associated with this arena is being
|
||||
* accessed concurrently, e.g. by a
|
||||
* {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle}
|
||||
* @throws WrongThreadException if this arena is confined, and this method is called
|
||||
* from a thread other than the arena's owner thread
|
||||
* @throws UnsupportedOperationException if this arena cannot be closed explicitly
|
||||
*/
|
||||
@Override
|
||||
|
@ -34,13 +34,16 @@ import java.util.List;
|
||||
import jdk.internal.foreign.FunctionDescriptorImpl;
|
||||
|
||||
/**
|
||||
* A function descriptor models the signature of a foreign function. A function descriptor is made up of zero or more
|
||||
* argument layouts, and zero or one return layout. A function descriptor is used to create
|
||||
* {@linkplain Linker#downcallHandle(MemorySegment, FunctionDescriptor, Linker.Option...) downcall method handles} and
|
||||
* A function descriptor models the signature of a foreign function. A function
|
||||
* descriptor is made up of zero or more argument layouts, and zero or one return layout.
|
||||
* A function descriptor is used to create
|
||||
* {@linkplain Linker#downcallHandle(MemorySegment, FunctionDescriptor, Linker.Option...) downcall method handles}
|
||||
* and
|
||||
* {@linkplain Linker#upcallStub(MethodHandle, FunctionDescriptor, Arena, Linker.Option...) upcall stubs}.
|
||||
*
|
||||
* @implSpec
|
||||
* Implementing classes are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
* Implementing classes are immutable, thread-safe and
|
||||
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @see MemoryLayout
|
||||
* @since 22
|
||||
@ -53,35 +56,39 @@ public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
|
||||
Optional<MemoryLayout> returnLayout();
|
||||
|
||||
/**
|
||||
* {@return the argument layouts of this function descriptor (as an unmodifiable list)}.
|
||||
* {@return the argument layouts of this function descriptor (as an unmodifiable list)}
|
||||
*/
|
||||
List<MemoryLayout> argumentLayouts();
|
||||
|
||||
/**
|
||||
* Returns a function descriptor with the given argument layouts appended to the argument layouts
|
||||
* of this function descriptor.
|
||||
* @param addedLayouts the argument layouts to append.
|
||||
* @throws IllegalArgumentException if one of the layouts in {@code addedLayouts} is a padding layout
|
||||
* @return a new function descriptor, with the provided additional argument layouts.
|
||||
* Returns a function descriptor with the given argument layouts appended to the
|
||||
* argument layouts of this function descriptor.
|
||||
*
|
||||
* @param addedLayouts the argument layouts to append
|
||||
* @throws IllegalArgumentException if one of the layouts in {@code addedLayouts} is
|
||||
* a padding layout
|
||||
* @return a new function descriptor, with the provided additional argument layouts
|
||||
*/
|
||||
FunctionDescriptor appendArgumentLayouts(MemoryLayout... addedLayouts);
|
||||
|
||||
/**
|
||||
* Returns a function descriptor with the given argument layouts inserted at the given index, into the argument
|
||||
* layout array of this function descriptor.
|
||||
* Returns a function descriptor with the given argument layouts inserted at the
|
||||
* given index, into the argument layout array of this function descriptor.
|
||||
*
|
||||
* @param index the index at which to insert the arguments
|
||||
* @param addedLayouts the argument layouts to insert at the given index.
|
||||
* @return a new function descriptor, with the provided additional argument layouts.
|
||||
* @throws IllegalArgumentException if one of the layouts in {@code addedLayouts} is a padding layout
|
||||
* @param addedLayouts the argument layouts to insert at given index
|
||||
* @return a new function descriptor, with the provided additional argument layouts
|
||||
* @throws IllegalArgumentException if one of the layouts in {@code addedLayouts}
|
||||
* is a padding layout
|
||||
* @throws IllegalArgumentException if {@code index < 0 || index > argumentLayouts().size()}
|
||||
*/
|
||||
FunctionDescriptor insertArgumentLayouts(int index, MemoryLayout... addedLayouts);
|
||||
|
||||
/**
|
||||
* Returns a function descriptor with the provided return layout.
|
||||
* @param newReturn the new return layout.
|
||||
* @param newReturn the new return layout
|
||||
* @throws IllegalArgumentException if {@code newReturn} is a padding layout
|
||||
* @return a new function descriptor, with the provided return layout.
|
||||
* @return a new function descriptor, with the provided return layout
|
||||
*/
|
||||
FunctionDescriptor changeReturnLayout(MemoryLayout newReturn);
|
||||
|
||||
@ -91,28 +98,35 @@ public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
|
||||
FunctionDescriptor dropReturnLayout();
|
||||
|
||||
/**
|
||||
* Returns the method type consisting of the carrier types of the layouts in this function descriptor.
|
||||
* Returns the method type consisting of the carrier types of the layouts in this
|
||||
* function descriptor.
|
||||
* <p>
|
||||
* The carrier type of a layout {@code L} is determined as follows:
|
||||
* <ul>
|
||||
* <li>If {@code L} is a {@link ValueLayout} the carrier type is determined through {@link ValueLayout#carrier()}.</li>
|
||||
* <li>If {@code L} is a {@link GroupLayout} or a {@link SequenceLayout}, the carrier type is {@link MemorySegment}.</li>
|
||||
* <li>If {@code L} is a {@link ValueLayout} the carrier type is
|
||||
* determined through {@link ValueLayout#carrier()}.</li>
|
||||
* <li>If {@code L} is a {@link GroupLayout} or a {@link SequenceLayout},
|
||||
* the carrier type is {@link MemorySegment}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @apiNote A function descriptor cannot, by construction, contain any padding layouts. As such, it is not
|
||||
* necessary to specify how padding layouts should be mapped to carrier types.
|
||||
* @apiNote A function descriptor cannot, by construction, contain any padding
|
||||
* layouts. As such, it is not necessary to specify how padding layout
|
||||
* should be mapped to carrier types.
|
||||
*
|
||||
* @return the method type consisting of the carrier types of the layouts in this function descriptor.
|
||||
* @return the method type consisting of the carrier types of the layouts in this
|
||||
* function descriptor
|
||||
*/
|
||||
MethodType toMethodType();
|
||||
|
||||
/**
|
||||
* Creates a function descriptor with the given return and argument layouts.
|
||||
* @param resLayout the return layout.
|
||||
* @param argLayouts the argument layouts.
|
||||
*
|
||||
* @param resLayout the return layout
|
||||
* @param argLayouts the argument layouts
|
||||
* @throws IllegalArgumentException if {@code resLayout} is a padding layout
|
||||
* @throws IllegalArgumentException if one of the layouts in {@code argLayouts} is a padding layout
|
||||
* @return a new function descriptor with the provided return and argument layouts.
|
||||
* @throws IllegalArgumentException if one of the layouts in {@code argLayouts}
|
||||
* is a padding layout
|
||||
* @return a new function descriptor with the provided return and argument layouts
|
||||
*/
|
||||
static FunctionDescriptor of(MemoryLayout resLayout, MemoryLayout... argLayouts) {
|
||||
Objects.requireNonNull(resLayout);
|
||||
@ -121,11 +135,13 @@ public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a function descriptor with the given argument layouts and no return layout. This is useful for modeling functions
|
||||
* that return no values.
|
||||
* @param argLayouts the argument layouts.
|
||||
* @throws IllegalArgumentException if one of the layouts in {@code argLayouts} is a padding layout
|
||||
* @return a new function descriptor with the provided argument layouts.
|
||||
* Creates a function descriptor with the given argument layouts and no return
|
||||
* layout. This is useful to model functions that return no values.
|
||||
*
|
||||
* @param argLayouts the argument layouts
|
||||
* @throws IllegalArgumentException if one of the layouts in {@code argLayouts}
|
||||
* is a padding layout
|
||||
* @return a new function descriptor with the provided argument layouts
|
||||
*/
|
||||
static FunctionDescriptor ofVoid(MemoryLayout... argLayouts) {
|
||||
// Null checks are implicit in List.of(argLayouts)
|
||||
|
@ -28,13 +28,16 @@ package java.lang.foreign;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A compound layout that is an aggregation of multiple, heterogeneous <em>member layouts</em>. There are two ways in which member layouts
|
||||
* can be combined: if member layouts are laid out one after the other, the resulting group layout is a
|
||||
* {@linkplain StructLayout struct layout}; conversely, if all member layouts are laid out at the same starting offset,
|
||||
* the resulting group layout is a {@linkplain UnionLayout union layout}.
|
||||
* A compound layout that is an aggregation of multiple, heterogeneous
|
||||
* <em>member layouts</em>. There are two ways in which member layouts can be combined:
|
||||
* if member layouts are laid out one after the other, the resulting group layout is a
|
||||
* {@linkplain StructLayout struct layout}; conversely, if all member layouts are laid
|
||||
* out at the same starting offset, the resulting group layout is a
|
||||
* {@linkplain UnionLayout union layout}.
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
* This class is immutable, thread-safe and
|
||||
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @sealedGraph
|
||||
* @since 22
|
||||
@ -44,9 +47,10 @@ public sealed interface GroupLayout extends MemoryLayout permits StructLayout, U
|
||||
/**
|
||||
* {@return the member layouts of this group layout}
|
||||
*
|
||||
* @apiNote the order in which member layouts are returned in the same order in which member layouts have
|
||||
* been passed to one of the group layout factory methods (see {@link MemoryLayout#structLayout(MemoryLayout...)},
|
||||
* {@link MemoryLayout#unionLayout(MemoryLayout...)}).
|
||||
* @apiNote the order in which member layouts are returned is the same order in which
|
||||
* member layouts have been passed to one of the group layout factory methods
|
||||
* (see {@link MemoryLayout#structLayout(MemoryLayout...)} and
|
||||
* {@link MemoryLayout#unionLayout(MemoryLayout...)}).
|
||||
*/
|
||||
List<MemoryLayout> memberLayouts();
|
||||
|
||||
@ -65,8 +69,9 @@ public sealed interface GroupLayout extends MemoryLayout permits StructLayout, U
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws IllegalArgumentException {@inheritDoc}
|
||||
* @throws IllegalArgumentException if {@code byteAlignment} is less than {@code M}, where {@code M} is
|
||||
* the maximum alignment constraint in any of the member layouts associated with this group layout
|
||||
* @throws IllegalArgumentException if {@code byteAlignment} is less than {@code M},
|
||||
* where {@code M} is the maximum alignment constraint in any of the
|
||||
* member layouts associated with this group layout
|
||||
*/
|
||||
@Override
|
||||
GroupLayout withByteAlignment(long byteAlignment);
|
||||
|
@ -41,42 +41,49 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* A linker provides access to foreign functions from Java code, and access to Java code from foreign functions.
|
||||
* A linker provides access to foreign functions from Java code, and access to Java code
|
||||
* from foreign functions.
|
||||
* <p>
|
||||
* Foreign functions typically reside in libraries that can be loaded on demand. Each library conforms to
|
||||
* a specific ABI (Application Binary Interface). An ABI is a set of calling conventions and data types associated with
|
||||
* the compiler, OS, and processor where the library was built. For example, a C compiler on Linux/x64 usually
|
||||
* builds libraries that conform to the SystemV ABI.
|
||||
* Foreign functions typically reside in libraries that can be loaded on demand. Each
|
||||
* library conforms to a specific ABI (Application Binary Interface). An ABI is a set of
|
||||
* calling conventions and data types associated with the compiler, OS, and processor where
|
||||
* the library was built. For example, a C compiler on Linux/x64 usually builds libraries
|
||||
* that conform to the SystemV ABI.
|
||||
* <p>
|
||||
* A linker has detailed knowledge of the calling conventions and data types used by a specific ABI.
|
||||
* For any library that conforms to that ABI, the linker can mediate between Java code running
|
||||
* in the JVM and foreign functions in the library. In particular:
|
||||
* A linker has detailed knowledge of the calling conventions and data types used by a
|
||||
* specific ABI. For any library that conforms to that ABI, the linker can mediate
|
||||
* between Java code running in the JVM and foreign functions in the library. In
|
||||
* particular:
|
||||
* <ul>
|
||||
* <li>A linker allows Java code to link against foreign functions, via
|
||||
* {@linkplain #downcallHandle(MemorySegment, FunctionDescriptor, Option...) downcall method handles}; and</li>
|
||||
* <li>A linker allows foreign functions to call Java method handles,
|
||||
* via the generation of {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...) upcall stubs}.</li>
|
||||
* {@linkplain #downcallHandle(MemorySegment, FunctionDescriptor, Option...) downcall method handles};
|
||||
* and</li>
|
||||
* <li>A linker allows foreign functions to call Java method handles, via the generation
|
||||
* of {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...) upcall stubs}.</li>
|
||||
* </ul>
|
||||
* A linker provides a way to look up the <em>canonical layouts</em> associated with the data types used by the ABI.
|
||||
* For example, a linker implementing the C ABI might choose to provide a canonical layout for the C {@code size_t}
|
||||
* type. On 64-bit platforms, this canonical layout might be equal to {@link ValueLayout#JAVA_LONG}. The canonical
|
||||
* layouts supported by a linker are exposed via the {@link #canonicalLayouts()} method, which returns a map from
|
||||
* type names to canonical layouts.
|
||||
* A linker provides a way to look up the <em>canonical layouts</em> associated with the
|
||||
* data types used by the ABI. For example, a linker implementing the C ABI might choose
|
||||
* to provide a canonical layout for the C {@code size_t} type. On 64-bit platforms,
|
||||
* this canonical layout might be equal to {@link ValueLayout#JAVA_LONG}. The canonical
|
||||
* layouts supported by a linker are exposed via the {@link #canonicalLayouts()} method,
|
||||
* which returns a map from type names to canonical layouts.
|
||||
* <p>
|
||||
* In addition, a linker provides a way to look up foreign functions in libraries that conform to the ABI. Each linker
|
||||
* chooses a set of libraries that are commonly used on the OS and processor combination associated with the ABI.
|
||||
* For example, a linker for Linux/x64 might choose two libraries: {@code libc} and {@code libm}. The functions in these
|
||||
* libraries are exposed via a {@linkplain #defaultLookup() symbol lookup}.
|
||||
* In addition, a linker provides a way to look up foreign functions in libraries that
|
||||
* conform to the ABI. Each linker chooses a set of libraries that are commonly used on
|
||||
* the OS and processor combination associated with the ABI. For example, a linker for
|
||||
* Linux/x64 might choose two libraries: {@code libc} and {@code libm}. The functions in
|
||||
* these libraries are exposed via a {@linkplain #defaultLookup() symbol lookup}.
|
||||
*
|
||||
* <h2 id="native-linker">Calling native functions</h2>
|
||||
*
|
||||
* The {@linkplain #nativeLinker() native linker} can be used to link against functions
|
||||
* defined in C libraries (native functions). Suppose we wish to downcall from Java to the {@code strlen} function
|
||||
* defined in the standard C library:
|
||||
* defined in C libraries (native functions). Suppose we wish to downcall from Java to
|
||||
* the {@code strlen} function defined in the standard C library:
|
||||
* {@snippet lang = c:
|
||||
* size_t strlen(const char *s);
|
||||
* }
|
||||
* A downcall method handle that exposes {@code strlen} is obtained, using the native linker, as follows:
|
||||
* A downcall method handle that exposes {@code strlen} is obtained, using the native
|
||||
* linker, as follows:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* Linker linker = Linker.nativeLinker();
|
||||
@ -87,12 +94,12 @@ import java.util.stream.Stream;
|
||||
* }
|
||||
*
|
||||
* Note how the native linker also provides access, via its {@linkplain #defaultLookup() default lookup},
|
||||
* to the native functions defined by the C libraries loaded with the Java runtime. Above, the default lookup
|
||||
* is used to search the address of the {@code strlen} native function. That address is then passed, along with
|
||||
* a <em>platform-dependent description</em> of the signature of the function expressed as a
|
||||
* {@link FunctionDescriptor} (more on that below) to the native linker's
|
||||
* {@link #downcallHandle(MemorySegment, FunctionDescriptor, Option...)} method.
|
||||
* The obtained downcall method handle is then invoked as follows:
|
||||
* to the native functions defined by the C libraries loaded with the Java runtime.
|
||||
* Above, the default lookup is used to search the address of the {@code strlen} native
|
||||
* function. That address is then passed, along with a <em>platform-dependent description</em>
|
||||
* of the signature of the function expressed as a {@link FunctionDescriptor} (more on
|
||||
* that below) to the native linker's {@link #downcallHandle(MemorySegment, FunctionDescriptor, Option...)}
|
||||
* method. The obtained downcall method handle is then invoked as follows:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* try (Arena arena = Arena.ofConfined()) {
|
||||
@ -102,28 +109,34 @@ import java.util.stream.Stream;
|
||||
*}
|
||||
* <h3 id="describing-c-sigs">Describing C signatures</h3>
|
||||
*
|
||||
* When interacting with the native linker, clients must provide a platform-dependent description of the signature
|
||||
* of the C function they wish to link against. This description, a {@link FunctionDescriptor function descriptor},
|
||||
* defines the layouts associated with the parameter types and return type (if any) of the C function.
|
||||
* When interacting with the native linker, clients must provide a platform-dependent
|
||||
* description of the signature of the C function they wish to link against. This
|
||||
* description, a {@link FunctionDescriptor function descriptor}, defines the layouts
|
||||
* associated with the parameter types and return type (if any) of the C function.
|
||||
* <p>
|
||||
* Scalar C types such as {@code bool}, {@code int} are modeled as {@linkplain ValueLayout value layouts}
|
||||
* of a suitable carrier. The {@linkplain #canonicalLayouts() mapping} between a scalar type and its corresponding
|
||||
* Scalar C types such as {@code bool}, {@code int} are modeled as
|
||||
* {@linkplain ValueLayout value layouts} of a suitable carrier. The
|
||||
* {@linkplain #canonicalLayouts() mapping} between a scalar type and its corresponding
|
||||
* canonical layout is dependent on the ABI implemented by the native linker (see below).
|
||||
* <p>
|
||||
* Composite types are modeled as {@linkplain GroupLayout group layouts}. More specifically, a C {@code struct} type
|
||||
* maps to a {@linkplain StructLayout struct layout}, whereas a C {@code union} type maps to a {@link UnionLayout union
|
||||
* layout}. When defining a struct or union layout, clients must pay attention to the size and alignment constraint
|
||||
* of the corresponding composite type definition in C. For instance, padding between two struct fields
|
||||
* must be modeled explicitly, by adding an adequately sized {@linkplain PaddingLayout padding layout} member
|
||||
* to the resulting struct layout.
|
||||
* Composite types are modeled as {@linkplain GroupLayout group layouts}. More
|
||||
* specifically, a C {@code struct} type maps to a {@linkplain StructLayout struct layout},
|
||||
* whereas a C {@code union} type maps to a {@link UnionLayout union layout}. When defining
|
||||
* a struct or union layout, clients must pay attention to the size and alignment constraint
|
||||
* of the corresponding composite type definition in C. For instance, padding between two
|
||||
* struct fields must be modeled explicitly, by adding an adequately sized
|
||||
* {@linkplain PaddingLayout padding layout} member to the resulting struct layout.
|
||||
* <p>
|
||||
* Finally, pointer types such as {@code int**} and {@code int(*)(size_t*, size_t*)} are modeled as
|
||||
* {@linkplain AddressLayout address layouts}. When the spatial bounds of the pointer type are known statically,
|
||||
* the address layout can be associated with a {@linkplain AddressLayout#targetLayout() target layout}. For instance,
|
||||
* a pointer that is known to point to a C {@code int[2]} array can be modeled as an address layout whose
|
||||
* target layout is a sequence layout whose element count is 2, and whose element type is {@link ValueLayout#JAVA_INT}.
|
||||
* Finally, pointer types such as {@code int**} and {@code int(*)(size_t*, size_t*)}
|
||||
* are modeled as {@linkplain AddressLayout address layouts}. When the spatial bounds of
|
||||
* the pointer type are known statically, the address layout can be associated with a
|
||||
* {@linkplain AddressLayout#targetLayout() target layout}. For instance, a pointer that
|
||||
* is known to point to a C {@code int[2]} array can be modeled as an address layout
|
||||
* whose target layout is a sequence layout whose element count is 2, and whose
|
||||
* element type is {@link ValueLayout#JAVA_INT}.
|
||||
* <p>
|
||||
* All native linker implementations are guaranteed to provide canonical layouts for the following set of types:
|
||||
* All native linker implementations are guaranteed to provide canonical layouts for the
|
||||
* following set of types:
|
||||
* <ul>
|
||||
* <li>{@code bool}</li>
|
||||
* <li>{@code char}</li>
|
||||
@ -137,19 +150,23 @@ import java.util.stream.Stream;
|
||||
* <li>{@code wchar_t}</li>
|
||||
* <li>{@code void*}</li>
|
||||
* </ul>
|
||||
* As noted above, the specific canonical layout associated with each type can vary, depending on the data model
|
||||
* supported by a given ABI. For instance, the C type {@code long} maps to the layout constant {@link ValueLayout#JAVA_LONG}
|
||||
* on Linux/x64, but maps to the layout constant {@link ValueLayout#JAVA_INT} on Windows/x64. Similarly, the C type
|
||||
* {@code size_t} maps to the layout constant {@link ValueLayout#JAVA_LONG} on 64-bit platforms, but maps to the layout
|
||||
* constant {@link ValueLayout#JAVA_INT} on 32-bit platforms.
|
||||
* As noted above, the specific canonical layout associated with each type can vary,
|
||||
* depending on the data model supported by a given ABI. For instance, the C type
|
||||
* {@code long} maps to the layout constant {@link ValueLayout#JAVA_LONG} on Linux/x64,
|
||||
* but maps to the layout constant {@link ValueLayout#JAVA_INT} on Windows/x64.
|
||||
* Similarly, the C type {@code size_t} maps to the layout constant
|
||||
* {@link ValueLayout#JAVA_LONG} on 64-bit platforms, but maps to the layout constant
|
||||
* {@link ValueLayout#JAVA_INT} on 32-bit platforms.
|
||||
* <p>
|
||||
* A native linker typically does not provide canonical layouts for C's unsigned integral types. Instead, they are
|
||||
* modeled using the canonical layouts associated with their corresponding signed integral types. For instance,
|
||||
* the C type {@code unsigned long} maps to the layout constant {@link ValueLayout#JAVA_LONG} on Linux/x64, but maps to
|
||||
* A native linker typically does not provide canonical layouts for C's unsigned integral
|
||||
* types. Instead, they are modeled using the canonical layouts associated with their
|
||||
* corresponding signed integral types. For instance, the C type {@code unsigned long}
|
||||
* maps to the layout constant {@link ValueLayout#JAVA_LONG} on Linux/x64, but maps to
|
||||
* the layout constant {@link ValueLayout#JAVA_INT} on Windows/x64.
|
||||
* <p>
|
||||
* The following table shows some examples of how C types are modeled in Linux/x64 according to the
|
||||
* "System V Application Binary Interface" (all the examples provided here will assume these platform-dependent mappings):
|
||||
* The following table shows some examples of how C types are modeled in Linux/x64
|
||||
* according to the "System V Application Binary Interface"
|
||||
* (all the examples provided here will assume these platform-dependent mappings):
|
||||
*
|
||||
* <blockquote><table class="plain">
|
||||
* <caption style="display:none">Mapping C types</caption>
|
||||
@ -230,24 +247,30 @@ import java.util.stream.Stream;
|
||||
* <li>{@code L} is a value layout {@code V} and {@code V.withoutName()} is a canonical layout</li>
|
||||
* <li>{@code L} is a sequence layout {@code S} and all the following conditions hold:
|
||||
* <ol>
|
||||
* <li>the alignment constraint of {@code S} is set to its <a href="MemoryLayout.html#layout-align">natural alignment</a>, and</li>
|
||||
* <li>the alignment constraint of {@code S} is set to its
|
||||
* <a href="MemoryLayout.html#layout-align">natural alignment</a>, and</li>
|
||||
* <li>{@code S.elementLayout()} is a layout supported by {@code NL}.</li>
|
||||
* </ol>
|
||||
* </li>
|
||||
* <li>{@code L} is a group layout {@code G} and all the following conditions hold:
|
||||
* <ol>
|
||||
* <li>the alignment constraint of {@code G} is set to its <a href="MemoryLayout.html#layout-align">natural alignment</a>;</li>
|
||||
* <li>the alignment constraint of {@code G} is set to its
|
||||
* <a href="MemoryLayout.html#layout-align">natural alignment</a>;</li>
|
||||
* <li>the size of {@code G} is a multiple of its alignment constraint;</li>
|
||||
* <li>each member layout in {@code G.memberLayouts()} is either a padding layout or a layout supported by {@code NL}, and</li>
|
||||
* <li>{@code G} does not contain padding other than what is strictly required to align its non-padding layout elements, or to satisfy (2).</li>
|
||||
* <li>each member layout in {@code G.memberLayouts()} is either a padding layout or
|
||||
* a layout supported by {@code NL}, and</li>
|
||||
* <li>{@code G} does not contain padding other than what is strictly required to align
|
||||
* its non-padding layout elements, or to satisfy (2).</li>
|
||||
* </ol>
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* Linker implementations may optionally support additional layouts, such as <em>packed</em> struct layouts.
|
||||
* A packed struct is a struct in which there is at least one member layout {@code L} that has an alignment
|
||||
* constraint less strict than its natural alignment. This allows to avoid padding between member layouts,
|
||||
* Linker implementations may optionally support additional layouts, such as
|
||||
* <em>packed</em> struct layouts. A packed struct is a struct in which there is
|
||||
* at least one member layout {@code L} that has an alignment constraint less strict
|
||||
* than its natural alignment. This allows to avoid padding between member layouts,
|
||||
* as well as avoiding padding at the end of the struct layout. For example:
|
||||
|
||||
* {@snippet lang = java:
|
||||
* // No padding between the 2 element layouts:
|
||||
* MemoryLayout noFieldPadding = MemoryLayout.structLayout(
|
||||
@ -260,23 +283,25 @@ import java.util.stream.Stream;
|
||||
* ValueLayout.JAVA_INT);
|
||||
* }
|
||||
* <p>
|
||||
* A native linker only supports function descriptors whose argument/return layouts are layouts supported by that linker
|
||||
* and are not sequence layouts.
|
||||
* A native linker only supports function descriptors whose argument/return layouts are
|
||||
* layouts supported by that linker and are not sequence layouts.
|
||||
*
|
||||
* <h3 id="function-pointers">Function pointers</h3>
|
||||
*
|
||||
* Sometimes, it is useful to pass Java code as a function pointer to some native function; this is achieved by using
|
||||
* an {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...) upcall stub}. To demonstrate this,
|
||||
* let's consider the following function from the C standard library:
|
||||
* Sometimes, it is useful to pass Java code as a function pointer to some native
|
||||
* function; this is achieved by using an
|
||||
* {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...) upcall stub}.
|
||||
* To demonstrate this, let's consider the following function from the C standard library:
|
||||
*
|
||||
* {@snippet lang = c:
|
||||
* void qsort(void *base, size_t nmemb, size_t size,
|
||||
* int (*compar)(const void *, const void *));
|
||||
* }
|
||||
*
|
||||
* The {@code qsort} function can be used to sort the contents of an array, using a custom comparator function which is
|
||||
* passed as a function pointer (the {@code compar} parameter). To be able to call the {@code qsort} function from Java,
|
||||
* we must first create a downcall method handle for it, as follows:
|
||||
* The {@code qsort} function can be used to sort the contents of an array, using a
|
||||
* custom comparator function which is passed as a function pointer
|
||||
* (the {@code compar} parameter). To be able to call the {@code qsort} function from
|
||||
* Java, we must first create a downcall method handle for it, as follows:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* Linker linker = Linker.nativeLinker();
|
||||
@ -286,12 +311,14 @@ import java.util.stream.Stream;
|
||||
* );
|
||||
* }
|
||||
*
|
||||
* As before, we use {@link ValueLayout#JAVA_LONG} to map the C type {@code size_t} type, and {@link ValueLayout#ADDRESS}
|
||||
* for both the first pointer parameter (the array pointer) and the last parameter (the function pointer).
|
||||
* As before, we use {@link ValueLayout#JAVA_LONG} to map the C type {@code size_t} type,
|
||||
* and {@link ValueLayout#ADDRESS} for both the first pointer parameter (the array
|
||||
* pointer) and the last parameter (the function pointer).
|
||||
* <p>
|
||||
* To invoke the {@code qsort} downcall handle obtained above, we need a function pointer to be passed as the last
|
||||
* parameter. That is, we need to create a function pointer out of an existing method handle. First, let's write a
|
||||
* Java method that can compare two int elements passed as pointers (i.e. as {@linkplain MemorySegment memory segments}):
|
||||
* To invoke the {@code qsort} downcall handle obtained above, we need a function pointer
|
||||
* to be passed as the last parameter. That is, we need to create a function pointer out
|
||||
* of an existing method handle. First, let's write a Java method that can compare two
|
||||
* int elements passed as pointers (i.e. as {@linkplain MemorySegment memory segments}):
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* class Qsort {
|
||||
@ -312,13 +339,16 @@ import java.util.stream.Stream;
|
||||
* comparDesc.toMethodType());
|
||||
* }
|
||||
*
|
||||
* First, we create a function descriptor for the function pointer type. Since we know that the parameters passed to
|
||||
* the comparator method will be pointers to elements of a C {@code int[]} array, we can specify {@link ValueLayout#JAVA_INT}
|
||||
* as the target layout for the address layouts of both parameters. This will allow the comparator method to access
|
||||
* the contents of the array elements to be compared. We then {@linkplain FunctionDescriptor#toMethodType() turn}
|
||||
* that function descriptor into a suitable {@linkplain java.lang.invoke.MethodType method type} which we then use to look up
|
||||
* the comparator method handle. We can now create an upcall stub that points to that method, and pass it, as a function
|
||||
* pointer, to the {@code qsort} downcall handle, as follows:
|
||||
* First, we create a function descriptor for the function pointer type. Since we know
|
||||
* that the parameters passed to the comparator method will be pointers to elements of
|
||||
* a C {@code int[]} array, we can specify {@link ValueLayout#JAVA_INT} as the target
|
||||
* layout for the address layouts of both parameters. This will allow the comparator
|
||||
* method to access the contents of the array elements to be compared. We then
|
||||
* {@linkplain FunctionDescriptor#toMethodType() turn} that function descriptor into
|
||||
* a suitable {@linkplain java.lang.invoke.MethodType method type} which we then use to
|
||||
* look up the comparator method handle. We can now create an upcall stub that points to
|
||||
* that method, and pass it, as a function pointer, to the {@code qsort} downcall handle,
|
||||
* as follows:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* try (Arena arena = Arena.ofConfined()) {
|
||||
@ -329,34 +359,39 @@ import java.util.stream.Stream;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* This code creates an off-heap array, copies the contents of a Java array into it, and then passes the array to the
|
||||
* {@code qsort} method handle along with the comparator function we obtained from the native linker. After the invocation, the contents
|
||||
* of the off-heap array will be sorted according to our comparator function, written in Java. We then extract a
|
||||
* new Java array from the segment, which contains the sorted elements.
|
||||
* This code creates an off-heap array, copies the contents of a Java array into it, and
|
||||
* then passes the array to the {@code qsort} method handle along with the comparator
|
||||
* function we obtained from the native linker. After the invocation, the contents
|
||||
* of the off-heap array will be sorted according to our comparator function, written in
|
||||
* Java. We then extract a new Java array from the segment, which contains the sorted
|
||||
* elements.
|
||||
*
|
||||
* <h3 id="by-ref">Functions returning pointers</h3>
|
||||
*
|
||||
* When interacting with native functions, it is common for those functions to allocate a region of memory and return
|
||||
* a pointer to that region. Let's consider the following function from the C standard library:
|
||||
* When interacting with native functions, it is common for those functions to allocate
|
||||
* a region of memory and return a pointer to that region. Let's consider the following
|
||||
* function from the C standard library:
|
||||
*
|
||||
* {@snippet lang = c:
|
||||
* void *malloc(size_t size);
|
||||
* }
|
||||
*
|
||||
* The {@code malloc} function allocates a region of memory with the given size,
|
||||
* and returns a pointer to that region of memory, which is later deallocated using another function from
|
||||
* the C standard library:
|
||||
* and returns a pointer to that region of memory, which is later deallocated using
|
||||
* another function from the C standard library:
|
||||
*
|
||||
* {@snippet lang = c:
|
||||
* void free(void *ptr);
|
||||
* }
|
||||
*
|
||||
* The {@code free} function takes a pointer to a region of memory and deallocates that region. In this section we
|
||||
* will show how to interact with these native functions, with the aim of providing a <em>safe</em> allocation
|
||||
* API (the approach outlined below can of course be generalized to allocation functions other than {@code malloc}
|
||||
* and {@code free}).
|
||||
* The {@code free} function takes a pointer to a region of memory and deallocates that
|
||||
* region. In this section we will show how to interact with these native functions,
|
||||
* with the aim of providing a <em>safe</em> allocation API (the approach outlined below
|
||||
* can of course be generalized to allocation functions other than {@code malloc} and
|
||||
* {@code free}).
|
||||
* <p>
|
||||
* First, we need to create the downcall method handles for {@code malloc} and {@code free}, as follows:
|
||||
* First, we need to create the downcall method handles for {@code malloc} and
|
||||
* {@code free}, as follows:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* Linker linker = Linker.nativeLinker();
|
||||
@ -372,8 +407,9 @@ import java.util.stream.Stream;
|
||||
* );
|
||||
* }
|
||||
*
|
||||
* When a native function returning a pointer (such as {@code malloc}) is invoked using a downcall method handle,
|
||||
* the Java runtime has no insight into the size or the lifetime of the returned pointer. Consider the following code:
|
||||
* When a native function returning a pointer (such as {@code malloc}) is invoked using
|
||||
* a downcall method handle, the Java runtime has no insight into the size or the
|
||||
* lifetime of the returned pointer. Consider the following code:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* MemorySegment segment = (MemorySegment)malloc.invokeExact(100);
|
||||
@ -382,11 +418,12 @@ import java.util.stream.Stream;
|
||||
* The size of the segment returned by the {@code malloc} downcall method handle is
|
||||
* <a href="MemorySegment.html#wrapping-addresses">zero</a>. Moreover, the scope of the
|
||||
* returned segment is the global scope. To provide safe access to the segment, we must,
|
||||
* unsafely, resize the segment to the desired size (100, in this case). It might also be desirable to
|
||||
* attach the segment to some existing {@linkplain Arena arena}, so that the lifetime of the region of memory
|
||||
* backing the segment can be managed automatically, as for any other native segment created directly from Java code.
|
||||
* Both of these operations are accomplished using the restricted method {@link MemorySegment#reinterpret(long, Arena, Consumer)},
|
||||
* as follows:
|
||||
* unsafely, resize the segment to the desired size (100, in this case). It might also
|
||||
* be desirable to attach the segment to some existing {@linkplain Arena arena}, so that
|
||||
* the lifetime of the region of memory backing the segment can be managed automatically,
|
||||
* as for any other native segment created directly from Java code. Both of these
|
||||
* operations are accomplished using the restricted method
|
||||
* {@link MemorySegment#reinterpret(long, Arena, Consumer)}, as follows:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* MemorySegment allocateMemory(long byteSize, Arena arena) throws Throwable {
|
||||
@ -401,12 +438,14 @@ import java.util.stream.Stream;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* The {@code allocateMemory} method defined above accepts two parameters: a size and an arena. The method calls the
|
||||
* {@code malloc} downcall method handle, and unsafely reinterprets the returned segment, by giving it a new size
|
||||
* (the size passed to the {@code allocateMemory} method) and a new scope (the scope of the provided arena).
|
||||
* The method also specifies a <em>cleanup action</em> to be executed when the provided arena is closed. Unsurprisingly,
|
||||
* the cleanup action passes the segment to the {@code free} downcall method handle, to deallocate the underlying
|
||||
* region of memory. We can use the {@code allocateMemory} method as follows:
|
||||
* The {@code allocateMemory} method defined above accepts two parameters: a size and an
|
||||
* arena. The method calls the {@code malloc} downcall method handle, and unsafely
|
||||
* reinterprets the returned segment, by giving it a new size (the size passed to the
|
||||
* {@code allocateMemory} method) and a new scope (the scope of the provided arena).
|
||||
* The method also specifies a <em>cleanup action</em> to be executed when the provided
|
||||
* arena is closed. Unsurprisingly, the cleanup action passes the segment to the
|
||||
* {@code free} downcall method handle, to deallocate the underlying region of memory.
|
||||
* We can use the {@code allocateMemory} method as follows:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* try (Arena arena = Arena.ofConfined()) {
|
||||
@ -414,65 +453,79 @@ import java.util.stream.Stream;
|
||||
* } // 'free' called here
|
||||
* }
|
||||
*
|
||||
* Note how the segment obtained from {@code allocateMemory} acts as any other segment managed by the confined arena. More
|
||||
* specifically, the obtained segment has the desired size, can only be accessed by a single thread (the thread that created
|
||||
* the confined arena), and its lifetime is tied to the surrounding <em>try-with-resources</em> block.
|
||||
* Note how the segment obtained from {@code allocateMemory} acts as any other segment
|
||||
* managed by the confined arena. More specifically, the obtained segment has the desired
|
||||
* size, can only be accessed by a single thread (the thread that created the confined
|
||||
* arena), and its lifetime is tied to the surrounding <em>try-with-resources</em> block.
|
||||
*
|
||||
* <h3 id="variadic-funcs">Variadic functions</h3>
|
||||
*
|
||||
* Variadic functions are C functions that can accept a variable number and type of arguments. They are declared with a
|
||||
* trailing ellipsis ({@code ...}) at the end of the formal parameter list, such as: {@code void foo(int x, ...);}
|
||||
* The arguments passed in place of the ellipsis are called <em>variadic arguments</em>. Variadic functions are,
|
||||
* essentially, templates that can be <em>specialized</em> into multiple non-variadic functions by replacing the
|
||||
* {@code ...} with a list of <em>variadic parameters</em> of a fixed number and type.
|
||||
* Variadic functions are C functions that can accept a variable number and type of
|
||||
* arguments. They are declared with a trailing ellipsis ({@code ...}) at the end of the
|
||||
* formal parameter list, such as: {@code void foo(int x, ...);}
|
||||
* The arguments passed in place of the ellipsis are called <em>variadic arguments</em>.
|
||||
* Variadic functions are, essentially, templates that can be <em>specialized</em> into
|
||||
* multiple non-variadic functions by replacing the {@code ...} with a list of
|
||||
* <em>variadic parameters</em> of a fixed number and type.
|
||||
* <p>
|
||||
* It should be noted that values passed as variadic arguments undergo default argument promotion in C. For instance, the
|
||||
* following argument promotions are applied:
|
||||
* It should be noted that values passed as variadic arguments undergo default argument
|
||||
* promotion in C. For instance, the following argument promotions are applied:
|
||||
* <ul>
|
||||
* <li>{@code _Bool} -> {@code unsigned int}</li>
|
||||
* <li>{@code [signed] char} -> {@code [signed] int}</li>
|
||||
* <li>{@code [signed] short} -> {@code [signed] int}</li>
|
||||
* <li>{@code float} -> {@code double}</li>
|
||||
* </ul>
|
||||
* whereby the signed-ness of the source type corresponds to the signed-ness of the promoted type. The complete process
|
||||
* of default argument promotion is described in the C specification. In effect, these promotions place limits on the
|
||||
* types that can be used to replace the {@code ...}, as the variadic parameters of the specialized form of a variadic
|
||||
* function will always have a promoted type.
|
||||
* whereby the signed-ness of the source type corresponds to the signed-ness of the
|
||||
* promoted type. The complete process of default argument promotion is described in the
|
||||
* C specification. In effect, these promotions place limits on the types that can be
|
||||
* used to replace the {@code ...}, as the variadic parameters of the specialized form
|
||||
* of a variadic function will always have a promoted type.
|
||||
* <p>
|
||||
* The native linker only supports linking the specialized form of a variadic function. A variadic function in its specialized
|
||||
* form can be linked using a function descriptor describing the specialized form. Additionally, the
|
||||
* {@link Linker.Option#firstVariadicArg(int)} linker option must be provided to indicate the first variadic parameter in
|
||||
* the parameter list. The corresponding argument layout (if any), and all following argument layouts in the specialized
|
||||
* function descriptor, are called <em>variadic argument layouts</em>.
|
||||
* The native linker only supports linking the specialized form of a variadic function.
|
||||
* A variadic function in its specialized form can be linked using a function descriptor
|
||||
* describing the specialized form. Additionally, the {@link Linker.Option#firstVariadicArg(int)}
|
||||
* linker option must be provided to indicate the first variadic parameter in the
|
||||
* parameter list. The corresponding argument layout (if any), and all following
|
||||
* argument layouts in the specialized function descriptor, are called
|
||||
* <em>variadic argument layouts</em>.
|
||||
* <p>
|
||||
* The native linker does not automatically perform default argument promotions. However, since passing an argument of a
|
||||
* non-promoted type as a variadic argument is not supported in C, the native linker will reject an attempt to link a
|
||||
* specialized function descriptor with any variadic argument value layouts corresponding to a non-promoted C type.
|
||||
* Since the size of the C {@code int} type is platform-specific, exactly which layouts will be rejected is
|
||||
* platform-specific as well. As an example: on Linux/x64 the layouts corresponding to the C types {@code _Bool},
|
||||
* {@code (unsigned) char}, {@code (unsigned) short}, and {@code float} (among others), will be rejected by the linker.
|
||||
* The {@link #canonicalLayouts()} method can be used to find which layout corresponds to a particular C type.
|
||||
* The native linker does not automatically perform default argument promotions. However,
|
||||
* since passing an argument of a non-promoted type as a variadic argument is not
|
||||
* supported in C, the native linker will reject an attempt to link a specialized
|
||||
* function descriptor with any variadic argument value layouts corresponding to a
|
||||
* non-promoted C type. Since the size of the C {@code int} type is platform-specific,
|
||||
* exactly which layouts will be rejected is platform-specific as well. As an example:
|
||||
* on Linux/x64 the layouts corresponding to the C types {@code _Bool},
|
||||
* {@code (unsigned) char}, {@code (unsigned) short}, and {@code float} (among others),
|
||||
* will be rejected by the linker. The {@link #canonicalLayouts()} method can be used to
|
||||
* find which layout corresponds to a particular C type.
|
||||
* <p>
|
||||
* A well-known variadic function is the {@code printf} function, defined in the C standard library:
|
||||
* A well-known variadic function is the {@code printf} function, defined in the
|
||||
* C standard library:
|
||||
*
|
||||
* {@snippet lang = c:
|
||||
* int printf(const char *format, ...);
|
||||
* }
|
||||
*
|
||||
* This function takes a format string, and a number of additional arguments (the number of such arguments is
|
||||
* dictated by the format string). Consider the following variadic call:
|
||||
* This function takes a format string, and a number of additional arguments (the number
|
||||
* of such arguments is dictated by the format string). Consider the following
|
||||
* variadic call:
|
||||
*
|
||||
* {@snippet lang = c:
|
||||
* printf("%d plus %d equals %d", 2, 2, 4);
|
||||
* }
|
||||
*
|
||||
* To perform an equivalent call using a downcall method handle we must create a function descriptor which
|
||||
* describes the specialized signature of the C function we want to call. This descriptor must include an additional layout
|
||||
* for each variadic argument we intend to provide. In this case, the specialized signature of the C
|
||||
* function is {@code (char*, int, int, int)} as the format string accepts three integer parameters. We then need to use
|
||||
* a {@linkplain Linker.Option#firstVariadicArg(int) linker option} to specify the position of the first variadic layout
|
||||
* in the provided function descriptor (starting from 0). In this case, since the first parameter is the format string
|
||||
* (a non-variadic argument), the first variadic index needs to be set to 1, as follows:
|
||||
* To perform an equivalent call using a downcall method handle we must create a function
|
||||
* descriptor which describes the specialized signature of the C function we want to
|
||||
* call. This descriptor must include an additional layout for each variadic argument we
|
||||
* intend to provide. In this case, the specialized signature of the C function is
|
||||
* {@code (char*, int, int, int)} as the format string accepts three integer parameters.
|
||||
* We then need to use a {@linkplain Linker.Option#firstVariadicArg(int) linker option}
|
||||
* to specify the position of the first variadic layout in the provided function
|
||||
* descriptor (starting from 0). In this case, since the first parameter is the format
|
||||
* string (a non-variadic argument), the first variadic index needs to be set to 1, as
|
||||
* follows:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* Linker linker = Linker.nativeLinker();
|
||||
@ -487,64 +540,81 @@ import java.util.stream.Stream;
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* try (Arena arena = Arena.ofConfined()) {
|
||||
* int res = (int)printf.invokeExact(arena.allocateFrom("%d plus %d equals %d"), 2, 2, 4); //prints "2 plus 2 equals 4"
|
||||
* //prints "2 plus 2 equals 4"
|
||||
* int res = (int)printf.invokeExact(arena.allocateFrom("%d plus %d equals %d"), 2, 2, 4);
|
||||
* }
|
||||
*}
|
||||
*
|
||||
* <h2 id="safety">Safety considerations</h2>
|
||||
*
|
||||
* Creating a downcall method handle is intrinsically unsafe. A symbol in a foreign library does not, in general,
|
||||
* contain enough signature information (e.g. arity and types of foreign function parameters). As a consequence,
|
||||
* the linker runtime cannot validate linkage requests. When a client interacts with a downcall method handle obtained
|
||||
* through an invalid linkage request (e.g. by specifying a function descriptor featuring too many argument layouts),
|
||||
* the result of such interaction is unspecified and can lead to JVM crashes.
|
||||
* Creating a downcall method handle is intrinsically unsafe. A symbol in a foreign
|
||||
* library does not, in general, contain enough signature information (e.g. arity and
|
||||
* types of foreign function parameters). As a consequence, the linker runtime cannot
|
||||
* validate linkage requests. When a client interacts with a downcall method handle
|
||||
* obtained through an invalid linkage request (e.g. by specifying a function descriptor
|
||||
* featuring too many argument layouts), the result of such interaction is unspecified
|
||||
* and can lead to JVM crashes.
|
||||
* <p>
|
||||
* When an upcall stub is passed to a foreign function, a JVM crash might occur, if the foreign code casts the function pointer
|
||||
* associated with the upcall stub to a type that is incompatible with the type of the upcall stub, and then attempts to
|
||||
* invoke the function through the resulting function pointer. Moreover, if the method
|
||||
* handle associated with an upcall stub returns a {@linkplain MemorySegment memory segment}, clients must ensure
|
||||
* that this address cannot become invalid after the upcall is completed. This can lead to unspecified behavior,
|
||||
* and even JVM crashes, since an upcall is typically executed in the context of a downcall method handle invocation.
|
||||
* When an upcall stub is passed to a foreign function, a JVM crash might occur, if the
|
||||
* foreign code casts the function pointer associated with the upcall stub to a type that
|
||||
* is incompatible with the type of the upcall stub, and then attempts to invoke the
|
||||
* function through the resulting function pointer. Moreover, if the method handle
|
||||
* associated with an upcall stub returns a {@linkplain MemorySegment memory segment},
|
||||
* clients must ensure that this address cannot become invalid after the upcall is
|
||||
* completed. This can lead to unspecified behavior, and even JVM crashes, since an
|
||||
* upcall is typically executed in the context of a downcall method handle invocation.
|
||||
*
|
||||
* @implSpec
|
||||
* Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
* Implementations of this interface are immutable, thread-safe and
|
||||
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @since 22
|
||||
*/
|
||||
public sealed interface Linker permits AbstractLinker {
|
||||
|
||||
/**
|
||||
* {@return a linker for the ABI associated with the underlying native platform} The underlying native platform
|
||||
* is the combination of OS and processor where the Java runtime is currently executing.
|
||||
* {@return a linker for the ABI associated with the underlying native platform}
|
||||
* <p>
|
||||
* The underlying native platform is the combination of OS and processor where the
|
||||
* Java runtime is currently executing.
|
||||
*
|
||||
* @apiNote It is not currently possible to obtain a linker for a different combination of OS and processor.
|
||||
* @implSpec A native linker implementation is guaranteed to provide canonical layouts for
|
||||
* <a href="#describing-c-sigs">basic C types</a>.
|
||||
* @implNote The libraries exposed by the {@linkplain #defaultLookup() default lookup} associated with the returned
|
||||
* linker are the native libraries loaded in the process where the Java runtime is currently executing. For example,
|
||||
* on Linux, these libraries typically include {@code libc}, {@code libm} and {@code libdl}.
|
||||
* @apiNote It is not currently possible to obtain a linker for a different
|
||||
* combination of OS and processor.
|
||||
* @implSpec A native linker implementation is guaranteed to provide canonical
|
||||
* layouts for <a href="#describing-c-sigs">basic C types</a>.
|
||||
* @implNote The libraries exposed by the {@linkplain #defaultLookup() default lookup}
|
||||
* associated with the returned linker are the native libraries loaded in
|
||||
* the process where the Java runtime is currently executing. For example,
|
||||
* on Linux, these libraries typically include {@code libc}, {@code libm}
|
||||
* and {@code libdl}.
|
||||
*/
|
||||
static Linker nativeLinker() {
|
||||
return SharedUtils.getSystemLinker();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a method handle that is used to call a foreign function with the given signature and address.
|
||||
* Creates a method handle that is used to call a foreign function with
|
||||
* the given signature and address.
|
||||
* <p>
|
||||
* Calling this method is equivalent to the following code:
|
||||
* {@snippet lang=java :
|
||||
* linker.downcallHandle(function).bindTo(symbol);
|
||||
* }
|
||||
*
|
||||
* @param address the native memory segment whose {@linkplain MemorySegment#address() base address} is the
|
||||
* address of the target foreign function.
|
||||
* @param function the function descriptor of the target foreign function.
|
||||
* @param options the linker options associated with this linkage request.
|
||||
* @return a downcall method handle.
|
||||
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker
|
||||
* @throws IllegalArgumentException if {@code !address.isNative()}, or if {@code address.equals(MemorySegment.NULL)}
|
||||
* @throws IllegalArgumentException if an invalid combination of linker options is given
|
||||
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled
|
||||
* @param address the native memory segment whose
|
||||
* {@linkplain MemorySegment#address() base address} is the address
|
||||
* of the target foreign function
|
||||
* @param function the function descriptor of the target foreign function
|
||||
* @param options the linker options associated with this linkage request
|
||||
* @return a downcall method handle
|
||||
* @throws IllegalArgumentException if the provided function descriptor is not
|
||||
* supported by this linker
|
||||
* @throws IllegalArgumentException if {@code !address.isNative()}, or if
|
||||
* {@code address.equals(MemorySegment.NULL)}
|
||||
* @throws IllegalArgumentException if an invalid combination of linker options
|
||||
* is given
|
||||
* @throws IllegalCallerException If the caller is in a module that does not have
|
||||
* native access enabled
|
||||
*
|
||||
* @see SymbolLookup
|
||||
*/
|
||||
@ -555,87 +625,111 @@ public sealed interface Linker permits AbstractLinker {
|
||||
Option... options);
|
||||
|
||||
/**
|
||||
* Creates a method handle that is used to call a foreign function with the given signature.
|
||||
* Creates a method handle that is used to call a foreign function with
|
||||
* the given signature.
|
||||
* <p>
|
||||
* The Java {@linkplain java.lang.invoke.MethodType method type} associated with the returned method handle is
|
||||
* {@linkplain FunctionDescriptor#toMethodType() derived} from the argument and return layouts in the function descriptor,
|
||||
* but features an additional leading parameter of type {@link MemorySegment}, from which the address of the target
|
||||
* foreign function is derived. Moreover, if the function descriptor's return layout is a group layout, the resulting
|
||||
* downcall method handle accepts an additional leading parameter of type {@link SegmentAllocator}, which is used by
|
||||
* the linker runtime to allocate the memory region associated with the struct returned by the downcall method handle.
|
||||
* The Java {@linkplain java.lang.invoke.MethodType method type} associated with the
|
||||
* returned method handle is {@linkplain FunctionDescriptor#toMethodType() derived}
|
||||
* from the argument and return layouts in the function descriptor, but features an
|
||||
* additional leading parameter of type {@link MemorySegment}, from which the address
|
||||
* of the target foreign function is derived. Moreover, if the function descriptor's
|
||||
* return layout is a group layout, the resulting downcall method handle accepts an
|
||||
* additional leading parameter of type {@link SegmentAllocator}, which is used by
|
||||
* the linker runtime to allocate the memory region associated with the struct
|
||||
* returned by the downcall method handle.
|
||||
* <p>
|
||||
* Upon invoking a downcall method handle, the linker provides the following guarantees for any argument
|
||||
* {@code A} of type {@link MemorySegment} whose corresponding layout is an {@linkplain AddressLayout address layout}:
|
||||
* Upon invoking a downcall method handle, the linker provides the following
|
||||
* guarantees for any argument {@code A} of type {@link MemorySegment} whose
|
||||
* corresponding layout is an {@linkplain AddressLayout address layout}:
|
||||
* <ul>
|
||||
* <li>{@code A.scope().isAlive() == true}. Otherwise, the invocation throws {@link IllegalStateException};</li>
|
||||
* <li>The invocation occurs in a thread {@code T} such that {@code A.isAccessibleBy(T) == true}.
|
||||
* Otherwise, the invocation throws {@link WrongThreadException}; and</li>
|
||||
* <li>{@code A} is kept alive during the invocation. For instance, if {@code A} has been obtained using a
|
||||
* {@linkplain Arena#ofShared() shared arena}, any attempt to {@linkplain Arena#close() close}
|
||||
* the arena while the downcall method handle is still executing will result in an {@link IllegalStateException}.</li>
|
||||
* <li>{@code A.scope().isAlive() == true}. Otherwise, the invocation
|
||||
* throws {@link IllegalStateException};</li>
|
||||
* <li>The invocation occurs in a thread {@code T} such that
|
||||
* {@code A.isAccessibleBy(T) == true}.
|
||||
* Otherwise, the invocation throws {@link WrongThreadException}; and</li>
|
||||
* <li>{@code A} is kept alive during the invocation. For instance,
|
||||
* if {@code A} has been obtained using a {@linkplain Arena#ofShared() shared arena},
|
||||
* any attempt to {@linkplain Arena#close() close} the arena while the
|
||||
* downcall method handle is still executing will result in an
|
||||
* {@link IllegalStateException}.</li>
|
||||
*</ul>
|
||||
* <p>
|
||||
* Moreover, if the provided function descriptor's return layout is an {@linkplain AddressLayout address layout},
|
||||
* invoking the returned method handle will return a native segment associated with
|
||||
* the global scope. Under normal conditions, the size of the returned segment is {@code 0}.
|
||||
* However, if the function descriptor's return layout has a {@linkplain AddressLayout#targetLayout() target layout}
|
||||
* {@code T}, then the size of the returned segment is set to {@code T.byteSize()}.
|
||||
* Moreover, if the provided function descriptor's return layout is an
|
||||
* {@linkplain AddressLayout address layout}, invoking the returned method handle
|
||||
* will return a native segment associated with the global scope. Under normal
|
||||
* conditions, the size of the returned segment is {@code 0}. However, if the
|
||||
* function descriptor's return layout has a
|
||||
* {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size
|
||||
* of the returned segment is set to {@code T.byteSize()}.
|
||||
* <p>
|
||||
* The returned method handle will throw an {@link IllegalArgumentException} if the {@link MemorySegment}
|
||||
* representing the target address of the foreign function is the {@link MemorySegment#NULL} address. If an argument
|
||||
* is a {@link MemorySegment}, whose corresponding layout is a {@linkplain GroupLayout group layout}, the linker
|
||||
* might attempt to access the contents of the segment. As such, one of the exceptions specified by the
|
||||
* {@link MemorySegment#get(ValueLayout.OfByte, long)} or the
|
||||
* {@link MemorySegment#copy(MemorySegment, long, MemorySegment, long, long)} methods may be thrown.
|
||||
* The returned method handle will additionally throw {@link NullPointerException} if any argument
|
||||
* passed to it is {@code null}.
|
||||
* The returned method handle will throw an {@link IllegalArgumentException} if the
|
||||
* {@link MemorySegment} representing the target address of the foreign function is
|
||||
* the {@link MemorySegment#NULL} address. If an argument is a {@link MemorySegment},
|
||||
* whose corresponding layout is a {@linkplain GroupLayout group layout}, the linker
|
||||
* might attempt to access the contents of the segment. As such, one of the
|
||||
* exceptions specified by the {@link MemorySegment#get(ValueLayout.OfByte, long)} or
|
||||
* the {@link MemorySegment#copy(MemorySegment, long, MemorySegment, long, long)}
|
||||
* methods may be thrown. The returned method handle will additionally throw
|
||||
* {@link NullPointerException} if any argument passed to it is {@code null}.
|
||||
*
|
||||
* @param function the function descriptor of the target foreign function.
|
||||
* @param options the linker options associated with this linkage request.
|
||||
* @return a downcall method handle.
|
||||
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker
|
||||
* @throws IllegalArgumentException if an invalid combination of linker options is given
|
||||
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled
|
||||
* @param function the function descriptor of the target foreign function
|
||||
* @param options the linker options associated with this linkage request
|
||||
* @return a downcall method handle
|
||||
* @throws IllegalArgumentException if the provided function descriptor is not
|
||||
* supported by this linker
|
||||
* @throws IllegalArgumentException if an invalid combination of linker options
|
||||
* is given
|
||||
* @throws IllegalCallerException If the caller is in a module that does not have
|
||||
* native access enabled
|
||||
*/
|
||||
@CallerSensitive
|
||||
@Restricted
|
||||
MethodHandle downcallHandle(FunctionDescriptor function, Option... options);
|
||||
|
||||
/**
|
||||
* Creates an upcall stub which can be passed to other foreign functions as a function pointer, associated with the given
|
||||
* arena. Calling such a function pointer from foreign code will result in the execution of the provided
|
||||
* method handle.
|
||||
* Creates an upcall stub which can be passed to other foreign functions as a
|
||||
* function pointer, associated with the given arena. Calling such a function
|
||||
* pointer from foreign code will result in the execution of the provided method
|
||||
* handle.
|
||||
* <p>
|
||||
* The returned memory segment's address points to the newly allocated upcall stub, and is associated with
|
||||
* the provided arena. As such, the lifetime of the returned upcall stub segment is controlled by the
|
||||
* provided arena. For instance, if the provided arena is a confined arena, the returned
|
||||
* upcall stub segment will be deallocated when the provided confined arena is {@linkplain Arena#close() closed}.
|
||||
* The returned memory segment's address points to the newly allocated upcall stub,
|
||||
* and is associated with the provided arena. As such, the lifetime of the returned
|
||||
* upcall stub segment is controlled by the provided arena. For instance, if the
|
||||
* provided arena is a confined arena, the returned upcall stub segment will be
|
||||
* deallocated when the provided confined arena is {@linkplain Arena#close() closed}.
|
||||
* <p>
|
||||
* An upcall stub argument whose corresponding layout is an {@linkplain AddressLayout address layout}
|
||||
* is a native segment associated with the global scope.
|
||||
* Under normal conditions, the size of this segment argument is {@code 0}.
|
||||
* However, if the address layout has a {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size of the
|
||||
* segment argument is set to {@code T.byteSize()}.
|
||||
* An upcall stub argument whose corresponding layout is an
|
||||
* {@linkplain AddressLayout address layout} is a native segment associated with the
|
||||
* global scope. Under normal conditions, the size of this segment argument is
|
||||
* {@code 0}. However, if the address layout has a
|
||||
* {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size
|
||||
* of the segment argument is set to {@code T.byteSize()}.
|
||||
* <p>
|
||||
* The target method handle should not throw any exceptions. If the target method handle does throw an exception,
|
||||
* the JVM will terminate abruptly. To avoid this, clients should wrap the code in the target method handle in a
|
||||
* try/catch block to catch any unexpected exceptions. This can be done using the
|
||||
* {@link java.lang.invoke.MethodHandles#catchException(MethodHandle, Class, MethodHandle)} method handle combinator,
|
||||
* and handle exceptions as desired in the corresponding catch block.
|
||||
* The target method handle should not throw any exceptions. If the target method
|
||||
* handle does throw an exception, the JVM will terminate abruptly. To avoid this,
|
||||
* clients should wrap the code in the target method handle in a try/catch block to
|
||||
* catch any unexpected exceptions. This can be done using the
|
||||
* {@link java.lang.invoke.MethodHandles#catchException(MethodHandle, Class, MethodHandle)}
|
||||
* method handle combinator, and handle exceptions as desired in the corresponding
|
||||
* catch block.
|
||||
*
|
||||
* @param target the target method handle.
|
||||
* @param function the upcall stub function descriptor.
|
||||
* @param arena the arena associated with the returned upcall stub segment.
|
||||
* @param options the linker options associated with this linkage request.
|
||||
* @return a zero-length segment whose address is the address of the upcall stub.
|
||||
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker
|
||||
* @throws IllegalArgumentException if the type of {@code target} is incompatible with the
|
||||
* type {@linkplain FunctionDescriptor#toMethodType() derived} from {@code function}
|
||||
* @throws IllegalArgumentException if it is determined that the target method handle can throw an exception
|
||||
* @param target the target method handle
|
||||
* @param function the upcall stub function descriptor
|
||||
* @param arena the arena associated with the returned upcall stub segment
|
||||
* @param options the linker options associated with this linkage request
|
||||
* @return a zero-length segment whose address is the address of the upcall stub
|
||||
* @throws IllegalArgumentException if the provided function descriptor is not
|
||||
* supported by this linker
|
||||
* @throws IllegalArgumentException if the type of {@code target} is incompatible
|
||||
* with the type {@linkplain FunctionDescriptor#toMethodType() derived}
|
||||
* from {@code function}
|
||||
* @throws IllegalArgumentException if it is determined that the target method handle
|
||||
* can throw an exception
|
||||
* @throws IllegalStateException if {@code arena.scope().isAlive() == false}
|
||||
* @throws WrongThreadException if {@code arena} is a confined arena, and this method is called from a
|
||||
* thread {@code T}, other than the arena's owner thread
|
||||
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled
|
||||
* @throws WrongThreadException if {@code arena} is a confined arena, and this method
|
||||
* is called from a thread {@code T}, other than the arena's owner thread
|
||||
* @throws IllegalCallerException If the caller is in a module that does not have
|
||||
* native access enabled
|
||||
*/
|
||||
@CallerSensitive
|
||||
@Restricted
|
||||
@ -647,31 +741,44 @@ public sealed interface Linker permits AbstractLinker {
|
||||
/**
|
||||
* Returns a symbol lookup for symbols in a set of commonly used libraries.
|
||||
* <p>
|
||||
* Each {@link Linker} is responsible for choosing libraries that are widely recognized as useful on the OS
|
||||
* and processor combination supported by the {@link Linker}. Accordingly, the precise set of symbols exposed by the
|
||||
* symbol lookup is unspecified; it varies from one {@link Linker} to another.
|
||||
* @implNote It is strongly recommended that the result of {@link #defaultLookup} exposes a set of symbols that is stable over time.
|
||||
* Clients of {@link #defaultLookup()} are likely to fail if a symbol that was previously exposed by the symbol lookup is no longer exposed.
|
||||
* <p>If an implementer provides {@link Linker} implementations for multiple OS and processor combinations, then it is strongly
|
||||
* recommended that the result of {@link #defaultLookup()} exposes, as much as possible, a consistent set of symbols
|
||||
* across all the OS and processor combinations.
|
||||
* @return a symbol lookup for symbols in a set of commonly used libraries.
|
||||
* Each {@link Linker} is responsible for choosing libraries that are widely
|
||||
* recognized as useful on the OS and processor combination supported by the
|
||||
* {@link Linker}. Accordingly, the precise set of symbols exposed by the symbol
|
||||
* lookup is unspecified; it varies from one {@link Linker} to another.
|
||||
*
|
||||
* @implNote It is strongly recommended that the result of {@link #defaultLookup}
|
||||
* exposes a set of symbols that is stable over time. Clients of
|
||||
* {@link #defaultLookup()} are likely to fail if a symbol that was
|
||||
* previously exposed by the symbol lookup is no longer exposed.
|
||||
* <p>If an implementer provides {@link Linker} implementations for
|
||||
* multiple OS and processor combinations, then it is strongly
|
||||
* recommended that the result of {@link #defaultLookup()} exposes, as much
|
||||
* as possible, a consistent set of symbols across all the OS and processor
|
||||
* combinations.
|
||||
*
|
||||
* @return a symbol lookup for symbols in a set of commonly used libraries
|
||||
*/
|
||||
SymbolLookup defaultLookup();
|
||||
|
||||
/**
|
||||
* {@return an unmodifiable mapping between the names of data types used by the ABI implemented by this linker and their
|
||||
* <em>canonical layouts</em>}
|
||||
* {@return an unmodifiable mapping between the names of data types used by the ABI
|
||||
* implemented by this linker and their <em>canonical layouts</em>}
|
||||
* <p>
|
||||
* Each {@link Linker} is responsible for choosing the data types that are widely recognized as useful on the OS
|
||||
* and processor combination supported by the {@link Linker}. Accordingly, the precise set of data type names
|
||||
* and canonical layouts exposed by the linker are unspecified; they vary from one {@link Linker} to another.
|
||||
* @implNote It is strongly recommended that the result of {@link #canonicalLayouts()} exposes a set of symbols that is stable over time.
|
||||
* Clients of {@link #canonicalLayouts()} are likely to fail if a data type that was previously exposed by the linker
|
||||
* is no longer exposed, or if its canonical layout is updated.
|
||||
* <p>If an implementer provides {@link Linker} implementations for multiple OS and processor combinations, then it is strongly
|
||||
* recommended that the result of {@link #canonicalLayouts()} exposes, as much as possible, a consistent set of symbols
|
||||
* across all the OS and processor combinations.
|
||||
* Each {@link Linker} is responsible for choosing the data types that are widely
|
||||
* recognized as useful on the OS and processor combination supported by the
|
||||
* {@link Linker}. Accordingly, the precise set of data type names and canonical
|
||||
* layouts exposed by the linker are unspecified; they vary from one {@link Linker}
|
||||
* to another.
|
||||
*
|
||||
* @implNote It is strongly recommended that the result of {@link #canonicalLayouts()}
|
||||
* exposes a set of symbols that is stable over time. Clients of
|
||||
* {@link #canonicalLayouts()} are likely to fail if a data type that was
|
||||
* previously exposed by the linker is no longer exposed, or if its
|
||||
* canonical layout is updated.
|
||||
* <p>If an implementer provides {@link Linker} implementations for multiple
|
||||
* OS and processor combinations, then it is strongly recommended that the
|
||||
* result of {@link #canonicalLayouts()} exposes, as much as possible,
|
||||
* a consistent set of symbols across all the OS and processor combinations.
|
||||
*/
|
||||
Map<String, MemoryLayout> canonicalLayouts();
|
||||
|
||||
@ -683,49 +790,57 @@ public sealed interface Linker permits AbstractLinker {
|
||||
permits LinkerOptions.LinkerOptionImpl {
|
||||
|
||||
/**
|
||||
* {@return a linker option used to denote the index indicating the start of the variadic arguments passed to the
|
||||
* function described by the function descriptor associated with a downcall linkage request}
|
||||
* {@return a linker option used to denote the index indicating the start of the
|
||||
* variadic arguments passed to the function described by the function
|
||||
* descriptor associated with a downcall linkage request}
|
||||
* <p>
|
||||
* The {@code index} value must conform to {@code 0 <= index <= N}, where {@code N} is the number of argument
|
||||
* layouts of the function descriptor used in conjunction with this linker option. When the {@code index} is:
|
||||
* The {@code index} value must conform to {@code 0 <= index <= N}, where
|
||||
* {@code N} is the number of argument layouts of the function descriptor used in
|
||||
* conjunction with this linker option. When the {@code index} is:
|
||||
* <ul>
|
||||
* <li>{@code 0}, all arguments passed to the function are passed as variadic arguments</li>
|
||||
* <li>{@code N}, none of the arguments passed to the function are passed as variadic arguments</li>
|
||||
* <li>{@code n}, where {@code 0 < m < N}, the arguments {@code m..N} are passed as variadic arguments</li>
|
||||
* <li>{@code 0}, all arguments passed to the function are passed as variadic
|
||||
* arguments</li>
|
||||
* <li>{@code N}, none of the arguments passed to the function are passed as
|
||||
* variadic arguments</li>
|
||||
* <li>{@code n}, where {@code 0 < m < N}, the arguments {@code m..N} are passed
|
||||
* as variadic arguments</li>
|
||||
* </ul>
|
||||
* It is important to always use this linker option when linking a <a href=Linker.html#variadic-funcs>variadic
|
||||
* function</a>, even if no variadic argument is passed (the second case in the list
|
||||
* above), as this might still affect the calling convention on certain platforms.
|
||||
* It is important to always use this linker option when linking a
|
||||
* <a href=Linker.html#variadic-funcs>variadic function</a>, even if no variadic
|
||||
* argument is passed (the second case in the list above), as this might still
|
||||
* affect the calling convention on certain platforms.
|
||||
*
|
||||
* @implNote The index value is validated when making a linkage request, which is when the function descriptor
|
||||
* against which the index is validated is available.
|
||||
* @implNote The index value is validated when making a linkage request, which is
|
||||
* when the function descriptor against which the index is validated is
|
||||
* available.
|
||||
*
|
||||
* @param index the index of the first variadic argument layout in the function descriptor associated
|
||||
* with a downcall linkage request.
|
||||
* @param index the index of the first variadic argument layout in the function
|
||||
* descriptor associated with a downcall linkage request
|
||||
*/
|
||||
static Option firstVariadicArg(int index) {
|
||||
return new LinkerOptions.FirstVariadicArg(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a linker option used to save portions of the execution state immediately after
|
||||
* calling a foreign function associated with a downcall method handle,
|
||||
* before it can be overwritten by the Java runtime, or read through conventional means}
|
||||
* {@return a linker option used to save portions of the execution state
|
||||
* immediately after calling a foreign function associated with a
|
||||
* downcall method handle, before it can be overwritten by the Java
|
||||
* runtime, or read through conventional means}
|
||||
* <p>
|
||||
* Execution state is captured by a downcall method handle on invocation, by writing it
|
||||
* to a native segment provided by the user to the downcall method handle.
|
||||
* For this purpose, a downcall method handle linked with this
|
||||
* option will feature an additional {@link MemorySegment} parameter directly
|
||||
* following the target address, and optional {@link SegmentAllocator} parameters.
|
||||
* This parameter, the <em>capture state segment</em>, represents the native segment into which
|
||||
* the captured state is written.
|
||||
* Execution state is captured by a downcall method handle on invocation, by
|
||||
* writing it to a native segment provided by the user to the downcall method
|
||||
* handle. For this purpose, a downcall method handle linked with this option
|
||||
* will feature an additional {@link MemorySegment} parameter directly following
|
||||
* the target address, and optional {@link SegmentAllocator} parameters. This
|
||||
* parameter, the <em>capture state segment</em>, represents the native segment
|
||||
* into which the captured state is written.
|
||||
* <p>
|
||||
* The capture state segment must have size and alignment compatible with the layout returned by
|
||||
* {@linkplain #captureStateLayout}. This layout is a struct layout which has a named field for
|
||||
* each captured value.
|
||||
* The capture state segment must have size and alignment compatible with the
|
||||
* layout returned by {@linkplain #captureStateLayout}. This layout is a struct
|
||||
* layout which has a named field for each captured value.
|
||||
* <p>
|
||||
* Captured state can be retrieved from the capture state segment by constructing var handles
|
||||
* from the {@linkplain #captureStateLayout capture state layout}.
|
||||
* Captured state can be retrieved from the capture state segment by constructing
|
||||
* var handles from the {@linkplain #captureStateLayout capture state layout}.
|
||||
* <p>
|
||||
* The following example demonstrates the use of this linker option:
|
||||
* {@snippet lang = "java":
|
||||
@ -745,9 +860,9 @@ public sealed interface Linker permits AbstractLinker {
|
||||
* <p>
|
||||
* This linker option can not be combined with {@link #critical}.
|
||||
*
|
||||
* @param capturedState the names of the values to save.
|
||||
* @throws IllegalArgumentException if at least one of the provided {@code capturedState} names
|
||||
* is unsupported on the current platform
|
||||
* @param capturedState the names of the values to save
|
||||
* @throws IllegalArgumentException if at least one of the provided
|
||||
* {@code capturedState} names is unsupported on the current platform
|
||||
* @see #captureStateLayout()
|
||||
*/
|
||||
static Option captureCallState(String... capturedState) {
|
||||
@ -759,8 +874,9 @@ public sealed interface Linker permits AbstractLinker {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a struct layout that represents the layout of the capture state segment that is passed
|
||||
* to a downcall handle linked with {@link #captureCallState(String...)}}
|
||||
* {@return a struct layout that represents the layout of the capture state
|
||||
* segment that is passed to a downcall handle linked with
|
||||
* {@link #captureCallState(String...)}}
|
||||
* <p>
|
||||
* The capture state layout is <em>platform-dependent</em> but is guaranteed to be
|
||||
* a {@linkplain StructLayout struct layout} containing only {@linkplain ValueLayout value layouts}
|
||||
@ -789,14 +905,15 @@ public sealed interface Linker permits AbstractLinker {
|
||||
/**
|
||||
* {@return a linker option used to mark a foreign function as <em>critical</em>}
|
||||
* <p>
|
||||
* A critical function is a function that has an extremely short running time in all cases
|
||||
* (similar to calling an empty function), and does not call back into Java (e.g. using an upcall stub).
|
||||
* A critical function is a function that has an extremely short running time in
|
||||
* all cases (similar to calling an empty function), and does not call back into
|
||||
* Java (e.g. using an upcall stub).
|
||||
* <p>
|
||||
* Using this linker option is a hint that some implementations may use to apply
|
||||
* optimizations that are only valid for critical functions.
|
||||
* <p>
|
||||
* Using this linker option when linking non-critical functions is likely to have adverse effects,
|
||||
* such as loss of performance or JVM crashes.
|
||||
* Using this linker option when linking non-critical functions is likely to have
|
||||
* adverse effects, such as loss of performance or JVM crashes.
|
||||
*/
|
||||
static Option critical() {
|
||||
return LinkerOptions.Critical.INSTANCE;
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -28,11 +28,13 @@ package java.lang.foreign;
|
||||
import jdk.internal.foreign.layout.PaddingLayoutImpl;
|
||||
|
||||
/**
|
||||
* A padding layout. A padding layout specifies the size of extra space which is typically not accessed by applications,
|
||||
* and is typically used for aligning member layouts around word boundaries.
|
||||
* A padding layout. A padding layout specifies the size of extra space which is
|
||||
* typically not accessed by applications, and is typically used for aligning member
|
||||
* layouts around word boundaries.
|
||||
*
|
||||
* @implSpec
|
||||
* Implementing classes are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
* Implementing classes are immutable, thread-safe and
|
||||
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @since 22
|
||||
*/
|
||||
|
@ -36,12 +36,14 @@ import jdk.internal.foreign.StringSupport;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
|
||||
/**
|
||||
* An object that may be used to allocate {@linkplain MemorySegment memory segments}. Clients implementing this interface
|
||||
* must implement the {@link #allocate(long, long)} method. A segment allocator defines several methods
|
||||
* which can be useful to create segments from several kinds of Java values such as primitives and arrays.
|
||||
* An object that may be used to allocate {@linkplain MemorySegment memory segments}.
|
||||
* Clients implementing this interface must implement the {@link #allocate(long, long)}
|
||||
* method. A segment allocator defines several methods which can be useful to create
|
||||
* segments from several kinds of Java values such as primitives and arrays.
|
||||
* <p>
|
||||
* {@code SegmentAllocator} is a {@linkplain FunctionalInterface functional interface}. Clients can easily obtain a new
|
||||
* segment allocator by using either a lambda expression or a method reference:
|
||||
* {@code SegmentAllocator} is a {@linkplain FunctionalInterface functional interface}.
|
||||
* Clients can easily obtain a new segment allocator by using either a lambda expression
|
||||
* or a method reference:
|
||||
*
|
||||
* {@snippet lang=java :
|
||||
* SegmentAllocator autoAllocator = (byteSize, byteAlignment) -> Arena.ofAuto().allocate(byteSize, byteAlignment);
|
||||
@ -49,25 +51,29 @@ import jdk.internal.vm.annotation.ForceInline;
|
||||
* <p>
|
||||
* This interface defines factories for commonly used allocators:
|
||||
* <ul>
|
||||
* <li>{@link #slicingAllocator(MemorySegment)} obtains an efficient slicing allocator, where memory
|
||||
* is allocated by repeatedly slicing the provided memory segment;</li>
|
||||
* <li>{@link #prefixAllocator(MemorySegment)} obtains an allocator which wraps a segment
|
||||
* and recycles its content upon each new allocation request.</li>
|
||||
* <li>{@link #slicingAllocator(MemorySegment)} obtains an efficient slicing
|
||||
* allocator, where memory is allocated by repeatedly slicing the provided
|
||||
* memory segment;</li>
|
||||
* <li>{@link #prefixAllocator(MemorySegment)} obtains an allocator which wraps a
|
||||
* segment and recycles its content upon each new allocation request.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Passing a segment allocator to an API can be especially useful in circumstances where a client wants to communicate <em>where</em>
|
||||
* the results of a certain operation (performed by the API) should be stored, as a memory segment. For instance,
|
||||
* {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handles} can accept an additional
|
||||
* {@link SegmentAllocator} parameter if the underlying foreign function is known to return a struct by-value. Effectively,
|
||||
* the allocator parameter tells the linker where to store the return value of the foreign function.
|
||||
* Passing a segment allocator to an API can be especially useful in circumstances where
|
||||
* a client wants to communicate <em>where</em> the results of a certain operation
|
||||
* (performed by the API) should be stored, as a memory segment. For instance,
|
||||
* {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handles}
|
||||
* can accept an additional {@link SegmentAllocator} parameter if the underlying
|
||||
* foreign function is known to return a struct by-value. Effectively, the allocator
|
||||
* parameter tells the linker where to store the return value of the foreign function.
|
||||
*
|
||||
* @apiNote Unless otherwise specified, the {@link #allocate(long, long)} method is not thread-safe.
|
||||
* Furthermore, memory segments allocated by a segment allocator can be associated with different
|
||||
* lifetimes, and can even be backed by overlapping regions of memory. For these reasons, clients should generally
|
||||
* only interact with a segment allocator they own.
|
||||
* @apiNote Unless otherwise specified, the {@link #allocate(long, long)} method is
|
||||
* not thread-safe. Furthermore, memory segments allocated by a segment
|
||||
* allocator can be associated with different lifetimes, and can even be backed
|
||||
* by overlapping regions of memory. For these reasons, clients should
|
||||
* generally only interact with a segment allocator they own.
|
||||
* <p>
|
||||
* Clients should consider using an {@linkplain Arena arena} instead, which, provides strong thread-safety,
|
||||
* lifetime and non-overlapping guarantees.
|
||||
* Clients should consider using an {@linkplain Arena arena} instead, which, provides
|
||||
* strong thread-safety, lifetime and non-overlapping guarantees.
|
||||
*
|
||||
* @since 22
|
||||
*/
|
||||
@ -75,16 +81,17 @@ import jdk.internal.vm.annotation.ForceInline;
|
||||
public interface SegmentAllocator {
|
||||
|
||||
/**
|
||||
* Converts a Java string into a null-terminated C string using the {@linkplain StandardCharsets#UTF_8 UTF-8} charset,
|
||||
* storing the result into a memory segment.
|
||||
* Converts a Java string into a null-terminated C string using the
|
||||
* {@linkplain StandardCharsets#UTF_8 UTF-8} charset, storing the result into a
|
||||
* memory segment.
|
||||
* <p>
|
||||
* Calling this method is equivalent to the following code:
|
||||
* {@snippet lang = java:
|
||||
* allocateFrom(str, StandardCharsets.UTF_8);
|
||||
*}
|
||||
*
|
||||
* @param str the Java string to be converted into a C string.
|
||||
* @return a new native segment containing the converted C string.
|
||||
* @param str the Java string to be converted into a C string
|
||||
* @return a new native segment containing the converted C string
|
||||
*/
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(String str) {
|
||||
@ -97,7 +104,7 @@ public interface SegmentAllocator {
|
||||
* and storing the result into a memory segment.
|
||||
* <p>
|
||||
* This method always replaces malformed-input and unmappable-character
|
||||
* sequences with this charset's default replacement byte array. The
|
||||
* sequences with this charset's default replacement byte array. The
|
||||
* {@link java.nio.charset.CharsetEncoder} class should be used when more
|
||||
* control over the encoding process is required.
|
||||
* <p>
|
||||
@ -106,17 +113,21 @@ public interface SegmentAllocator {
|
||||
* the string, such as {@link MemorySegment#getString(long)}, the string
|
||||
* will appear truncated when read again.
|
||||
*
|
||||
* @param str the Java string to be converted into a C string.
|
||||
* @param charset the charset used to {@linkplain Charset#newEncoder() encode} the string bytes.
|
||||
* @return a new native segment containing the converted C string.
|
||||
* @throws IllegalArgumentException if {@code charset} is not a {@linkplain StandardCharsets standard charset}
|
||||
* @implSpec The default implementation for this method copies the contents of the provided Java string
|
||||
* into a new memory segment obtained by calling {@code this.allocate(B + N)}, where:
|
||||
* @param str the Java string to be converted into a C string
|
||||
* @param charset the charset used to {@linkplain Charset#newEncoder() encode} the
|
||||
* string bytes
|
||||
* @return a new native segment containing the converted C string
|
||||
* @throws IllegalArgumentException if {@code charset} is not a
|
||||
* {@linkplain StandardCharsets standard charset}
|
||||
* @implSpec The default implementation for this method copies the contents of the
|
||||
* provided Java string into a new memory segment obtained by calling
|
||||
* {@code this.allocate(B + N)}, where:
|
||||
* <ul>
|
||||
* <li>{@code B} is the size, in bytes, of the string encoded using the provided charset
|
||||
* (e.g. {@code str.getBytes(charset).length});</li>
|
||||
* <li>{@code N} is the size (in bytes) of the terminator char according to the provided charset. For instance,
|
||||
* this is 1 for {@link StandardCharsets#US_ASCII} and 2 for {@link StandardCharsets#UTF_16}.</li>
|
||||
* <li>{@code B} is the size, in bytes, of the string encoded using the
|
||||
* provided charset (e.g. {@code str.getBytes(charset).length});</li>
|
||||
* <li>{@code N} is the size (in bytes) of the terminator char according to the
|
||||
* provided charset. For instance, this is 1 for {@link StandardCharsets#US_ASCII}
|
||||
* and 2 for {@link StandardCharsets#UTF_16}.</li>
|
||||
* </ul>
|
||||
*/
|
||||
@ForceInline
|
||||
@ -143,11 +154,12 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the provided byte value.}
|
||||
* {@return a new memory segment initialized with the provided byte value}
|
||||
* <p>
|
||||
* The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout.
|
||||
* The given value is written into the segment according to the byte order and alignment constraint of the
|
||||
* given layout.
|
||||
* The size of the allocated memory segment is the
|
||||
* {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is
|
||||
* written into the segment according to the byte order and alignment constraint of
|
||||
* the given layout.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
@ -156,8 +168,8 @@ public interface SegmentAllocator {
|
||||
* return seg;
|
||||
* }
|
||||
*
|
||||
* @param layout the layout of the block of memory to be allocated.
|
||||
* @param value the value to be set in the newly allocated memory segment.
|
||||
* @param layout the layout of the block of memory to be allocated
|
||||
* @param value the value to be set in the newly allocated memory segment
|
||||
*/
|
||||
default MemorySegment allocateFrom(ValueLayout.OfByte layout, byte value) {
|
||||
Objects.requireNonNull(layout);
|
||||
@ -167,11 +179,12 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the provided char value.}
|
||||
* {@return a new memory segment initialized with the provided char value}
|
||||
* <p>
|
||||
* The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout.
|
||||
* The given value is written into the segment according to the byte order and alignment constraint of the
|
||||
* given layout.
|
||||
* The size of the allocated memory segment is the
|
||||
* {@linkplain MemoryLayout#byteSize() size} of the given layout.
|
||||
* The given value is written into the segment according to the byte order and
|
||||
* alignment constraint of the given layout.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
@ -180,8 +193,8 @@ public interface SegmentAllocator {
|
||||
* return seg;
|
||||
* }
|
||||
*
|
||||
* @param layout the layout of the block of memory to be allocated.
|
||||
* @param value the value to be set in the newly allocated memory segment.
|
||||
* @param layout the layout of the block of memory to be allocated
|
||||
* @param value the value to be set in the newly allocated memory segment
|
||||
*/
|
||||
default MemorySegment allocateFrom(ValueLayout.OfChar layout, char value) {
|
||||
Objects.requireNonNull(layout);
|
||||
@ -191,11 +204,12 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the provided short value.}
|
||||
* {@return a new memory segment initialized with the provided short value}
|
||||
* <p>
|
||||
* The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout.
|
||||
* The given value is written into the segment according to the byte order and alignment constraint of the
|
||||
* given layout.
|
||||
* The size of the allocated memory segment is the
|
||||
* {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is
|
||||
* written into the segment according to the byte order and alignment constraint of
|
||||
* the given layout.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
@ -204,8 +218,8 @@ public interface SegmentAllocator {
|
||||
* return seg;
|
||||
* }
|
||||
*
|
||||
* @param layout the layout of the block of memory to be allocated.
|
||||
* @param value the value to be set in the newly allocated memory segment.
|
||||
* @param layout the layout of the block of memory to be allocated
|
||||
* @param value the value to be set in the newly allocated memory segment
|
||||
*/
|
||||
default MemorySegment allocateFrom(ValueLayout.OfShort layout, short value) {
|
||||
Objects.requireNonNull(layout);
|
||||
@ -215,11 +229,12 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the provided int value.}
|
||||
* {@return a new memory segment initialized with the provided int value}
|
||||
* <p>
|
||||
* The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout.
|
||||
* The given value is written into the segment according to the byte order and alignment constraint of the
|
||||
* given layout.
|
||||
* The size of the allocated memory segment is the
|
||||
* {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is
|
||||
* written into the segment according to the byte order and alignment constraint of
|
||||
* the given layout.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
@ -228,8 +243,8 @@ public interface SegmentAllocator {
|
||||
* return seg;
|
||||
* }
|
||||
*
|
||||
* @param layout the layout of the block of memory to be allocated.
|
||||
* @param value the value to be set in the newly allocated memory segment.
|
||||
* @param layout the layout of the block of memory to be allocated
|
||||
* @param value the value to be set in the newly allocated memory segment
|
||||
*/
|
||||
default MemorySegment allocateFrom(ValueLayout.OfInt layout, int value) {
|
||||
Objects.requireNonNull(layout);
|
||||
@ -239,11 +254,12 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the provided float value.}
|
||||
* {@return a new memory segment initialized with the provided float value}
|
||||
* <p>
|
||||
* The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout.
|
||||
* The given value is written into the segment according to the byte order and alignment constraint of the
|
||||
* given layout.
|
||||
* The size of the allocated memory segment is the
|
||||
* {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is
|
||||
* written into the segment according to the byte order and alignment constraint of
|
||||
* the given layout.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
@ -252,8 +268,8 @@ public interface SegmentAllocator {
|
||||
* return seg;
|
||||
* }
|
||||
*
|
||||
* @param layout the layout of the block of memory to be allocated.
|
||||
* @param value the value to be set in the newly allocated memory segment.
|
||||
* @param layout the layout of the block of memory to be allocated
|
||||
* @param value the value to be set in the newly allocated memory segment
|
||||
*/
|
||||
default MemorySegment allocateFrom(ValueLayout.OfFloat layout, float value) {
|
||||
Objects.requireNonNull(layout);
|
||||
@ -263,11 +279,12 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the provided long value.}
|
||||
* {@return a new memory segment initialized with the provided long value}
|
||||
* <p>
|
||||
* The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout.
|
||||
* The given value is written into the segment according to the byte order and alignment constraint of the
|
||||
* given layout.
|
||||
* The size of the allocated memory segment is the
|
||||
* {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is
|
||||
* written into the segment according to the byte order and alignment constraint of
|
||||
* the given layout.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
@ -276,8 +293,8 @@ public interface SegmentAllocator {
|
||||
* return seg;
|
||||
* }
|
||||
*
|
||||
* @param layout the layout of the block of memory to be allocated.
|
||||
* @param value the value to be set in the newly allocated memory segment.
|
||||
* @param layout the layout of the block of memory to be allocated
|
||||
* @param value the value to be set in the newly allocated memory segment
|
||||
*/
|
||||
default MemorySegment allocateFrom(ValueLayout.OfLong layout, long value) {
|
||||
Objects.requireNonNull(layout);
|
||||
@ -287,11 +304,12 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the provided double value.}
|
||||
* {@return a new memory segment initialized with the provided double value}
|
||||
* <p>
|
||||
* The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout.
|
||||
* The given value is written into the segment according to the byte order and alignment constraint of the
|
||||
* given layout.
|
||||
* The size of the allocated memory segment is the
|
||||
* {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is
|
||||
* written into the segment according to the byte order and alignment constraint of
|
||||
* the given layout.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
@ -300,8 +318,8 @@ public interface SegmentAllocator {
|
||||
* return seg;
|
||||
* }
|
||||
*
|
||||
* @param layout the layout of the block of memory to be allocated.
|
||||
* @param value the value to be set in the newly allocated memory segment.
|
||||
* @param layout the layout of the block of memory to be allocated
|
||||
* @param value the value to be set in the newly allocated memory segment
|
||||
*/
|
||||
default MemorySegment allocateFrom(ValueLayout.OfDouble layout, double value) {
|
||||
Objects.requireNonNull(layout);
|
||||
@ -311,13 +329,16 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the {@linkplain MemorySegment#address() address} of the provided memory segment.}
|
||||
* {@return a new memory segment initialized with the
|
||||
* {@linkplain MemorySegment#address() address} of the provided memory segment}
|
||||
* <p>
|
||||
* The address value might be narrowed according to the platform address size (see {@link ValueLayout#ADDRESS}).
|
||||
* The address value might be narrowed according to the platform address size
|
||||
* (see {@link ValueLayout#ADDRESS}).
|
||||
* <p>
|
||||
* The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout.
|
||||
* The given value is written into the segment according to the byte order and alignment constraint of the
|
||||
* given layout.
|
||||
* The size of the allocated memory segment is the
|
||||
* {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is
|
||||
* written into the segment according to the byte order and alignment constraint of
|
||||
* the given layout.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
@ -327,9 +348,10 @@ public interface SegmentAllocator {
|
||||
* return seg;
|
||||
* }
|
||||
*
|
||||
* @param layout the layout of the block of memory to be allocated.
|
||||
* @param value the value to be set in the newly allocated memory segment.
|
||||
* @throws UnsupportedOperationException if {@code value} is not a {@linkplain MemorySegment#isNative() native} segment
|
||||
* @param layout the layout of the block of memory to be allocated
|
||||
* @param value the value to be set in the newly allocated memory segment
|
||||
* @throws UnsupportedOperationException if {@code value} is not
|
||||
* a {@linkplain MemorySegment#isNative() native} segment
|
||||
*/
|
||||
default MemorySegment allocateFrom(AddressLayout layout, MemorySegment value) {
|
||||
Objects.requireNonNull(value);
|
||||
@ -340,11 +362,12 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the contents of the provided segment.}
|
||||
* {@return a new memory segment initialized with the contents of the provided segment}
|
||||
* <p>
|
||||
* The size of the allocated memory segment is the {@code elementLayout.byteSize() * elementCount}.
|
||||
* The contents of the source segment is copied into the result segment element by element, according to the byte
|
||||
* order and alignment constraint of the given element layout.
|
||||
* The size of the allocated memory segment is the
|
||||
* {@code elementLayout.byteSize() * elementCount}. The contents of the
|
||||
* source segment is copied into the result segment element by element, according
|
||||
* to the byte order and alignment constraint of the given element layout.
|
||||
*
|
||||
* @implSpec The default implementation for this method is equivalent to the following code:
|
||||
* {@snippet lang = java:
|
||||
@ -352,19 +375,19 @@ public interface SegmentAllocator {
|
||||
* MemorySegment.copy(source, sourceElementLayout, sourceOffset, dest, elementLayout, 0, elementCount);
|
||||
* return dest;
|
||||
* }
|
||||
* @param elementLayout the element layout of the allocated array.
|
||||
* @param source the source segment.
|
||||
* @param sourceElementLayout the element layout of the source segment.
|
||||
* @param sourceOffset the starting offset, in bytes, of the source segment.
|
||||
* @param elementCount the number of elements in the source segment to be copied.
|
||||
* @param elementLayout the element layout of the allocated array
|
||||
* @param source the source segment
|
||||
* @param sourceElementLayout the element layout of the source segment
|
||||
* @param sourceOffset the starting offset, in bytes, of the source segment
|
||||
* @param elementCount the number of elements in the source segment to be copied
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteSize() != sourceElementLayout.byteSize()}
|
||||
* @throws IllegalArgumentException if the source segment/offset
|
||||
* are <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a>
|
||||
* in the source element layout.
|
||||
* in the source element layout
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
|
||||
* @throws IllegalArgumentException if {@code sourceElementLayout.byteAlignment() > sourceElementLayout.byteSize()}
|
||||
* @throws IllegalStateException if the {@linkplain MemorySegment#scope() scope} associated with {@code source} is not
|
||||
* {@linkplain MemorySegment.Scope#isAlive() alive}
|
||||
* @throws IllegalStateException if the {@linkplain MemorySegment#scope() scope} associated
|
||||
* with {@code source} is not {@linkplain MemorySegment.Scope#isAlive() alive}
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code source.isAccessibleBy(T) == false}
|
||||
* @throws IndexOutOfBoundsException if {@code elementCount * sourceElementLayout.byteSize()} overflows
|
||||
@ -386,20 +409,25 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the elements in the provided byte array.}
|
||||
* {@return a new memory segment initialized with the elements in the provided
|
||||
* byte array}
|
||||
* <p>
|
||||
* The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}.
|
||||
* The contents of the source array is copied into the result segment element by element, according to the byte
|
||||
* order and alignment constraint of the given element layout.
|
||||
* The size of the allocated memory segment is
|
||||
* {@code elementLayout.byteSize() * elements.length}. The contents of the
|
||||
* source array is copied into the result segment element by element, according
|
||||
* to the byte order and alignment constraint of the given element layout.
|
||||
*
|
||||
* @implSpec The default implementation for this method is equivalent to the following code:
|
||||
* @implSpec The default implementation for this method is equivalent to the
|
||||
* following code:
|
||||
* {@snippet lang = java:
|
||||
* this.allocateFrom(layout, MemorySegment.ofArray(array),
|
||||
* ValueLayout.JAVA_BYTE, 0, array.length)
|
||||
*}
|
||||
* @param elementLayout the element layout of the array to be allocated.
|
||||
* @param elements the byte elements to be copied to the newly allocated memory block.
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
|
||||
* @param elementLayout the element layout of the array to be allocated
|
||||
* @param elements the byte elements to be copied to the newly allocated
|
||||
* memory block
|
||||
* @throws IllegalArgumentException if
|
||||
* {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
|
||||
*/
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(ValueLayout.OfByte elementLayout, byte... elements) {
|
||||
@ -408,20 +436,25 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the elements in the provided short array.}
|
||||
* {@return a new memory segment initialized with the elements in the provided
|
||||
* short array}
|
||||
* <p>
|
||||
* The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}.
|
||||
* The contents of the source array are copied into the result segment element by element, according to the byte
|
||||
* order and alignment constraint of the given element layout.
|
||||
* The size of the allocated memory segment is
|
||||
* {@code elementLayout.byteSize() * elements.length}. The contents of the
|
||||
* source array are copied into the result segment element by element, according
|
||||
* to the byte order and alignment constraint of the given element layout.
|
||||
*
|
||||
* @implSpec The default implementation for this method is equivalent to the following code:
|
||||
* @implSpec The default implementation for this method is equivalent to the
|
||||
* following code:
|
||||
* {@snippet lang = java:
|
||||
* this.allocateFrom(layout, MemorySegment.ofArray(array),
|
||||
* ValueLayout.JAVA_SHORT, 0, array.length)
|
||||
*}
|
||||
* @param elementLayout the element layout of the array to be allocated.
|
||||
* @param elements the short elements to be copied to the newly allocated memory block.
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
|
||||
* @param elementLayout the element layout of the array to be allocated
|
||||
* @param elements the short elements to be copied to the newly allocated
|
||||
* memory block
|
||||
* @throws IllegalArgumentException if
|
||||
* {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
|
||||
*/
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(ValueLayout.OfShort elementLayout, short... elements) {
|
||||
@ -430,20 +463,25 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the elements in the provided char array.}
|
||||
* {@return a new memory segment initialized with the elements in the provided
|
||||
* char array}
|
||||
* <p>
|
||||
* The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}.
|
||||
* The contents of the source array is copied into the result segment element by element, according to the byte
|
||||
* order and alignment constraint of the given element layout.
|
||||
* The size of the allocated memory segment is
|
||||
* {@code elementLayout.byteSize() * elements.length}. The contents of the
|
||||
* source array is copied into the result segment element by element, according
|
||||
* to the byte order and alignment constraint of the given element layout.
|
||||
*
|
||||
* @implSpec The default implementation for this method is equivalent to the following code:
|
||||
* @implSpec The default implementation for this method is equivalent to the
|
||||
* following code:
|
||||
* {@snippet lang = java:
|
||||
* this.allocateFrom(layout, MemorySegment.ofArray(array),
|
||||
* ValueLayout.JAVA_CHAR, 0, array.length)
|
||||
*}
|
||||
* @param elementLayout the element layout of the array to be allocated.
|
||||
* @param elements the char elements to be copied to the newly allocated memory block.
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
|
||||
* @param elementLayout the element layout of the array to be allocated
|
||||
* @param elements the char elements to be copied to the newly allocated
|
||||
* memory block
|
||||
* @throws IllegalArgumentException if
|
||||
* {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
|
||||
*/
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(ValueLayout.OfChar elementLayout, char... elements) {
|
||||
@ -452,20 +490,25 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the elements in the provided int array.}
|
||||
* {@return a new memory segment initialized with the elements in the provided
|
||||
* int array}
|
||||
* <p>
|
||||
* The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}.
|
||||
* The contents of the source array is copied into the result segment element by element, according to the byte
|
||||
* order and alignment constraint of the given element layout.
|
||||
* The size of the allocated memory segment is
|
||||
* {@code elementLayout.byteSize() * elements.length}. The contents of the
|
||||
* source array is copied into the result segment element by element, according
|
||||
* to the byte order and alignment constraint of the given element layout.
|
||||
*
|
||||
* @implSpec The default implementation for this method is equivalent to the following code:
|
||||
* @implSpec The default implementation for this method is equivalent to the
|
||||
* following code:
|
||||
* {@snippet lang = java:
|
||||
* this.allocateFrom(layout, MemorySegment.ofArray(array),
|
||||
* ValueLayout.JAVA_INT, 0, array.length)
|
||||
*}
|
||||
* @param elementLayout the element layout of the array to be allocated.
|
||||
* @param elements the int elements to be copied to the newly allocated memory block.
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
|
||||
* @param elementLayout the element layout of the array to be allocated
|
||||
* @param elements the int elements to be copied to the newly allocated
|
||||
* memory block
|
||||
* @throws IllegalArgumentException if
|
||||
* {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
|
||||
*/
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(ValueLayout.OfInt elementLayout, int... elements) {
|
||||
@ -474,20 +517,25 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the elements in the provided float array.}
|
||||
* {@return a new memory segment initialized with the elements in the provided
|
||||
* float array}
|
||||
* <p>
|
||||
* The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}.
|
||||
* The contents of the source array is copied into the result segment element by element, according to the byte
|
||||
* order and alignment constraint of the given element layout.
|
||||
* The size of the allocated memory segment is
|
||||
* {@code elementLayout.byteSize() * elements.length}. The contents of
|
||||
* the source array is copied into the result segment element by element, according
|
||||
* to the byte order and alignment constraint of the given element layout.
|
||||
*
|
||||
* @implSpec The default implementation for this method is equivalent to the following code:
|
||||
* @implSpec The default implementation for this method is equivalent to the
|
||||
* following code:
|
||||
* {@snippet lang = java:
|
||||
* this.allocateFrom(layout, MemorySegment.ofArray(array),
|
||||
* ValueLayout.JAVA_FLOAT, 0, array.length)
|
||||
*}
|
||||
* @param elementLayout the element layout of the array to be allocated.
|
||||
* @param elements the float elements to be copied to the newly allocated memory block.
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
|
||||
* @param elementLayout the element layout of the array to be allocated
|
||||
* @param elements the float elements to be copied to the newly allocated
|
||||
* memory block
|
||||
* @throws IllegalArgumentException if
|
||||
* {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
|
||||
*/
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(ValueLayout.OfFloat elementLayout, float... elements) {
|
||||
@ -496,20 +544,25 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the elements in the provided long array.}
|
||||
* {@return a new memory segment initialized with the elements in the provided
|
||||
* long array}
|
||||
* <p>
|
||||
* The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}.
|
||||
* The contents of the source array is copied into the result segment element by element, according to the byte
|
||||
* order and alignment constraint of the given element layout.
|
||||
* The size of the allocated memory segment is
|
||||
* {@code elementLayout.byteSize() * elements.length}. The contents of
|
||||
* the source array is copied into the result segment element by element, according
|
||||
* to the byte order and alignment constraint of the given element layout.
|
||||
*
|
||||
* @implSpec The default implementation for this method is equivalent to the following code:
|
||||
* @implSpec The default implementation for this method is equivalent to the
|
||||
* following code:
|
||||
* {@snippet lang = java:
|
||||
* this.allocateFrom(layout, MemorySegment.ofArray(array),
|
||||
* ValueLayout.JAVA_LONG, 0, array.length)
|
||||
*}
|
||||
* @param elementLayout the element layout of the array to be allocated.
|
||||
* @param elements the long elements to be copied to the newly allocated memory block.
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
|
||||
* @param elementLayout the element layout of the array to be allocated
|
||||
* @param elements the long elements to be copied to the newly allocated
|
||||
* memory block
|
||||
* @throws IllegalArgumentException if
|
||||
* {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
|
||||
*/
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(ValueLayout.OfLong elementLayout, long... elements) {
|
||||
@ -518,20 +571,25 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the elements in the provided double array.}
|
||||
* {@return a new memory segment initialized with the elements in the provided
|
||||
* double array}
|
||||
* <p>
|
||||
* The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}.
|
||||
* The contents of the source array is copied into the result segment element by element, according to the byte
|
||||
* order and alignment constraint of the given element layout.
|
||||
* The size of the allocated memory segment is
|
||||
* {@code elementLayout.byteSize() * elements.length}. The contents of
|
||||
* the source array is copied into the result segment element by element, according
|
||||
* to the byte order and alignment constraint of the given element layout.
|
||||
*
|
||||
* @implSpec The default implementation for this method is equivalent to the following code:
|
||||
* @implSpec The default implementation for this method is equivalent to the
|
||||
* following code:
|
||||
* {@snippet lang = java:
|
||||
* this.allocateFrom(layout, MemorySegment.ofArray(array),
|
||||
* ValueLayout.JAVA_DOUBLE, 0, array.length)
|
||||
*}
|
||||
* @param elementLayout the element layout of the array to be allocated.
|
||||
* @param elements the double elements to be copied to the newly allocated memory block.
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
|
||||
* @param elementLayout the element layout of the array to be allocated
|
||||
* @param elements the double elements to be copied to the newly allocated
|
||||
* memory block
|
||||
* @throws IllegalArgumentException if
|
||||
* {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
|
||||
*/
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(ValueLayout.OfDouble elementLayout, double... elements) {
|
||||
@ -543,9 +601,9 @@ public interface SegmentAllocator {
|
||||
* {@return a new memory segment with the given layout}
|
||||
*
|
||||
* @implSpec The default implementation for this method calls
|
||||
* {@code this.allocate(layout.byteSize(), layout.byteAlignment())}.
|
||||
* {@code this.allocate(layout.byteSize(), layout.byteAlignment())}.
|
||||
*
|
||||
* @param layout the layout of the block of memory to be allocated.
|
||||
* @param layout the layout of the block of memory to be allocated
|
||||
*/
|
||||
default MemorySegment allocate(MemoryLayout layout) {
|
||||
Objects.requireNonNull(layout);
|
||||
@ -556,11 +614,12 @@ public interface SegmentAllocator {
|
||||
* {@return a new memory segment with the given {@code elementLayout} and {@code count}}
|
||||
*
|
||||
* @implSpec The default implementation for this method calls
|
||||
* {@code this.allocate(MemoryLayout.sequenceLayout(count, elementLayout))}.
|
||||
* {@code this.allocate(MemoryLayout.sequenceLayout(count, elementLayout))}.
|
||||
*
|
||||
* @param elementLayout the array element layout.
|
||||
* @param count the array element count.
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteSize() * count} overflows
|
||||
* @param elementLayout the array element layout
|
||||
* @param count the array element count
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteSize() * count}
|
||||
* overflows
|
||||
* @throws IllegalArgumentException if {@code count < 0}
|
||||
*/
|
||||
default MemorySegment allocate(MemoryLayout elementLayout, long count) {
|
||||
@ -575,9 +634,9 @@ public interface SegmentAllocator {
|
||||
* {@return a new memory segment with the given {@code byteSize}}
|
||||
*
|
||||
* @implSpec The default implementation for this method calls
|
||||
* {@code this.allocate(byteSize, 1)}.
|
||||
* {@code this.allocate(byteSize, 1)}.
|
||||
*
|
||||
* @param byteSize the size (in bytes) of the block of memory to be allocated.
|
||||
* @param byteSize the size (in bytes) of the block of memory to be allocated
|
||||
* @throws IllegalArgumentException if {@code byteSize < 0}
|
||||
*/
|
||||
default MemorySegment allocate(long byteSize) {
|
||||
@ -585,26 +644,31 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment with the given {@code byteSize} and {@code byteAlignment}}
|
||||
* {@return a new memory segment with the given {@code byteSize} and
|
||||
* {@code byteAlignment}}
|
||||
*
|
||||
* @param byteSize the size (in bytes) of the block of memory to be allocated.
|
||||
* @param byteAlignment the alignment (in bytes) of the block of memory to be allocated.
|
||||
* @throws IllegalArgumentException if {@code byteSize < 0}, {@code byteAlignment <= 0},
|
||||
* @param byteSize the size (in bytes) of the block of memory
|
||||
* to be allocated
|
||||
* @param byteAlignment the alignment (in bytes) of the block of memory
|
||||
* to be allocated
|
||||
* @throws IllegalArgumentException if {@code byteSize < 0},
|
||||
* {@code byteAlignment <= 0},
|
||||
* or if {@code byteAlignment} is not a power of 2
|
||||
*/
|
||||
MemorySegment allocate(long byteSize, long byteAlignment);
|
||||
|
||||
/**
|
||||
* Returns a segment allocator that responds to allocation requests by returning consecutive slices
|
||||
* obtained from the provided segment. Each new allocation request will return a new slice starting at the
|
||||
* current offset (modulo additional padding to satisfy alignment constraint), with given size.
|
||||
* Returns a segment allocator that responds to allocation requests by returning
|
||||
* consecutive slices obtained from the provided segment. Each new allocation
|
||||
* request will return a new slice starting at the current offset (modulo additional
|
||||
* padding to satisfy alignment constraint), with given size.
|
||||
* <p>
|
||||
* The returned allocator throws {@link IndexOutOfBoundsException} when a slice of the provided
|
||||
* segment with the requested size and alignment cannot be found.
|
||||
* The returned allocator throws {@link IndexOutOfBoundsException} when a slice of
|
||||
* the provided segment with the requested size and alignment cannot be found.
|
||||
*
|
||||
* @implNote A slicing allocator is not <em>thread-safe</em>.
|
||||
*
|
||||
* @param segment the segment from which the returned allocator should slice from.
|
||||
* @param segment the segment from which the returned allocator should slice from
|
||||
* @return a new slicing allocator
|
||||
*/
|
||||
static SegmentAllocator slicingAllocator(MemorySegment segment) {
|
||||
@ -613,25 +677,29 @@ public interface SegmentAllocator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a segment allocator that responds to allocation requests by recycling a single segment. Each
|
||||
* new allocation request will return a new slice starting at the segment offset {@code 0}, hence the name
|
||||
* <em>prefix allocator</em>.
|
||||
* Returns a segment allocator that responds to allocation requests by recycling a
|
||||
* single segment. Each new allocation request will return a new slice starting at
|
||||
* the segment offset {@code 0}, hence the name <em>prefix allocator</em>.
|
||||
* <p>
|
||||
* Equivalent to (but likely more efficient than) the following code:
|
||||
* {@snippet lang=java :
|
||||
* MemorySegment segment = ...
|
||||
* SegmentAllocator prefixAllocator = (size, align) -> segment.asSlice(0, size, align);
|
||||
* }
|
||||
* The returned allocator throws {@link IndexOutOfBoundsException} when a slice of the provided
|
||||
* segment with the requested size and alignment cannot be found.
|
||||
* The returned allocator throws {@link IndexOutOfBoundsException} when a slice of
|
||||
* the provided segment with the requested size and alignment cannot be found.
|
||||
*
|
||||
* @apiNote A prefix allocator can be useful to limit allocation requests in case a client
|
||||
* knows that they have fully processed the contents of the allocated segment before the subsequent allocation request
|
||||
* takes place.
|
||||
* @implNote While a prefix allocator is <em>thread-safe</em>, concurrent access on the same recycling
|
||||
* allocator might cause a thread to overwrite contents written to the underlying segment by a different thread.
|
||||
* @apiNote A prefix allocator can be useful to limit allocation requests in case a
|
||||
* client knows that they have fully processed the contents of the allocated
|
||||
* segment before the subsequent allocation request takes place.
|
||||
*
|
||||
* @param segment the memory segment to be recycled by the returned allocator.
|
||||
* @return an allocator that recycles an existing segment upon each new allocation request.
|
||||
* @implNote While a prefix allocator is <em>thread-safe</em>, concurrent access on
|
||||
* the same recycling allocator might cause a thread to overwrite contents
|
||||
* written to the underlying segment by a different thread.
|
||||
*
|
||||
* @param segment the memory segment to be recycled by the returned allocator
|
||||
* @return an allocator that recycles an existing segment upon each new
|
||||
* allocation request
|
||||
*/
|
||||
static SegmentAllocator prefixAllocator(MemorySegment segment) {
|
||||
return (AbstractMemorySegmentImpl)Objects.requireNonNull(segment);
|
||||
|
@ -28,10 +28,11 @@ package java.lang.foreign;
|
||||
import jdk.internal.foreign.layout.SequenceLayoutImpl;
|
||||
|
||||
/**
|
||||
* A compound layout that denotes a homogeneous repetition of a given <em>element layout</em>.
|
||||
* The repetition count is said to be the sequence layout's <em>element count</em>. A sequence layout can be thought of as a
|
||||
* struct layout where the sequence layout's element layout is repeated a number of times that is equal to the sequence
|
||||
* layout's element count. In other words this layout:
|
||||
* A compound layout that denotes a homogeneous repetition of a given
|
||||
* <em>element layout</em>. The repetition count is said to be the sequence layout's
|
||||
* <em>element count</em>. A sequence layout can be thought of as a struct layout where
|
||||
* the sequence layout's element layout is repeated a number of times that is equal to
|
||||
* the sequence layout's element count. In other words this layout:
|
||||
*
|
||||
* {@snippet lang=java :
|
||||
* MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN));
|
||||
@ -47,7 +48,8 @@ import jdk.internal.foreign.layout.SequenceLayoutImpl;
|
||||
* }
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
* This class is immutable, thread-safe and
|
||||
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @since 22
|
||||
*/
|
||||
@ -65,18 +67,21 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
|
||||
long elementCount();
|
||||
|
||||
/**
|
||||
* {@return a sequence layout with the same characteristics of this layout, but with the given element count}
|
||||
* @param elementCount the new element count.
|
||||
* {@return a sequence layout with the same characteristics of this layout, but with
|
||||
* the given element count}
|
||||
* @param elementCount the new element count
|
||||
* @throws IllegalArgumentException if {@code elementCount} is negative
|
||||
* @throws IllegalArgumentException if {@code elementLayout.bitSize() * elementCount} overflows
|
||||
* @throws IllegalArgumentException if {@code elementLayout.bitSize() * elementCount}
|
||||
* overflows
|
||||
*/
|
||||
SequenceLayout withElementCount(long elementCount);
|
||||
|
||||
/**
|
||||
* Rearranges the elements in this sequence layout into a multi-dimensional sequence layout.
|
||||
* The resulting layout is a sequence layout where element layouts in the {@linkplain #flatten() flattened projection}
|
||||
* of this sequence layout are rearranged into one or more nested sequence layouts
|
||||
* according to the provided element counts. This transformation preserves the layout size;
|
||||
* Rearranges the elements in this sequence layout into a multidimensional sequence
|
||||
* layout. The resulting layout is a sequence layout where element layouts in the
|
||||
* {@linkplain #flatten() flattened projection} of this sequence layout are
|
||||
* rearranged into one or more nested sequence layouts according to the provided
|
||||
* element counts. This transformation preserves the layout size;
|
||||
* that is, multiplying the provided element counts must yield the same element count
|
||||
* as the flattened projection of this sequence layout.
|
||||
* <p>
|
||||
@ -89,27 +94,32 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
|
||||
* var reshapeSeq = MemoryLayout.sequenceLayout(2, MemoryLayout.sequenceLayout(6, ValueLayout.JAVA_INT));
|
||||
* }
|
||||
* <p>
|
||||
* If one of the provided element counts is the special value {@code -1}, then the element
|
||||
* count in that position will be inferred from the remaining element counts and the
|
||||
* element count of the flattened projection of this layout. For instance, a layout equivalent to
|
||||
* the above {@code reshapeSeq} can also be computed in the following ways:
|
||||
* If one of the provided element counts is the special value {@code -1}, then
|
||||
* the element count in that position will be inferred from the remaining element
|
||||
* counts and the element count of the flattened projection of this layout.
|
||||
* For instance, a layout equivalent to the above {@code reshapeSeq} can also be
|
||||
* computed in the following ways:
|
||||
* {@snippet lang=java :
|
||||
* var reshapeSeqImplicit1 = seq.reshape(-1, 6);
|
||||
* var reshapeSeqImplicit2 = seq.reshape(2, -1);
|
||||
* }
|
||||
* @param elementCounts an array of element counts, of which at most one can be {@code -1}.
|
||||
* @return a sequence layout where element layouts in the {@linkplain #flatten() flattened projection} of this
|
||||
* sequence layout (see {@link #flatten()}) are re-arranged into one or more nested sequence layouts.
|
||||
* @throws IllegalArgumentException if two or more element counts are set to {@code -1}, or if one
|
||||
* or more element count is {@code <= 0} (but other than {@code -1}) or, if, after any required inference,
|
||||
* multiplying the element counts does not yield the same element count as the flattened projection of this
|
||||
* @param elementCounts an array of element counts, of which at most one can be {@code -1}
|
||||
* @return a sequence layout where element layouts in the
|
||||
* {@linkplain #flatten() flattened projection} of this sequence layout
|
||||
* (see {@link #flatten()}) are re-arranged into one or more nested
|
||||
* sequence layouts
|
||||
* @throws IllegalArgumentException if two or more element counts are set to {@code -1},
|
||||
* or if one or more element count is {@code <= 0} (but other than {@code -1}) or,
|
||||
* if, after any required inference, multiplying the element counts does not
|
||||
* yield the same element count as the flattened projection of this
|
||||
* sequence layout
|
||||
*/
|
||||
SequenceLayout reshape(long... elementCounts);
|
||||
|
||||
/**
|
||||
* Returns a flattened sequence layout. The element layout of the returned sequence layout
|
||||
* is the first non-sequence layout found by inspecting (recursively, if needed) the element layout of this sequence layout:
|
||||
* Returns a flattened sequence layout. The element layout of the returned
|
||||
* sequence layout is the first non-sequence layout found by inspecting
|
||||
* (recursively, if needed) the element layout of this sequence layout:
|
||||
* {@snippet lang=java :
|
||||
* MemoryLayout flatElementLayout(SequenceLayout sequenceLayout) {
|
||||
* return switch (sequenceLayout.elementLayout()) {
|
||||
@ -119,9 +129,10 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
|
||||
* }
|
||||
* }
|
||||
* <p>
|
||||
* This transformation preserves the layout size; nested sequence layout in this sequence layout will
|
||||
* be dropped and their element counts will be incorporated into that of the returned sequence layout.
|
||||
* For instance, given a sequence layout of the kind:
|
||||
* This transformation preserves the layout size; nested sequence layout in this
|
||||
* sequence layout will be dropped and their element counts will be incorporated
|
||||
* into that of the returned sequence layout. For instance, given a
|
||||
* sequence layout of the kind:
|
||||
* {@snippet lang=java :
|
||||
* var seq = MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT));
|
||||
* }
|
||||
@ -129,8 +140,9 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
|
||||
* {@snippet lang=java :
|
||||
* var flattenedSeq = MemoryLayout.sequenceLayout(12, ValueLayout.JAVA_INT);
|
||||
* }
|
||||
* @return a sequence layout with the same size as this layout (but, possibly, with different
|
||||
* element count), whose element layout is not a sequence layout.
|
||||
* @return a sequence layout with the same size as this layout
|
||||
* (but, possibly, with different element count), whose
|
||||
* element layout is not a sequence layout
|
||||
*/
|
||||
SequenceLayout flatten();
|
||||
|
||||
@ -149,7 +161,8 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws IllegalArgumentException {@inheritDoc}
|
||||
* @throws IllegalArgumentException if {@code byteAlignment < elementLayout().byteAlignment()}
|
||||
* @throws IllegalArgumentException if
|
||||
* {@code byteAlignment < elementLayout().byteAlignment()}
|
||||
*/
|
||||
SequenceLayout withByteAlignment(long byteAlignment);
|
||||
}
|
||||
|
@ -31,7 +31,8 @@ import jdk.internal.foreign.layout.StructLayoutImpl;
|
||||
* A group layout whose member layouts are laid out one after the other.
|
||||
*
|
||||
* @implSpec
|
||||
* Implementing classes are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
* Implementing classes are immutable, thread-safe and
|
||||
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @since 22
|
||||
*/
|
||||
|
@ -46,26 +46,34 @@ import java.util.function.BiFunction;
|
||||
* A <em>symbol lookup</em> retrieves the address of a symbol in one or more libraries.
|
||||
* A symbol is a named entity, such as a function or a global variable.
|
||||
* <p>
|
||||
* A symbol lookup is created with respect to a particular library (or libraries). Subsequently, the {@link SymbolLookup#find(String)}
|
||||
* method takes the name of a symbol and returns the address of the symbol in that library.
|
||||
* A symbol lookup is created with respect to a particular library (or libraries).
|
||||
* Subsequently, the {@link SymbolLookup#find(String)} method takes the name of a symbol
|
||||
* and returns the address of the symbol in that library.
|
||||
* <p>
|
||||
* The address of a symbol is modeled as a zero-length {@linkplain MemorySegment memory segment}. The segment can be used in different ways:
|
||||
* The address of a symbol is modeled as a zero-length
|
||||
* {@linkplain MemorySegment memory segment}. The segment can be used in different ways:
|
||||
* <ul>
|
||||
* <li>It can be passed to a {@link Linker} to create a downcall method handle, which can then be used to call the foreign function at the segment's address.</li>
|
||||
* <li>It can be passed to an existing {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle}, as an argument to the underlying foreign function.</li>
|
||||
* <li>It can be {@linkplain MemorySegment#set(AddressLayout, long, MemorySegment) stored} inside another memory segment.</li>
|
||||
* <li>It can be used to access the region of memory backing a global variable (this requires
|
||||
* {@linkplain MemorySegment#reinterpret(long) resizing} the segment first).</li>
|
||||
* <li>It can be passed to a {@link Linker} to create a downcall method handle, which
|
||||
* can then be used to call the foreign function at the segment's address.</li>
|
||||
* <li>It can be passed to an existing
|
||||
* {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle},
|
||||
* as an argument to the underlying foreign function.</li>
|
||||
* <li>It can be {@linkplain MemorySegment#set(AddressLayout, long, MemorySegment) stored}
|
||||
* inside another memory segment.</li>
|
||||
* <li>It can be used to access the region of memory backing a global variable
|
||||
* (this requires {@linkplain MemorySegment#reinterpret(long) resizing}
|
||||
* the segment first).</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2 id="obtaining">Obtaining a symbol lookup</h2>
|
||||
*
|
||||
* The factory methods {@link #libraryLookup(String, Arena)} and {@link #libraryLookup(Path, Arena)}
|
||||
* create a symbol lookup for a library known to the operating system. The library is specified by either its name or a path.
|
||||
* The library is loaded if not already loaded. The symbol lookup, which is known as a <em>library lookup</em>, and its
|
||||
* lifetime is controlled by an {@linkplain Arena arena}. For instance, if the provided arena is a
|
||||
* confined arena, the library associated with the symbol lookup is unloaded when the confined arena
|
||||
* is {@linkplain Arena#close() closed}:
|
||||
* The factory methods {@link #libraryLookup(String, Arena)} and
|
||||
* {@link #libraryLookup(Path, Arena)} create a symbol lookup for a library known to
|
||||
* the operating system. The library is specified by either its name or a path.
|
||||
* The library is loaded if not already loaded. The symbol lookup, which is known as a
|
||||
* <em>library lookup</em>, and its lifetime is controlled by an {@linkplain Arena arena}.
|
||||
* For instance, if the provided arena is a confined arena, the library associated with
|
||||
* the symbol lookup is unloaded when the confined arena is {@linkplain Arena#close() closed}:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* try (Arena arena = Arena.ofConfined()) {
|
||||
@ -76,8 +84,9 @@ import java.util.function.BiFunction;
|
||||
*}
|
||||
* <p>
|
||||
* If a library was previously loaded through JNI, i.e., by {@link System#load(String)}
|
||||
* or {@link System#loadLibrary(String)}, then the library was also associated with a particular class loader. The factory
|
||||
* method {@link #loaderLookup()} creates a symbol lookup for all the libraries associated with the caller's class loader:
|
||||
* or {@link System#loadLibrary(String)}, then the library was also associated with
|
||||
* a particular class loader. The factory method {@link #loaderLookup()} creates
|
||||
* a symbol lookup for all the libraries associated with the caller's class loader:
|
||||
*
|
||||
* {@snippet lang=java :
|
||||
* System.loadLibrary("GL"); // libGL.so loaded here
|
||||
@ -86,21 +95,24 @@ import java.util.function.BiFunction;
|
||||
* MemorySegment glGetString = libGL.find("glGetString").orElseThrow();
|
||||
* }
|
||||
*
|
||||
* This symbol lookup, which is known as a <em>loader lookup</em>, is dynamic with respect to the libraries associated
|
||||
* with the class loader. If other libraries are subsequently loaded through JNI and associated with the class loader,
|
||||
* then the loader lookup will expose their symbols automatically.
|
||||
* This symbol lookup, which is known as a <em>loader lookup</em>, is dynamic with
|
||||
* respect to the libraries associated with the class loader. If other libraries are
|
||||
* subsequently loaded through JNI and associated with the class loader, then the loader
|
||||
* lookup will expose their symbols automatically.
|
||||
* <p>
|
||||
* Note that a loader lookup only exposes symbols in libraries that were previously loaded through JNI, i.e.,
|
||||
* by {@link System#load(String)} or {@link System#loadLibrary(String)}. A loader lookup does not expose symbols in libraries
|
||||
* that were loaded in the course of creating a library lookup:
|
||||
* Note that a loader lookup only exposes symbols in libraries that were previously
|
||||
* loaded through JNI, i.e., by {@link System#load(String)} or {@link System#loadLibrary(String)}.
|
||||
* A loader lookup does not expose symbols in libraries that were loaded in the course
|
||||
* of creating a library lookup:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* libraryLookup("libGL.so", arena).find("glGetString").isPresent(); // true
|
||||
* loaderLookup().find("glGetString").isPresent(); // false
|
||||
*}
|
||||
*
|
||||
* Note also that a library lookup for library {@code L} exposes symbols in {@code L} even if {@code L} was previously loaded
|
||||
* through JNI (the association with a class loader is immaterial to the library lookup):
|
||||
* Note also that a library lookup for library {@code L} exposes symbols in {@code L}
|
||||
* even if {@code L} was previously loaded through JNI (the association with
|
||||
* a class loader is immaterial to the library lookup):
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* System.loadLibrary("GL"); // libGL.so loaded here
|
||||
@ -108,10 +120,11 @@ import java.util.function.BiFunction;
|
||||
*}
|
||||
*
|
||||
* <p>
|
||||
* Finally, each {@link Linker} provides a symbol lookup for libraries that are commonly used on the OS and processor
|
||||
* combination supported by that {@link Linker}. This symbol lookup, which is known as a <em>default lookup</em>,
|
||||
* helps clients to quickly find addresses of well-known symbols. For example, a {@link Linker} for Linux/x64 might choose to
|
||||
* expose symbols in {@code libc} through the default lookup:
|
||||
* Finally, each {@link Linker} provides a symbol lookup for libraries that are commonly
|
||||
* used on the OS and processor combination supported by that {@link Linker}. This
|
||||
* symbol lookup, which is known as a <em>default lookup</em>, helps clients to quickly
|
||||
* find addresses of well-known symbols. For example, a {@link Linker} for Linux/x64
|
||||
* might choose to expose symbols in {@code libc} through the default lookup:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* Linker nativeLinker = Linker.nativeLinker();
|
||||
@ -126,27 +139,33 @@ public interface SymbolLookup {
|
||||
|
||||
/**
|
||||
* Returns the address of the symbol with the given name.
|
||||
* @param name the symbol name.
|
||||
* @return a zero-length memory segment whose address indicates the address of the symbol, if found.
|
||||
*
|
||||
* @param name the symbol name
|
||||
* @return a zero-length memory segment whose address indicates the address of
|
||||
* the symbol, if found
|
||||
*/
|
||||
Optional<MemorySegment> find(String name);
|
||||
|
||||
/**
|
||||
* {@return a composed symbol lookup that returns the result of finding the symbol with this lookup if found,
|
||||
* otherwise returns the result of finding the symbol with the other lookup}
|
||||
* {@return a composed symbol lookup that returns the result of finding the symbol
|
||||
* with this lookup if found, otherwise returns the result of finding
|
||||
* the symbol with the other lookup}
|
||||
*
|
||||
* @apiNote This method could be used to chain multiple symbol lookups together, e.g. so that symbols could
|
||||
* be retrieved, in order, from multiple libraries:
|
||||
* @apiNote This method could be used to chain multiple symbol lookups together,
|
||||
* e.g. so that symbols could be retrieved, in order, from multiple
|
||||
* libraries:
|
||||
* {@snippet lang = java:
|
||||
* var lookup = SymbolLookup.libraryLookup("foo", arena)
|
||||
* .or(SymbolLookup.libraryLookup("bar", arena))
|
||||
* .or(SymbolLookup.loaderLookup());
|
||||
*}
|
||||
* The above code creates a symbol lookup that first searches for symbols in the "foo" library. If no symbol is found
|
||||
* in "foo" then "bar" is searched. Finally, if a symbol is neither found in "foo" nor in "bar", the {@linkplain
|
||||
* SymbolLookup#loaderLookup() loader lookup} is used.
|
||||
* The above code creates a symbol lookup that first searches for symbols in
|
||||
* the "foo" library. If no symbol is found in "foo" then "bar" is searched.
|
||||
* Finally, if a symbol is neither found in "foo" nor in "bar", the
|
||||
* {@linkplain SymbolLookup#loaderLookup() loader lookup} is used.
|
||||
*
|
||||
* @param other the symbol lookup that should be used to look for symbols not found in this lookup.
|
||||
* @param other the symbol lookup that should be used to look for symbols not found
|
||||
* in this lookup
|
||||
*/
|
||||
default SymbolLookup or(SymbolLookup other) {
|
||||
Objects.requireNonNull(other);
|
||||
@ -154,27 +173,33 @@ public interface SymbolLookup {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a symbol lookup for symbols in the libraries associated with the caller's class loader.
|
||||
* Returns a symbol lookup for symbols in the libraries associated with the caller's
|
||||
* class loader.
|
||||
* <p>
|
||||
* A library is associated with a class loader {@code CL} when the library is loaded via an invocation of
|
||||
* {@link System#load(String)} or {@link System#loadLibrary(String)} from code in a class defined by {@code CL}.
|
||||
* If that code makes further invocations of {@link System#load(String)} or {@link System#loadLibrary(String)},
|
||||
* then more libraries are loaded and associated with {@code CL}. The symbol lookup returned by this method is always
|
||||
* current: it reflects all the libraries associated with the relevant class loader, even if they were loaded after
|
||||
* this method returned.
|
||||
* A library is associated with a class loader {@code CL} when the library is loaded
|
||||
* via an invocation of {@link System#load(String)} or
|
||||
* {@link System#loadLibrary(String)} from code in a class defined by {@code CL}.
|
||||
* If that code makes further invocations of {@link System#load(String)} or
|
||||
* {@link System#loadLibrary(String)} then more libraries are loaded and associated
|
||||
* with {@code CL}. The symbol lookup returned by this method is always current: it
|
||||
* reflects all the libraries associated with the relevant class loader, even if they
|
||||
* were loaded after this method returned.
|
||||
* <p>
|
||||
* Libraries associated with a class loader are unloaded when the class loader becomes
|
||||
* <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>. The symbol lookup
|
||||
* returned by this method is associated with an automatic {@linkplain MemorySegment.Scope scope} which keeps the caller's
|
||||
* class loader reachable. Therefore, libraries associated with the caller's class loader are kept loaded
|
||||
* (and their symbols available) as long as a loader lookup for that class loader, or any of the segments
|
||||
* obtained by it, is reachable.
|
||||
* <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>. The
|
||||
* symbol lookup returned by this method is associated with an automatic
|
||||
* {@linkplain MemorySegment.Scope scope} which keeps the caller's class loader
|
||||
* reachable. Therefore, libraries associated with the caller's class loader are
|
||||
* kept loaded (and their symbols available) as long as a loader lookup for that
|
||||
* class loader, or any of the segments obtained by it, is reachable.
|
||||
* <p>
|
||||
* In cases where this method is called from a context where there is no caller frame on the stack
|
||||
* (e.g. when called directly from a JNI attached thread), the caller's class loader defaults to the
|
||||
* In cases where this method is called from a context where there is no caller
|
||||
* frame on the stack (e.g. when called directly from a JNI attached thread), the
|
||||
* caller's class loader defaults to the
|
||||
* {@linkplain ClassLoader#getSystemClassLoader system class loader}.
|
||||
*
|
||||
* @return a symbol lookup for symbols in the libraries associated with the caller's class loader.
|
||||
* @return a symbol lookup for symbols in the libraries associated with
|
||||
* the caller's class loader
|
||||
* @see System#load(String)
|
||||
* @see System#loadLibrary(String)
|
||||
*/
|
||||
@ -206,24 +231,28 @@ public interface SymbolLookup {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a library with the given name (if not already loaded) and creates a symbol lookup for symbols in that library.
|
||||
* The lifetime of the returned library lookup is controlled by the provided arena.
|
||||
* For instance, if the provided arena is a confined arena, the library
|
||||
* associated with the returned lookup will be unloaded when the provided confined arena is
|
||||
* {@linkplain Arena#close() closed}.
|
||||
* Loads a library with the given name (if not already loaded) and creates a symbol
|
||||
* lookup for symbols in that library. The lifetime of the returned library lookup
|
||||
* is controlled by the provided arena. For instance, if the provided arena is a
|
||||
* confined arena, the library associated with the returned lookup will be unloaded
|
||||
* when the provided confined arena is {@linkplain Arena#close() closed}.
|
||||
*
|
||||
* @implNote The process of resolving a library name is OS-specific. For instance, in a POSIX-compliant OS,
|
||||
* the library name is resolved according to the specification of the {@code dlopen} function for that OS.
|
||||
* In Windows, the library name is resolved according to the specification of the {@code LoadLibrary} function.
|
||||
* @implNote The process of resolving a library name is OS-specific. For instance,
|
||||
* in a POSIX-compliant OS, the library name is resolved according to the
|
||||
* specification of the {@code dlopen} function for that OS. In Windows,
|
||||
* the library name is resolved according to the specification of the
|
||||
* {@code LoadLibrary} function.
|
||||
*
|
||||
* @param name the name of the library in which symbols should be looked up.
|
||||
* @param arena the arena associated with symbols obtained from the returned lookup.
|
||||
* @return a new symbol lookup suitable to find symbols in a library with the given name.
|
||||
* @param name the name of the library in which symbols should be looked up
|
||||
* @param arena the arena associated with symbols obtained from the returned lookup
|
||||
* @return a new symbol lookup suitable to find symbols in a library with the
|
||||
* given name
|
||||
* @throws IllegalStateException if {@code arena.scope().isAlive() == false}
|
||||
* @throws WrongThreadException if {@code arena} is a confined arena, and this method is called from a
|
||||
* thread {@code T}, other than the arena's owner thread
|
||||
* @throws WrongThreadException if {@code arena} is a confined arena, and this method
|
||||
* is called from a thread {@code T}, other than the arena's owner thread
|
||||
* @throws IllegalArgumentException if {@code name} does not identify a valid library
|
||||
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled
|
||||
* @throws IllegalCallerException If the caller is in a module that does not have
|
||||
* native access enabled
|
||||
*/
|
||||
@CallerSensitive
|
||||
@Restricted
|
||||
@ -237,22 +266,26 @@ public interface SymbolLookup {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a library from the given path (if not already loaded) and creates a symbol lookup for symbols
|
||||
* in that library. The lifetime of the returned library lookup is controlled by the provided arena.
|
||||
* For instance, if the provided arena is a confined arena, the library
|
||||
* associated with the returned lookup will be unloaded when the provided confined arena is
|
||||
* {@linkplain Arena#close() closed}.
|
||||
* Loads a library from the given path (if not already loaded) and creates a symbol
|
||||
* lookup for symbols in that library. The lifetime of the returned library lookup
|
||||
* is controlled by the provided arena. For instance, if the provided arena is a
|
||||
* confined arena, the library associated with the returned lookup will be unloaded
|
||||
* when the provided confined arena is {@linkplain Arena#close() closed}.
|
||||
*
|
||||
* @implNote On Linux, the functionalities provided by this factory method and the returned symbol lookup are
|
||||
* implemented using the {@code dlopen}, {@code dlsym} and {@code dlclose} functions.
|
||||
* @param path the path of the library in which symbols should be looked up.
|
||||
* @param arena the arena associated with symbols obtained from the returned lookup.
|
||||
* @return a new symbol lookup suitable to find symbols in a library with the given path.
|
||||
* @implNote On Linux, the functionalities provided by this factory method and the
|
||||
* returned symbol lookup are implemented using the {@code dlopen},
|
||||
* {@code dlsym} and {@code dlclose} functions.
|
||||
*
|
||||
* @param path the path of the library in which symbols should be looked up
|
||||
* @param arena the arena associated with symbols obtained from the returned lookup
|
||||
* @return a new symbol lookup suitable to find symbols in a library with the given
|
||||
* path
|
||||
* @throws IllegalStateException if {@code arena.scope().isAlive() == false}
|
||||
* @throws WrongThreadException if {@code arena} is a confined arena, and this method is called from a
|
||||
* thread {@code T}, other than the arena's owner thread
|
||||
* @throws WrongThreadException if {@code arena} is a confined arena, and this method
|
||||
* is called from a thread {@code T}, other than the arena's owner thread
|
||||
* @throws IllegalArgumentException if {@code path} does not point to a valid library
|
||||
* @throws IllegalCallerException If the caller is in a module that does not have native access enabled
|
||||
* @throws IllegalCallerException If the caller is in a module that does not have
|
||||
* native access enabled
|
||||
*/
|
||||
@CallerSensitive
|
||||
@Restricted
|
||||
|
@ -31,7 +31,8 @@ import jdk.internal.foreign.layout.UnionLayoutImpl;
|
||||
* A group layout whose member layouts are laid out at the same starting offset.
|
||||
*
|
||||
* @implSpec
|
||||
* Implementing classes are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
* Implementing classes are immutable, thread-safe and
|
||||
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @since 22
|
||||
*/
|
||||
|
@ -30,22 +30,29 @@ import java.nio.ByteOrder;
|
||||
import jdk.internal.foreign.layout.ValueLayouts;
|
||||
|
||||
/**
|
||||
* A layout that models values of basic data types. Examples of values modeled by a value layout are
|
||||
* <em>integral</em> values (either signed or unsigned), <em>floating-point</em> values and
|
||||
* <em>address</em> values.
|
||||
* A layout that models values of basic data types. Examples of values modeled by
|
||||
* a value layout are <em>integral</em> values (either signed or unsigned),
|
||||
* <em>floating-point</em> values and <em>address</em> values.
|
||||
* <p>
|
||||
* Each value layout has a size, an alignment (both expressed in bytes),
|
||||
* a {@linkplain ByteOrder byte order}, and a <em>carrier</em>, that is, the Java type that should be used when
|
||||
* {@linkplain MemorySegment#get(OfInt, long) accessing} a region of memory using the value layout.
|
||||
* a {@linkplain ByteOrder byte order}, and a <em>carrier</em>, that is, the Java type
|
||||
* that should be used when {@linkplain MemorySegment#get(OfInt, long) accessing} a
|
||||
* region of memory using the value layout.
|
||||
* <p>
|
||||
* This class defines useful value layout constants for Java primitive types and addresses.
|
||||
* @apiNote Some characteristics of the Java layout constants are platform-dependent. For instance, the byte order of
|
||||
* these constants is set to the {@linkplain ByteOrder#nativeOrder() native byte order}, thus making it easy to work
|
||||
* with other APIs, such as arrays and {@link java.nio.ByteBuffer}. Moreover, the alignment constraint of
|
||||
* {@link ValueLayout#JAVA_LONG} and {@link ValueLayout#JAVA_DOUBLE} are set to 8 bytes on 64-bit platforms, but only to
|
||||
* 4 bytes on 32-bit platforms.
|
||||
|
||||
* This class defines useful value layout constants for Java primitive types and
|
||||
* addresses.
|
||||
*
|
||||
* @implSpec implementing classes and subclasses are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
* @apiNote Some characteristics of the Java layout constants are platform-dependent.
|
||||
* For instance, the byte order of these constants is set to the
|
||||
* {@linkplain ByteOrder#nativeOrder() native byte order}, thus making it easy
|
||||
* to work with other APIs, such as arrays and {@link java.nio.ByteBuffer}.
|
||||
* Moreover, the alignment constraint of {@link ValueLayout#JAVA_LONG} and
|
||||
* {@link ValueLayout#JAVA_DOUBLE} is set to 8 bytes on 64-bit platforms,
|
||||
* but only to 4 bytes on 32-bit platforms.
|
||||
*
|
||||
* @implSpec implementing classes and subclasses are immutable, thread-safe and
|
||||
* <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @sealedGraph
|
||||
* @since 22
|
||||
@ -63,7 +70,7 @@ public sealed interface ValueLayout extends MemoryLayout
|
||||
/**
|
||||
* {@return a value layout with the same characteristics as this layout, but with the given byte order}
|
||||
*
|
||||
* @param order the desired byte order.
|
||||
* @param order the desired byte order
|
||||
*/
|
||||
ValueLayout withOrder(ByteOrder order);
|
||||
|
||||
@ -93,21 +100,26 @@ public sealed interface ValueLayout extends MemoryLayout
|
||||
ValueLayout withByteAlignment(long byteAlignment);
|
||||
|
||||
/**
|
||||
* {@return a var handle which can be used to access values described by this value layout, in a given memory segment.}
|
||||
* {@return a var handle which can be used to access values described by this value
|
||||
* layout, in a given memory segment}
|
||||
* <p>
|
||||
* The returned var handle's {@linkplain VarHandle#varType() var type} is the {@linkplain ValueLayout#carrier() carrier type} of
|
||||
* this value layout, and the list of coordinate types is {@code (MemorySegment, long)}, where the memory segment coordinate
|
||||
* corresponds to the memory segment to be accessed, and the {@code long} coordinate corresponds to the byte offset
|
||||
* into the accessed memory segment at which the access occurs.
|
||||
* The returned var handle's {@linkplain VarHandle#varType() var type} is the
|
||||
* {@linkplain ValueLayout#carrier() carrier type} of this value layout, and the
|
||||
* list of coordinate types is {@code (MemorySegment, long)}, where the
|
||||
* memory segment coordinate corresponds to the memory segment to be accessed, and
|
||||
* the {@code long} coordinate corresponds to the byte offset into the accessed
|
||||
* memory segment at which the access occurs.
|
||||
* <p>
|
||||
* The returned var handle checks that accesses are aligned according to this value layout's
|
||||
* {@linkplain MemoryLayout#byteAlignment() alignment constraint}.
|
||||
* The returned var handle checks that accesses are aligned according to
|
||||
* this value layout's {@linkplain MemoryLayout#byteAlignment() alignment constraint}.
|
||||
*
|
||||
* @apiNote This method is similar, but more efficient than calling {@code MemoryLayout#varHandle(PathElement...)}
|
||||
* with an empty path element array, as it avoids the creation of the var args array.
|
||||
* @apiNote This method is similar, but more efficient than calling
|
||||
* {@code MemoryLayout#varHandle(PathElement...)} with an empty path
|
||||
* element array, as it avoids the creation of the var args array.
|
||||
*
|
||||
* @apiNote The returned var handle features certain <a href="MemoryLayout.html#access-mode-restrictions">access mode
|
||||
* restrictions</a> common to all memory access var handles derived from memory layouts.
|
||||
* @apiNote The returned var handle features certain
|
||||
* <a href="MemoryLayout.html#access-mode-restrictions">access mode restrictions</a>
|
||||
* common to all memory access var handles derived from memory layouts.
|
||||
*
|
||||
* @see MemoryLayout#varHandle(PathElement...)
|
||||
*/
|
||||
@ -399,8 +411,9 @@ public sealed interface ValueLayout extends MemoryLayout
|
||||
}
|
||||
|
||||
/**
|
||||
* An address layout constant whose size is the same as that of a machine address ({@code size_t}),
|
||||
* byte alignment set to {@code sizeof(size_t)}, byte order set to {@link ByteOrder#nativeOrder()}.
|
||||
* An address layout constant whose size is the same as that of a
|
||||
* machine address ({@code size_t}), byte alignment set to {@code sizeof(size_t)},
|
||||
* byte order set to {@link ByteOrder#nativeOrder()}.
|
||||
*/
|
||||
AddressLayout ADDRESS = ValueLayouts.OfAddressImpl.of(ByteOrder.nativeOrder());
|
||||
|
||||
@ -455,14 +468,15 @@ public sealed interface ValueLayout extends MemoryLayout
|
||||
OfDouble JAVA_DOUBLE = ValueLayouts.OfDoubleImpl.of(ByteOrder.nativeOrder());
|
||||
|
||||
/**
|
||||
* An unaligned address layout constant whose size is the same as that of a machine address ({@code size_t}),
|
||||
* and byte order set to {@link ByteOrder#nativeOrder()}.
|
||||
* An unaligned address layout constant whose size is the same as that of a
|
||||
* machine address ({@code size_t}), and byte order set to
|
||||
* {@link ByteOrder#nativeOrder()}.
|
||||
* Equivalent to the following code:
|
||||
* {@snippet lang=java :
|
||||
* ADDRESS.withByteAlignment(1);
|
||||
* }
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may induce
|
||||
* performance and portability issues.
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may
|
||||
* induce performance and portability issues.
|
||||
*/
|
||||
AddressLayout ADDRESS_UNALIGNED = ADDRESS.withByteAlignment(1);
|
||||
|
||||
@ -473,8 +487,8 @@ public sealed interface ValueLayout extends MemoryLayout
|
||||
* {@snippet lang=java :
|
||||
* JAVA_CHAR.withByteAlignment(1);
|
||||
* }
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may induce
|
||||
* performance and portability issues.
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may
|
||||
* induce performance and portability issues.
|
||||
*/
|
||||
OfChar JAVA_CHAR_UNALIGNED = JAVA_CHAR.withByteAlignment(1);
|
||||
|
||||
@ -485,8 +499,8 @@ public sealed interface ValueLayout extends MemoryLayout
|
||||
* {@snippet lang=java :
|
||||
* JAVA_SHORT.withByteAlignment(1);
|
||||
* }
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may induce
|
||||
* performance and portability issues.
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may
|
||||
* induce performance and portability issues.
|
||||
*/
|
||||
OfShort JAVA_SHORT_UNALIGNED = JAVA_SHORT.withByteAlignment(1);
|
||||
|
||||
@ -497,8 +511,8 @@ public sealed interface ValueLayout extends MemoryLayout
|
||||
* {@snippet lang=java :
|
||||
* JAVA_INT.withByteAlignment(1);
|
||||
* }
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may induce
|
||||
* performance and portability issues.
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may
|
||||
* induce performance and portability issues.
|
||||
*/
|
||||
OfInt JAVA_INT_UNALIGNED = JAVA_INT.withByteAlignment(1);
|
||||
|
||||
@ -509,8 +523,8 @@ public sealed interface ValueLayout extends MemoryLayout
|
||||
* {@snippet lang=java :
|
||||
* JAVA_LONG.withByteAlignment(1);
|
||||
* }
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may induce
|
||||
* performance and portability issues.
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may
|
||||
* induce performance and portability issues.
|
||||
*/
|
||||
OfLong JAVA_LONG_UNALIGNED = JAVA_LONG.withByteAlignment(1);
|
||||
|
||||
@ -521,8 +535,8 @@ public sealed interface ValueLayout extends MemoryLayout
|
||||
* {@snippet lang=java :
|
||||
* JAVA_FLOAT.withByteAlignment(1);
|
||||
* }
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may induce
|
||||
* performance and portability issues.
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may
|
||||
* induce performance and portability issues.
|
||||
*/
|
||||
OfFloat JAVA_FLOAT_UNALIGNED = JAVA_FLOAT.withByteAlignment(1);
|
||||
|
||||
@ -533,8 +547,8 @@ public sealed interface ValueLayout extends MemoryLayout
|
||||
* {@snippet lang=java :
|
||||
* JAVA_DOUBLE.withByteAlignment(1);
|
||||
* }
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may induce
|
||||
* performance and portability issues.
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may
|
||||
* induce performance and portability issues.
|
||||
*/
|
||||
OfDouble JAVA_DOUBLE_UNALIGNED = JAVA_DOUBLE.withByteAlignment(1);
|
||||
|
||||
|
@ -29,18 +29,21 @@
|
||||
* <h2 id="fma">Foreign memory access</h2>
|
||||
*
|
||||
* <p>
|
||||
* The main abstraction introduced to support foreign memory access is {@link java.lang.foreign.MemorySegment}, which
|
||||
* models a contiguous region of memory, residing either inside or outside the Java heap. Memory segments are
|
||||
* typically allocated using an {@link java.lang.foreign.Arena}, which controls the lifetime of the regions of memory
|
||||
* backing the segments it allocates. The contents of a memory segment can be described using a
|
||||
* {@link java.lang.foreign.MemoryLayout memory layout}, which provides basic operations to query sizes, offsets, and
|
||||
* alignment constraints. Memory layouts also provide an alternate, more abstract way, to
|
||||
* The main abstraction introduced to support foreign memory access is
|
||||
* {@link java.lang.foreign.MemorySegment}, that models a contiguous region of memory,
|
||||
* residing either inside or outside the Java heap. Memory segments are typically
|
||||
* allocated using an {@link java.lang.foreign.Arena}, which controls the lifetime of
|
||||
* the regions of memory backing the segments it allocates. The contents of a
|
||||
* memory segment can be described using a {@link java.lang.foreign.MemoryLayout memory layout},
|
||||
* which provides basic operations to query sizes, offsets, and alignment constraints.
|
||||
* Memory layouts also provide an alternate, more abstract way, to
|
||||
* <a href=MemorySegment.html#segment-deref>access memory segments</a> using
|
||||
* {@linkplain java.lang.foreign.MemoryLayout#varHandle(java.lang.foreign.MemoryLayout.PathElement...) var handles},
|
||||
* which can be computed using <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>.
|
||||
*
|
||||
* For example, to allocate an off-heap region of memory big enough to hold 10 values of the primitive type {@code int},
|
||||
* and fill it with values ranging from {@code 0} to {@code 9}, we can use the following code:
|
||||
* <p>
|
||||
* For example, to allocate an off-heap region of memory big enough to hold 10 values of
|
||||
* the primitive type {@code int}, and fill it with values ranging from {@code 0} to
|
||||
* {@code 9}, we can use the following code:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* try (Arena arena = Arena.ofConfined()) {
|
||||
@ -51,38 +54,47 @@
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* This code creates a <em>native</em> memory segment, that is, a memory segment backed by
|
||||
* off-heap memory; the size of the segment is 40 bytes, enough to store 10 values of the primitive type {@code int}.
|
||||
* The native segment is allocated using a {@linkplain java.lang.foreign.Arena#ofConfined() confined arena}.
|
||||
* As such, access to the native segment is restricted to the current thread (the thread that created the arena).
|
||||
* Moreover, when the arena is closed, the native segment is invalidated, and its backing region of memory is
|
||||
* deallocated. Note the use of the <em>try-with-resources</em> construct: this idiom ensures that the off-heap region
|
||||
* of memory backing the native segment will be released at the end of the block, according to the semantics described
|
||||
* This code creates a <em>native</em> memory segment, that is, a memory segment backed
|
||||
* by off-heap memory; the size of the segment is 40 bytes, enough to store 10 values of
|
||||
* the primitive type {@code int}. The native segment is allocated using a
|
||||
* {@linkplain java.lang.foreign.Arena#ofConfined() confined arena}. As such, access to
|
||||
* the native segment is restricted to the current thread (the thread that created the
|
||||
* arena). Moreover, when the arena is closed, the native segment is invalidated, and
|
||||
* its backing region of memory is deallocated. Note the use of the <em>try-with-resources</em>
|
||||
* construct: this idiom ensures that the off-heap region of memory backing the native
|
||||
* segment will be released at the end of the block, according to the semantics described
|
||||
* in Section {@jls 14.20.3} of <cite>The Java Language Specification</cite>.
|
||||
* <p>
|
||||
* Memory segments provide strong safety guarantees when it comes to memory access. First, when accessing a memory segment,
|
||||
* the access coordinates are validated (upon access), to make sure that access does not occur at any address that resides
|
||||
* <em>outside</em> the boundaries of the memory segment used by the access operation. We call this guarantee <em>spatial safety</em>;
|
||||
* in other words, access to memory segments is bounds-checked, in the same way as array access is, as described in
|
||||
* Memory segments provide strong safety guarantees when it comes to memory access.
|
||||
* First, when accessing a memory segment, the access coordinates are validated
|
||||
* (upon access), to make sure that access does not occur at any address that resides
|
||||
* <em>outside</em> the boundaries of the memory segment used by the access operation.
|
||||
* We call this guarantee <em>spatial safety</em>; in other words, access to
|
||||
* memory segments is bounds-checked, in the same way as array access is, as described in
|
||||
* Section {@jls 15.10.4} of <cite>The Java Language Specification</cite>.
|
||||
* <p>
|
||||
* Additionally, to prevent a region of memory from being accessed <em>after</em> it has been deallocated
|
||||
* (i.e. <em>use-after-free</em>), a segment is also validated (upon access) to make sure that the arena from which it
|
||||
* has been obtained has not been closed. We call this guarantee <em>temporal safety</em>.
|
||||
* Additionally, to prevent a region of memory from being accessed <em>after</em> it has
|
||||
* been deallocated (i.e. <em>use-after-free</em>), a segment is also validated
|
||||
* (upon access) to make sure that the arena from which it has been obtained has not
|
||||
* been closed. We call this guarantee <em>temporal safety</em>.
|
||||
* <p>
|
||||
* Together, spatial and temporal safety ensure that each memory access operation either succeeds - and accesses a valid
|
||||
* location within the region of memory backing the memory segment - or fails.
|
||||
* Together, spatial and temporal safety ensure that each memory access operation either
|
||||
* succeeds - and accesses a valid location within the region of memory backing the
|
||||
* memory segment - or fails.
|
||||
*
|
||||
* <h2 id="ffa">Foreign function access</h2>
|
||||
* The key abstractions introduced to support foreign function access are {@link java.lang.foreign.SymbolLookup},
|
||||
* {@link java.lang.foreign.FunctionDescriptor} and {@link java.lang.foreign.Linker}. The first is used to look up symbols
|
||||
* inside libraries; the second is used to model the signature of foreign functions, while the third is used
|
||||
* to link foreign functions as {@link java.lang.invoke.MethodHandle} instances,
|
||||
* so that clients can perform foreign function calls directly in Java, without the need for intermediate layers of C/C++
|
||||
* code (as is the case with the <a href="{@docRoot}/../specs/jni/index.html">Java Native Interface (JNI)</a>).
|
||||
*
|
||||
* The key abstractions introduced to support foreign function access are
|
||||
* {@link java.lang.foreign.SymbolLookup}, {@link java.lang.foreign.FunctionDescriptor} and
|
||||
* {@link java.lang.foreign.Linker}. The first is used to look up symbols inside
|
||||
* libraries; the second is used to model the signature of foreign functions, while the
|
||||
* third is used to link foreign functions as {@link java.lang.invoke.MethodHandle}
|
||||
* instances, so that clients can perform foreign function calls directly in Java,
|
||||
* without the need for intermediate layers of C/C++ code (as is the case with the
|
||||
* <a href="{@docRoot}/../specs/jni/index.html">Java Native Interface (JNI)</a>).
|
||||
* <p>
|
||||
* For example, to compute the length of a string using the C standard library function {@code strlen} on a Linux/x64 platform,
|
||||
* we can use the following code:
|
||||
* For example, to compute the length of a string using the C standard library function
|
||||
* {@code strlen} on a Linux/x64 platform, we can use the following code:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* Linker linker = Linker.nativeLinker();
|
||||
@ -98,52 +110,65 @@
|
||||
* }
|
||||
*}
|
||||
*
|
||||
* Here, we obtain a {@linkplain java.lang.foreign.Linker#nativeLinker() native linker} and we use it
|
||||
* to {@linkplain java.lang.foreign.SymbolLookup#find(java.lang.String) look up} the {@code strlen} function in the
|
||||
* standard C library; a <em>downcall method handle</em> targeting said function is subsequently
|
||||
* Here, we obtain a {@linkplain java.lang.foreign.Linker#nativeLinker() native linker}
|
||||
* and we use it to {@linkplain java.lang.foreign.SymbolLookup#find(java.lang.String) look up}
|
||||
* the {@code strlen} function in the standard C library; a <em>downcall method handle</em>
|
||||
* targeting said function is subsequently
|
||||
* {@linkplain java.lang.foreign.Linker#downcallHandle(FunctionDescriptor, Linker.Option...) obtained}.
|
||||
* To complete the linking successfully, we must provide a {@link java.lang.foreign.FunctionDescriptor} instance,
|
||||
* describing the signature of the {@code strlen} function.
|
||||
* From this information, the linker will uniquely determine the sequence of steps which will turn
|
||||
* the method handle invocation (here performed using {@link java.lang.invoke.MethodHandle#invokeExact(java.lang.Object...)})
|
||||
* into a foreign function call, according to the rules specified by the ABI of the underlying platform.
|
||||
* To complete the linking successfully, we must provide a
|
||||
* {@link java.lang.foreign.FunctionDescriptor} instance, describing the signature of the
|
||||
* {@code strlen} function. From this information, the linker will uniquely determine
|
||||
* the sequence of steps which will turn the method handle invocation (here performed
|
||||
* using {@link java.lang.invoke.MethodHandle#invokeExact(java.lang.Object...)})
|
||||
* into a foreign function call, according to the rules specified by the ABI of the
|
||||
* underlying platform.
|
||||
* <p>
|
||||
* The {@link java.lang.foreign.Arena} class also provides many useful methods for
|
||||
* interacting with foreign code, such as
|
||||
* {@linkplain java.lang.foreign.SegmentAllocator#allocateFrom(java.lang.String) converting} Java strings into
|
||||
* zero-terminated, UTF-8 strings, as demonstrated in the above example.
|
||||
* {@linkplain java.lang.foreign.SegmentAllocator#allocateFrom(java.lang.String) converting}
|
||||
* Java strings into zero-terminated, UTF-8 strings, as demonstrated in the above example.
|
||||
*
|
||||
* <h2 id="restricted">Restricted methods</h2>
|
||||
* Some methods in this package are considered <em>restricted</em>. Restricted methods are typically used to bind native
|
||||
* foreign data and/or functions to first-class Java API elements which can then be used directly by clients. For instance
|
||||
* the restricted method {@link java.lang.foreign.MemorySegment#reinterpret(long)}
|
||||
* can be used to create a fresh segment with the same address and temporal bounds,
|
||||
* but with the provided size. This can be useful to resize memory segments obtained when interacting with native functions.
|
||||
* <p>
|
||||
* Binding foreign data and/or functions is generally unsafe and, if done incorrectly, can result in VM crashes,
|
||||
* or memory corruption when the bound Java API element is accessed. For instance, incorrectly resizing a native
|
||||
* memory segment using {@link java.lang.foreign.MemorySegment#reinterpret(long)} can lead to a JVM crash, or, worse,
|
||||
* lead to silent memory corruption when attempting to access the resized segment. For these reasons, it is crucial for
|
||||
* code that calls a restricted method to never pass arguments that might cause incorrect binding of foreign data and/or
|
||||
* functions to a Java API.
|
||||
* <p>
|
||||
* Given the potential danger of restricted methods, the Java runtime issues a warning on the standard error stream
|
||||
* every time a restricted method is invoked. Such warnings can be disabled by granting access to restricted methods
|
||||
* to selected modules. This can be done either via implementation-specific command line options or programmatically, e.g. by calling
|
||||
* {@link java.lang.ModuleLayer.Controller#enableNativeAccess(java.lang.Module)}.
|
||||
* <p>
|
||||
* For every class in this package, unless specified otherwise, any method arguments of reference
|
||||
* type must not be null, and any null argument will elicit a {@code NullPointerException}. This fact is not individually
|
||||
* documented for methods of this API.
|
||||
*
|
||||
* @apiNote Usual memory model guarantees (see {@jls 17.4}) do not apply when accessing native memory segments as
|
||||
* these segments are backed by off-heap regions of memory.
|
||||
* Some methods in this package are considered <em>restricted</em>. Restricted methods
|
||||
* are typically used to bind native foreign data and/or functions to first-class
|
||||
* Java API elements which can then be used directly by clients. For instance the
|
||||
* restricted method {@link java.lang.foreign.MemorySegment#reinterpret(long)} can be
|
||||
* used to create a fresh segment with the same address and temporal bounds, but with
|
||||
* the provided size. This can be useful to resize memory segments obtained when
|
||||
* interacting with native functions.
|
||||
* <p>
|
||||
* Binding foreign data and/or functions is generally unsafe and, if done incorrectly,
|
||||
* can result in VM crashes, or memory corruption when the bound Java API element
|
||||
* is accessed. For instance, incorrectly resizing a native memory segment using
|
||||
* {@link java.lang.foreign.MemorySegment#reinterpret(long)} can lead to a JVM crash, or,
|
||||
* worse, lead to silent memory corruption when attempting to access the resized segment.
|
||||
* For these reasons, it is crucial for code that calls a restricted method to never pass
|
||||
* arguments that might cause incorrect binding of foreign data and/or functions to
|
||||
* a Java API.
|
||||
* <p>
|
||||
* Given the potential danger of restricted methods, the Java runtime issues a warning on
|
||||
* the standard error stream every time a restricted method is invoked. Such warnings can
|
||||
* be disabled by granting access to restricted methods to selected modules. This can be
|
||||
* done either via implementation-specific command line options or programmatically, e.g.
|
||||
* by calling {@link java.lang.ModuleLayer.Controller#enableNativeAccess(java.lang.Module)}.
|
||||
* <p>
|
||||
* For every class in this package, unless specified otherwise, any method arguments of
|
||||
* reference type must not be {@code null}, and any null argument will elicit a
|
||||
* {@code NullPointerException}. This fact is not individually documented for methods of
|
||||
* this API.
|
||||
*
|
||||
* @apiNote Usual memory model guarantees (see {@jls 17.4}) do not apply when accessing
|
||||
* native memory segments as these segments are backed by off-heap regions of memory.
|
||||
*
|
||||
* @implNote
|
||||
* In the reference implementation, access to restricted methods can be granted to specific modules using the command line option
|
||||
* {@code --enable-native-access=M1,M2, ... Mn}, where {@code M1}, {@code M2}, {@code ... Mn} are module names
|
||||
* (for the unnamed module, the special value {@code ALL-UNNAMED} can be used). If this option is specified, access to
|
||||
* restricted methods are only granted to the modules listed by that option. If this option is not specified,
|
||||
* access to restricted methods is enabled for all modules, but access to restricted methods will result in runtime warnings.
|
||||
* In the reference implementation, access to restricted methods can be granted to
|
||||
* specific modules using the command line option {@code --enable-native-access=M1,M2, ... Mn},
|
||||
* where {@code M1}, {@code M2}, {@code ... Mn} are module names (for the unnamed module,
|
||||
* the special value {@code ALL-UNNAMED} can be used). If this option is specified,
|
||||
* access to restricted methods are only granted to the modules listed by that option.
|
||||
* If this option is not specified, access to restricted methods is enabled for all
|
||||
* modules, but access to restricted methods will result in runtime warnings.
|
||||
*
|
||||
* @spec jni/index.html Java Native Interface Specification
|
||||
*
|
||||
|
@ -1045,48 +1045,48 @@ public abstract class FileChannel
|
||||
* The file mapping mode, see
|
||||
* {@link FileChannel#map(FileChannel.MapMode, long, long)};
|
||||
* the mapping mode might affect the behavior of the returned
|
||||
* memory mapped segment (see {@link MemorySegment#force()}).
|
||||
* memory mapped segment (see {@link MemorySegment#force()})
|
||||
*
|
||||
* @param offset
|
||||
* The offset (expressed in bytes) within the file at which the
|
||||
* mapped segment is to start.
|
||||
* mapped segment is to start
|
||||
*
|
||||
* @param size
|
||||
* The size (in bytes) of the mapped memory backing the memory
|
||||
* segment.
|
||||
* segment
|
||||
*
|
||||
* @param arena
|
||||
* The segment arena.
|
||||
* The segment arena
|
||||
*
|
||||
* @return A new mapped memory segment.
|
||||
* @return A new mapped memory segment
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* If {@code offset < 0}, {@code size < 0} or
|
||||
* {@code offset + size} overflows the range of {@code long}.
|
||||
* {@code offset + size} overflows the range of {@code long}
|
||||
*
|
||||
* @throws IllegalStateException
|
||||
* If {@code arena.isAlive() == false}.
|
||||
* If {@code arena.isAlive() == false}
|
||||
*
|
||||
* @throws WrongThreadException
|
||||
* If {@code arena} is a confined scoped arena, and this method is called from a
|
||||
* thread {@code T}, other than the scoped arena's owner thread.
|
||||
* If {@code arena} is a confined scoped arena, and this method is called
|
||||
* from a thread {@code T}, other than the scoped arena's owner thread
|
||||
*
|
||||
* @throws NonReadableChannelException
|
||||
* If the {@code mode} is {@link MapMode#READ_ONLY READ_ONLY} or
|
||||
* an implementation specific map mode requiring read access,
|
||||
* but this channel was not opened for reading.
|
||||
* but this channel was not opened for reading
|
||||
*
|
||||
* @throws NonWritableChannelException
|
||||
* If the {@code mode} is {@link MapMode#READ_WRITE READ_WRITE},
|
||||
* {@link MapMode#PRIVATE PRIVATE} or an implementation specific
|
||||
* map mode requiring write access, but this channel was not
|
||||
* opened for both reading and writing.
|
||||
* opened for both reading and writing
|
||||
*
|
||||
* @throws IOException
|
||||
* If some other I/O error occurs.
|
||||
* If some other I/O error occurs
|
||||
*
|
||||
* @throws UnsupportedOperationException
|
||||
* If an unsupported map mode is specified.
|
||||
* If an unsupported map mode is specified
|
||||
*
|
||||
* @since 22
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user