mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8312522
: Implementation of Foreign Function & Memory API
Co-authored-by: Maurizio Cimadamore <mcimadamore@openjdk.org> Co-authored-by: Jorn Vernee <jvernee@openjdk.org> Co-authored-by: Per Minborg <pminborg@openjdk.org> Reviewed-by: dholmes, psandoz, mcimadamore, alanb
This commit is contained in:
parent
9728e21db1
commit
32ac72c3d3
261 changed files with 3141 additions and 2126 deletions
|
@ -26,7 +26,6 @@
|
|||
package java.lang.foreign;
|
||||
|
||||
import jdk.internal.foreign.layout.ValueLayouts;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
import jdk.internal.javac.Restricted;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
|
||||
|
@ -51,11 +50,13 @@ import java.util.Optional;
|
|||
* <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>.
|
||||
*
|
||||
* @see #ADDRESS
|
||||
* @see #ADDRESS_UNALIGNED
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
public sealed interface AddressLayout extends ValueLayout permits ValueLayouts.OfAddressImpl {
|
||||
|
||||
/**
|
||||
|
@ -95,13 +96,12 @@ public sealed interface AddressLayout extends ValueLayout permits ValueLayouts.O
|
|||
* {@snippet lang = java:
|
||||
* AddressLayout addressLayout = ...
|
||||
* AddressLayout unboundedLayout = addressLayout.withTargetLayout(
|
||||
* MemoryLayout.sequenceLayout(ValueLayout.JAVA_BYTE));
|
||||
* MemoryLayout.sequenceLayout(Long.MAX_VALUE, ValueLayout.JAVA_BYTE));
|
||||
*}
|
||||
* <p>
|
||||
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
|
||||
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
|
||||
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
|
||||
* restricted methods, and use safe and supported functionalities, where possible.
|
||||
* the JVM or, worse, silently result in memory corruption.
|
||||
*
|
||||
* @param layout the target layout.
|
||||
* @return an address layout with same characteristics as this layout, but with the provided target layout.
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
package java.lang.foreign;
|
||||
|
||||
import jdk.internal.foreign.MemorySessionImpl;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
import jdk.internal.ref.CleanerFactory;
|
||||
|
||||
import java.lang.foreign.MemorySegment.Scope;
|
||||
|
@ -184,7 +183,7 @@ import java.lang.foreign.MemorySegment.Scope;
|
|||
* {@snippet lang = java:
|
||||
* try (Arena slicingArena = new SlicingArena(1000)) {
|
||||
* for (int i = 0; i < 10; i++) {
|
||||
* MemorySegment s = slicingArena.allocateArray(JAVA_INT, 1, 2, 3, 4, 5);
|
||||
* MemorySegment s = slicingArena.allocateFrom(JAVA_INT, 1, 2, 3, 4, 5);
|
||||
* ...
|
||||
* }
|
||||
* } // all memory allocated is released here
|
||||
|
@ -195,9 +194,8 @@ import java.lang.foreign.MemorySegment.Scope;
|
|||
*
|
||||
* @see MemorySegment
|
||||
*
|
||||
* @since 20
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public interface Arena extends SegmentAllocator, AutoCloseable {
|
||||
|
||||
/**
|
||||
|
@ -269,9 +267,7 @@ public interface Arena extends SegmentAllocator, AutoCloseable {
|
|||
* other than the arena's owner thread.
|
||||
*/
|
||||
@Override
|
||||
default MemorySegment allocate(long byteSize, long byteAlignment) {
|
||||
return ((MemorySessionImpl)scope()).allocate(byteSize, byteAlignment);
|
||||
}
|
||||
MemorySegment allocate(long byteSize, long byteAlignment);
|
||||
|
||||
/**
|
||||
* {@return the arena scope}
|
||||
|
|
|
@ -32,7 +32,6 @@ import java.util.Optional;
|
|||
import java.util.List;
|
||||
|
||||
import jdk.internal.foreign.FunctionDescriptorImpl;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
* A function descriptor models the signature of a foreign function. A function descriptor is made up of zero or more
|
||||
|
@ -44,9 +43,8 @@ import jdk.internal.javac.PreviewFeature;
|
|||
* Implementing classes are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @see MemoryLayout
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
package java.lang.foreign;
|
||||
|
||||
import java.util.List;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
* A compound layout that is an aggregation of multiple, heterogeneous <em>member layouts</em>. There are two ways in which member layouts
|
||||
|
@ -38,9 +37,8 @@ import jdk.internal.javac.PreviewFeature;
|
|||
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @sealedGraph
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public sealed interface GroupLayout extends MemoryLayout permits StructLayout, UnionLayout {
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,15 +29,12 @@ import jdk.internal.foreign.abi.AbstractLinker;
|
|||
import jdk.internal.foreign.abi.LinkerOptions;
|
||||
import jdk.internal.foreign.abi.CapturableState;
|
||||
import jdk.internal.foreign.abi.SharedUtils;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
import jdk.internal.javac.Restricted;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -60,6 +57,12 @@ import java.util.stream.Stream;
|
|||
* <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.
|
||||
* <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
|
||||
|
@ -93,10 +96,10 @@ import java.util.stream.Stream;
|
|||
*
|
||||
* {@snippet lang = java:
|
||||
* try (Arena arena = Arena.ofConfined()) {
|
||||
* MemorySegment str = arena.allocateUtf8String("Hello");
|
||||
* MemorySegment str = arena.allocateFrom("Hello");
|
||||
* long len = (long) strlen.invokeExact(str); // 5
|
||||
* }
|
||||
* }
|
||||
*}
|
||||
* <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
|
||||
|
@ -104,11 +107,8 @@ import java.util.stream.Stream;
|
|||
* 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 modelled as {@linkplain ValueLayout value layouts}
|
||||
* of a suitable carrier. The mapping between a scalar type and its corresponding layout is dependent on the ABI
|
||||
* implemented by the native linker. 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.
|
||||
* 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 modelled 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
|
||||
|
@ -123,7 +123,33 @@ import java.util.stream.Stream;
|
|||
* a pointer that is known to point to a C {@code int[2]} array can be modelled 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>
|
||||
* The following table shows some examples of how C types are modelled in Linux/x64:
|
||||
* 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>
|
||||
* <li>{@code short}</li>
|
||||
* <li>{@code int}</li>
|
||||
* <li>{@code long}</li>
|
||||
* <li>{@code long long}</li>
|
||||
* <li>{@code float}</li>
|
||||
* <li>{@code double}</li>
|
||||
* <li>{@code size_t}</li>
|
||||
* <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.
|
||||
* <p>
|
||||
* A native linker typically does not provide canonical layouts for C's unsigned integral types. Instead, they are
|
||||
* modelled 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 modelled 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>
|
||||
|
@ -138,19 +164,19 @@ import java.util.stream.Stream;
|
|||
* <tr><th scope="row" style="font-weight:normal">{@code bool}</th>
|
||||
* <td style="text-align:center;">{@link ValueLayout#JAVA_BOOLEAN}</td>
|
||||
* <td style="text-align:center;">{@code boolean}</td>
|
||||
* <tr><th scope="row" style="font-weight:normal">{@code char}</th>
|
||||
* <tr><th scope="row" style="font-weight:normal">{@code char} <br> {@code unsigned char}</th>
|
||||
* <td style="text-align:center;">{@link ValueLayout#JAVA_BYTE}</td>
|
||||
* <td style="text-align:center;">{@code byte}</td>
|
||||
* <tr><th scope="row" style="font-weight:normal">{@code short}</th>
|
||||
* <tr><th scope="row" style="font-weight:normal">{@code short} <br> {@code unsigned short}</th>
|
||||
* <td style="text-align:center;">{@link ValueLayout#JAVA_SHORT}</td>
|
||||
* <td style="text-align:center;">{@code short}</td>
|
||||
* <tr><th scope="row" style="font-weight:normal">{@code int}</th>
|
||||
* <tr><th scope="row" style="font-weight:normal">{@code int} <br> {@code unsigned int}</th>
|
||||
* <td style="text-align:center;">{@link ValueLayout#JAVA_INT}</td>
|
||||
* <td style="text-align:center;">{@code int}</td>
|
||||
* <tr><th scope="row" style="font-weight:normal">{@code long}</th>
|
||||
* <tr><th scope="row" style="font-weight:normal">{@code long} <br> {@code unsigned long}</th>
|
||||
* <td style="text-align:center;">{@link ValueLayout#JAVA_LONG}</td>
|
||||
* <td style="text-align:center;">{@code long}</td>
|
||||
* <tr><th scope="row" style="font-weight:normal">{@code long long}</th>
|
||||
* <tr><th scope="row" style="font-weight:normal">{@code long long} <br> {@code unsigned long long}</th>
|
||||
* <td style="text-align:center;">{@link ValueLayout#JAVA_LONG}</td>
|
||||
* <td style="text-align:center;">{@code long}</td>
|
||||
* <tr><th scope="row" style="font-weight:normal">{@code float}</th>
|
||||
|
@ -201,20 +227,7 @@ import java.util.stream.Stream;
|
|||
* All native linker implementations operate on a subset of memory layouts. More formally, a layout {@code L}
|
||||
* is supported by a native linker {@code NL} if:
|
||||
* <ul>
|
||||
* <li>{@code L} is a value layout {@code V} and {@code V.withoutName()} is {@linkplain MemoryLayout#equals(Object) equal}
|
||||
* to one of the following layout constants:
|
||||
* <ul>
|
||||
* <li>{@link ValueLayout#JAVA_BOOLEAN}</li>
|
||||
* <li>{@link ValueLayout#JAVA_BYTE}</li>
|
||||
* <li>{@link ValueLayout#JAVA_CHAR}</li>
|
||||
* <li>{@link ValueLayout#JAVA_SHORT}</li>
|
||||
* <li>{@link ValueLayout#JAVA_INT}</li>
|
||||
* <li>{@link ValueLayout#JAVA_LONG}</li>
|
||||
* <li>{@link ValueLayout#JAVA_FLOAT}</li>
|
||||
* <li>{@link ValueLayout#JAVA_DOUBLE}</li>
|
||||
* </ul></li>
|
||||
* <li>{@code L} is an address layout {@code A} and {@code A.withoutTargetLayout().withoutName()} is
|
||||
* {@linkplain MemoryLayout#equals(Object) equal} to {@link ValueLayout#ADDRESS}</li>
|
||||
* <li>{@code L} is a value layout {@code V} and {@code V.withoutName()} is a canonical layout</li>
|
||||
* <li>{@code L} is a sequence layout {@code S} and all the following conditions hold:
|
||||
* <ol>
|
||||
* <li>the alignment constraint of {@code S} is set to its <a href="MemoryLayout.html#layout-align">natural alignment</a>, and</li>
|
||||
|
@ -294,7 +307,7 @@ import java.util.stream.Stream;
|
|||
* {@snippet lang = java:
|
||||
* try (Arena arena = Arena.ofConfined()) {
|
||||
* MemorySegment comparFunc = linker.upcallStub(comparHandle, comparDesc, arena);
|
||||
* MemorySegment array = arena.allocateArray(JAVA_INT, 0, 9, 3, 4, 6, 5, 1, 8, 2, 7);
|
||||
* MemorySegment array = arena.allocateFrom(JAVA_INT, 0, 9, 3, 4, 6, 5, 1, 8, 2, 7);
|
||||
* qsort.invokeExact(array, 10L, 4L, comparFunc);
|
||||
* int[] sorted = array.toArray(JAVA_INT); // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
|
||||
* }
|
||||
|
@ -391,15 +404,11 @@ import java.util.stream.Stream;
|
|||
*
|
||||
* <h3 id="variadic-funcs">Variadic functions</h3>
|
||||
*
|
||||
* Variadic functions are C functions which can accept a variable number and type of arguments. They are declared:
|
||||
* <ol>
|
||||
* <li>With a trailing ellipsis ({@code ...}) at the end of the formal parameter list, such as: {@code void foo(int x, ...);}</li>
|
||||
* <li>With an empty formal parameter list, called a prototype-less function, such as: {@code void foo();}</li>
|
||||
* </ol>
|
||||
* The arguments passed in place of the ellipsis, or the arguments passed to a prototype-less function 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 ...} or empty formal parameter list with a list of <em>variadic parameters</em>
|
||||
* of a fixed number and type.
|
||||
* Variadic functions are C functions which 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:
|
||||
|
@ -411,21 +420,22 @@ import java.util.stream.Stream;
|
|||
* </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
|
||||
* specialized form of a variadic function, as the variadic parameters of the specialized form will always have a promoted
|
||||
* type.
|
||||
* 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>. For a prototype-less function, the index passed to
|
||||
* {@link Linker.Option#firstVariadicArg(int)} should always be {@code 0}.
|
||||
* function descriptor, are called <em>variadic argument layouts</em>.
|
||||
* <p>
|
||||
* The native linker will reject an attempt to link a specialized function descriptor with any variadic argument layouts
|
||||
* corresponding to a C type that would be subject to default argument promotion (as described above). Exactly which layouts
|
||||
* will be rejected is platform specific, but as an example: on Linux/x64 the layouts {@link ValueLayout#JAVA_BOOLEAN},
|
||||
* {@link ValueLayout#JAVA_BYTE}, {@link ValueLayout#JAVA_CHAR}, {@link ValueLayout#JAVA_SHORT}, and
|
||||
* {@link ValueLayout#JAVA_FLOAT} will be rejected.
|
||||
* 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:
|
||||
*
|
||||
|
@ -461,9 +471,9 @@ import java.util.stream.Stream;
|
|||
*
|
||||
* {@snippet lang = java:
|
||||
* try (Arena arena = Arena.ofConfined()) {
|
||||
* int res = (int)printf.invokeExact(arena.allocateUtf8String("%d plus %d equals %d"), 2, 2, 4); //prints "2 plus 2 equals 4"
|
||||
* }
|
||||
* int res = (int)printf.invokeExact(arena.allocateFrom("%d plus %d equals %d"), 2, 2, 4); //prints "2 plus 2 equals 4"
|
||||
* }
|
||||
*}
|
||||
*
|
||||
* <h2 id="safety">Safety considerations</h2>
|
||||
*
|
||||
|
@ -483,9 +493,8 @@ import java.util.stream.Stream;
|
|||
* @implSpec
|
||||
* Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public sealed interface Linker permits AbstractLinker {
|
||||
|
||||
/**
|
||||
|
@ -493,11 +502,11 @@ public sealed interface Linker permits AbstractLinker {
|
|||
* 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}.
|
||||
*
|
||||
* @throws UnsupportedOperationException if the underlying native platform is not supported.
|
||||
*/
|
||||
static Linker nativeLinker() {
|
||||
return SharedUtils.getSystemLinker();
|
||||
|
@ -513,8 +522,7 @@ public sealed interface Linker permits AbstractLinker {
|
|||
* <p>
|
||||
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
|
||||
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
|
||||
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
|
||||
* restricted methods, and use safe and supported functionalities, where possible.
|
||||
* the JVM or, worse, silently result in memory corruption.
|
||||
*
|
||||
* @param address the native memory segment whose {@linkplain MemorySegment#address() base address} is the
|
||||
* address of the target foreign function.
|
||||
|
@ -560,13 +568,17 @@ public sealed interface Linker permits AbstractLinker {
|
|||
* {@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.
|
||||
* The returned method handle will additionally throw {@link NullPointerException} if any argument passed to it is {@code null}.
|
||||
* 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}.
|
||||
* <p>
|
||||
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
|
||||
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
|
||||
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
|
||||
* restricted methods, and use safe and supported functionalities, where possible.
|
||||
* the JVM or, worse, silently result in memory corruption.
|
||||
*
|
||||
* @param function the function descriptor of the target foreign function.
|
||||
* @param options the linker options associated with this linkage request.
|
||||
|
@ -603,8 +615,7 @@ public sealed interface Linker permits AbstractLinker {
|
|||
* <p>
|
||||
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
|
||||
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
|
||||
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
|
||||
* restricted methods, and use safe and supported functionalities, where possible.
|
||||
* the JVM or, worse, silently result in memory corruption.
|
||||
*
|
||||
* @param target the target method handle.
|
||||
* @param function the upcall stub function descriptor.
|
||||
|
@ -640,10 +651,25 @@ public sealed interface Linker permits AbstractLinker {
|
|||
SymbolLookup defaultLookup();
|
||||
|
||||
/**
|
||||
* A linker option is used to provide additional parameters to a linkage request.
|
||||
* @since 20
|
||||
* {@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 is unspecified; it varies 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();
|
||||
|
||||
/**
|
||||
* A linker option is used to provide additional parameters to a linkage request.
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface Option
|
||||
permits LinkerOptions.LinkerOptionImpl {
|
||||
|
||||
|
@ -707,6 +733,8 @@ public sealed interface Linker permits AbstractLinker {
|
|||
* // use errno
|
||||
* }
|
||||
* }
|
||||
* <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
|
||||
|
@ -750,19 +778,19 @@ public sealed interface Linker permits AbstractLinker {
|
|||
}
|
||||
|
||||
/**
|
||||
* {@return a linker option used to mark a foreign function as <em>trivial</em>}
|
||||
* {@return a linker option used to mark a foreign function as <em>critical</em>}
|
||||
* <p>
|
||||
* A trivial 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 which some implementations may use to apply
|
||||
* optimizations that are only valid for trivial functions.
|
||||
* optimizations that are only valid for critical functions.
|
||||
* <p>
|
||||
* Using this linker option when linking non trivial functions is likely to have adverse effects,
|
||||
* 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 isTrivial() {
|
||||
return LinkerOptions.IsTrivial.INSTANCE;
|
||||
static Option critical() {
|
||||
return LinkerOptions.Critical.INSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ package java.lang.foreign;
|
|||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
|
@ -43,12 +44,12 @@ import jdk.internal.foreign.layout.PaddingLayoutImpl;
|
|||
import jdk.internal.foreign.layout.SequenceLayoutImpl;
|
||||
import jdk.internal.foreign.layout.StructLayoutImpl;
|
||||
import jdk.internal.foreign.layout.UnionLayoutImpl;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
|
||||
/**
|
||||
* A memory layout describes the contents of a memory segment.
|
||||
* <p>
|
||||
* There are two leaves in the layout hierarchy, {@linkplain ValueLayout value layouts}, which are used to represent values of given size and kind (see
|
||||
* There are two leaves in the layout hierarchy, {@linkplain ValueLayout value layouts}, which are used to represent values of given size and kind
|
||||
* and {@linkplain PaddingLayout padding layouts} which are used, as the name suggests, to represent a portion of a memory
|
||||
* segment whose contents should be ignored, and which are primarily present for alignment reasons.
|
||||
* Some common value layout constants, such as {@link ValueLayout#JAVA_INT} and {@link ValueLayout#JAVA_FLOAT_UNALIGNED}
|
||||
|
@ -231,13 +232,49 @@ import jdk.internal.javac.PreviewFeature;
|
|||
* Any attempt to provide a layout path {@code P} that is not well-formed for an initial layout {@code C_0} will result
|
||||
* in an {@link IllegalArgumentException}.
|
||||
*
|
||||
* <h2 id="access-mode-restrictions">Access mode restrictions</h2>
|
||||
*
|
||||
* A var handle returned by {@link #varHandle(PathElement...)} or {@link ValueLayout#varHandle()} features certain
|
||||
* access characteristics, which are derived from the selected layout {@code L}:
|
||||
* <ul>
|
||||
* <li>A carrier type {@code T}, derived from {@code L.carrier()}</li>
|
||||
* <li>An alignment constraint {@code A}, derived from {@code L.byteAlignment()}</li>
|
||||
* <li>An access size {@code S}, derived from {@code L.byteSize()}</li>
|
||||
* </ul>
|
||||
* Depending on the above characteristics, the returned var handle might feature certain <i>access mode restrictions</i>.
|
||||
* We say that a var handle is <em>aligned</em> if its alignment constraint {@code A} is compatible with the access size
|
||||
* {@code S}, that is if {@code A >= S}. An aligned var handle is guaranteed to support the following access modes:
|
||||
* <ul>
|
||||
* <li>read write access modes for all {@code T}. On 32-bit platforms, access modes
|
||||
* {@code get} and {@code set} for {@code long}, {@code double} and {@code MemorySegment}
|
||||
* are supported but might lead to word tearing, as described in Section {@jls 17.7}.
|
||||
* of <cite>The Java Language Specification</cite>.
|
||||
* <li>atomic update access modes for {@code int}, {@code long},
|
||||
* {@code float}, {@code double} and {@link MemorySegment}.
|
||||
* (Future major platform releases of the JDK may support additional
|
||||
* types for certain currently unsupported access modes.)
|
||||
* <li>numeric atomic update access modes for {@code int}, {@code long} and {@link MemorySegment}.
|
||||
* (Future major platform releases of the JDK may support additional
|
||||
* numeric types for certain currently unsupported access modes.)
|
||||
* <li>bitwise atomic update access modes for {@code int}, {@code long} and {@link MemorySegment}.
|
||||
* (Future major platform releases of the JDK may support additional
|
||||
* numeric types for certain currently unsupported access modes.)
|
||||
* </ul>
|
||||
* If {@code T} is {@code float}, {@code double} or {@link MemorySegment} then atomic update access modes compare
|
||||
* values using their bitwise representation (see {@link Float#floatToRawIntBits}, {@link Double#doubleToRawLongBits}
|
||||
* and {@link MemorySegment#address()}, respectively).
|
||||
* <p>
|
||||
* Alternatively, a var handle is <em>unaligned</em> if its alignment constraint {@code A} is incompatible with the
|
||||
* access size {@code S}, that is, if {@code A < S}. An unaligned var handle only supports the {@code get} and {@code set}
|
||||
* access modes. All other access modes will result in {@link UnsupportedOperationException} being thrown. Moreover,
|
||||
* while supported, access modes {@code get} and {@code set} might lead to word tearing.
|
||||
*
|
||||
* @implSpec
|
||||
* Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @sealedGraph
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, PaddingLayout, ValueLayout {
|
||||
|
||||
/**
|
||||
|
@ -292,6 +329,44 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
|
|||
*/
|
||||
MemoryLayout withByteAlignment(long byteAlignment);
|
||||
|
||||
/**
|
||||
* {@return {@code offset + (byteSize() * index)}}
|
||||
*
|
||||
* @param offset the base offset
|
||||
* @param index the index to be scaled by the byte size of this layout
|
||||
* @throws IllegalArgumentException if {@code offset} or {@code index} is negative
|
||||
* @throws ArithmeticException if either the addition or multiplication overflows
|
||||
*/
|
||||
@ForceInline
|
||||
default long scale(long offset, long index) {
|
||||
if (offset < 0) {
|
||||
throw new IllegalArgumentException("Negative offset: " + offset);
|
||||
}
|
||||
if (index < 0) {
|
||||
throw new IllegalArgumentException("Negative index: " + index);
|
||||
}
|
||||
|
||||
return Math.addExact(offset, Math.multiplyExact(byteSize(), index));
|
||||
}
|
||||
|
||||
/**
|
||||
*{@return a method handle that can be used to invoke {@link #scale(long, long)} on this layout}
|
||||
*/
|
||||
default MethodHandle scaleHandle() {
|
||||
class Holder {
|
||||
static final MethodHandle MH_SCALE;
|
||||
static {
|
||||
try {
|
||||
MH_SCALE = MethodHandles.lookup().findVirtual(MemoryLayout.class, "scale",
|
||||
MethodType.methodType(long.class, long.class, long.class));
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new ExceptionInInitializerError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Holder.MH_SCALE.bindTo(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the
|
||||
* path is this layout.
|
||||
|
@ -314,7 +389,8 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
|
|||
* The returned method handle has the following characteristics:
|
||||
* <ul>
|
||||
* <li>its return type is {@code long};</li>
|
||||
* <li>it has as zero or more parameters of type {@code long}, one for each <a href=#open-path-elements>open path element</a>
|
||||
* <li>it has one leading {@code long} parameter representing the base offset;</li>
|
||||
* <li>it has as zero or more trailing parameters of type {@code long}, one for each <a href=#open-path-elements>open path element</a>
|
||||
* in the provided layout path. The order of these parameters corresponds to the order in which the open path
|
||||
* elements occur in the provided layout path.
|
||||
* </ul>
|
||||
|
@ -322,13 +398,14 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
|
|||
* The final offset returned by the method handle is computed as follows:
|
||||
*
|
||||
* <blockquote><pre>{@code
|
||||
* offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
|
||||
* offset = b + c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
|
||||
* }</pre></blockquote>
|
||||
*
|
||||
* where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
|
||||
* arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
|
||||
* and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
|
||||
* the layout path.
|
||||
* where {@code b} represents the base offset provided as a <em>dynamic</em> {@code long} argument, {@code x_1}, {@code x_2},
|
||||
* ... {@code x_n} represent indices into sequences provided as <em>dynamic</em> {@code long} arguments, whereas
|
||||
* {@code s_1}, {@code s_2}, ... {@code s_n} are <em>static</em> stride constants derived from the size of the element
|
||||
* layout of a sequence, and {@code c_1}, {@code c_2}, ... {@code c_m} are other <em>static</em> offset constants
|
||||
* (such as field offsets) which are derived from the layout path.
|
||||
*
|
||||
* @apiNote The returned method handle can be used to compute a layout offset, similarly to {@link #byteOffset(PathElement...)},
|
||||
* but more flexibly, as some indices can be specified when invoking the method handle.
|
||||
|
@ -351,71 +428,93 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
|
|||
* <ul>
|
||||
* <li>its type is derived from the {@linkplain ValueLayout#carrier() carrier} of the
|
||||
* selected value layout;</li>
|
||||
* <li>it has as zero or more access coordinates of type {@code long}, one for each
|
||||
* <a href=#open-path-elements>open path element</a> in the provided layout path. The order of these access
|
||||
* coordinates corresponds to the order in which the open path elements occur in the provided
|
||||
* layout path.
|
||||
* <li>it has a leading parameter of type {@code MemorySegment} representing the accessed segment</li>
|
||||
* <li>a following {@code long} parameter, corresponding to the base offset, denoted as {@code B};</li>
|
||||
* <li>it has zero or more trailing access coordinates of type {@code long}, one for each
|
||||
* <a href=#open-path-elements>open path element</a> in the provided layout path, denoted as
|
||||
* {@code I1, I2, ... In}, respectively. The order of these access coordinates corresponds to the order
|
||||
* in which the open path elements occur in the provided layout path.
|
||||
* </ul>
|
||||
* <p>
|
||||
* The final address accessed by the returned var handle can be computed as follows:
|
||||
* If the provided layout path {@code P} contains no dereference elements, then the offset {@code O} of the access
|
||||
* operation is computed as follows:
|
||||
*
|
||||
* <blockquote><pre>{@code
|
||||
* address = base(segment) + offset
|
||||
* }</pre></blockquote>
|
||||
*
|
||||
* Where {@code base(segment)} denotes a function that returns the physical base address of the accessed
|
||||
* memory segment. For native segments, this function just returns the native segment's
|
||||
* {@linkplain MemorySegment#address() address}. For heap segments, this function is more complex, as the address
|
||||
* of heap segments is virtualized. The {@code offset} value can be expressed in the following form:
|
||||
*
|
||||
* <blockquote><pre>{@code
|
||||
* offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
|
||||
* }</pre></blockquote>
|
||||
*
|
||||
* where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
|
||||
* arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
|
||||
* and {@code s_1}, {@code s_2}, ... {@code s_n} are <em>static</em> stride constants which are derived from
|
||||
* the layout path.
|
||||
* {@snippet lang = "java":
|
||||
* O = this.offsetHandle(P).invokeExact(B, I1, I2, ... In);
|
||||
* }
|
||||
* <p>
|
||||
* Additionally, the provided dynamic values must conform to bounds which are derived from the layout path, that is,
|
||||
* {@code 0 <= x_i < b_i}, where {@code 1 <= i <= n}, or {@link IndexOutOfBoundsException} is thrown.
|
||||
* Accessing a memory segment using the var handle returned by this method is subject to the following checks:
|
||||
* <ul>
|
||||
* <li>The physical address of the accessed memory segment must be <a href="MemorySegment.html#segment-alignment">aligned</a>
|
||||
* according to the {@linkplain #byteAlignment() alignment constraint} of the root layout (this layout), or
|
||||
* an {@link IllegalArgumentException} will be issued. Note that the alignment constraint of the root layout
|
||||
* can be more strict (but not less) than the alignment constraint of the selected value layout.</li>
|
||||
* <li>The offset of the access operation (computed as above) must fall inside the spatial bounds of the
|
||||
* accessed memory segment, or an {@link IndexOutOfBoundsException} is thrown. This is the case when {@code O + A <= S},
|
||||
* where {@code O} is the accessed offset (computed as above), {@code A} is the size of the selected layout and {@code S}
|
||||
* is the size of the accessed memory segment.</li>
|
||||
* <li>The accessed memory segment must be {@link MemorySegment#isAccessibleBy(Thread) accessible} from the
|
||||
* thread performing the access operation, or a {@link WrongThreadException} is thrown.</li>
|
||||
* <li>The {@linkplain MemorySegment#scope() scope} associated with the accessed segment must be
|
||||
* {@linkplain MemorySegment.Scope#isAlive() alive}, or an {@link IllegalStateException} is thrown.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The base address must be <a href="MemorySegment.html#segment-alignment">aligned</a> according to the {@linkplain
|
||||
* #byteAlignment() alignment constraint} of the root layout (this layout). Note that this can be more strict
|
||||
* (but not less) than the alignment constraint of the selected value layout.
|
||||
* If the selected layout is an {@linkplain AddressLayout address layout}, calling {@link VarHandle#get(Object...)}
|
||||
* on the returned var handle will return a new memory segment. The segment is associated with a fresh scope that is
|
||||
* always alive. Moreover, the size of the segment depends on whether the address layout has a
|
||||
* {@linkplain AddressLayout#targetLayout() target layout}. More specifically:
|
||||
* <ul>
|
||||
* <li>If the address layout has a target layout {@code T}, then the size of the returned segment
|
||||
* is {@code T.byteSize()};</li>
|
||||
* <li>Otherwise, the address layout has no target layout, and the size of the returned segment
|
||||
* is <a href="MemorySegment.html#wrapping-addresses">zero</a>.</li>
|
||||
* </ul>
|
||||
* Moreover, if the selected layout is an {@linkplain AddressLayout address layout}, calling {@link VarHandle#set(Object...)}
|
||||
* can throw {@link IllegalArgumentException} if the memory segment representing the address to be written is not a
|
||||
* {@linkplain MemorySegment#isNative() native} memory segment.
|
||||
* <p>
|
||||
* Multiple paths can be chained, with <a href=#deref-path-elements>dereference path elements</a>.
|
||||
* A dereference path element constructs a fresh native memory segment whose base address is the address value
|
||||
* read obtained by accessing a memory segment at the offset determined by the layout path elements immediately preceding
|
||||
* the dereference path element. In other words, if a layout path contains one or more dereference path elements,
|
||||
* the final address accessed by the returned var handle can be computed as follows:
|
||||
* If the provided layout path has size {@code m} and contains a dereference path element in position {@code k}
|
||||
* (where {@code k <= m}) then two layout paths {@code P} and {@code P'} are derived, where P contains all the path
|
||||
* elements from 0 to {@code k - 1} and {@code P'} contains all the path elements from {@code k + 1} to
|
||||
* {@code m} (if any). Then, the returned var handle is computed as follows:
|
||||
*
|
||||
* <blockquote><pre>{@code
|
||||
* address_1 = base(segment) + offset_1
|
||||
* address_2 = base(segment_1) + offset_2
|
||||
* ...
|
||||
* address_k = base(segment_k-1) + offset_k
|
||||
* }</pre></blockquote>
|
||||
* {@snippet lang = "java":
|
||||
* VarHandle baseHandle = this.varHandle(P);
|
||||
* MemoryLayout target = ((AddressLayout)this.select(P)).targetLayout().get();
|
||||
* VarHandle targetHandle = target.varHandle(P');
|
||||
* targetHandle = MethodHandles.insertCoordinates(targetHandle, 1, 0L); // always access nested targets at offset 0
|
||||
* targetHandle = MethodHandles.collectCoordinates(targetHandle, 0,
|
||||
* baseHandle.toMethodHandle(VarHandle.AccessMode.GET));
|
||||
* }
|
||||
*
|
||||
* where {@code k} is the number of dereference path elements in a layout path, {@code segment} is the input segment,
|
||||
* {@code segment_1}, ... {@code segment_k-1} are the segments obtained by dereferencing the address associated with
|
||||
* a given dereference path element (e.g. {@code segment_1} is a native segment whose base address is {@code address_1}),
|
||||
* and {@code offset_1}, {@code offset_2}, ... {@code offset_k} are the offsets computed by evaluating
|
||||
* the path elements after a given dereference operation (these offsets are obtained using the computation described
|
||||
* above). In these more complex access operations, all memory accesses immediately preceding a dereference operation
|
||||
* (e.g. those at addresses {@code address_1}, {@code address_2}, ..., {@code address_k-1} are performed using the
|
||||
* {@link VarHandle.AccessMode#GET} access mode.
|
||||
* (The above can be trivially generalized to cases where the provided layout path contains more than one dereference
|
||||
* path elements).
|
||||
* <p>
|
||||
* As an example, consider the memory layout expressed by a {@link GroupLayout} instance constructed as follows:
|
||||
* {@snippet lang = "java":
|
||||
* GroupLayout grp = java.lang.foreign.MemoryLayout.structLayout(
|
||||
* MemoryLayout.paddingLayout(4),
|
||||
* ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value")
|
||||
* );
|
||||
* }
|
||||
* To access the member layout named {@code value}, we can construct a var handle as follows:
|
||||
* {@snippet lang = "java":
|
||||
* VarHandle handle = grp.varHandle(PathElement.groupElement("value")); //(MemorySegment, long) -> int
|
||||
* }
|
||||
*
|
||||
* @apiNote The resulting var handle features certain <em>access mode restrictions</em>, which are common to all
|
||||
* {@linkplain MethodHandles#memorySegmentViewVarHandle(ValueLayout) memory segment view handles}.
|
||||
* @apiNote The resulting var handle features certain <a href="#access-mode-restrictions"><em>access mode restrictions</em></a>,
|
||||
* which are common to all var handles derived from memory layouts.
|
||||
*
|
||||
* @param elements the layout path elements.
|
||||
* @return a var handle that accesses a memory segment at the offset selected by the given layout path.
|
||||
* @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout.
|
||||
* @throws IllegalArgumentException if the layout selected by the provided path is not a {@linkplain ValueLayout value layout}.
|
||||
* @see MethodHandles#memorySegmentViewVarHandle(ValueLayout)
|
||||
*/
|
||||
default VarHandle varHandle(PathElement... elements) {
|
||||
Objects.requireNonNull(elements);
|
||||
if (this instanceof ValueLayout vl && elements.length == 0) {
|
||||
return vl.varHandle(); // fast path
|
||||
}
|
||||
return computePathOp(LayoutPath.rootPath(this), LayoutPath::dereferenceHandle,
|
||||
Set.of(), elements);
|
||||
}
|
||||
|
@ -427,23 +526,27 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
|
|||
* The returned method handle has the following characteristics:
|
||||
* <ul>
|
||||
* <li>its return type is {@code MemorySegment};</li>
|
||||
* <li>it has a leading parameter of type {@code MemorySegment}, corresponding to the memory segment
|
||||
* to be sliced;</li>
|
||||
* <li>it has as zero or more parameters of type {@code long}, one for each <a href=#open-path-elements>open path element</a>
|
||||
* <li>it has a leading parameter of type {@code MemorySegment} corresponding to the memory segment to be sliced</li>
|
||||
* <li>a following {@code long} parameter, corresponding to the base offset</li>
|
||||
* <li>it has as zero or more trailing parameters of type {@code long}, one for each <a href=#open-path-elements>open path element</a>
|
||||
* in the provided layout path. The order of these parameters corresponds to the order in which the open path
|
||||
* elements occur in the provided layout path.
|
||||
* </ul>
|
||||
* <p>
|
||||
* The offset of the returned segment is computed as follows:
|
||||
* {@snippet lang=java :
|
||||
* long offset = byteOffset(elements);
|
||||
* long size = select(elements).byteSize();
|
||||
* MemorySegment slice = segment.asSlice(offset, size);
|
||||
* }
|
||||
* The offset {@code O} of the returned segment is computed as if by a call to a
|
||||
* {@linkplain #byteOffsetHandle(PathElement...) byte offset handle} constructed using the given path elements.
|
||||
* <p>
|
||||
* The segment to be sliced must be <a href="MemorySegment.html#segment-alignment">aligned</a> according to the
|
||||
* {@linkplain #byteAlignment() alignment constraint} of the root layout (this layout). Note that this can be more
|
||||
* strict (but not less) than the alignment constraint of the selected value layout.
|
||||
* Computing a slice of a memory segment using the method handle returned by this method is subject to the following checks:
|
||||
* <ul>
|
||||
* <li>The physical address of the accessed memory segment must be <a href="MemorySegment.html#segment-alignment">aligned</a>
|
||||
* according to the {@linkplain #byteAlignment() alignment constraint} of the root layout (this layout), or
|
||||
* an {@link IllegalArgumentException} will be issued. Note that the alignment constraint of the root layout
|
||||
* can be more strict (but not less) than the alignment constraint of the selected layout.</li>
|
||||
* <li>The start offset of the slicing operation (computed as above) must fall fall inside the spatial bounds of the
|
||||
* accessed memory segment, or an {@link IndexOutOfBoundsException} is thrown. This is the case when {@code O + A <= S},
|
||||
* where {@code O} is the start offset of the slicing operation (computed as above), {@code A} is the size of the
|
||||
* selected layout and {@code S} is the size of the accessed memory segment.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @apiNote The returned method handle can be used to obtain a memory segment slice, similarly to {@link MemorySegment#asSlice(long, long)},
|
||||
* but more flexibly, as some indices can be specified when invoking the method handle.
|
||||
|
@ -501,9 +604,8 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
|
|||
* @implSpec
|
||||
* Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface PathElement permits LayoutPath.PathElementImpl {
|
||||
|
||||
/**
|
||||
|
@ -669,24 +771,6 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
|
|||
SequenceLayoutImpl.of(elementCount, elementLayout));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a sequence layout with the given element layout and the maximum element
|
||||
* count such that it does not overflow a {@code long}.
|
||||
*
|
||||
* This is equivalent to the following code:
|
||||
* {@snippet lang = java:
|
||||
* sequenceLayout(Long.MAX_VALUE / elementLayout.byteSize(), elementLayout);
|
||||
* }
|
||||
*
|
||||
* @param elementLayout the sequence element layout.
|
||||
* @return a new sequence layout with the given element layout and maximum element count.
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}.
|
||||
*/
|
||||
static SequenceLayout sequenceLayout(MemoryLayout elementLayout) {
|
||||
Objects.requireNonNull(elementLayout);
|
||||
return sequenceLayout(Long.MAX_VALUE / elementLayout.byteSize(), elementLayout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a struct layout with the given member layouts.
|
||||
*
|
||||
|
|
|
@ -26,15 +26,13 @@
|
|||
package java.lang.foreign;
|
||||
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.foreign.Linker.Option;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.FileChannel.*;
|
||||
import java.nio.channels.FileChannel.MapMode;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
@ -46,10 +44,8 @@ import jdk.internal.foreign.AbstractMemorySegmentImpl;
|
|||
import jdk.internal.foreign.HeapMemorySegmentImpl;
|
||||
import jdk.internal.foreign.MemorySessionImpl;
|
||||
import jdk.internal.foreign.NativeMemorySegmentImpl;
|
||||
import jdk.internal.foreign.StringSupport;
|
||||
import jdk.internal.foreign.Utils;
|
||||
import jdk.internal.foreign.abi.SharedUtils;
|
||||
import jdk.internal.foreign.layout.ValueLayouts;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
import jdk.internal.javac.Restricted;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
|
@ -128,32 +124,47 @@ import jdk.internal.vm.annotation.ForceInline;
|
|||
* int value = segment.get(ValueLayout.JAVA_INT.withOrder(BIG_ENDIAN), 0);
|
||||
* }
|
||||
*
|
||||
* For more complex access operations (e.g. structured memory access), clients can obtain a
|
||||
* {@linkplain MethodHandles#memorySegmentViewVarHandle(ValueLayout) var handle}
|
||||
* that accepts a segment and a {@code long} offset. More complex var handles
|
||||
* can be obtained by adapting a segment var handle view using the var handle combinator functions defined in the
|
||||
* {@link java.lang.invoke.MethodHandles} class:
|
||||
* More complex access operations can be implemented using var handles. The {@link ValueLayout#varHandle()}
|
||||
* method can be used to obtain a var handle that can be used to get/set values represented by the given value layout on a memory segment.
|
||||
* A var handle obtained from a layout supports several additional <a href=MemoryLayout.html#access-mode-restrictions>
|
||||
* access modes</a>. More importantly, var handles can be <em>combined</em> with method handles to express complex access
|
||||
* operations. For instance, a var handle that can be used to access an element of an {@code int} array at a given logical
|
||||
* index can be created as follows:
|
||||
*
|
||||
* {@snippet lang=java:
|
||||
* MemorySegment segment = ...
|
||||
* VarHandle intHandle = ValueLayout.JAVA_INT.varHandle(); // (MemorySegment, long)
|
||||
* MethodHandle scale = ValueLayout.JAVA_INT.scaleHandle(); // <base offset> + <index> * JAVA_INT.byteSize()
|
||||
*
|
||||
* intHandle = MethodHandles.filterCoordinates(intHandle, 1, scale);
|
||||
* int value = (int) intHandle.get(segment, 0L, 3L); // get int element at offset 0 + 3 * 4 = 12
|
||||
* }
|
||||
*
|
||||
* To make the process of creating these var handles easier, the method
|
||||
* {@link MemoryLayout#varHandle(MemoryLayout.PathElement...)} can be used, by providing it a so called
|
||||
* <a href="MemoryLayout.html#layout-paths"><em>layout path</em></a>. A layout path, consisting of several <em>layout
|
||||
* path elements</em>, selects a value layout to be accessed, which can be nested inside another memory layout. For example,
|
||||
* we can express the access to an element of an {@code int} array using layout paths like so:
|
||||
*
|
||||
* {@snippet lang=java :
|
||||
* MemorySegment segment = ...
|
||||
* VarHandle intHandle = MethodHandles.memorySegmentViewVarHandle(ValueLayout.JAVA_INT);
|
||||
* MethodHandle multiplyExact = MethodHandles.lookup()
|
||||
* .findStatic(Math.class, "multiplyExact",
|
||||
* MethodType.methodType(long.class, long.class, long.class));
|
||||
* intHandle = MethodHandles.filterCoordinates(intHandle, 1,
|
||||
* MethodHandles.insertArguments(multiplyExact, 0, ValueLayout.JAVA_INT.byteSize()));
|
||||
* int value = (int) intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
|
||||
* MemoryLayout segmentLayout = MemoryLayout.structLayout(
|
||||
* ValueLayout.JAVA_INT.withName("size"),
|
||||
* MemoryLayout.sequenceLayout(4, ValueLayout.JAVA_INT).withName("data") // array of 4 elements
|
||||
* );
|
||||
* VarHandle intHandle = segmentLayout.varHandle(MemoryLayout.PathElement.groupElement("data"),
|
||||
* MemoryLayout.PathElement.sequenceElement());
|
||||
* int value = (int) intHandle.get(segment, 0L, 3L); // get int element at offset 0 + offsetof(data) + 3 * 4 = 12
|
||||
* }
|
||||
* Where {@code offsetof(data)} is the offset of the {@code data} element layout of the {@code segmentLayout} layout
|
||||
*
|
||||
* Alternatively, complex var handles can can be obtained
|
||||
* from {@linkplain MemoryLayout#varHandle(MemoryLayout.PathElement...) memory layouts}
|
||||
* by providing a so called <a href="MemoryLayout.html#layout-paths"><em>layout path</em></a>:
|
||||
*
|
||||
* {@snippet lang=java :
|
||||
* MemorySegment segment = ...
|
||||
* VarHandle intHandle = ValueLayout.JAVA_INT.arrayElementVarHandle();
|
||||
* int value = (int) intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
|
||||
* }
|
||||
* Both the var handle returned by {@link ValueLayout#varHandle()} and
|
||||
* {@link MemoryLayout#varHandle(MemoryLayout.PathElement...)}, as well as the method handle returned by
|
||||
* {@link MemoryLayout#byteOffsetHandle(MemoryLayout.PathElement...)} and {@link MemoryLayout#sliceHandle(MemoryLayout.PathElement...)}
|
||||
* feature a <em>base offset</em> parameter. This parameter represents a base offset for the offset computation. This
|
||||
* parameter allows a client to combine these handles further with additional offset computations. This is demonstrated
|
||||
* in the first of the two examples above, where {@code intHandle} is combined with a
|
||||
* {@linkplain MemoryLayout#scaleHandle() scale handle} obtained from {@code ValueLayout.JAVA_INT}.
|
||||
*
|
||||
* <h2 id="slicing">Slicing memory segments</h2>
|
||||
*
|
||||
|
@ -434,9 +445,8 @@ import jdk.internal.vm.annotation.ForceInline;
|
|||
* @implSpec
|
||||
* Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
||||
|
||||
/**
|
||||
|
@ -597,8 +607,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* <p>
|
||||
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
|
||||
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
|
||||
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
|
||||
* restricted methods, and use safe and supported functionalities, where possible.
|
||||
* the JVM or, worse, silently result in memory corruption.
|
||||
*
|
||||
* @param newSize the size of the returned segment.
|
||||
* @return a new memory segment that has the same address and scope as this segment, but the new
|
||||
|
@ -631,8 +640,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* <p>
|
||||
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
|
||||
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
|
||||
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
|
||||
* restricted methods, and use safe and supported functionalities, where possible.
|
||||
* the JVM or, worse, silently result in memory corruption.
|
||||
*
|
||||
* @apiNote The cleanup action (if present) should take care not to leak the received segment to external
|
||||
* clients which might access the segment after its backing region of memory is no longer available. Furthermore,
|
||||
|
@ -671,8 +679,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* <p>
|
||||
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
|
||||
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
|
||||
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
|
||||
* restricted methods, and use safe and supported functionalities, where possible.
|
||||
* the JVM or, worse, silently result in memory corruption.
|
||||
*
|
||||
* @apiNote The cleanup action (if present) should take care not to leak the received segment to external
|
||||
* clients which might access the segment after its backing region of memory is no longer available. Furthermore,
|
||||
|
@ -739,30 +746,6 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
Optional<MemorySegment> asOverlappingSlice(MemorySegment other);
|
||||
|
||||
/**
|
||||
* Returns the offset, in bytes, of the provided segment, relative to this
|
||||
* segment.
|
||||
*
|
||||
* <p>The offset is relative to the address of this segment and can be
|
||||
* a negative or positive value. For instance, if both segments are native
|
||||
* segments, or heap segments backed by the same array, the resulting offset
|
||||
* can be computed as follows:
|
||||
*
|
||||
* {@snippet lang=java :
|
||||
* other.address() - address()
|
||||
* }
|
||||
*
|
||||
* If the segments share the same address, {@code 0} is returned. If
|
||||
* {@code other} is a slice of this segment, the offset is always
|
||||
* {@code 0 <= x < this.byteSize()}.
|
||||
*
|
||||
* @param other the segment to retrieve an offset to.
|
||||
* @throws UnsupportedOperationException if the two segments cannot be compared, e.g. because they are of
|
||||
* different kinds, or because they are backed by different Java arrays.
|
||||
* @return the relative offset, in bytes, of the provided segment.
|
||||
*/
|
||||
long segmentOffset(MemorySegment other);
|
||||
|
||||
/**
|
||||
* Fills the contents of this memory segment with the given value.
|
||||
* <p>
|
||||
|
@ -771,7 +754,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*
|
||||
* {@snippet lang=java :
|
||||
* for (long offset = 0; offset < segment.byteSize(); offset++) {
|
||||
* byteHandle.set(ValueLayout.JAVA_BYTE, offset, value);
|
||||
* segment.set(ValueLayout.JAVA_BYTE, offset, value);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
|
@ -1072,29 +1055,89 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
double[] toArray(ValueLayout.OfDouble elementLayout);
|
||||
|
||||
/**
|
||||
* Reads a UTF-8 encoded, null-terminated string from this segment at the given offset.
|
||||
* Reads a null-terminated string from this segment at the given offset, using the
|
||||
* {@linkplain StandardCharsets#UTF_8 UTF-8} charset.
|
||||
* <p>
|
||||
* This method always replaces malformed-input and unmappable-character
|
||||
* sequences with this charset's default replacement string. The {@link
|
||||
* java.nio.charset.CharsetDecoder} class should be used when more control
|
||||
* over the decoding process is required.
|
||||
* Calling this method is equivalent to the following code:
|
||||
* {@snippet lang = java:
|
||||
* getString(offset, StandardCharsets.UTF_8);
|
||||
*}
|
||||
*
|
||||
* @param offset offset in bytes (relative to this segment address) at which this access operation will occur.
|
||||
* @return a Java string constructed from the bytes read from the given starting address up to (but not including)
|
||||
* the first {@code '\0'} terminator character (assuming one is found).
|
||||
* @throws IllegalArgumentException if the size of the UTF-8 string is greater than the largest string supported by the platform.
|
||||
* @throws IndexOutOfBoundsException if {@code offset < 0} or {@code offset > byteSize() - S}, where {@code S} is the size of the UTF-8
|
||||
* string (including the terminator character).
|
||||
* @throws IllegalArgumentException if the size of the string is greater than the largest string supported by the platform.
|
||||
* @throws IndexOutOfBoundsException if {@code offset < 0}.
|
||||
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - (B + 1)}, where {@code B} is the size,
|
||||
* in bytes, of the string encoded using UTF-8 charset {@code str.getBytes(StandardCharsets.UTF_8).length}).
|
||||
* @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not
|
||||
* {@linkplain Scope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
*/
|
||||
default String getUtf8String(long offset) {
|
||||
return SharedUtils.toJavaStringInternal(this, offset);
|
||||
default String getString(long offset) {
|
||||
return getString(offset, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given string into this segment at the given offset, converting it to a null-terminated byte sequence using UTF-8 encoding.
|
||||
* Reads a null-terminated string from this segment at the given offset, using the provided charset.
|
||||
* <p>
|
||||
* This method always replaces malformed-input and unmappable-character
|
||||
* sequences with this charset's default replacement string. The {@link
|
||||
* java.nio.charset.CharsetDecoder} class should be used when more control
|
||||
* over the decoding process is required.
|
||||
*
|
||||
* @param offset offset in bytes (relative to this segment address) at which this access operation will occur.
|
||||
* @param charset the charset used to {@linkplain Charset#newDecoder() decode} the string bytes.
|
||||
* @return a Java string constructed from the bytes read from the given starting address up to (but not including)
|
||||
* the first {@code '\0'} terminator character (assuming one is found).
|
||||
* @throws IllegalArgumentException if the size of the string is greater than the largest string supported by the platform.
|
||||
* @throws IndexOutOfBoundsException if {@code offset < 0}.
|
||||
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - (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>
|
||||
* </ul>
|
||||
* @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not
|
||||
* {@linkplain Scope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if {@code charset} is not a {@linkplain StandardCharsets standard charset}.
|
||||
*/
|
||||
default String getString(long offset, Charset charset) {
|
||||
Objects.requireNonNull(charset);
|
||||
return StringSupport.read(this, offset, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given string into this segment at the given offset, converting it to a null-terminated byte sequence
|
||||
* using the {@linkplain StandardCharsets#UTF_8 UTF-8} charset.
|
||||
* <p>
|
||||
* Calling this method is equivalent to the following code:
|
||||
* {@snippet lang = java:
|
||||
* setString(offset, str, StandardCharsets.UTF_8);
|
||||
*}
|
||||
* @param offset offset in bytes (relative to this segment address) at which this access operation will occur.
|
||||
* the final address of this write operation can be expressed as {@code address() + offset}.
|
||||
* @param str the Java string to be written into this segment.
|
||||
* @throws IndexOutOfBoundsException if {@code offset < 0}.
|
||||
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - (B + 1)}, where {@code B} is the size,
|
||||
* in bytes, of the string encoded using UTF-8 charset {@code str.getBytes(StandardCharsets.UTF_8).length}).
|
||||
* @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not
|
||||
* {@linkplain Scope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
*/
|
||||
default void setString(long offset, String str) {
|
||||
Objects.requireNonNull(str);
|
||||
setString(offset, str, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given string into this segment at the given offset, converting it to a null-terminated byte sequence
|
||||
* using the provided charset.
|
||||
* <p>
|
||||
* This method always replaces malformed-input and unmappable-character
|
||||
* sequences with this charset's default replacement string. The {@link
|
||||
|
@ -1103,22 +1146,33 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* <p>
|
||||
* If the given string contains any {@code '\0'} characters, they will be
|
||||
* copied as well. This means that, depending on the method used to read
|
||||
* the string, such as {@link MemorySegment#getUtf8String(long)}, the string
|
||||
* the string, such as {@link MemorySegment#getString(long)}, the string
|
||||
* will appear truncated when read again.
|
||||
* @param offset offset in bytes (relative to this segment address) at which this access operation will occur.
|
||||
* the final address of this write operation can be expressed as {@code address() + offset}.
|
||||
* @param str the Java string to be written into this segment.
|
||||
* @throws IndexOutOfBoundsException if {@code offset < 0} or {@code offset > byteSize() - str.getBytes().length() + 1}.
|
||||
* @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not
|
||||
* {@linkplain Scope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
*
|
||||
* @param offset offset in bytes (relative to this segment address) at which this access operation will occur.
|
||||
* the final address of this write operation can be expressed as {@code address() + offset}.
|
||||
* @param str the Java string to be written into this segment.
|
||||
* @param charset the charset used to {@linkplain Charset#newEncoder() encode} the string bytes.
|
||||
* @throws IndexOutOfBoundsException if {@code offset < 0}.
|
||||
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - (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>
|
||||
* </ul>
|
||||
* @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not
|
||||
* {@linkplain Scope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if {@code charset} is not a {@linkplain StandardCharsets standard charset}.
|
||||
*/
|
||||
default void setUtf8String(long offset, String str) {
|
||||
Utils.toCString(str.getBytes(StandardCharsets.UTF_8), SegmentAllocator.prefixAllocator(asSlice(offset)));
|
||||
default void setString(long offset, String str, Charset charset) {
|
||||
Objects.requireNonNull(charset);
|
||||
Objects.requireNonNull(str);
|
||||
StringSupport.write(this, offset, charset, str);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a memory segment that is backed by the same region of memory that backs the given {@link Buffer} instance.
|
||||
* The segment starts relative to the buffer's position (inclusive) and ends relative to the buffer's limit (exclusive).
|
||||
|
@ -1281,8 +1335,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* {@linkplain Scope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code dstSegment.isAccessibleBy(T) == false}.
|
||||
* @throws IndexOutOfBoundsException if {@code srcOffset > srcSegment.byteSize() - bytes} or if
|
||||
* {@code dstOffset > dstSegment.byteSize() - bytes}, or if either {@code srcOffset}, {@code dstOffset}
|
||||
* @throws IndexOutOfBoundsException if {@code srcOffset > srcSegment.byteSize() - bytes}.
|
||||
* @throws IndexOutOfBoundsException if {@code dstOffset > dstSegment.byteSize() - bytes}.
|
||||
* @throws IndexOutOfBoundsException if either {@code srcOffset}, {@code dstOffset}
|
||||
* or {@code bytes} are {@code < 0}.
|
||||
* @throws UnsupportedOperationException if {@code dstSegment} is {@linkplain #isReadOnly() read-only}.
|
||||
*/
|
||||
|
@ -1320,17 +1375,21 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @param elementCount the number of elements to be copied.
|
||||
* @throws IllegalArgumentException if the element layouts have different sizes, if the source (resp. destination) segment/offset are
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the source
|
||||
* (resp. destination) element layout, or if the source (resp. destination) element layout alignment is greater than its size.
|
||||
* (resp. destination) element layout.
|
||||
* @throws IllegalArgumentException if {@code srcElementLayout.byteAlignment() > srcElementLayout.byteSize()}.
|
||||
* @throws IllegalArgumentException if {@code dstElementLayout.byteAlignment() > dstElementLayout.byteSize()}.
|
||||
* @throws IllegalStateException if the {@linkplain #scope() scope} associated with {@code srcSegment} is not
|
||||
* {@linkplain Scope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code srcSegment().isAccessibleBy(T) == false}.
|
||||
* such that {@code srcSegment.isAccessibleBy(T) == false}.
|
||||
* @throws IllegalStateException if the {@linkplain #scope() scope} associated with {@code dstSegment} is not
|
||||
* {@linkplain Scope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code dstSegment().isAccessibleBy(T) == false}.
|
||||
* such that {@code dstSegment.isAccessibleBy(T) == false}.
|
||||
* @throws UnsupportedOperationException if {@code dstSegment} is {@linkplain #isReadOnly() read-only}.
|
||||
* @throws IndexOutOfBoundsException if {@code elementCount * srcLayout.byteSize()} or {@code elementCount * dtsLayout.byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code elementCount * srcLayout.byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code elementCount * dtsLayout.byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code srcOffset > srcSegment.byteSize() - (elementCount * srcLayout.byteSize())}.
|
||||
* @throws IndexOutOfBoundsException if {@code dstOffset > dstSegment.byteSize() - (elementCount * dstLayout.byteSize())}.
|
||||
* @throws IndexOutOfBoundsException if either {@code srcOffset}, {@code dstOffset} or {@code elementCount} are {@code < 0}.
|
||||
*/
|
||||
|
@ -1361,7 +1420,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default byte get(ValueLayout.OfByte layout, long offset) {
|
||||
return (byte) ((ValueLayouts.OfByteImpl) layout).accessHandle().get(this, offset);
|
||||
return (byte) layout.varHandle().get(this, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1381,7 +1440,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default void set(ValueLayout.OfByte layout, long offset, byte value) {
|
||||
((ValueLayouts.OfByteImpl) layout).accessHandle().set(this, offset, value);
|
||||
layout.varHandle().set(this, offset, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1400,7 +1459,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default boolean get(ValueLayout.OfBoolean layout, long offset) {
|
||||
return (boolean) ((ValueLayouts.OfBooleanImpl) layout).accessHandle().get(this, offset);
|
||||
return (boolean) layout.varHandle().get(this, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1420,7 +1479,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default void set(ValueLayout.OfBoolean layout, long offset, boolean value) {
|
||||
((ValueLayouts.OfBooleanImpl) layout).accessHandle().set(this, offset, value);
|
||||
layout.varHandle().set(this, offset, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1439,7 +1498,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default char get(ValueLayout.OfChar layout, long offset) {
|
||||
return (char) ((ValueLayouts.OfCharImpl) layout).accessHandle().get(this, offset);
|
||||
return (char) layout.varHandle().get(this, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1459,7 +1518,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default void set(ValueLayout.OfChar layout, long offset, char value) {
|
||||
((ValueLayouts.OfCharImpl) layout).accessHandle().set(this, offset, value);
|
||||
layout.varHandle().set(this, offset, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1478,7 +1537,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default short get(ValueLayout.OfShort layout, long offset) {
|
||||
return (short) ((ValueLayouts.OfShortImpl) layout).accessHandle().get(this, offset);
|
||||
return (short) layout.varHandle().get(this, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1498,7 +1557,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default void set(ValueLayout.OfShort layout, long offset, short value) {
|
||||
((ValueLayouts.OfShortImpl) layout).accessHandle().set(this, offset, value);
|
||||
layout.varHandle().set(this, offset, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1517,7 +1576,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default int get(ValueLayout.OfInt layout, long offset) {
|
||||
return (int) ((ValueLayouts.OfIntImpl) layout).accessHandle().get(this, offset);
|
||||
return (int) layout.varHandle().get(this, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1537,7 +1596,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default void set(ValueLayout.OfInt layout, long offset, int value) {
|
||||
((ValueLayouts.OfIntImpl) layout).accessHandle().set(this, offset, value);
|
||||
layout.varHandle().set(this, offset, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1556,7 +1615,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default float get(ValueLayout.OfFloat layout, long offset) {
|
||||
return (float)((ValueLayouts.OfFloatImpl) layout).accessHandle().get(this, offset);
|
||||
return (float)layout.varHandle().get(this, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1576,7 +1635,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default void set(ValueLayout.OfFloat layout, long offset, float value) {
|
||||
((ValueLayouts.OfFloatImpl) layout).accessHandle().set(this, offset, value);
|
||||
layout.varHandle().set(this, offset, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1595,7 +1654,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default long get(ValueLayout.OfLong layout, long offset) {
|
||||
return (long) ((ValueLayouts.OfLongImpl) layout).accessHandle().get(this, offset);
|
||||
return (long) layout.varHandle().get(this, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1615,7 +1674,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default void set(ValueLayout.OfLong layout, long offset, long value) {
|
||||
((ValueLayouts.OfLongImpl) layout).accessHandle().set(this, offset, value);
|
||||
layout.varHandle().set(this, offset, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1634,7 +1693,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default double get(ValueLayout.OfDouble layout, long offset) {
|
||||
return (double) ((ValueLayouts.OfDoubleImpl) layout).accessHandle().get(this, offset);
|
||||
return (double) layout.varHandle().get(this, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1654,7 +1713,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default void set(ValueLayout.OfDouble layout, long offset, double value) {
|
||||
((ValueLayouts.OfDoubleImpl) layout).accessHandle().set(this, offset, value);
|
||||
layout.varHandle().set(this, offset, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1679,7 +1738,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default MemorySegment get(AddressLayout layout, long offset) {
|
||||
return (MemorySegment) ((ValueLayouts.OfAddressImpl) layout).accessHandle().get(this, offset);
|
||||
return (MemorySegment) layout.varHandle().get(this, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1700,7 +1759,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
*/
|
||||
@ForceInline
|
||||
default void set(AddressLayout layout, long offset, MemorySegment value) {
|
||||
((ValueLayouts.OfAddressImpl) layout).accessHandle().set(this, offset, value);
|
||||
layout.varHandle().set(this, offset, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1715,8 +1774,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
*/
|
||||
|
@ -1724,7 +1783,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default byte getAtIndex(ValueLayout.OfByte layout, long index) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
return (byte) ((ValueLayouts.OfByteImpl) layout).accessHandle().get(this, index * layout.byteSize());
|
||||
return (byte) layout.varHandle().get(this, index * layout.byteSize());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1739,8 +1798,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
*/
|
||||
|
@ -1748,7 +1807,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default boolean getAtIndex(ValueLayout.OfBoolean layout, long index) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
return (boolean) ((ValueLayouts.OfBooleanImpl) layout).accessHandle().get(this, index * layout.byteSize());
|
||||
return (boolean) layout.varHandle().get(this, index * layout.byteSize());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1763,8 +1822,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
*/
|
||||
|
@ -1772,7 +1831,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default char getAtIndex(ValueLayout.OfChar layout, long index) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
return (char) ((ValueLayouts.OfCharImpl) layout).accessHandle().get(this, index * layout.byteSize());
|
||||
return (char) layout.varHandle().get(this, index * layout.byteSize());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1787,8 +1846,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
|
||||
|
@ -1797,7 +1856,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default void setAtIndex(ValueLayout.OfChar layout, long index, char value) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
((ValueLayouts.OfCharImpl) layout).accessHandle().set(this, index * layout.byteSize(), value);
|
||||
layout.varHandle().set(this, index * layout.byteSize(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1812,8 +1871,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
*/
|
||||
|
@ -1821,7 +1880,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default short getAtIndex(ValueLayout.OfShort layout, long index) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
return (short) ((ValueLayouts.OfShortImpl) layout).accessHandle().get(this, index * layout.byteSize());
|
||||
return (short) layout.varHandle().get(this, index * layout.byteSize());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1836,8 +1895,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
|
||||
|
@ -1846,7 +1905,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default void setAtIndex(ValueLayout.OfByte layout, long index, byte value) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
((ValueLayouts.OfByteImpl) layout).accessHandle().set(this, index * layout.byteSize(), value);
|
||||
layout.varHandle().set(this, index * layout.byteSize(), value);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1862,8 +1921,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
|
||||
|
@ -1872,7 +1931,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default void setAtIndex(ValueLayout.OfBoolean layout, long index, boolean value) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
((ValueLayouts.OfBooleanImpl) layout).accessHandle().set(this, index * layout.byteSize(), value);
|
||||
layout.varHandle().set(this, index * layout.byteSize(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1887,8 +1946,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
|
||||
|
@ -1897,7 +1956,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default void setAtIndex(ValueLayout.OfShort layout, long index, short value) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
((ValueLayouts.OfShortImpl) layout).accessHandle().set(this, index * layout.byteSize(), value);
|
||||
layout.varHandle().set(this, index * layout.byteSize(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1912,8 +1971,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
*/
|
||||
|
@ -1921,7 +1980,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default int getAtIndex(ValueLayout.OfInt layout, long index) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
return (int) ((ValueLayouts.OfIntImpl) layout).accessHandle().get(this, index * layout.byteSize());
|
||||
return (int) layout.varHandle().get(this, index * layout.byteSize());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1936,8 +1995,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
|
||||
|
@ -1946,7 +2005,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default void setAtIndex(ValueLayout.OfInt layout, long index, int value) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
((ValueLayouts.OfIntImpl) layout).accessHandle().set(this, index * layout.byteSize(), value);
|
||||
layout.varHandle().set(this, index * layout.byteSize(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1961,8 +2020,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
*/
|
||||
|
@ -1970,7 +2029,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default float getAtIndex(ValueLayout.OfFloat layout, long index) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
return (float) ((ValueLayouts.OfFloatImpl) layout).accessHandle().get(this, index * layout.byteSize());
|
||||
return (float) layout.varHandle().get(this, index * layout.byteSize());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1985,8 +2044,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
|
||||
|
@ -1995,7 +2054,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default void setAtIndex(ValueLayout.OfFloat layout, long index, float value) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
((ValueLayouts.OfFloatImpl) layout).accessHandle().set(this, index * layout.byteSize(), value);
|
||||
layout.varHandle().set(this, index * layout.byteSize(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2010,8 +2069,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
*/
|
||||
|
@ -2019,7 +2078,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default long getAtIndex(ValueLayout.OfLong layout, long index) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
return (long) ((ValueLayouts.OfLongImpl) layout).accessHandle().get(this, index * layout.byteSize());
|
||||
return (long) layout.varHandle().get(this, index * layout.byteSize());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2034,8 +2093,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
|
||||
|
@ -2044,7 +2103,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default void setAtIndex(ValueLayout.OfLong layout, long index, long value) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
((ValueLayouts.OfLongImpl) layout).accessHandle().set(this, index * layout.byteSize(), value);
|
||||
layout.varHandle().set(this, index * layout.byteSize(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2059,8 +2118,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
*/
|
||||
|
@ -2068,7 +2127,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default double getAtIndex(ValueLayout.OfDouble layout, long index) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
return (double) ((ValueLayouts.OfDoubleImpl) layout).accessHandle().get(this, index * layout.byteSize());
|
||||
return (double) layout.varHandle().get(this, index * layout.byteSize());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2083,8 +2142,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
|
||||
|
@ -2093,7 +2152,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default void setAtIndex(ValueLayout.OfDouble layout, long index, double value) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
((ValueLayouts.OfDoubleImpl) layout).accessHandle().set(this, index * layout.byteSize(), value);
|
||||
layout.varHandle().set(this, index * layout.byteSize(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2111,8 +2170,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IllegalArgumentException if provided address layout has a {@linkplain AddressLayout#targetLayout() target layout}
|
||||
* {@code T}, and the address of the returned segment
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in {@code T}.
|
||||
|
@ -2123,7 +2182,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default MemorySegment getAtIndex(AddressLayout layout, long index) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
return (MemorySegment) ((ValueLayouts.OfAddressImpl) layout).accessHandle().get(this, index * layout.byteSize());
|
||||
return (MemorySegment) layout.varHandle().get(this, index * layout.byteSize());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2138,8 +2197,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if the access operation is
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout,
|
||||
* or if the layout alignment is greater than its size.
|
||||
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
|
||||
* @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
|
||||
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
|
||||
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
|
||||
|
@ -2149,7 +2208,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
default void setAtIndex(AddressLayout layout, long index, MemorySegment value) {
|
||||
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
|
||||
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
|
||||
((ValueLayouts.OfAddressImpl) layout).accessHandle().set(this, index * layout.byteSize(), value);
|
||||
layout.varHandle().set(this, index * layout.byteSize(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2198,7 +2257,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws IllegalStateException if the {@linkplain #scope() scope} associated with {@code srcSegment} is not
|
||||
* {@linkplain Scope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code srcSegment().isAccessibleBy(T) == false}.
|
||||
* such that {@code srcSegment.isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if {@code dstArray} is not an array, or if it is an array but whose type is not supported.
|
||||
* @throws IllegalArgumentException if the destination array component type does not match {@code srcLayout.carrier()}.
|
||||
* @throws IllegalArgumentException if {@code offset} is <a href="MemorySegment.html#segment-alignment">incompatible
|
||||
|
@ -2237,7 +2296,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* @throws IllegalStateException if the {@linkplain #scope() scope} associated with {@code dstSegment} is not
|
||||
* {@linkplain Scope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code dstSegment().isAccessibleBy(T) == false}.
|
||||
* such that {@code dstSegment.isAccessibleBy(T) == false}.
|
||||
* @throws IllegalArgumentException if {@code srcArray} is not an array, or if it is an array but whose type is not supported.
|
||||
* @throws IllegalArgumentException if the source array component type does not match {@code srcLayout.carrier()}.
|
||||
* @throws IllegalArgumentException if {@code offset} is <a href="MemorySegment.html#segment-alignment">incompatible
|
||||
|
@ -2312,7 +2371,6 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
|
|||
* Scope instances can be compared for equality. That is, two scopes
|
||||
* are considered {@linkplain #equals(Object)} if they denote the same lifetime.
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface Scope permits MemorySessionImpl {
|
||||
/**
|
||||
* {@return {@code true}, if the regions of memory backing the memory segments associated with this scope are
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
package java.lang.foreign;
|
||||
|
||||
import jdk.internal.foreign.layout.PaddingLayoutImpl;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
* A padding layout. A padding layout specifies the size of extra space which is typically not accessed by applications,
|
||||
|
@ -35,9 +34,8 @@ import jdk.internal.javac.PreviewFeature;
|
|||
* @implSpec
|
||||
* Implementing classes are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @since 20
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public sealed interface PaddingLayout extends MemoryLayout permits PaddingLayoutImpl {
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,16 +25,15 @@
|
|||
|
||||
package java.lang.foreign;
|
||||
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.lang.reflect.Array;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jdk.internal.foreign.AbstractMemorySegmentImpl;
|
||||
import jdk.internal.foreign.ArenaImpl;
|
||||
import jdk.internal.foreign.SlicingAllocator;
|
||||
import jdk.internal.foreign.Utils;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
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
|
||||
|
@ -70,14 +69,32 @@ import jdk.internal.javac.PreviewFeature;
|
|||
* Clients should consider using an {@linkplain Arena arena} instead, which, provides strong thread-safety,
|
||||
* lifetime and non-overlapping guarantees.
|
||||
*
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@FunctionalInterface
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public interface SegmentAllocator {
|
||||
|
||||
/**
|
||||
* {@return a new memory segment with a Java string converted into a UTF-8 encoded, null-terminated C string}
|
||||
* 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.
|
||||
*/
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(String str) {
|
||||
Objects.requireNonNull(str);
|
||||
return allocateFrom(str, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Java string into a null-terminated C string using the provided charset,
|
||||
* 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
|
||||
|
@ -86,21 +103,42 @@ public interface SegmentAllocator {
|
|||
* <p>
|
||||
* If the given string contains any {@code '\0'} characters, they will be
|
||||
* copied as well. This means that, depending on the method used to read
|
||||
* the string, such as {@link MemorySegment#getUtf8String(long)}, the string
|
||||
* 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(str.length() + 1)}.
|
||||
* @param str the Java string to be converted into a C 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>
|
||||
* </ul>
|
||||
*/
|
||||
default MemorySegment allocateUtf8String(String str) {
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(String str, Charset charset) {
|
||||
Objects.requireNonNull(charset);
|
||||
Objects.requireNonNull(str);
|
||||
return Utils.toCString(str.getBytes(StandardCharsets.UTF_8), this);
|
||||
int termCharSize = StringSupport.CharsetKind.of(charset).terminatorCharSize();
|
||||
byte[] bytes = str.getBytes(charset);
|
||||
MemorySegment segment = allocateNoInit(bytes.length + termCharSize);
|
||||
MemorySegment.copy(bytes, 0, segment, ValueLayout.JAVA_BYTE, 0, bytes.length);
|
||||
for (int i = 0 ; i < termCharSize ; i++) {
|
||||
segment.set(ValueLayout.JAVA_BYTE, bytes.length + i, (byte)0);
|
||||
}
|
||||
return segment;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the provided {@code byte} {@code value} as
|
||||
* specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
|
||||
* {@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.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
|
@ -112,17 +150,19 @@ public interface SegmentAllocator {
|
|||
* @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 allocate(ValueLayout.OfByte layout, byte value) {
|
||||
default MemorySegment allocateFrom(ValueLayout.OfByte layout, byte value) {
|
||||
Objects.requireNonNull(layout);
|
||||
VarHandle handle = layout.varHandle();
|
||||
MemorySegment seg = allocate(layout);
|
||||
handle.set(seg, value);
|
||||
MemorySegment seg = allocateNoInit(layout);
|
||||
seg.set(layout, 0, value);
|
||||
return seg;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the provided {@code char} {@code value} as
|
||||
* specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
|
||||
* {@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.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
|
@ -134,17 +174,19 @@ public interface SegmentAllocator {
|
|||
* @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 allocate(ValueLayout.OfChar layout, char value) {
|
||||
default MemorySegment allocateFrom(ValueLayout.OfChar layout, char value) {
|
||||
Objects.requireNonNull(layout);
|
||||
VarHandle handle = layout.varHandle();
|
||||
MemorySegment seg = allocate(layout);
|
||||
handle.set(seg, value);
|
||||
MemorySegment seg = allocateNoInit(layout);
|
||||
seg.set(layout, 0, value);
|
||||
return seg;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the provided {@code short} {@code value} as
|
||||
* specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
|
||||
* {@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.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
|
@ -156,17 +198,19 @@ public interface SegmentAllocator {
|
|||
* @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 allocate(ValueLayout.OfShort layout, short value) {
|
||||
default MemorySegment allocateFrom(ValueLayout.OfShort layout, short value) {
|
||||
Objects.requireNonNull(layout);
|
||||
VarHandle handle = layout.varHandle();
|
||||
MemorySegment seg = allocate(layout);
|
||||
handle.set(seg, value);
|
||||
MemorySegment seg = allocateNoInit(layout);
|
||||
seg.set(layout, 0, value);
|
||||
return seg;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the provided {@code int} {@code value} as
|
||||
* specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
|
||||
* {@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.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
|
@ -178,17 +222,19 @@ public interface SegmentAllocator {
|
|||
* @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 allocate(ValueLayout.OfInt layout, int value) {
|
||||
default MemorySegment allocateFrom(ValueLayout.OfInt layout, int value) {
|
||||
Objects.requireNonNull(layout);
|
||||
VarHandle handle = layout.varHandle();
|
||||
MemorySegment seg = allocate(layout);
|
||||
handle.set(seg, value);
|
||||
MemorySegment seg = allocateNoInit(layout);
|
||||
seg.set(layout, 0, value);
|
||||
return seg;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the provided {@code float} {@code value} as
|
||||
* specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
|
||||
* {@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.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
|
@ -200,17 +246,19 @@ public interface SegmentAllocator {
|
|||
* @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 allocate(ValueLayout.OfFloat layout, float value) {
|
||||
default MemorySegment allocateFrom(ValueLayout.OfFloat layout, float value) {
|
||||
Objects.requireNonNull(layout);
|
||||
VarHandle handle = layout.varHandle();
|
||||
MemorySegment seg = allocate(layout);
|
||||
handle.set(seg, value);
|
||||
MemorySegment seg = allocateNoInit(layout);
|
||||
seg.set(layout, 0, value);
|
||||
return seg;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the provided {@code long} {@code value} as
|
||||
* specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
|
||||
* {@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.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
|
@ -222,17 +270,19 @@ public interface SegmentAllocator {
|
|||
* @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 allocate(ValueLayout.OfLong layout, long value) {
|
||||
default MemorySegment allocateFrom(ValueLayout.OfLong layout, long value) {
|
||||
Objects.requireNonNull(layout);
|
||||
VarHandle handle = layout.varHandle();
|
||||
MemorySegment seg = allocate(layout);
|
||||
handle.set(seg, value);
|
||||
MemorySegment seg = allocateNoInit(layout);
|
||||
seg.set(layout, 0, value);
|
||||
return seg;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the provided {@code double} {@code value} as
|
||||
* specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
|
||||
* {@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.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
|
@ -244,19 +294,21 @@ public interface SegmentAllocator {
|
|||
* @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 allocate(ValueLayout.OfDouble layout, double value) {
|
||||
default MemorySegment allocateFrom(ValueLayout.OfDouble layout, double value) {
|
||||
Objects.requireNonNull(layout);
|
||||
VarHandle handle = layout.varHandle();
|
||||
MemorySegment seg = allocate(layout);
|
||||
handle.set(seg, value);
|
||||
MemorySegment seg = allocateNoInit(layout);
|
||||
seg.set(layout, 0, value);
|
||||
return seg;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment initialized with the address of the provided {@code value} as
|
||||
* specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
|
||||
* {@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}).
|
||||
* <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.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
|
@ -268,164 +320,210 @@ public interface SegmentAllocator {
|
|||
*
|
||||
* @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 allocate(AddressLayout layout, MemorySegment value) {
|
||||
default MemorySegment allocateFrom(AddressLayout layout, MemorySegment value) {
|
||||
Objects.requireNonNull(value);
|
||||
Objects.requireNonNull(layout);
|
||||
MemorySegment seg = allocate(layout);
|
||||
layout.varHandle().set(seg, value);
|
||||
return seg;
|
||||
MemorySegment segment = allocateNoInit(layout);
|
||||
segment.set(layout, 0, value);
|
||||
return segment;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of
|
||||
* {@code E*layout.byteSize()} initialized with the provided {@code E} {@code byte} {@code elements} as
|
||||
* specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
|
||||
* {@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.
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
* int size = Objects.requireNonNull(elements).length;
|
||||
* MemorySegment seg = allocateArray(Objects.requireNonNull(elementLayout), size);
|
||||
* MemorySegment.copy(elements, 0, seg, elementLayout, 0, size);
|
||||
* return seg;
|
||||
* @implSpec the default implementation for this method is equivalent to the following code:
|
||||
* {@snippet lang = java:
|
||||
* MemorySegment dest = this.allocate(elementLayout, elementCount);
|
||||
* MemorySegment.copy(source, sourceElementLayout, sourceOffset, dest, elementLayout, 0, elementCount);
|
||||
* return dest;
|
||||
* }
|
||||
*
|
||||
* @param elementLayout the element layout of the array to be allocated.
|
||||
* @param elements the short elements to be copied to the newly allocated memory block.
|
||||
* @param 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.
|
||||
* @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 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.
|
||||
* @throws IndexOutOfBoundsException if {@code sourceOffset > source.byteSize() - (elementCount * sourceElementLayout.byteSize())}.
|
||||
* @throws IndexOutOfBoundsException if either {@code sourceOffset} or {@code elementCount} are {@code < 0}.
|
||||
*/
|
||||
default MemorySegment allocateArray(ValueLayout.OfByte elementLayout, byte... elements) {
|
||||
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(ValueLayout elementLayout, MemorySegment source,
|
||||
ValueLayout sourceElementLayout, long sourceOffset, long elementCount) {
|
||||
Objects.requireNonNull(source);
|
||||
Objects.requireNonNull(sourceElementLayout);
|
||||
Objects.requireNonNull(elementLayout);
|
||||
MemorySegment dest = allocateNoInit(elementLayout, elementCount);
|
||||
MemorySegment.copy(source, sourceElementLayout, sourceOffset, dest, elementLayout, 0, elementCount);
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of
|
||||
* {@code E*layout.byteSize()} initialized with the provided {@code E} {@code short} {@code elements} as
|
||||
* specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
* int size = Objects.requireNonNull(elements).length;
|
||||
* MemorySegment seg = allocateArray(Objects.requireNonNull(elementLayout), size);
|
||||
* MemorySegment.copy(elements, 0, seg, elementLayout, 0, size);
|
||||
* return seg;
|
||||
* }
|
||||
* {@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.
|
||||
*
|
||||
* @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 short elements to be copied to the newly allocated memory block.
|
||||
* @param elements the byte elements to be copied to the newly allocated memory block.
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}.
|
||||
*/
|
||||
default MemorySegment allocateArray(ValueLayout.OfShort elementLayout, short... elements) {
|
||||
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(ValueLayout.OfByte elementLayout, byte... elements) {
|
||||
return allocateFrom(elementLayout, MemorySegment.ofArray(elements),
|
||||
ValueLayout.JAVA_BYTE, 0, elements.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of
|
||||
* {@code E*layout.byteSize()} initialized with the provided {@code E} {@code char} {@code elements} as
|
||||
* specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
* int size = Objects.requireNonNull(elements).length;
|
||||
* MemorySegment seg = allocateArray(Objects.requireNonNull(elementLayout), size);
|
||||
* MemorySegment.copy(elements, 0, seg, elementLayout, 0, size);
|
||||
* return seg;
|
||||
* }
|
||||
* {@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 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:
|
||||
* 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()}.
|
||||
*/
|
||||
default MemorySegment allocateArray(ValueLayout.OfChar elementLayout, char... elements) {
|
||||
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(ValueLayout.OfShort elementLayout, short... elements) {
|
||||
return allocateFrom(elementLayout, MemorySegment.ofArray(elements),
|
||||
ValueLayout.JAVA_SHORT, 0, elements.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of
|
||||
* {@code E*layout.byteSize()} initialized with the provided {@code E} {@code int} {@code elements} as
|
||||
* specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
* int size = Objects.requireNonNull(elements).length;
|
||||
* MemorySegment seg = allocateArray(Objects.requireNonNull(elementLayout), size);
|
||||
* MemorySegment.copy(elements, 0, seg, elementLayout, 0, size);
|
||||
* return seg;
|
||||
* }
|
||||
* {@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.
|
||||
*
|
||||
* @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 short elements to be copied to the newly allocated memory block.
|
||||
* @param elements the char elements to be copied to the newly allocated memory block.
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}.
|
||||
*/
|
||||
default MemorySegment allocateArray(ValueLayout.OfInt elementLayout, int... elements) {
|
||||
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(ValueLayout.OfChar elementLayout, char... elements) {
|
||||
return allocateFrom(elementLayout, MemorySegment.ofArray(elements),
|
||||
ValueLayout.JAVA_CHAR, 0, elements.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of
|
||||
* {@code E*layout.byteSize()} initialized with the provided {@code E} {@code float} {@code elements} as
|
||||
* specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
* int size = Objects.requireNonNull(elements).length;
|
||||
* MemorySegment seg = allocateArray(Objects.requireNonNull(elementLayout), size);
|
||||
* MemorySegment.copy(elements, 0, seg, elementLayout, 0, size);
|
||||
* return seg;
|
||||
* }
|
||||
* {@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.
|
||||
*
|
||||
* @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 short elements to be copied to the newly allocated memory block.
|
||||
* @param elements the int elements to be copied to the newly allocated memory block.
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}.
|
||||
*/
|
||||
default MemorySegment allocateArray(ValueLayout.OfFloat elementLayout, float... elements) {
|
||||
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(ValueLayout.OfInt elementLayout, int... elements) {
|
||||
return allocateFrom(elementLayout, MemorySegment.ofArray(elements),
|
||||
ValueLayout.JAVA_INT, 0, elements.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of
|
||||
* {@code E*layout.byteSize()} initialized with the provided {@code E} {@code long} {@code elements} as
|
||||
* specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
* int size = Objects.requireNonNull(elements).length;
|
||||
* MemorySegment seg = allocateArray(Objects.requireNonNull(elementLayout), size);
|
||||
* MemorySegment.copy(elements, 0, seg, elementLayout, 0, size);
|
||||
* return seg;
|
||||
* }
|
||||
* {@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.
|
||||
*
|
||||
* @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 short elements to be copied to the newly allocated memory block.
|
||||
* @param elements the float elements to be copied to the newly allocated memory block.
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}.
|
||||
*/
|
||||
default MemorySegment allocateArray(ValueLayout.OfLong elementLayout, long... elements) {
|
||||
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(ValueLayout.OfFloat elementLayout, float... elements) {
|
||||
return allocateFrom(elementLayout, MemorySegment.ofArray(elements),
|
||||
ValueLayout.JAVA_FLOAT, 0, elements.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new memory segment with a {@linkplain MemorySegment#byteSize() byteSize()} of
|
||||
* {@code E*layout.byteSize()} initialized with the provided {@code E} {@code double} {@code elements} as
|
||||
* specified by the provided {@code layout} (i.e. byte ordering, alignment and size)}
|
||||
*
|
||||
* @implSpec The default implementation is equivalent to:
|
||||
* {@snippet lang=java :
|
||||
* int size = Objects.requireNonNull(elements).length;
|
||||
* MemorySegment seg = allocateArray(Objects.requireNonNull(elementLayout), size);
|
||||
* MemorySegment.copy(elements, 0, seg, elementLayout, 0, size);
|
||||
* return seg;
|
||||
* }
|
||||
* {@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.
|
||||
*
|
||||
* @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 short elements to be copied to the newly allocated memory block.
|
||||
* @param elements the long elements to be copied to the newly allocated memory block.
|
||||
* @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}.
|
||||
*/
|
||||
default MemorySegment allocateArray(ValueLayout.OfDouble elementLayout, double... elements) {
|
||||
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(ValueLayout.OfLong elementLayout, long... elements) {
|
||||
return allocateFrom(elementLayout, MemorySegment.ofArray(elements),
|
||||
ValueLayout.JAVA_LONG, 0, elements.length);
|
||||
}
|
||||
|
||||
private <Z> MemorySegment copyArrayWithSwapIfNeeded(Z array, ValueLayout elementLayout,
|
||||
Function<Z, MemorySegment> heapSegmentFactory) {
|
||||
int size = Array.getLength(Objects.requireNonNull(array));
|
||||
MemorySegment seg = allocateArray(Objects.requireNonNull(elementLayout), size);
|
||||
if (size > 0) {
|
||||
MemorySegment.copy(heapSegmentFactory.apply(array), elementLayout, 0,
|
||||
seg, elementLayout.withOrder(ByteOrder.nativeOrder()), 0, size);
|
||||
}
|
||||
return seg;
|
||||
/**
|
||||
* {@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.
|
||||
*
|
||||
* @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()}.
|
||||
*/
|
||||
@ForceInline
|
||||
default MemorySegment allocateFrom(ValueLayout.OfDouble elementLayout, double... elements) {
|
||||
return allocateFrom(elementLayout, MemorySegment.ofArray(elements),
|
||||
ValueLayout.JAVA_DOUBLE, 0, elements.length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -452,7 +550,7 @@ public interface SegmentAllocator {
|
|||
* @throws IllegalArgumentException if {@code elementLayout.byteSize() * count} overflows.
|
||||
* @throws IllegalArgumentException if {@code count < 0}.
|
||||
*/
|
||||
default MemorySegment allocateArray(MemoryLayout elementLayout, long count) {
|
||||
default MemorySegment allocate(MemoryLayout elementLayout, long count) {
|
||||
Objects.requireNonNull(elementLayout);
|
||||
if (count < 0) {
|
||||
throw new IllegalArgumentException("Negative array size");
|
||||
|
@ -525,4 +623,25 @@ public interface SegmentAllocator {
|
|||
static SegmentAllocator prefixAllocator(MemorySegment segment) {
|
||||
return (AbstractMemorySegmentImpl)Objects.requireNonNull(segment);
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
private MemorySegment allocateNoInit(long byteSize) {
|
||||
return this instanceof ArenaImpl arenaImpl ?
|
||||
arenaImpl.allocateNoInit(byteSize, 1) :
|
||||
allocate(byteSize);
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
private MemorySegment allocateNoInit(MemoryLayout layout) {
|
||||
return this instanceof ArenaImpl arenaImpl ?
|
||||
arenaImpl.allocateNoInit(layout.byteSize(), layout.byteAlignment()) :
|
||||
allocate(layout);
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
private MemorySegment allocateNoInit(MemoryLayout layout, long size) {
|
||||
return this instanceof ArenaImpl arenaImpl ?
|
||||
arenaImpl.allocateNoInit(layout.byteSize() * size, layout.byteAlignment()) :
|
||||
allocate(layout, size);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
package java.lang.foreign;
|
||||
|
||||
import jdk.internal.foreign.layout.SequenceLayoutImpl;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
* A compound layout that denotes a homogeneous repetition of a given <em>element layout</em>.
|
||||
|
@ -50,9 +49,8 @@ import jdk.internal.javac.PreviewFeature;
|
|||
* @implSpec
|
||||
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayoutImpl {
|
||||
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
package java.lang.foreign;
|
||||
|
||||
import jdk.internal.foreign.layout.StructLayoutImpl;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
* A group layout whose member layouts are laid out one after the other.
|
||||
|
@ -34,9 +33,8 @@ import jdk.internal.javac.PreviewFeature;
|
|||
* @implSpec
|
||||
* Implementing classes are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @since 20
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public sealed interface StructLayout extends GroupLayout permits StructLayoutImpl {
|
||||
|
||||
/**
|
||||
|
|
|
@ -29,7 +29,6 @@ import jdk.internal.access.JavaLangAccess;
|
|||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.foreign.MemorySessionImpl;
|
||||
import jdk.internal.foreign.Utils;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
import jdk.internal.javac.Restricted;
|
||||
import jdk.internal.loader.BuiltinClassLoader;
|
||||
import jdk.internal.loader.NativeLibrary;
|
||||
|
@ -120,9 +119,8 @@ import java.util.function.BiFunction;
|
|||
* MemorySegment malloc = stdlib.find("malloc").orElseThrow();
|
||||
*}
|
||||
*
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
@FunctionalInterface
|
||||
public interface SymbolLookup {
|
||||
|
||||
|
@ -216,8 +214,7 @@ public interface SymbolLookup {
|
|||
* <p>
|
||||
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
|
||||
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
|
||||
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
|
||||
* restricted methods, and use safe and supported functionalities, where possible.
|
||||
* the JVM or, worse, silently result in memory corruption.
|
||||
*
|
||||
* @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.
|
||||
|
@ -251,8 +248,7 @@ public interface SymbolLookup {
|
|||
* <p>
|
||||
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
|
||||
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
|
||||
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
|
||||
* restricted methods, and use safe and supported functionalities, where possible.
|
||||
* the JVM or, worse, silently result in memory corruption.
|
||||
*
|
||||
* @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.
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
package java.lang.foreign;
|
||||
|
||||
import jdk.internal.foreign.layout.UnionLayoutImpl;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
* A group layout whose member layouts are laid out at the same starting offset.
|
||||
|
@ -34,9 +33,8 @@ import jdk.internal.javac.PreviewFeature;
|
|||
* @implSpec
|
||||
* Implementing classes are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @since 20
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public sealed interface UnionLayout extends GroupLayout permits UnionLayoutImpl {
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,12 +25,9 @@
|
|||
|
||||
package java.lang.foreign;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import jdk.internal.foreign.layout.ValueLayouts;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
* A layout that models values of basic data types. Examples of values modelled by a value layout are
|
||||
|
@ -51,9 +48,8 @@ import jdk.internal.javac.PreviewFeature;
|
|||
* @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 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public sealed interface ValueLayout extends MemoryLayout permits
|
||||
ValueLayout.OfBoolean, ValueLayout.OfByte, ValueLayout.OfChar, ValueLayout.OfShort, ValueLayout.OfInt,
|
||||
ValueLayout.OfFloat, ValueLayout.OfLong, ValueLayout.OfDouble, AddressLayout {
|
||||
|
@ -76,66 +72,6 @@ public sealed interface ValueLayout extends MemoryLayout permits
|
|||
@Override
|
||||
ValueLayout withoutName();
|
||||
|
||||
/**
|
||||
* Creates a <em>strided</em> var handle that can be used to access a memory segment as multi-dimensional
|
||||
* array. This array has a notional sequence layout featuring {@code shape.length} nested sequence layouts. The element
|
||||
* layout of the innermost sequence layout in the notional sequence layout is this value layout. The resulting var handle
|
||||
* is obtained as if calling the {@link #varHandle(PathElement...)} method on the notional layout, with a layout
|
||||
* path containing exactly {@code shape.length + 1} {@linkplain PathElement#sequenceElement() open sequence layout path elements}.
|
||||
* <p>
|
||||
* For instance, the following method call:
|
||||
*
|
||||
* {@snippet lang=java :
|
||||
* VarHandle arrayHandle = ValueLayout.JAVA_INT.arrayElementVarHandle(10, 20);
|
||||
* }
|
||||
*
|
||||
* Is equivalent to the following code:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* SequenceLayout notionalLayout = MemoryLayout.sequenceLayout(
|
||||
* MemoryLayout.sequenceLayout(10, MemoryLayout.sequenceLayout(20, ValueLayout.JAVA_INT)));
|
||||
* VarHandle arrayHandle = notionalLayout.varHandle(PathElement.sequenceElement(),
|
||||
* PathElement.sequenceElement(),
|
||||
* PathElement.sequenceElement());
|
||||
*}
|
||||
*
|
||||
* The resulting var handle {@code arrayHandle} will feature 3 coordinates of type {@code long}; each coordinate
|
||||
* is interpreted as an index into the corresponding sequence layout. If we refer to the var handle coordinates, from left
|
||||
* to right, as {@code x}, {@code y} and {@code z} respectively, the final offset accessed by the var handle can be
|
||||
* computed with the following formula:
|
||||
*
|
||||
* <blockquote><pre>{@code
|
||||
* offset = (10 * 20 * 4 * x) + (20 * 4 * y) + (4 * z)
|
||||
* }</pre></blockquote>
|
||||
*
|
||||
* Additionally, the values of {@code x}, {@code y} and {@code z} are constrained as follows:
|
||||
* <ul>
|
||||
* <li>{@code 0 <= x < notionalLayout.elementCount() }</li>
|
||||
* <li>{@code 0 <= y < 10 }</li>
|
||||
* <li>{@code 0 <= z < 20 }</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Consider the following access expressions:
|
||||
* {@snippet lang=java :
|
||||
* int value1 = (int) arrayHandle.get(10, 2, 4); // ok, accessed offset = 8176
|
||||
* int value2 = (int) arrayHandle.get(0, 0, 30); // out of bounds value for z
|
||||
* }
|
||||
* In the first case, access is well-formed, as the values for {@code x}, {@code y} and {@code z} conform to
|
||||
* the bounds specified above. In the second case, access fails with {@link IndexOutOfBoundsException},
|
||||
* as the value for {@code z} is outside its specified bounds.
|
||||
*
|
||||
* @param shape the size of each nested array dimension.
|
||||
* @return a var handle which can be used to access a memory segment as a multi-dimensional array,
|
||||
* featuring {@code shape.length + 1}
|
||||
* {@code long} coordinates.
|
||||
* @throws IllegalArgumentException if {@code shape[i] < 0}, for at least one index {@code i}.
|
||||
* @throws UnsupportedOperationException if {@code byteAlignment() > byteSize()}.
|
||||
* @see MethodHandles#memorySegmentViewVarHandle
|
||||
* @see MemoryLayout#varHandle(PathElement...)
|
||||
* @see SequenceLayout
|
||||
*/
|
||||
VarHandle arrayElementVarHandle(int... shape);
|
||||
|
||||
/**
|
||||
* {@return the carrier associated with this value layout}
|
||||
*/
|
||||
|
@ -149,19 +85,40 @@ public sealed interface ValueLayout extends MemoryLayout permits
|
|||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws IllegalArgumentException {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
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.}
|
||||
* <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.
|
||||
* <p>
|
||||
* 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 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...)
|
||||
*/
|
||||
VarHandle varHandle();
|
||||
|
||||
/**
|
||||
* A value layout whose carrier is {@code boolean.class}.
|
||||
*
|
||||
* @see #JAVA_BOOLEAN
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfBoolean extends ValueLayout permits ValueLayouts.OfBooleanImpl {
|
||||
sealed interface OfBoolean extends ValueLayout permits ValueLayouts.OfBooleanImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
|
@ -194,10 +151,9 @@ public sealed interface ValueLayout extends MemoryLayout permits
|
|||
* A value layout whose carrier is {@code byte.class}.
|
||||
*
|
||||
* @see #JAVA_BYTE
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfByte extends ValueLayout permits ValueLayouts.OfByteImpl {
|
||||
sealed interface OfByte extends ValueLayout permits ValueLayouts.OfByteImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
|
@ -231,10 +187,9 @@ public sealed interface ValueLayout extends MemoryLayout permits
|
|||
*
|
||||
* @see #JAVA_CHAR
|
||||
* @see #JAVA_CHAR_UNALIGNED
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfChar extends ValueLayout permits ValueLayouts.OfCharImpl {
|
||||
sealed interface OfChar extends ValueLayout permits ValueLayouts.OfCharImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
|
@ -268,10 +223,9 @@ public sealed interface ValueLayout extends MemoryLayout permits
|
|||
*
|
||||
* @see #JAVA_SHORT
|
||||
* @see #JAVA_SHORT_UNALIGNED
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfShort extends ValueLayout permits ValueLayouts.OfShortImpl {
|
||||
sealed interface OfShort extends ValueLayout permits ValueLayouts.OfShortImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
|
@ -305,10 +259,9 @@ public sealed interface ValueLayout extends MemoryLayout permits
|
|||
*
|
||||
* @see #JAVA_INT
|
||||
* @see #JAVA_INT_UNALIGNED
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfInt extends ValueLayout permits ValueLayouts.OfIntImpl {
|
||||
sealed interface OfInt extends ValueLayout permits ValueLayouts.OfIntImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
|
@ -342,10 +295,9 @@ public sealed interface ValueLayout extends MemoryLayout permits
|
|||
*
|
||||
* @see #JAVA_FLOAT
|
||||
* @see #JAVA_FLOAT_UNALIGNED
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfFloat extends ValueLayout permits ValueLayouts.OfFloatImpl {
|
||||
sealed interface OfFloat extends ValueLayout permits ValueLayouts.OfFloatImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
|
@ -378,10 +330,9 @@ public sealed interface ValueLayout extends MemoryLayout permits
|
|||
*
|
||||
* @see #JAVA_LONG
|
||||
* @see #JAVA_LONG_UNALIGNED
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfLong extends ValueLayout permits ValueLayouts.OfLongImpl {
|
||||
sealed interface OfLong extends ValueLayout permits ValueLayouts.OfLongImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
|
@ -415,10 +366,9 @@ public sealed interface ValueLayout extends MemoryLayout permits
|
|||
*
|
||||
* @see #JAVA_DOUBLE
|
||||
* @see #JAVA_DOUBLE_UNALIGNED
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfDouble extends ValueLayout permits ValueLayouts.OfDoubleImpl {
|
||||
sealed interface OfDouble extends ValueLayout permits ValueLayouts.OfDoubleImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
* );
|
||||
*
|
||||
* try (Arena arena = Arena.ofConfined()) {
|
||||
* MemorySegment cString = arena.allocateUtf8String("Hello");
|
||||
* MemorySegment cString = arena.allocateFrom("Hello");
|
||||
* long len = (long)strlen.invokeExact(cString); // 5
|
||||
* }
|
||||
*}
|
||||
|
@ -109,7 +109,7 @@
|
|||
* into a foreign function call, according to the rules specified by the ABI of the underlying platform.
|
||||
* The {@link java.lang.foreign.Arena} class also provides many useful methods for
|
||||
* interacting with foreign code, such as
|
||||
* {@linkplain java.lang.foreign.SegmentAllocator#allocateUtf8String(java.lang.String) converting} Java strings into
|
||||
* {@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>
|
||||
|
@ -147,9 +147,7 @@
|
|||
*
|
||||
* @spec jni/index.html Java Native Interface Specification
|
||||
*
|
||||
* @since 19
|
||||
* @since 22
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
package java.lang.foreign;
|
||||
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
|
|
@ -122,7 +122,7 @@ class Snippets {
|
|||
// @start region="slicing-arena-main":
|
||||
try (Arena slicingArena = new SlicingArena(1000)) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
MemorySegment s = slicingArena.allocateArray(JAVA_INT, 1, 2, 3, 4, 5);
|
||||
MemorySegment s = slicingArena.allocateFrom(JAVA_INT, 1, 2, 3, 4, 5);
|
||||
// ...
|
||||
}
|
||||
} // all memory allocated is released here
|
||||
|
@ -148,7 +148,7 @@ class Snippets {
|
|||
void withTargetLayout() {
|
||||
AddressLayout addressLayout = ADDRESS;
|
||||
AddressLayout unboundedLayout = addressLayout.withTargetLayout(
|
||||
sequenceLayout(ValueLayout.JAVA_BYTE));
|
||||
sequenceLayout(Long.MAX_VALUE, ValueLayout.JAVA_BYTE));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,7 +168,7 @@ class Snippets {
|
|||
);
|
||||
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment str = arena.allocateUtf8String("Hello");
|
||||
MemorySegment str = arena.allocateFrom("Hello");
|
||||
long len = (long) strlen.invokeExact(str); // 5
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,7 @@ class Snippets {
|
|||
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment compareFunc = linker.upcallStub(comparHandle, comparDesc, arena);
|
||||
MemorySegment array = arena.allocateArray(JAVA_INT, 0, 9, 3, 4, 6, 5, 1, 8, 2, 7);
|
||||
MemorySegment array = arena.allocateFrom(JAVA_INT, 0, 9, 3, 4, 6, 5, 1, 8, 2, 7);
|
||||
qsort.invokeExact(array, 10L, 4L, compareFunc);
|
||||
int[] sorted = array.toArray(JAVA_INT); // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
|
||||
|
||||
|
@ -288,7 +288,7 @@ class Snippets {
|
|||
);
|
||||
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
int res = (int) printf.invokeExact(arena.allocateUtf8String("%d plus %d equals %d"), 2, 2, 4); //prints "2 plus 2 equals 4"
|
||||
int res = (int) printf.invokeExact(arena.allocateFrom("%d plus %d equals %d"), 2, 2, 4); //prints "2 plus 2 equals 4"
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -313,7 +313,7 @@ class Snippets {
|
|||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment capturedState = arena.allocate(capturedStateLayout);
|
||||
handle.invoke(capturedState);
|
||||
int errno = (int) errnoHandle.get(capturedState);
|
||||
int errno = (int) errnoHandle.get(capturedState, 0L);
|
||||
// use errno
|
||||
}
|
||||
}
|
||||
|
@ -351,8 +351,8 @@ class Snippets {
|
|||
|
||||
MethodHandle offsetHandle = taggedValues.byteOffsetHandle(PathElement.sequenceElement(),
|
||||
PathElement.groupElement("kind"));
|
||||
long offset1 = (long) offsetHandle.invokeExact(1L); // 8
|
||||
long offset2 = (long) offsetHandle.invokeExact(2L); // 16
|
||||
long offset1 = (long) offsetHandle.invokeExact(0L, 1L); // 8
|
||||
long offset2 = (long) offsetHandle.invokeExact(0L, 2L); // 16
|
||||
}
|
||||
|
||||
void sliceHandle() {
|
||||
|
@ -396,7 +396,7 @@ class Snippets {
|
|||
{
|
||||
MemorySegment segment = null; // ...
|
||||
|
||||
VarHandle intHandle = MethodHandles.memorySegmentViewVarHandle(ValueLayout.JAVA_INT);
|
||||
VarHandle intHandle = ValueLayout.JAVA_INT.varHandle();
|
||||
MethodHandle multiplyExact = MethodHandles.lookup()
|
||||
.findStatic(Math.class, "multiplyExact",
|
||||
MethodType.methodType(long.class, long.class, long.class));
|
||||
|
@ -408,8 +408,13 @@ class Snippets {
|
|||
{
|
||||
MemorySegment segment = null; // ...
|
||||
|
||||
VarHandle intHandle = ValueLayout.JAVA_INT.arrayElementVarHandle();
|
||||
int value = (int) intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
|
||||
MemoryLayout segmentLayout = MemoryLayout.structLayout(
|
||||
ValueLayout.JAVA_INT.withName("size"),
|
||||
MemoryLayout.sequenceLayout(4, ValueLayout.JAVA_INT).withName("data") // array of 4 elements
|
||||
);
|
||||
VarHandle intHandle = segmentLayout.varHandle(MemoryLayout.PathElement.groupElement("data"),
|
||||
MemoryLayout.PathElement.sequenceElement());
|
||||
int value = (int) intHandle.get(segment, 0L, 3L); // get int element at offset 0 + offsetof(data) + 3 * 4 = 12
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -524,10 +529,8 @@ class Snippets {
|
|||
MemorySegment segment = null;
|
||||
byte value = 42;
|
||||
|
||||
var byteHandle = MemoryLayout.sequenceLayout(ValueLayout.JAVA_BYTE)
|
||||
.varHandle(MemoryLayout.PathElement.sequenceElement());
|
||||
for (long l = 0; l < segment.byteSize(); l++) {
|
||||
byteHandle.set(segment.address(), l, value);
|
||||
segment.set(JAVA_BYTE, l, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -570,7 +573,7 @@ class Snippets {
|
|||
);
|
||||
|
||||
try (Arena arena = Arena.ofConfined()) {
|
||||
MemorySegment cString = arena.allocateUtf8String("Hello");
|
||||
MemorySegment cString = arena.allocateFrom("Hello");
|
||||
long len = (long) strlen.invokeExact(cString); // 5
|
||||
}
|
||||
|
||||
|
@ -654,17 +657,6 @@ class Snippets {
|
|||
|
||||
static class ValueLayoutSnippets {
|
||||
|
||||
void arrayElementVarHandle() {
|
||||
VarHandle arrayHandle = ValueLayout.JAVA_INT.arrayElementVarHandle(10, 20);
|
||||
|
||||
SequenceLayout arrayLayout = MemoryLayout.sequenceLayout(
|
||||
MemoryLayout.sequenceLayout(10,
|
||||
MemoryLayout.sequenceLayout(20, ValueLayout.JAVA_INT)));
|
||||
|
||||
int value1 = (int) arrayHandle.get(10, 2, 4); // ok, accessed offset = 8176
|
||||
int value2 = (int) arrayHandle.get(0, 0, 30); // out of bounds value for z
|
||||
}
|
||||
|
||||
void statics() {
|
||||
ADDRESS.withByteAlignment(1);
|
||||
JAVA_CHAR.withByteAlignment(1);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue