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:
Jorn Vernee 2023-10-12 19:50:08 +00:00
parent 9728e21db1
commit 32ac72c3d3
261 changed files with 3141 additions and 2126 deletions

View file

@ -83,6 +83,7 @@ import jdk.internal.reflect.Reflection;
import jdk.internal.reflect.ReflectionFactory;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.IntrinsicCandidate;
import jdk.internal.vm.annotation.Stable;
import sun.invoke.util.Wrapper;
import sun.reflect.generics.factory.CoreReflectionFactory;
@ -1060,6 +1061,7 @@ public final class Class<T> implements java.io.Serializable,
}
// set by VM
@Stable
private transient Module module;
// Initialized in JVM not by private constructor

View file

@ -272,9 +272,8 @@ public final class Module implements AnnotatedElement {
* <a href="foreign/package-summary.html#restricted"><em>restricted</em></a> methods.
*
* @return {@code true} if this module can access <em>restricted</em> methods.
* @since 20
* @since 22
*/
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
public boolean isNativeAccessEnabled() {
Module target = moduleForNativeAccess();
return EnableNativeAccess.isNativeAccessEnabled(target);
@ -309,7 +308,7 @@ public final class Module implements AnnotatedElement {
}
// This is invoked from Reflection.ensureNativeAccess
void ensureNativeAccess(Class<?> owner, String methodName) {
void ensureNativeAccess(Class<?> owner, String methodName, Class<?> currentClass) {
// The target module whose enableNativeAccess flag is ensured
Module target = moduleForNativeAccess();
if (!EnableNativeAccess.isNativeAccessEnabled(target)) {
@ -320,13 +319,15 @@ public final class Module implements AnnotatedElement {
// warn and set flag, so that only one warning is reported per module
String cls = owner.getName();
String mtd = cls + "::" + methodName;
String mod = isNamed() ? "module " + getName() : "the unnamed module";
String mod = isNamed() ? "module " + getName() : "an unnamed module";
String modflag = isNamed() ? getName() : "ALL-UNNAMED";
String caller = currentClass != null ? currentClass.getName() : "code";
System.err.printf("""
WARNING: A restricted method in %s has been called
WARNING: %s has been called by %s
WARNING: Use --enable-native-access=%s to avoid a warning for this module
%n""", cls, mtd, mod, modflag);
WARNING: %s has been called by %s in %s
WARNING: Use --enable-native-access=%s to avoid a warning for callers in this module
WARNING: Restricted methods will be blocked in a future release unless native access is enabled
%n""", cls, mtd, caller, mod, modflag);
}
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -307,9 +307,7 @@ public final class ModuleLayer {
*
* <p> This method is <a href="foreign/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 module to update
@ -322,9 +320,8 @@ public final class ModuleLayer {
* @throws IllegalCallerException
* If the caller is in a module that does not have native access enabled
*
* @since 20
* @since 22
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
@CallerSensitive
@Restricted
public Controller enableNativeAccess(Module target) {

View file

@ -2454,8 +2454,8 @@ public final class System {
public void addEnableNativeAccessToAllUnnamed() {
Module.implAddEnableNativeAccessToAllUnnamed();
}
public void ensureNativeAccess(Module m, Class<?> owner, String methodName) {
m.ensureNativeAccess(owner, methodName);
public void ensureNativeAccess(Module m, Class<?> owner, String methodName, Class<?> currentClass) {
m.ensureNativeAccess(owner, methodName, currentClass);
}
public ServicesCatalog getServicesCatalog(ModuleLayer layer) {
return layer.getServicesCatalog();

View file

@ -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.

View file

@ -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}

View file

@ -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 {
/**

View file

@ -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 {
/**

View file

@ -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;
}
}
}

View file

@ -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.
*

View file

@ -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

View file

@ -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 {
/**

View file

@ -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);
}
}

View file

@ -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 {

View file

@ -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 {
/**

View file

@ -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.

View file

@ -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 {
/**

View file

@ -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}

View file

@ -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;

View file

@ -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);

View file

@ -26,8 +26,6 @@
package java.lang.invoke;
import jdk.internal.access.SharedSecrets;
import jdk.internal.foreign.Utils;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.misc.Unsafe;
import jdk.internal.misc.VM;
import jdk.internal.org.objectweb.asm.ClassReader;
@ -45,10 +43,6 @@ import sun.reflect.misc.ReflectUtil;
import sun.security.util.SecurityConstants;
import java.lang.constant.ConstantDescs;
import java.lang.foreign.GroupLayout;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.LambdaForm.BasicType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@ -7978,85 +7972,6 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
return expectedType;
}
/**
* Creates a var handle object, which can be used to dereference a {@linkplain java.lang.foreign.MemorySegment memory segment}
* at a given byte offset, using the provided value layout.
*
* <p>The provided layout specifies the {@linkplain ValueLayout#carrier() carrier type},
* the {@linkplain ValueLayout#byteSize() byte size},
* the {@linkplain ValueLayout#byteAlignment() byte alignment} and the {@linkplain ValueLayout#order() byte order}
* associated with the returned var handle.
*
* <p>The list of coordinate types associated with the returned var handle is {@code (MemorySegment, long)},
* where the {@code long} coordinate type corresponds to byte offset into the given memory segment coordinate.
* Thus, the returned var handle accesses bytes at an offset in a given memory segment, composing bytes to or from
* a value of the var handle type. Moreover, the access operation will honor the endianness and the
* alignment constraints expressed in the provided layout.
*
* <p>As an example, consider the memory layout expressed by a {@link GroupLayout} instance constructed as follows:
* {@snippet lang="java" :
* GroupLayout seq = 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 memory segment view var handle as follows:
* {@snippet lang="java" :
* VarHandle handle = MethodHandles.memorySegmentViewVarHandle(ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN)); //(MemorySegment, long) -> int
* handle = MethodHandles.insertCoordinates(handle, 1, 4); //(MemorySegment) -> int
* }
*
* @apiNote The resulting var handle features certain <i>access mode restrictions</i>,
* which are common to all memory segment view var handles. A memory segment view var handle is associated
* with an access size {@code S} and an alignment constraint {@code B}
* (both expressed in bytes). We say that a memory access operation is <em>fully aligned</em> if it occurs
* at a memory address {@code A} which is compatible with both alignment constraints {@code S} and {@code B}.
* If access is fully aligned then following access modes are supported and are
* guaranteed to support atomic access:
* <ul>
* <li>read write access modes for all {@code T}, with the exception of
* access modes {@code get} and {@code set} for {@code long} and
* {@code double} on 32-bit platforms.
* <li>atomic update access modes for {@code int}, {@code long},
* {@code float}, {@code double} or {@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 memory access operation is <em>partially aligned</em> if it occurs at a memory address {@code A}
* which is only compatible with the alignment constraint {@code B}; in such cases, access for anything other than the
* {@code get} and {@code set} access modes will result in an {@code IllegalStateException}. If access is partially aligned,
* atomic access is only guaranteed with respect to the largest power of two that divides the GCD of {@code A} and {@code S}.
* <p>
* In all other cases, we say that a memory access operation is <em>misaligned</em>; in such cases an
* {@code IllegalStateException} is thrown, irrespective of the access mode being used.
* <p>
* Finally, if {@code T} is {@code MemorySegment} all write access modes throw {@link IllegalArgumentException}
* unless the value to be written is a {@linkplain MemorySegment#isNative() native} memory segment.
*
* @param layout the value layout for which a memory access handle is to be obtained.
* @return the new memory segment view var handle.
* @throws NullPointerException if {@code layout} is {@code null}.
* @see MemoryLayout#varHandle(MemoryLayout.PathElement...)
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static VarHandle memorySegmentViewVarHandle(ValueLayout layout) {
Objects.requireNonNull(layout);
return Utils.makeSegmentViewVarHandle(layout);
}
/**
* Adapts a target var handle by pre-processing incoming and outgoing values using a pair of filter functions.
* <p>
@ -8087,9 +8002,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* other than {@code (A... , S) -> T} and {@code (A... , T) -> S}, respectively, where {@code T} is the type of the target var handle,
* or if it's determined that either {@code filterFromTarget} or {@code filterToTarget} throws any checked exceptions.
* @throws NullPointerException if any of the arguments is {@code null}.
* @since 19
* @since 22
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget) {
return VarHandles.filterValue(target, filterToTarget, filterFromTarget);
}
@ -8123,9 +8037,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* or if more filters are provided than the actual number of coordinate types available starting at {@code pos},
* or if it's determined that any of the filters throws any checked exceptions.
* @throws NullPointerException if any of the arguments is {@code null} or {@code filters} contains {@code null}.
* @since 19
* @since 22
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static VarHandle filterCoordinates(VarHandle target, int pos, MethodHandle... filters) {
return VarHandles.filterCoordinates(target, pos, filters);
}
@ -8155,9 +8068,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* other than {@code T1, T2 ... Tn }, where {@code T1, T2 ... Tn} are the coordinate types starting at position {@code pos}
* of the target var handle.
* @throws NullPointerException if any of the arguments is {@code null} or {@code values} contains {@code null}.
* @since 19
* @since 22
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static VarHandle insertCoordinates(VarHandle target, int pos, Object... values) {
return VarHandles.insertCoordinates(target, pos, values);
}
@ -8198,9 +8110,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* a coordinate of {@code newCoordinates}, or if two corresponding coordinate types in
* the target var handle and in {@code newCoordinates} are not identical.
* @throws NullPointerException if any of the arguments is {@code null} or {@code newCoordinates} contains {@code null}.
* @since 19
* @since 22
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static VarHandle permuteCoordinates(VarHandle target, List<Class<?>> newCoordinates, int... reorder) {
return VarHandles.permuteCoordinates(target, newCoordinates, reorder);
}
@ -8242,9 +8153,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* if the resulting var handle's type would have <a href="MethodHandle.html#maxarity">too many coordinates</a>,
* or if it's determined that {@code filter} throws any checked exceptions.
* @throws NullPointerException if any of the arguments is {@code null}.
* @since 19
* @since 22
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle filter) {
return VarHandles.collectCoordinates(target, pos, filter);
}
@ -8268,9 +8178,8 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* before calling the target var handle
* @throws IllegalArgumentException if {@code pos} is not between 0 and the target var handle coordinate arity, inclusive.
* @throws NullPointerException if any of the arguments is {@code null} or {@code valueTypes} contains {@code null}.
* @since 19
* @since 22
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static VarHandle dropCoordinates(VarHandle target, int pos, Class<?>... valueTypes) {
return VarHandles.dropCoordinates(target, pos, valueTypes);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -56,4 +56,8 @@ abstract sealed class VarHandleSegmentViewBase extends VarHandle permits
static IllegalArgumentException newIllegalArgumentExceptionForMisalignedAccess(long address) {
return new IllegalArgumentException("Misaligned access at address: " + address);
}
static UnsupportedOperationException newUnsupportedAccessModeForAlignment(long alignment) {
return new UnsupportedOperationException("Unsupported access mode for alignment: " + alignment);
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -43,7 +43,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
static final int VM_ALIGN = $BoxType$.BYTES - 1;
static final int NON_PLAIN_ACCESS_MIN_ALIGN_MASK = $BoxType$.BYTES - 1;
static final VarForm FORM = new VarForm(VarHandleSegmentAs$Type$s.class, MemorySegment.class, $type$.class, long.class);
@ -104,16 +104,15 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
}
@ForceInline
static long offset(AbstractMemorySegmentImpl bb, long offset, long alignmentMask) {
long address = offsetNoVMAlignCheck(bb, offset, alignmentMask);
if ((address & VM_ALIGN) != 0) {
throw VarHandleSegmentViewBase.newIllegalArgumentExceptionForMisalignedAccess(address);
static long offsetNonPlain(AbstractMemorySegmentImpl bb, long offset, long alignmentMask) {
if ((alignmentMask & NON_PLAIN_ACCESS_MIN_ALIGN_MASK) != NON_PLAIN_ACCESS_MIN_ALIGN_MASK) {
throw VarHandleSegmentViewBase.newUnsupportedAccessModeForAlignment(alignmentMask + 1);
}
return address;
return offsetPlain(bb, offset, alignmentMask);
}
@ForceInline
static long offsetNoVMAlignCheck(AbstractMemorySegmentImpl bb, long offset, long alignmentMask) {
static long offsetPlain(AbstractMemorySegmentImpl bb, long offset, long alignmentMask) {
long base = bb.unsafeGetOffset();
long address = base + offset;
long maxAlignMask = bb.maxAlignMask();
@ -130,18 +129,18 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
#if[floatingPoint]
$rawType$ rawValue = SCOPED_MEMORY_ACCESS.get$RawType$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
offsetPlain(bb, base, handle.alignmentMask),
handle.be);
return $Type$.$rawType$BitsTo$Type$(rawValue);
#else[floatingPoint]
#if[byte]
return SCOPED_MEMORY_ACCESS.get$Type$(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask));
offsetPlain(bb, base, handle.alignmentMask));
#else[byte]
return SCOPED_MEMORY_ACCESS.get$Type$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
offsetPlain(bb, base, handle.alignmentMask),
handle.be);
#end[byte]
#end[floatingPoint]
@ -154,19 +153,19 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
#if[floatingPoint]
SCOPED_MEMORY_ACCESS.put$RawType$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
offsetPlain(bb, base, handle.alignmentMask),
$Type$.$type$ToRaw$RawType$Bits(value),
handle.be);
#else[floatingPoint]
#if[byte]
SCOPED_MEMORY_ACCESS.put$Type$(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
offsetPlain(bb, base, handle.alignmentMask),
value);
#else[byte]
SCOPED_MEMORY_ACCESS.put$Type$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
offsetPlain(bb, base, handle.alignmentMask),
value,
handle.be);
#end[byte]
@ -180,7 +179,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask)));
offsetNonPlain(bb, base, handle.alignmentMask)));
}
@ForceInline
@ -189,7 +188,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
SCOPED_MEMORY_ACCESS.put$RawType$Volatile(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
convEndian(handle.be, value));
}
@ -200,7 +199,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.get$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask)));
offsetNonPlain(bb, base, handle.alignmentMask)));
}
@ForceInline
@ -209,7 +208,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
SCOPED_MEMORY_ACCESS.put$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
convEndian(handle.be, value));
}
@ -220,7 +219,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.get$RawType$Opaque(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask)));
offsetNonPlain(bb, base, handle.alignmentMask)));
}
@ForceInline
@ -229,7 +228,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
SCOPED_MEMORY_ACCESS.put$RawType$Opaque(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
convEndian(handle.be, value));
}
#if[CAS]
@ -240,7 +239,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return SCOPED_MEMORY_ACCESS.compareAndSet$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ -251,7 +250,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value)));
}
@ -262,7 +261,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value)));
}
@ -273,7 +272,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value)));
}
@ -283,7 +282,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Plain(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ -293,7 +292,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ -303,7 +302,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ -313,7 +312,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ -324,7 +323,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.getAndSet$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
convEndian(handle.be, value)));
}
@ -335,7 +334,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.getAndSet$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
convEndian(handle.be, value)));
}
@ -346,7 +345,7 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.getAndSet$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
convEndian(handle.be, value)));
}
#end[CAS]
@ -359,10 +358,10 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
delta);
} else {
return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta);
return getAndAddConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), delta);
}
}
@ -373,10 +372,10 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
delta);
} else {
return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta);
return getAndAddConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), delta);
}
}
@ -387,10 +386,10 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
delta);
} else {
return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta);
return getAndAddConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), delta);
}
}
@ -415,10 +414,10 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
return getAndBitwiseOrConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value);
}
}
@ -429,10 +428,10 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
return getAndBitwiseOrConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value);
}
}
@ -443,10 +442,10 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
return getAndBitwiseOrConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value);
}
}
@ -469,10 +468,10 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
return getAndBitwiseAndConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value);
}
}
@ -483,10 +482,10 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
return getAndBitwiseAndConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value);
}
}
@ -497,10 +496,10 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
return getAndBitwiseAndConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value);
}
}
@ -524,10 +523,10 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
return getAndBitwiseXorConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value);
}
}
@ -538,10 +537,10 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
return getAndBitwiseXorConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value);
}
}
@ -552,10 +551,10 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
offsetNonPlain(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
return getAndBitwiseXorConvEndianWithCAS(bb, offsetNonPlain(bb, base, handle.alignmentMask), value);
}
}