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

@ -1,5 +1,5 @@
#
# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2022, 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
@ -146,8 +146,8 @@ jobs:
apt-architecture: 'i386'
# Some multilib libraries do not have proper inter-dependencies, so we have to
# install their dependencies manually.
apt-extra-packages: 'libfreetype-dev:i386 libtiff-dev:i386 libcupsimage2-dev:i386 libc6-i386 libgcc-s1:i386 libstdc++6:i386'
extra-conf-options: '--with-target-bits=32'
apt-extra-packages: 'libfreetype-dev:i386 libtiff-dev:i386 libcupsimage2-dev:i386 libc6-i386 libgcc-s1:i386 libstdc++6:i386 libffi-dev:i386'
extra-conf-options: '--with-target-bits=32 --enable-fallback-linker --enable-libffi-bundling'
configure-arguments: ${{ github.event.inputs.configure-arguments }}
make-arguments: ${{ github.event.inputs.make-arguments }}
if: needs.select.outputs.linux-x86 == 'true'

View File

@ -426,9 +426,14 @@ var getJibProfilesProfiles = function (input, common, data) {
target_os: "linux",
target_cpu: "x86",
build_cpu: "x64",
dependencies: ["devkit", "gtest"],
configure_args: concat(common.configure_args_32bit,
"--with-jvm-variants=minimal,server", "--with-zlib=system"),
dependencies: ["devkit", "gtest", "libffi"],
configure_args: concat(common.configure_args_32bit, [
"--with-jvm-variants=minimal,server",
"--with-zlib=system",
"--with-libffi=" + input.get("libffi", "home_path"),
"--enable-libffi-bundling",
"--enable-fallback-linker"
])
},
"macosx-x64": {

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

View File

@ -1088,9 +1088,8 @@ public abstract class FileChannel
* @throws UnsupportedOperationException
* If an unsupported map mode is specified.
*
* @since 19
* @since 22
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public MemorySegment map(MapMode mode, long offset, long size, Arena arena)
throws IOException
{

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -715,9 +715,10 @@ public class Attributes implements Map<Object,Object>, Cloneable {
// small footprint cost, but is likely to be quickly paid for by
// reducing allocation when reading and parsing typical manifests
// JDK internal attributes
// JDK specific attributes
addName(names, new Name("Add-Exports"));
addName(names, new Name("Add-Opens"));
addName(names, new Name("Enable-Native-Access"));
// LauncherHelper attributes
addName(names, new Name("Launcher-Agent-Class"));
addName(names, new Name("JavaFX-Application-Class"));

View File

@ -273,7 +273,7 @@ public interface JavaLangAccess {
* Ensure that the given module has native access. If not, warn or
* throw exception depending on the configuration.
*/
void ensureNativeAccess(Module m, Class<?> owner, String methodName);
void ensureNativeAccess(Module m, Class<?> owner, String methodName, Class<?> currentClass);
/**
* Returns the ServicesCatalog for the given Layer.

View File

@ -264,7 +264,7 @@ public abstract sealed class AbstractMemorySegmentImpl
final long thatEnd = thatStart + that.byteSize();
if (thisStart < thatEnd && thisEnd > thatStart) { //overlap occurs
long offsetToThat = this.segmentOffset(that);
long offsetToThat = that.address() - this.address();
long newOffset = offsetToThat >= 0 ? offsetToThat : 0;
return Optional.of(asSlice(newOffset, Math.min(this.byteSize() - newOffset, that.byteSize() + offsetToThat)));
}
@ -272,15 +272,6 @@ public abstract sealed class AbstractMemorySegmentImpl
return Optional.empty();
}
@Override
public final long segmentOffset(MemorySegment other) {
AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl) Objects.requireNonNull(other);
if (unsafeGetBase() == that.unsafeGetBase()) {
return that.unsafeGetOffset() - this.unsafeGetOffset();
}
throw new UnsupportedOperationException("Cannot compute offset from native to heap (or vice versa).");
}
@Override
public void load() {
throw notAMappedSegment();

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.foreign;
import java.lang.foreign.Arena;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySegment.Scope;
import java.util.Objects;
public final class ArenaImpl implements Arena {
private final MemorySessionImpl session;
private final boolean shouldReserveMemory;
ArenaImpl(MemorySessionImpl session) {
this.session = session;
shouldReserveMemory = session instanceof ImplicitSession;
}
@Override
public Scope scope() {
return session;
}
@Override
public void close() {
session.close();
}
public MemorySegment allocateNoInit(long byteSize, long byteAlignment) {
Utils.checkAllocationSizeAndAlign(byteSize, byteAlignment);
return NativeMemorySegmentImpl.makeNativeSegmentNoZeroing(byteSize, byteAlignment, session, shouldReserveMemory);
}
@Override
public MemorySegment allocate(long byteSize, long byteAlignment) {
MemorySegment segment = allocateNoInit(byteSize, byteAlignment);
return segment.fill((byte)0);
}
}

View File

@ -39,8 +39,10 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.UnaryOperator;
import java.util.stream.IntStream;
/**
* This class provide support for constructing layout paths; that is, starting from a root path (see {@link #rootPath(MemoryLayout)},
@ -61,6 +63,7 @@ public class LayoutPath {
private static final MethodHandle MH_SLICE_LAYOUT;
private static final MethodHandle MH_CHECK_ALIGN;
private static final MethodHandle MH_SEGMENT_RESIZE;
private static final MethodHandle MH_ADD;
static {
try {
@ -72,9 +75,11 @@ public class LayoutPath {
MH_SLICE_LAYOUT = lookup.findVirtual(MemorySegment.class, "asSlice",
MethodType.methodType(MemorySegment.class, long.class, MemoryLayout.class));
MH_CHECK_ALIGN = lookup.findStatic(LayoutPath.class, "checkAlign",
MethodType.methodType(MemorySegment.class, MemorySegment.class, MemoryLayout.class));
MethodType.methodType(void.class, MemorySegment.class, long.class, MemoryLayout.class));
MH_SEGMENT_RESIZE = lookup.findStatic(LayoutPath.class, "resizeSegment",
MethodType.methodType(MemorySegment.class, MemorySegment.class, MemoryLayout.class));
MH_ADD = lookup.findStatic(Long.class, "sum",
MethodType.methodType(long.class, long.class, long.class));
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
@ -202,20 +207,34 @@ public class LayoutPath {
// If we have an enclosing layout, drop the alignment check for the accessed element,
// we check the root layout instead
ValueLayout accessedLayout = enclosing != null ? valueLayout.withByteAlignment(1) : valueLayout;
VarHandle handle = Utils.makeSegmentViewVarHandle(accessedLayout);
VarHandle handle = accessedLayout.varHandle();
handle = MethodHandles.collectCoordinates(handle, 1, offsetHandle());
// we only have to check the alignment of the root layout for the first dereference we do,
// as each dereference checks the alignment of the target address when constructing its segment
// (see Utils::longToAddress)
if (derefAdapters.length == 0 && enclosing != null) {
MethodHandle checkHandle = MethodHandles.insertArguments(MH_CHECK_ALIGN, 1, rootLayout());
handle = MethodHandles.filterCoordinates(handle, 0, checkHandle);
// insert align check for the root layout on the initial MS + offset
List<Class<?>> coordinateTypes = handle.coordinateTypes();
MethodHandle alignCheck = MethodHandles.insertArguments(MH_CHECK_ALIGN, 2, rootLayout());
handle = MethodHandles.collectCoordinates(handle, 0, alignCheck);
int[] reorder = IntStream.concat(IntStream.of(0, 1), IntStream.range(0, coordinateTypes.size())).toArray();
handle = MethodHandles.permuteCoordinates(handle, coordinateTypes, reorder);
}
if (adapt) {
if (derefAdapters.length > 0) {
// plug up the base offset if we have at least 1 enclosing dereference
handle = MethodHandles.insertCoordinates(handle, 1, 0);
}
for (int i = derefAdapters.length; i > 0; i--) {
handle = MethodHandles.collectCoordinates(handle, 0, derefAdapters[i - 1]);
MethodHandle adapter = derefAdapters[i - 1];
// the first/outermost adapter will have a base offset coordinate, the rest are constant 0
if (i > 1) {
// plug in a constant 0 base offset for all but the outermost access in a deref chain
adapter = MethodHandles.insertArguments(adapter, 1, 0);
}
handle = MethodHandles.collectCoordinates(handle, 0, adapter);
}
}
return handle;
@ -228,14 +247,14 @@ public class LayoutPath {
}
public MethodHandle offsetHandle() {
MethodHandle mh = MethodHandles.identity(long.class);
for (int i = strides.length - 1; i >=0; i--) {
MethodHandle mh = MethodHandles.insertArguments(MH_ADD, 0, offset);
for (int i = strides.length - 1; i >= 0; i--) {
MethodHandle collector = MethodHandles.insertArguments(MH_ADD_SCALED_OFFSET, 2, strides[i], bounds[i]);
// (J, ...) -> J to (J, J, ...) -> J
// i.e. new coord is prefixed. Last coord will correspond to innermost layout
mh = MethodHandles.collectArguments(mh, 0, collector);
}
mh = MethodHandles.insertArguments(mh, 0, offset);
return mh;
}
@ -253,21 +272,24 @@ public class LayoutPath {
sliceHandle = MH_SLICE_LAYOUT; // (MS, long, MemoryLayout) -> MS
sliceHandle = MethodHandles.insertArguments(sliceHandle, 2, layout); // (MS, long) -> MS
}
sliceHandle = MethodHandles.collectArguments(sliceHandle, 1, offsetHandle()); // (MS, ...) -> MS
sliceHandle = MethodHandles.collectArguments(sliceHandle, 1, offsetHandle()); // (MS, long, ...) -> MS
if (enclosing != null) {
MethodHandle checkHandle = MethodHandles.insertArguments(MH_CHECK_ALIGN, 1, rootLayout());
sliceHandle = MethodHandles.filterArguments(sliceHandle, 0, checkHandle);
// insert align check for the root layout on the initial MS + offset
MethodType oldType = sliceHandle.type();
MethodHandle alignCheck = MethodHandles.insertArguments(MH_CHECK_ALIGN, 2, rootLayout());
sliceHandle = MethodHandles.collectArguments(sliceHandle, 0, alignCheck); // (MS, long, MS, long) -> MS
int[] reorder = IntStream.concat(IntStream.of(0, 1), IntStream.range(0, oldType.parameterCount())).toArray();
sliceHandle = MethodHandles.permuteArguments(sliceHandle, oldType, reorder); // (MS, long, ...) -> MS
}
return sliceHandle;
}
private static MemorySegment checkAlign(MemorySegment segment, MemoryLayout constraint) {
if (!((AbstractMemorySegmentImpl) segment).isAlignedForElement(0, constraint)) {
private static void checkAlign(MemorySegment segment, long offset, MemoryLayout constraint) {
if (!((AbstractMemorySegmentImpl) segment).isAlignedForElement(offset, constraint)) {
throw new IllegalArgumentException("Target offset incompatible with alignment constraints: " + constraint.byteAlignment());
}
return segment;
}
public MemoryLayout layout() {

View File

@ -77,17 +77,7 @@ public abstract sealed class MemorySessionImpl
}
public Arena asArena() {
return new Arena() {
@Override
public Scope scope() {
return MemorySessionImpl.this;
}
@Override
public void close() {
MemorySessionImpl.this.close();
}
};
return new ArenaImpl(this);
}
@ForceInline
@ -153,11 +143,6 @@ public abstract sealed class MemorySessionImpl
return new ImplicitSession(cleaner);
}
public MemorySegment allocate(long byteSize, long byteAlignment) {
Utils.checkAllocationSizeAndAlign(byteSize, byteAlignment);
return NativeMemorySegmentImpl.makeNativeSegment(byteSize, byteAlignment, this);
}
public abstract void release0();
public abstract void acquire0();

View File

@ -33,7 +33,6 @@ import java.util.Optional;
import jdk.internal.misc.Unsafe;
import jdk.internal.misc.VM;
import jdk.internal.vm.annotation.ForceInline;
import sun.security.action.GetBooleanAction;
/**
* Implementation for native memory segments. A native memory segment is essentially a wrapper around
@ -46,7 +45,6 @@ public sealed class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl pe
// The maximum alignment supported by malloc - typically 16 bytes on
// 64-bit platforms and 8 bytes on 32-bit platforms.
private static final long MAX_MALLOC_ALIGN = Unsafe.ADDRESS_SIZE == 4 ? 8 : 16;
private static final boolean SKIP_ZERO_MEMORY = GetBooleanAction.privilegedGetProperty("jdk.internal.foreign.skipZeroMemory");
final long min;
@ -115,7 +113,8 @@ public sealed class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl pe
// factories
public static MemorySegment makeNativeSegment(long byteSize, long byteAlignment, MemorySessionImpl sessionImpl) {
public static MemorySegment makeNativeSegmentNoZeroing(long byteSize, long byteAlignment, MemorySessionImpl sessionImpl,
boolean shouldReserve) {
sessionImpl.checkValidState();
if (VM.isDirectMemoryPageAligned()) {
byteAlignment = Math.max(byteAlignment, NIO_ACCESS.pageSize());
@ -124,12 +123,11 @@ public sealed class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl pe
byteSize + (byteAlignment - 1) :
byteSize);
NIO_ACCESS.reserveMemory(alignedSize, byteSize);
long buf = UNSAFE.allocateMemory(alignedSize);
if (!SKIP_ZERO_MEMORY) {
UNSAFE.setMemory(buf, alignedSize, (byte)0);
if (shouldReserve) {
NIO_ACCESS.reserveMemory(alignedSize, byteSize);
}
long buf = allocateMemoryWrapper(alignedSize);
long alignedBuf = Utils.alignUp(buf, byteAlignment);
AbstractMemorySegmentImpl segment = new NativeMemorySegmentImpl(buf, alignedSize,
false, sessionImpl);
@ -137,7 +135,9 @@ public sealed class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl pe
@Override
public void cleanup() {
UNSAFE.freeMemory(buf);
NIO_ACCESS.unreserveMemory(alignedSize, byteSize);
if (shouldReserve) {
NIO_ACCESS.unreserveMemory(alignedSize, byteSize);
}
}
});
if (alignedSize != byteSize) {
@ -147,6 +147,14 @@ public sealed class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl pe
return segment;
}
private static long allocateMemoryWrapper(long size) {
try {
return UNSAFE.allocateMemory(size);
} catch (IllegalArgumentException ex) {
throw new OutOfMemoryError();
}
}
// Unsafe native segment factories. These are used by the implementation code, to skip the sanity checks
// associated with MemorySegment::ofAddress.

View File

@ -31,13 +31,11 @@ import java.lang.foreign.SegmentAllocator;
public final class SlicingAllocator implements SegmentAllocator {
private final MemorySegment segment;
private final long maxAlign;
private long sp = 0L;
public SlicingAllocator(MemorySegment segment) {
this.segment = segment;
this.maxAlign = ((AbstractMemorySegmentImpl)segment).maxAlignMask();
}
MemorySegment trySlice(long byteSize, long byteAlignment) {

View File

@ -0,0 +1,154 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.foreign;
import java.lang.foreign.MemorySegment;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import static java.lang.foreign.ValueLayout.JAVA_BYTE;
import static java.lang.foreign.ValueLayout.JAVA_SHORT;
import static java.lang.foreign.ValueLayout.JAVA_INT;
/**
* Miscellaneous functions to read and write strings, in various charsets.
*/
public class StringSupport {
public static String read(MemorySegment segment, long offset, Charset charset) {
return switch (CharsetKind.of(charset)) {
case SINGLE_BYTE -> readFast_byte(segment, offset, charset);
case DOUBLE_BYTE -> readFast_short(segment, offset, charset);
case QUAD_BYTE -> readFast_int(segment, offset, charset);
};
}
public static void write(MemorySegment segment, long offset, Charset charset, String string) {
switch (CharsetKind.of(charset)) {
case SINGLE_BYTE -> writeFast_byte(segment, offset, charset, string);
case DOUBLE_BYTE -> writeFast_short(segment, offset, charset, string);
case QUAD_BYTE -> writeFast_int(segment, offset, charset, string);
}
}
private static String readFast_byte(MemorySegment segment, long offset, Charset charset) {
long len = strlen_byte(segment, offset);
byte[] bytes = new byte[(int)len];
MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, (int)len);
return new String(bytes, charset);
}
private static void writeFast_byte(MemorySegment segment, long offset, Charset charset, String string) {
byte[] bytes = string.getBytes(charset);
MemorySegment.copy(bytes, 0, segment, JAVA_BYTE, offset, bytes.length);
segment.set(JAVA_BYTE, offset + bytes.length, (byte)0);
}
private static String readFast_short(MemorySegment segment, long offset, Charset charset) {
long len = strlen_short(segment, offset);
byte[] bytes = new byte[(int)len];
MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, (int)len);
return new String(bytes, charset);
}
private static void writeFast_short(MemorySegment segment, long offset, Charset charset, String string) {
byte[] bytes = string.getBytes(charset);
MemorySegment.copy(bytes, 0, segment, JAVA_BYTE, offset, bytes.length);
segment.set(JAVA_SHORT, offset + bytes.length, (short)0);
}
private static String readFast_int(MemorySegment segment, long offset, Charset charset) {
long len = strlen_int(segment, offset);
byte[] bytes = new byte[(int)len];
MemorySegment.copy(segment, JAVA_BYTE, offset, bytes, 0, (int)len);
return new String(bytes, charset);
}
private static void writeFast_int(MemorySegment segment, long offset, Charset charset, String string) {
byte[] bytes = string.getBytes(charset);
MemorySegment.copy(bytes, 0, segment, JAVA_BYTE, offset, bytes.length);
segment.set(JAVA_INT, offset + bytes.length, 0);
}
private static int strlen_byte(MemorySegment segment, long start) {
// iterate until overflow (String can only hold a byte[], whose length can be expressed as an int)
for (int offset = 0; offset >= 0; offset++) {
byte curr = segment.get(JAVA_BYTE, start + offset);
if (curr == 0) {
return offset;
}
}
throw new IllegalArgumentException("String too large");
}
private static int strlen_short(MemorySegment segment, long start) {
// iterate until overflow (String can only hold a byte[], whose length can be expressed as an int)
for (int offset = 0; offset >= 0; offset += 2) {
short curr = segment.get(JAVA_SHORT, start + offset);
if (curr == 0) {
return offset;
}
}
throw new IllegalArgumentException("String too large");
}
private static int strlen_int(MemorySegment segment, long start) {
// iterate until overflow (String can only hold a byte[], whose length can be expressed as an int)
for (int offset = 0; offset >= 0; offset += 4) {
int curr = segment.get(JAVA_INT, start + offset);
if (curr == 0) {
return offset;
}
}
throw new IllegalArgumentException("String too large");
}
public enum CharsetKind {
SINGLE_BYTE(1),
DOUBLE_BYTE(2),
QUAD_BYTE(4);
final int terminatorCharSize;
CharsetKind(int terminatorCharSize) {
this.terminatorCharSize = terminatorCharSize;
}
public int terminatorCharSize() {
return terminatorCharSize;
}
public static CharsetKind of(Charset charset) {
if (charset == StandardCharsets.UTF_8 || charset == StandardCharsets.ISO_8859_1 || charset == StandardCharsets.US_ASCII) {
return CharsetKind.SINGLE_BYTE;
} else if (charset == StandardCharsets.UTF_16LE || charset == StandardCharsets.UTF_16BE || charset == StandardCharsets.UTF_16) {
return CharsetKind.DOUBLE_BYTE;
} else if (charset == StandardCharsets.UTF_32LE || charset == StandardCharsets.UTF_32BE || charset == StandardCharsets.UTF_32) {
return CharsetKind.QUAD_BYTE;
} else {
throw new IllegalArgumentException("Unsupported charset: " + charset);
}
}
}
}

View File

@ -29,7 +29,6 @@ package jdk.internal.foreign;
import java.lang.foreign.AddressLayout;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.SegmentAllocator;
import java.lang.foreign.StructLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
@ -47,7 +46,6 @@ import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.vm.annotation.ForceInline;
import sun.invoke.util.Wrapper;
import static java.lang.foreign.ValueLayout.JAVA_BYTE;
import static sun.security.action.GetPropertyAction.privilegedGetProperty;
/**
@ -98,7 +96,19 @@ public final class Utils {
VarHandle prev = HANDLE_MAP.putIfAbsent(layout, handle);
return prev != null ? prev : handle;
}
static VarHandle get(ValueLayout layout) {
return HANDLE_MAP.get(layout);
}
}
layout = layout.withoutName(); // name doesn't matter
// keep the addressee layout as it's used below
VarHandle handle = VarHandleCache.get(layout);
if (handle != null) {
return handle;
}
Class<?> baseCarrier = layout.carrier();
if (layout.carrier() == MemorySegment.class) {
baseCarrier = switch ((int) ValueLayout.ADDRESS.byteSize()) {
@ -110,7 +120,7 @@ public final class Utils {
baseCarrier = byte.class;
}
VarHandle handle = SharedSecrets.getJavaLangInvokeAccess().memorySegmentViewHandle(baseCarrier,
handle = SharedSecrets.getJavaLangInvokeAccess().memorySegmentViewHandle(baseCarrier,
layout.byteAlignment() - 1, layout.order());
if (layout.carrier() == boolean.class) {
@ -149,18 +159,6 @@ public final class Utils {
return NativeMemorySegmentImpl.makeNativeSegmentUnchecked(addr, size, scope);
}
public static void copy(MemorySegment addr, byte[] bytes) {
var heapSegment = MemorySegment.ofArray(bytes);
addr.copyFrom(heapSegment);
addr.set(JAVA_BYTE, bytes.length, (byte)0);
}
public static MemorySegment toCString(byte[] bytes, SegmentAllocator allocator) {
MemorySegment addr = allocator.allocate(bytes.length + 1);
copy(addr, bytes);
return addr;
}
@ForceInline
public static boolean isAligned(long offset, long align) {
return (offset & (align - 1)) == 0;

View File

@ -54,6 +54,7 @@ import java.lang.foreign.UnionLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.util.HashSet;
import java.util.List;
import java.nio.ByteOrder;
import java.util.Objects;
@ -73,6 +74,7 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
private record LinkRequest(FunctionDescriptor descriptor, LinkerOptions options) {}
private final SoftReferenceCache<LinkRequest, MethodHandle> DOWNCALL_CACHE = new SoftReferenceCache<>();
private final SoftReferenceCache<LinkRequest, UpcallStubFactory> UPCALL_CACHE = new SoftReferenceCache<>();
private final Set<MemoryLayout> CANONICAL_LAYOUTS_CACHE = new HashSet<>(canonicalLayouts().values());
@Override
@CallerSensitive
@ -213,7 +215,7 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
}
// check for trailing padding
private static void checkGroupSize(GroupLayout gl, long maxUnpaddedOffset) {
private void checkGroupSize(GroupLayout gl, long maxUnpaddedOffset) {
long expectedSize = Utils.alignUp(maxUnpaddedOffset, gl.byteAlignment());
if (gl.byteSize() != expectedSize) {
throw new IllegalArgumentException("Layout '" + gl + "' has unexpected size: "
@ -223,7 +225,7 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
// checks both that there is no excess padding between 'memberLayout' and
// the previous layout
private static void checkMemberOffset(StructLayout parent, MemoryLayout memberLayout,
private void checkMemberOffset(StructLayout parent, MemoryLayout memberLayout,
long lastUnpaddedOffset, long offset) {
long expectedOffset = Utils.alignUp(lastUnpaddedOffset, memberLayout.byteAlignment());
if (expectedOffset != offset) {
@ -232,17 +234,17 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
}
}
private static void checkSupported(ValueLayout valueLayout) {
private void checkSupported(ValueLayout valueLayout) {
valueLayout = valueLayout.withoutName();
if (valueLayout instanceof AddressLayout addressLayout) {
valueLayout = addressLayout.withoutTargetLayout();
}
if (!SUPPORTED_LAYOUTS.contains(valueLayout.withoutName())) {
if (!CANONICAL_LAYOUTS_CACHE.contains(valueLayout.withoutName())) {
throw new IllegalArgumentException("Unsupported layout: " + valueLayout);
}
}
private static void checkHasNaturalAlignment(MemoryLayout layout) {
private void checkHasNaturalAlignment(MemoryLayout layout) {
if (!((AbstractLayout<?>) layout).hasNaturalAlignment()) {
throw new IllegalArgumentException("Layout alignment must be natural alignment: " + layout);
}
@ -273,16 +275,4 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
.map(rl -> FunctionDescriptor.of(stripNames(rl), stripNames(function.argumentLayouts())))
.orElseGet(() -> FunctionDescriptor.ofVoid(stripNames(function.argumentLayouts())));
}
private static final Set<MemoryLayout> SUPPORTED_LAYOUTS = Set.of(
ValueLayout.JAVA_BOOLEAN,
ValueLayout.JAVA_BYTE,
ValueLayout.JAVA_CHAR,
ValueLayout.JAVA_SHORT,
ValueLayout.JAVA_INT,
ValueLayout.JAVA_FLOAT,
ValueLayout.JAVA_LONG,
ValueLayout.JAVA_DOUBLE,
ValueLayout.ADDRESS
);
}

View File

@ -49,12 +49,12 @@ public class BindingInterpreter {
}
@FunctionalInterface
interface StoreFunc {
public interface StoreFunc {
void store(VMStorage storage, Class<?> type, Object o);
}
@FunctionalInterface
interface LoadFunc {
public interface LoadFunc {
Object load(VMStorage storage, Class<?> type);
}
}

View File

@ -192,7 +192,7 @@ public class CallingSequence {
}
public boolean needsTransition() {
return !linkerOptions.isTrivial();
return !linkerOptions.isCritical();
}
public int numLeadingParams() {

View File

@ -63,7 +63,11 @@ public class LinkerOptions {
optionMap.put(option.getClass(), opImpl);
}
return new LinkerOptions(optionMap);
LinkerOptions linkerOptions = new LinkerOptions(optionMap);
if (linkerOptions.hasCapturedCallState() && linkerOptions.isCritical()) {
throw new IllegalArgumentException("Incompatible linker options: captureCallState, critical");
}
return linkerOptions;
}
public static LinkerOptions empty() {
@ -97,9 +101,9 @@ public class LinkerOptions {
return getOption(FirstVariadicArg.class).index();
}
public boolean isTrivial() {
IsTrivial it = getOption(IsTrivial.class);
return it != null;
public boolean isCritical() {
Critical c = getOption(Critical.class);
return c != null;
}
@Override
@ -115,7 +119,7 @@ public class LinkerOptions {
}
public sealed interface LinkerOptionImpl extends Linker.Option
permits CaptureCallState, FirstVariadicArg, IsTrivial {
permits CaptureCallState, FirstVariadicArg, Critical {
default void validateForDowncall(FunctionDescriptor descriptor) {
throw new IllegalArgumentException("Not supported for downcall: " + this);
}
@ -141,8 +145,8 @@ public class LinkerOptions {
}
}
public record IsTrivial() implements LinkerOptionImpl {
public static IsTrivial INSTANCE = new IsTrivial();
public record Critical() implements LinkerOptionImpl {
public static Critical INSTANCE = new Critical();
@Override
public void validateForDowncall(FunctionDescriptor descriptor) {

View File

@ -83,7 +83,7 @@ public final class SharedUtils {
private static final MethodHandle MH_CHECK_CAPTURE_SEGMENT;
public static final AddressLayout C_POINTER = ADDRESS
.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE));
.withTargetLayout(MemoryLayout.sequenceLayout(Long.MAX_VALUE, JAVA_BYTE));
public static final Arena DUMMY_ARENA = new Arena() {
@Override
@ -92,7 +92,7 @@ public final class SharedUtils {
}
@Override
public MemorySegment allocate(long byteSize) {
public MemorySegment allocate(long byteSize, long byteAlignment) {
throw new UnsupportedOperationException();
}
@ -251,24 +251,6 @@ public final class SharedUtils {
};
}
public static String toJavaStringInternal(MemorySegment segment, long start) {
int len = strlen(segment, start);
byte[] bytes = new byte[len];
MemorySegment.copy(segment, JAVA_BYTE, start, bytes, 0, len);
return new String(bytes, StandardCharsets.UTF_8);
}
private static int strlen(MemorySegment segment, long start) {
// iterate until overflow (String can only hold a byte[], whose length can be expressed as an int)
for (int offset = 0; offset >= 0; offset++) {
byte curr = segment.get(JAVA_BYTE, start + offset);
if (curr == 0) {
return offset;
}
}
throw new IllegalArgumentException("String too large");
}
static Map<VMStorage, Integer> indexMap(Binding.Move[] moves) {
return IntStream.range(0, moves.length)
.boxed()
@ -434,20 +416,6 @@ public final class SharedUtils {
};
}
public static final class SimpleVaArg {
public final MemoryLayout layout;
public final Object value;
public SimpleVaArg(MemoryLayout layout, Object value) {
this.layout = layout;
this.value = value;
}
public VarHandle varHandle() {
return layout.varHandle();
}
}
static void writeOverSized(MemorySegment ptr, Class<?> type, Object o) {
// use VH_LONG for integers to zero out the whole register in the process
if (type == long.class) {
@ -515,4 +483,35 @@ public final class SharedUtils {
throw new IllegalArgumentException("Unsupported carrier: " + type);
}
}
public static Map<String, MemoryLayout> canonicalLayouts(ValueLayout longLayout, ValueLayout sizetLayout, ValueLayout wchartLayout) {
return Map.ofEntries(
// specified canonical layouts
Map.entry("bool", ValueLayout.JAVA_BOOLEAN),
Map.entry("char", ValueLayout.JAVA_BYTE),
Map.entry("short", ValueLayout.JAVA_SHORT),
Map.entry("int", ValueLayout.JAVA_INT),
Map.entry("float", ValueLayout.JAVA_FLOAT),
Map.entry("long", longLayout),
Map.entry("long long", ValueLayout.JAVA_LONG),
Map.entry("double", ValueLayout.JAVA_DOUBLE),
Map.entry("void*", ValueLayout.ADDRESS),
Map.entry("size_t", sizetLayout),
Map.entry("wchar_t", wchartLayout),
// unspecified size-dependent layouts
Map.entry("int8_t", ValueLayout.JAVA_BYTE),
Map.entry("int16_t", ValueLayout.JAVA_SHORT),
Map.entry("int32_t", ValueLayout.JAVA_INT),
Map.entry("int64_t", ValueLayout.JAVA_LONG),
// unspecified JNI layouts
Map.entry("jboolean", ValueLayout.JAVA_BOOLEAN),
Map.entry("jchar", ValueLayout.JAVA_CHAR),
Map.entry("jbyte", ValueLayout.JAVA_BYTE),
Map.entry("jshort", ValueLayout.JAVA_SHORT),
Map.entry("jint", ValueLayout.JAVA_INT),
Map.entry("jlong", ValueLayout.JAVA_LONG),
Map.entry("jfloat", ValueLayout.JAVA_FLOAT),
Map.entry("jdouble", ValueLayout.JAVA_DOUBLE)
);
}
}

View File

@ -27,12 +27,16 @@ package jdk.internal.foreign.abi.aarch64.linux;
import jdk.internal.foreign.abi.AbstractLinker;
import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.aarch64.CallArranger;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteOrder;
import java.util.Map;
/**
* ABI implementation based on ARM document "Procedure Call Standard for
@ -40,6 +44,9 @@ import java.nio.ByteOrder;
*/
public final class LinuxAArch64Linker extends AbstractLinker {
static final Map<String, MemoryLayout> CANONICAL_LAYOUTS =
SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT);
public static LinuxAArch64Linker getInstance() {
final class Holder {
private static final LinuxAArch64Linker INSTANCE = new LinuxAArch64Linker();
@ -66,4 +73,9 @@ public final class LinuxAArch64Linker extends AbstractLinker {
protected ByteOrder linkerByteOrder() {
return ByteOrder.LITTLE_ENDIAN;
}
@Override
public Map<String, MemoryLayout> canonicalLayouts() {
return CANONICAL_LAYOUTS;
}
}

View File

@ -27,12 +27,16 @@ package jdk.internal.foreign.abi.aarch64.macos;
import jdk.internal.foreign.abi.AbstractLinker;
import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.aarch64.CallArranger;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteOrder;
import java.util.Map;
/**
* ABI implementation for macOS on Apple silicon. Based on AAPCS with
@ -40,6 +44,9 @@ import java.nio.ByteOrder;
*/
public final class MacOsAArch64Linker extends AbstractLinker {
static final Map<String, MemoryLayout> CANONICAL_LAYOUTS =
SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT);
public static MacOsAArch64Linker getInstance() {
final class Holder {
private static final MacOsAArch64Linker INSTANCE = new MacOsAArch64Linker();
@ -66,4 +73,9 @@ public final class MacOsAArch64Linker extends AbstractLinker {
protected ByteOrder linkerByteOrder() {
return ByteOrder.LITTLE_ENDIAN;
}
@Override
public Map<String, MemoryLayout> canonicalLayouts() {
return CANONICAL_LAYOUTS;
}
}

View File

@ -28,18 +28,25 @@ package jdk.internal.foreign.abi.aarch64.windows;
import jdk.internal.foreign.abi.AbstractLinker;
import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.aarch64.CallArranger;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteOrder;
import java.util.Map;
/**
* ABI implementation for Windows/AArch64. Based on AAPCS with
* changes to va_list.
*/
public final class WindowsAArch64Linker extends AbstractLinker {
static final Map<String, MemoryLayout> CANONICAL_LAYOUTS =
SharedUtils.canonicalLayouts(ValueLayout.JAVA_INT, ValueLayout.JAVA_LONG, ValueLayout.JAVA_CHAR);
private static WindowsAArch64Linker instance;
public static WindowsAArch64Linker getInstance() {
@ -63,4 +70,9 @@ public final class WindowsAArch64Linker extends AbstractLinker {
protected ByteOrder linkerByteOrder() {
return ByteOrder.LITTLE_ENDIAN;
}
@Override
public Map<String, MemoryLayout> canonicalLayouts() {
return CANONICAL_LAYOUTS;
}
}

View File

@ -37,13 +37,13 @@ import java.lang.foreign.UnionLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.VarHandle;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;
import static java.lang.foreign.ValueLayout.ADDRESS;
import static java.lang.foreign.ValueLayout.JAVA_BYTE;
import static java.lang.foreign.ValueLayout.JAVA_INT;
import static java.lang.foreign.ValueLayout.JAVA_LONG;
import static java.lang.foreign.ValueLayout.JAVA_SHORT;
@ -58,18 +58,14 @@ import static java.lang.foreign.ValueLayout.JAVA_SHORT;
* } ffi_type;
*/
class FFIType {
private static final ValueLayout SIZE_T = switch ((int) ADDRESS.byteSize()) {
case 8 -> JAVA_LONG;
case 4 -> JAVA_INT;
default -> throw new IllegalStateException("Address size not supported: " + ADDRESS.byteSize());
};
static final ValueLayout SIZE_T = layoutFor((int)ADDRESS.byteSize());
private static final ValueLayout UNSIGNED_SHORT = JAVA_SHORT;
private static final StructLayout LAYOUT = Utils.computePaddedStructLayout(
SIZE_T, UNSIGNED_SHORT, UNSIGNED_SHORT.withName("type"), ADDRESS.withName("elements"));
private static final VarHandle VH_TYPE = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("type"));
private static final VarHandle VH_ELEMENTS = LAYOUT.varHandle(MemoryLayout.PathElement.groupElement("elements"));
private static final VarHandle VH_SIZE_T_ARRAY = SIZE_T.arrayElementVarHandle();
private static final VarHandle VH_SIZE_T = SIZE_T.varHandle();
private static MemorySegment make(List<MemoryLayout> elements, FFIABI abi, Arena scope) {
MemorySegment elementsSeg = scope.allocate((elements.size() + 1) * ADDRESS.byteSize());
@ -83,8 +79,8 @@ class FFIType {
elementsSeg.setAtIndex(ADDRESS, i, MemorySegment.NULL);
MemorySegment ffiType = scope.allocate(LAYOUT);
VH_TYPE.set(ffiType, LibFallback.structTag());
VH_ELEMENTS.set(ffiType, elementsSeg);
VH_TYPE.set(ffiType, 0L, LibFallback.structTag());
VH_ELEMENTS.set(ffiType, 0L, elementsSeg);
return ffiType;
}
@ -132,7 +128,7 @@ class FFIType {
int offsetIdx = 0;
for (MemoryLayout element : structLayout.memberLayouts()) {
if (!(element instanceof PaddingLayout)) {
long ffiOffset = (long) VH_SIZE_T_ARRAY.get(offsetsOut, offsetIdx++);
long ffiOffset = sizeTAtIndex(offsetsOut, offsetIdx++);
if (ffiOffset != expectedOffset) {
throw new IllegalArgumentException("Invalid group layout." +
" Offset of '" + element.name().orElse("<unnamed>")
@ -143,4 +139,23 @@ class FFIType {
}
}
}
static ValueLayout layoutFor(int byteSize) {
return switch (byteSize) {
case 1 -> JAVA_BYTE;
case 2 -> JAVA_SHORT;
case 4 -> JAVA_INT;
case 8 -> JAVA_LONG;
default -> throw new IllegalStateException("Unsupported size: " + byteSize);
};
}
private static long sizeTAtIndex(MemorySegment segment, int index) {
long offset = SIZE_T.scale(0, index);
if (VH_SIZE_T.varType() == long.class) {
return (long) VH_SIZE_T.get(segment, offset);
} else {
return (int) VH_SIZE_T.get(segment, offset); // 'erase' to long
}
}
}

View File

@ -46,9 +46,18 @@ import java.lang.ref.Reference;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import static java.lang.foreign.ValueLayout.ADDRESS;
import static java.lang.foreign.ValueLayout.JAVA_BOOLEAN;
import static java.lang.foreign.ValueLayout.JAVA_BYTE;
import static java.lang.foreign.ValueLayout.JAVA_CHAR;
import static java.lang.foreign.ValueLayout.JAVA_DOUBLE;
import static java.lang.foreign.ValueLayout.JAVA_FLOAT;
import static java.lang.foreign.ValueLayout.JAVA_INT;
import static java.lang.foreign.ValueLayout.JAVA_LONG;
import static java.lang.foreign.ValueLayout.JAVA_SHORT;
import static java.lang.invoke.MethodHandles.foldArguments;
public final class FallbackLinker extends AbstractLinker {
@ -283,4 +292,47 @@ public final class FallbackLinker extends AbstractLinker {
assert layout == null;
return null;
}
@Override
public Map<String, MemoryLayout> canonicalLayouts() {
// Avoid eager dependency on LibFallback, so we can safely check LibFallback.SUPPORTED
class Holder {
static final Map<String, MemoryLayout> CANONICAL_LAYOUTS;
static {
int wchar_size = LibFallback.wcharSize();
MemoryLayout wchartLayout = switch(wchar_size) {
case 2 -> JAVA_CHAR; // prefer JAVA_CHAR
default -> FFIType.layoutFor(wchar_size);
};
CANONICAL_LAYOUTS = Map.ofEntries(
// specified canonical layouts
Map.entry("bool", JAVA_BOOLEAN),
Map.entry("char", JAVA_BYTE),
Map.entry("float", JAVA_FLOAT),
Map.entry("long long", JAVA_LONG),
Map.entry("double", JAVA_DOUBLE),
Map.entry("void*", ADDRESS),
// platform-dependent sizes
Map.entry("size_t", FFIType.SIZE_T),
Map.entry("short", FFIType.layoutFor(LibFallback.shortSize())),
Map.entry("int", FFIType.layoutFor(LibFallback.intSize())),
Map.entry("long", FFIType.layoutFor(LibFallback.longSize())),
Map.entry("wchar_t", wchartLayout),
// JNI types
Map.entry("jboolean", JAVA_BOOLEAN),
Map.entry("jchar", JAVA_CHAR),
Map.entry("jbyte", JAVA_BYTE),
Map.entry("jshort", JAVA_SHORT),
Map.entry("jint", JAVA_INT),
Map.entry("jlong", JAVA_LONG),
Map.entry("jfloat", JAVA_FLOAT),
Map.entry("jdouble", JAVA_DOUBLE)
);
}
}
return Holder.CANONICAL_LAYOUTS;
}
}

View File

@ -65,6 +65,12 @@ final class LibFallback {
static MemorySegment pointerType() { return NativeConstants.POINTER_TYPE; }
static MemorySegment voidType() { return NativeConstants.VOID_TYPE; }
// platform-dependent types
static int shortSize() { return NativeConstants.SIZEOF_SHORT; }
static int intSize() { return NativeConstants.SIZEOF_INT; }
static int longSize() {return NativeConstants.SIZEOF_LONG; }
static int wcharSize() {return NativeConstants.SIZEOF_WCHAR; }
static short structTag() { return NativeConstants.STRUCT_TAG; }
private static final MethodType UPCALL_TARGET_TYPE = MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class);
@ -222,6 +228,10 @@ final class LibFallback {
private static native long ffi_type_float();
private static native long ffi_type_double();
private static native long ffi_type_pointer();
private static native int ffi_sizeof_short();
private static native int ffi_sizeof_int();
private static native int ffi_sizeof_long();
private static native int ffi_sizeof_wchar();
// put these in a separate class to avoid an UnsatisfiedLinkError
// when LibFallback is initialized but the library is not present
@ -239,6 +249,11 @@ final class LibFallback {
static final MemorySegment FLOAT_TYPE = MemorySegment.ofAddress(ffi_type_float());
static final MemorySegment DOUBLE_TYPE = MemorySegment.ofAddress(ffi_type_double());
static final MemorySegment POINTER_TYPE = MemorySegment.ofAddress(ffi_type_pointer());
static final int SIZEOF_SHORT = ffi_sizeof_short();
static final int SIZEOF_INT = ffi_sizeof_int();
static final int SIZEOF_LONG = ffi_sizeof_long();
static final int SIZEOF_WCHAR = ffi_sizeof_wchar();
static final MemorySegment VOID_TYPE = MemorySegment.ofAddress(ffi_type_void());
static final short STRUCT_TAG = ffi_type_struct();

View File

@ -27,15 +27,22 @@ package jdk.internal.foreign.abi.ppc64.linux;
import jdk.internal.foreign.abi.AbstractLinker;
import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.ppc64.CallArranger;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteOrder;
import java.util.Map;
public final class LinuxPPC64Linker extends AbstractLinker {
static final Map<String, MemoryLayout> CANONICAL_LAYOUTS =
SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT);
public static LinuxPPC64Linker getInstance() {
final class Holder {
private static final LinuxPPC64Linker INSTANCE = new LinuxPPC64Linker();
@ -62,4 +69,9 @@ public final class LinuxPPC64Linker extends AbstractLinker {
protected ByteOrder linkerByteOrder() {
return ByteOrder.BIG_ENDIAN;
}
@Override
public Map<String, MemoryLayout> canonicalLayouts() {
return CANONICAL_LAYOUTS;
}
}

View File

@ -27,15 +27,22 @@ package jdk.internal.foreign.abi.ppc64.linux;
import jdk.internal.foreign.abi.AbstractLinker;
import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.ppc64.CallArranger;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteOrder;
import java.util.Map;
public final class LinuxPPC64leLinker extends AbstractLinker {
static final Map<String, MemoryLayout> CANONICAL_LAYOUTS =
SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT);
public static LinuxPPC64leLinker getInstance() {
final class Holder {
private static final LinuxPPC64leLinker INSTANCE = new LinuxPPC64leLinker();
@ -62,4 +69,9 @@ public final class LinuxPPC64leLinker extends AbstractLinker {
protected ByteOrder linkerByteOrder() {
return ByteOrder.LITTLE_ENDIAN;
}
@Override
public Map<String, MemoryLayout> canonicalLayouts() {
return CANONICAL_LAYOUTS;
}
}

View File

@ -30,14 +30,21 @@ package jdk.internal.foreign.abi.riscv64.linux;
import jdk.internal.foreign.abi.AbstractLinker;
import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.SharedUtils;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteOrder;
import java.util.Map;
public final class LinuxRISCV64Linker extends AbstractLinker {
static final Map<String, MemoryLayout> CANONICAL_LAYOUTS =
SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT);
public static LinuxRISCV64Linker getInstance() {
final class Holder {
private static final LinuxRISCV64Linker INSTANCE = new LinuxRISCV64Linker();
@ -64,4 +71,9 @@ public final class LinuxRISCV64Linker extends AbstractLinker {
protected ByteOrder linkerByteOrder() {
return ByteOrder.LITTLE_ENDIAN;
}
@Override
public Map<String, MemoryLayout> canonicalLayouts() {
return CANONICAL_LAYOUTS;
}
}

View File

@ -27,14 +27,21 @@ package jdk.internal.foreign.abi.s390.linux;
import jdk.internal.foreign.abi.AbstractLinker;
import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.SharedUtils;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteOrder;
import java.util.Map;
public final class LinuxS390Linker extends AbstractLinker {
private static final Map<String, MemoryLayout> CANONICAL_LAYOUTS =
SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT);
public static LinuxS390Linker getInstance() {
final class Holder {
private static final LinuxS390Linker INSTANCE = new LinuxS390Linker();
@ -61,4 +68,9 @@ public final class LinuxS390Linker extends AbstractLinker {
protected ByteOrder linkerByteOrder() {
return ByteOrder.BIG_ENDIAN;
}
@Override
public Map<String, MemoryLayout> canonicalLayouts() {
return CANONICAL_LAYOUTS;
}
}

View File

@ -27,17 +27,24 @@ package jdk.internal.foreign.abi.x64.sysv;
import jdk.internal.foreign.abi.AbstractLinker;
import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.SharedUtils;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteOrder;
import java.util.Map;
/**
* ABI implementation based on System V ABI AMD64 supplement v.0.99.6
*/
public final class SysVx64Linker extends AbstractLinker {
static final Map<String, MemoryLayout> CANONICAL_LAYOUTS =
SharedUtils.canonicalLayouts(ValueLayout.JAVA_LONG, ValueLayout.JAVA_LONG, ValueLayout.JAVA_INT);
public static SysVx64Linker getInstance() {
final class Holder {
private static final SysVx64Linker INSTANCE = new SysVx64Linker();
@ -64,4 +71,9 @@ public final class SysVx64Linker extends AbstractLinker {
protected ByteOrder linkerByteOrder() {
return ByteOrder.LITTLE_ENDIAN;
}
@Override
public Map<String, MemoryLayout> canonicalLayouts() {
return CANONICAL_LAYOUTS;
}
}

View File

@ -26,17 +26,24 @@ package jdk.internal.foreign.abi.x64.windows;
import jdk.internal.foreign.abi.AbstractLinker;
import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.SharedUtils;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.ByteOrder;
import java.util.Map;
/**
* ABI implementation based on Windows ABI AMD64 supplement v.0.99.6
*/
public final class Windowsx64Linker extends AbstractLinker {
static final Map<String, MemoryLayout> CANONICAL_LAYOUTS =
SharedUtils.canonicalLayouts(ValueLayout.JAVA_INT, ValueLayout.JAVA_LONG, ValueLayout.JAVA_CHAR);
public static Windowsx64Linker getInstance() {
final class Holder {
private static final Windowsx64Linker INSTANCE = new Windowsx64Linker();
@ -63,4 +70,9 @@ public final class Windowsx64Linker extends AbstractLinker {
protected ByteOrder linkerByteOrder() {
return ByteOrder.LITTLE_ENDIAN;
}
@Override
public Map<String, MemoryLayout> canonicalLayouts() {
return CANONICAL_LAYOUTS;
}
}

View File

@ -39,8 +39,6 @@ import java.util.stream.Collectors;
*
* @implSpec
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @since 19
*/
public sealed abstract class AbstractGroupLayout<L extends AbstractGroupLayout<L> & MemoryLayout>
extends AbstractLayout<L>

View File

@ -53,8 +53,9 @@ public abstract sealed class AbstractLayout<L extends AbstractLayout<L> & Memory
return dup(byteAlignment(), Optional.of(name));
}
@SuppressWarnings("unchecked")
public final L withoutName() {
return dup(byteAlignment(), Optional.empty());
return name.isPresent() ? dup(byteAlignment(), Optional.empty()) : (L) this;
}
public final Optional<String> name() {

View File

@ -31,16 +31,13 @@ import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Stable;
import sun.invoke.util.Wrapper;
import java.lang.foreign.AddressLayout;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.AddressLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.VarHandle;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@ -115,24 +112,6 @@ public final class ValueLayouts {
order.equals(otherValue.order);
}
public final VarHandle arrayElementVarHandle(int... shape) {
Objects.requireNonNull(shape);
if (!Utils.isElementAligned((ValueLayout) this)) {
throw new UnsupportedOperationException("Layout alignment greater than its size");
}
MemoryLayout layout = self();
List<MemoryLayout.PathElement> path = new ArrayList<>();
for (int i = shape.length; i > 0; i--) {
int size = shape[i - 1];
if (size < 0) throw new IllegalArgumentException("Invalid shape size: " + size);
layout = MemoryLayout.sequenceLayout(size, layout);
path.add(MemoryLayout.PathElement.sequenceElement());
}
layout = MemoryLayout.sequenceLayout(layout);
path.add(MemoryLayout.PathElement.sequenceElement());
return layout.varHandle(path.toArray(new MemoryLayout.PathElement[0]));
}
/**
* {@return the carrier associated with this value layout}
*/
@ -177,7 +156,7 @@ public final class ValueLayouts {
}
@ForceInline
public final VarHandle accessHandle() {
public final VarHandle varHandle() {
if (handle == null) {
// this store to stable field is safe, because return value of 'makeMemoryAccessVarHandle' has stable identity
handle = Utils.makeSegmentViewVarHandle(self());

View File

@ -64,10 +64,10 @@ public @interface PreviewFeature {
* Values should be annotated with the feature's {@code JEP}.
*/
public enum Feature {
// not used
// not used, but required for interim javac to not warn.
VIRTUAL_THREADS,
@JEP(number=442, title="Foreign Function & Memory API", status="Third Preview")
FOREIGN,
@JEP(number=430, title="String Templates")
STRING_TEMPLATES,
@JEP(number=443, title="Unnamed Patterns and Variables")

View File

@ -148,6 +148,7 @@ public class VM {
// User-controllable flag that determines if direct buffers should be page
// aligned. The "-XX:+PageAlignDirectMemory" option can be used to force
// buffers, allocated by ByteBuffer.allocateDirect, to be page aligned.
@Stable
private static boolean pageAlignDirectMemory;
// Returns {@code true} if the direct buffers should be page aligned. This

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 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
@ -134,6 +134,13 @@ public class Modules {
JLA.addOpensToAllUnnamed(m, pn);
}
/**
* Adds native access to all unnamed modules.
*/
public static void addEnableNativeAccessToAllUnnamed() {
JLA.addEnableNativeAccessToAllUnnamed();
}
/**
* Updates module m to use a service.
* Same as m2.addUses(service) but without a caller check.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 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
@ -31,6 +31,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.VM;
import jdk.internal.module.ModuleBootstrap;
@ -115,7 +116,10 @@ public class Reflection {
Module module = currentClass != null ?
currentClass.getModule() :
ClassLoader.getSystemClassLoader().getUnnamedModule();
SharedSecrets.getJavaLangAccess().ensureNativeAccess(module, owner, methodName);
class Holder {
static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
}
Holder.JLA.ensureNativeAccess(module, owner, methodName, currentClass);
}
/**

View File

@ -149,7 +149,7 @@ module java.base {
exports jdk.internal.javac to
java.compiler,
jdk.compiler,
jdk.incubator.vector, // participates in preview features
jdk.incubator.vector,
jdk.jshell;
exports jdk.internal.access to
java.desktop,

View File

@ -102,6 +102,7 @@ public final class LauncherHelper {
private static final String MAIN_CLASS = "Main-Class";
private static final String ADD_EXPORTS = "Add-Exports";
private static final String ADD_OPENS = "Add-Opens";
private static final String ENABLE_NATIVE_ACCESS = "Enable-Native-Access";
private static StringBuilder outBuf = new StringBuilder();
@ -632,6 +633,13 @@ public final class LauncherHelper {
if (opens != null) {
addExportsOrOpens(opens, true);
}
String enableNativeAccess = mainAttrs.getValue(ENABLE_NATIVE_ACCESS);
if (enableNativeAccess != null) {
if (!enableNativeAccess.equals("ALL-UNNAMED")) {
abort(null, "java.launcher.jar.error.illegal.ena.value", enableNativeAccess);
}
Modules.addEnableNativeAccessToAllUnnamed();
}
/*
* Hand off to FXHelper if it detects a JavaFX application

View File

@ -268,6 +268,8 @@ java.launcher.jar.error1=\
java.launcher.jar.error2=manifest not found in {0}
java.launcher.jar.error3=no main manifest attribute, in {0}
java.launcher.jar.error4=error loading java agent in {0}
java.launcher.jar.error.illegal.ena.value=\
Error: illegal value \"{0}\" for Enable-Native-Access manifest attribute. Only 'ALL-UNNAMED' is allowed
java.launcher.init.error=initialization error
java.launcher.javafx.error1=\
Error: The JavaFX launchApplication method has the wrong signature, it\n\

View File

@ -29,6 +29,7 @@
#include <errno.h>
#include <stdint.h>
#include <wchar.h>
#ifdef _WIN64
#include <Windows.h>
#include <Winsock2.h>
@ -206,3 +207,23 @@ JNIEXPORT jlong JNICALL
Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1type_1pointer(JNIEnv* env, jclass cls) {
return ptr_to_jlong(&ffi_type_pointer);
}
JNIEXPORT jint JNICALL
Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1sizeof_1short(JNIEnv* env, jclass cls) {
return sizeof(short);
}
JNIEXPORT jint JNICALL
Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1sizeof_1int(JNIEnv* env, jclass cls) {
return sizeof(int);
}
JNIEXPORT jint JNICALL
Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1sizeof_1long(JNIEnv* env, jclass cls) {
return sizeof(long);
}
JNIEXPORT jint JNICALL
Java_jdk_internal_foreign_abi_fallback_LibFallback_ffi_1sizeof_1wchar(JNIEnv* env, jclass cls) {
return sizeof(wchar_t);
}

View File

@ -23,8 +23,6 @@
* questions.
*/
import jdk.internal.javac.ParticipatesInPreview;
/**
* Defines an API for expressing computations that can be reliably compiled
* at runtime into SIMD instructions, such as AVX instructions on x64, and
@ -33,7 +31,6 @@ import jdk.internal.javac.ParticipatesInPreview;
*
* @moduleGraph
*/
@ParticipatesInPreview
module jdk.incubator.vector {
exports jdk.incubator.vector;
}

View File

@ -28,8 +28,7 @@
* @library /test/lib /
* @requires vm.debug & vm.compiler2.enabled & (os.simpleArch == "x64" | os.arch == "aarch64")
* @modules jdk.incubator.vector
* @compile --enable-preview -source ${jdk.version} TestRangeCheckHoistingScaledIV.java
* @run main/othervm --enable-preview compiler.rangechecks.TestRangeCheckHoistingScaledIV
* @run main/othervm compiler.rangechecks.TestRangeCheckHoistingScaledIV
*/
package compiler.rangechecks;
@ -83,7 +82,7 @@ public class TestRangeCheckHoistingScaledIV {
public static void main(String[] args) throws Exception {
ProcessBuilder pb = ProcessTools.createTestJvm(
"--enable-preview", "--add-modules", "jdk.incubator.vector",
"--add-modules", "jdk.incubator.vector",
"-Xbatch", "-XX:+TraceLoopPredicate", Launcher.class.getName());
OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
analyzer.shouldHaveExitValue(0);

View File

@ -29,7 +29,6 @@ import java.nio.ByteOrder;
/*
* @test
* @enablePreview
* @bug 8262998
* @summary Vector API intrinsincs should not modify IR when bailing out
* @modules jdk.incubator.vector

View File

@ -38,42 +38,42 @@ public class TestVectorErgonomics {
public static void main(String[] args) throws Throwable {
ProcessTools.executeTestJvm("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions",
"-XX:+EnableVectorReboxing", "-Xlog:compilation", "-version", "--enable-preview")
"-XX:+EnableVectorReboxing", "-Xlog:compilation", "-version")
.shouldHaveExitValue(0)
.shouldContain("EnableVectorReboxing=true");
ProcessTools.executeTestJvm("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions",
"-XX:+EnableVectorAggressiveReboxing", "-Xlog:compilation", "-version", "--enable-preview")
"-XX:+EnableVectorAggressiveReboxing", "-Xlog:compilation", "-version")
.shouldHaveExitValue(0)
.shouldContain("EnableVectorAggressiveReboxing=true");
ProcessTools.executeTestJvm("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions",
"-XX:-EnableVectorReboxing", "-Xlog:compilation", "-version", "--enable-preview")
"-XX:-EnableVectorReboxing", "-Xlog:compilation", "-version")
.shouldHaveExitValue(0)
.shouldContain("EnableVectorReboxing=false")
.shouldContain("EnableVectorAggressiveReboxing=false");
ProcessTools.executeTestJvm("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions",
"-XX:-EnableVectorAggressiveReboxing", "-Xlog:compilation", "-version", "--enable-preview")
"-XX:-EnableVectorAggressiveReboxing", "-Xlog:compilation", "-version")
.shouldHaveExitValue(0)
.shouldContain("EnableVectorAggressiveReboxing=false");
ProcessTools.executeTestJvm("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions",
"-XX:-EnableVectorSupport", "-Xlog:compilation", "-version", "--enable-preview")
"-XX:-EnableVectorSupport", "-Xlog:compilation", "-version")
.shouldHaveExitValue(0)
.shouldContain("EnableVectorSupport=false")
.shouldContain("EnableVectorReboxing=false")
.shouldContain("EnableVectorAggressiveReboxing=false");
ProcessTools.executeTestJvm("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions",
"-XX:-EnableVectorSupport", "-XX:+EnableVectorReboxing", "-Xlog:compilation", "-version", "--enable-preview")
"-XX:-EnableVectorSupport", "-XX:+EnableVectorReboxing", "-Xlog:compilation", "-version")
.shouldHaveExitValue(0)
.shouldContain("EnableVectorSupport=false")
.shouldContain("EnableVectorReboxing=false")
.shouldContain("EnableVectorAggressiveReboxing=false");
ProcessTools.executeTestJvm("--add-modules=jdk.incubator.vector", "-XX:+UnlockExperimentalVMOptions",
"-XX:-EnableVectorSupport", "-XX:+EnableVectorAggressiveReboxing", "-Xlog:compilation", "-version", "--enable-preview")
"-XX:-EnableVectorSupport", "-XX:+EnableVectorAggressiveReboxing", "-Xlog:compilation", "-version")
.shouldHaveExitValue(0)
.shouldContain("EnableVectorSupport=false")
.shouldContain("EnableVectorReboxing=false")

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, Rado Smogura. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@ -26,7 +26,6 @@
/*
* @test
* @enablePreview
* @summary Test if memory ordering is preserved
*
* @run main/othervm -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -37,7 +37,6 @@ import jdk.internal.vm.annotation.ForceInline;
/*
* @test id=ZSinglegen
* @bug 8260473
* @enablePreview
* @requires vm.gc.ZSinglegen
* @modules jdk.incubator.vector
* @modules java.base/jdk.internal.vm.annotation
@ -48,7 +47,6 @@ import jdk.internal.vm.annotation.ForceInline;
/*
* @test id=ZGenerational
* @bug 8260473
* @enablePreview
* @requires vm.gc.ZGenerational
* @modules jdk.incubator.vector
* @modules java.base/jdk.internal.vm.annotation

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -30,7 +30,6 @@ import compiler.vectorapi.reshape.utils.VectorReshapeHelper;
/*
* @test
* @bug 8259610
* @enablePreview
* @key randomness
* @modules jdk.incubator.vector
* @modules java.base/jdk.internal.misc

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -30,7 +30,6 @@ import compiler.vectorapi.reshape.utils.VectorReshapeHelper;
/*
* @test
* @bug 8259610
* @enablePreview
* @key randomness
* @modules jdk.incubator.vector
* @modules java.base/jdk.internal.misc

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -30,7 +30,6 @@ import compiler.vectorapi.reshape.utils.VectorReshapeHelper;
/*
* @test
* @bug 8259610
* @enablePreview
* @key randomness
* @modules jdk.incubator.vector
* @modules java.base/jdk.internal.misc

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -30,7 +30,6 @@ import compiler.vectorapi.reshape.utils.VectorReshapeHelper;
/*
* @test
* @bug 8278623
* @enablePreview
* @key randomness
* @modules jdk.incubator.vector
* @modules java.base/jdk.internal.misc

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -30,7 +30,6 @@ import compiler.vectorapi.reshape.utils.VectorReshapeHelper;
/*
* @test
* @bug 8259610
* @enablePreview
* @key randomness
* @modules jdk.incubator.vector
* @modules java.base/jdk.internal.misc

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -30,7 +30,6 @@ import compiler.vectorapi.reshape.utils.VectorReshapeHelper;
/*
* @test
* @bug 8259610
* @enablePreview
* @key randomness
* @modules jdk.incubator.vector
* @modules java.base/jdk.internal.misc

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -30,7 +30,6 @@ import compiler.vectorapi.reshape.utils.VectorReshapeHelper;
/*
* @test
* @bug 8259610
* @enablePreview
* @key randomness
* @modules jdk.incubator.vector
* @modules java.base/jdk.internal.misc

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -36,7 +36,6 @@ import jdk.incubator.vector.VectorSpecies;
* @test
* @bug 8259610
* @key randomness
* @enablePreview
* @modules jdk.incubator.vector
* @modules java.base/jdk.internal.misc
* @summary Test that vector reinterpret intrinsics work as intended.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -77,7 +77,7 @@ public class VectorReshapeHelper {
var test = new TestFramework(testClass);
test.setDefaultWarmup(1);
test.addHelperClasses(VectorReshapeHelper.class);
test.addFlags("--add-modules=jdk.incubator.vector", "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED", "--enable-preview");
test.addFlags("--add-modules=jdk.incubator.vector", "--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED");
test.addFlags(flags);
String testMethodNames = testMethods
.filter(p -> p.isp().length() <= VectorSpecies.ofLargestShape(p.isp().elementType()).length())

View File

@ -23,7 +23,6 @@
/**
* @test
* @enablePreview
* @bug 8259937
* @summary guarantee(loc != NULL) failed: missing saved register with native invoke
*

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@ -42,7 +42,7 @@ public class ClassFileVersionTest {
* compilation. If a particular class becomes non-preview, any
* currently preview class can be substituted in.
*/
private static final Class<?> PREVIEW_API = java.lang.foreign.MemorySegment.class;
private static final Class<?> PREVIEW_API = java.lang.ScopedValue.class;
static Method m;
public static void testIt(String className, int expectedResult) throws Exception {

View File

@ -34,7 +34,6 @@ import static org.testng.Assert.*;
/*
* @test
* @enablePreview
* @run testng CompositeLookupTest
*/
public class CompositeLookupTest {

View File

@ -35,8 +35,6 @@ import static org.testng.Assert.*;
/*
* @test
* @enablePreview
* @requires jdk.foreign.linker != "UNSUPPORTED"
* @run testng/othervm --enable-native-access=ALL-UNNAMED LibraryLookupTest
*/
public class LibraryLookupTest {

View File

@ -23,7 +23,6 @@
/*
* @test
* @enablePreview
* @run testng/othervm MemoryLayoutPrincipalTotalityTest
*/

View File

@ -23,7 +23,6 @@
/*
* @test
* @enablePreview
* @run testng/othervm MemoryLayoutTypeRetentionTest
*/

View File

@ -86,44 +86,63 @@ public class NativeTestHelper {
return layout instanceof ValueLayout valueLayout && valueLayout.carrier() == MemorySegment.class;
}
public static final Linker LINKER = Linker.nativeLinker();
// the constants below are useful aliases for C types. The type/carrier association is only valid for 64-bit platforms.
/**
* The layout for the {@code bool} C type
*/
public static final ValueLayout.OfBoolean C_BOOL = ValueLayout.JAVA_BOOLEAN;
public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) LINKER.canonicalLayouts().get("bool");
/**
* The layout for the {@code char} C type
*/
public static final ValueLayout.OfByte C_CHAR = ValueLayout.JAVA_BYTE;
public static final ValueLayout.OfByte C_CHAR = (ValueLayout.OfByte) LINKER.canonicalLayouts().get("char");
/**
* The layout for the {@code short} C type
*/
public static final ValueLayout.OfShort C_SHORT = ValueLayout.JAVA_SHORT;
public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) LINKER.canonicalLayouts().get("short");
/**
* The layout for the {@code int} C type
*/
public static final ValueLayout.OfInt C_INT = ValueLayout.JAVA_INT;
public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) LINKER.canonicalLayouts().get("int");
/**
* The layout for the {@code long long} C type.
*/
public static final ValueLayout.OfLong C_LONG_LONG = ValueLayout.JAVA_LONG;
public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) LINKER.canonicalLayouts().get("long long");
/**
* The layout for the {@code float} C type
*/
public static final ValueLayout.OfFloat C_FLOAT = ValueLayout.JAVA_FLOAT;
public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) LINKER.canonicalLayouts().get("float");
/**
* The layout for the {@code double} C type
*/
public static final ValueLayout.OfDouble C_DOUBLE = ValueLayout.JAVA_DOUBLE;
public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) LINKER.canonicalLayouts().get("double");
/**
* The {@code T*} native type.
*/
public static final AddressLayout C_POINTER = ValueLayout.ADDRESS
.withTargetLayout(MemoryLayout.sequenceLayout(C_CHAR));
public static final AddressLayout C_POINTER = ((AddressLayout) LINKER.canonicalLayouts().get("void*"))
.withTargetLayout(MemoryLayout.sequenceLayout(Long.MAX_VALUE, C_CHAR));
/**
* The layout for the {@code size_t} C type
*/
public static final ValueLayout C_SIZE_T = (ValueLayout) LINKER.canonicalLayouts().get("size_t");
public static final Linker LINKER = Linker.nativeLinker();
// Common layout shared by some tests
// struct S_PDI { void* p0; double p1; int p2; };
public static final MemoryLayout S_PDI_LAYOUT = switch ((int) ValueLayout.ADDRESS.byteSize()) {
case 8 -> MemoryLayout.structLayout(
C_POINTER.withName("p0"),
C_DOUBLE.withName("p1"),
C_INT.withName("p2"),
MemoryLayout.paddingLayout(4));
case 4 -> MemoryLayout.structLayout(
C_POINTER.withName("p0"),
C_DOUBLE.withName("p1"),
C_INT.withName("p2"));
default -> throw new UnsupportedOperationException("Unsupported address size");
};
private static final MethodHandle FREE = LINKER.downcallHandle(
LINKER.defaultLookup().find("free").get(), FunctionDescriptor.ofVoid(C_POINTER));
@ -248,8 +267,8 @@ public class NativeTestHelper {
} else {
VarHandle accessor = containerLayout.varHandle(fieldPath);
//set value
accessor.set(container, fieldValue.value());
return actual -> fieldCheck.accept(accessor.get((MemorySegment) actual));
accessor.set(container, 0L, fieldValue.value());
return actual -> fieldCheck.accept(accessor.get((MemorySegment) actual, 0L));
}
}
@ -257,7 +276,7 @@ public class NativeTestHelper {
MethodHandle slicer = containerLayout.sliceHandle(fieldPath);
return container -> {
try {
return (MemorySegment) slicer.invokeExact(container);
return (MemorySegment) slicer.invokeExact(container, 0L);
} catch (Throwable e) {
throw new IllegalStateException(e);
}

View File

@ -23,8 +23,6 @@
/*
* @test
* @enablePreview
* @requires jdk.foreign.linker != "UNSUPPORTED"
* @run testng/othervm --enable-native-access=ALL-UNNAMED SafeFunctionAccessTest
*/

View File

@ -23,8 +23,6 @@
/*
* @test
* @enablePreview
* @requires jdk.foreign.linker != "UNSUPPORTED"
* @run testng/othervm --enable-native-access=ALL-UNNAMED StdLibTest
*/
@ -51,7 +49,6 @@ import org.testng.annotations.*;
import static org.testng.Assert.*;
@Test
public class StdLibTest extends NativeTestHelper {
final static Linker abi = Linker.nativeLinker();
@ -121,16 +118,20 @@ public class StdLibTest extends NativeTestHelper {
@Test(dataProvider = "printfArgs")
void test_printf(List<PrintfArg> args) throws Throwable {
String formatArgs = args.stream()
.map(a -> a.format)
String javaFormatArgs = args.stream()
.map(a -> a.javaFormat)
.collect(Collectors.joining(","));
String nativeFormatArgs = args.stream()
.map(a -> a.nativeFormat)
.collect(Collectors.joining(","));
String formatString = "hello(" + formatArgs + ")\n";
String javaFormatString = "hello(" + javaFormatArgs + ")\n";
String nativeFormatString = "hello(" + nativeFormatArgs + ")\n";
String expected = String.format(formatString, args.stream()
String expected = String.format(javaFormatString, args.stream()
.map(a -> a.javaValue).toArray());
int found = stdLibHelper.printf(formatString, args);
int found = stdLibHelper.printf(nativeFormatString, args);
assertEquals(found, expected.length());
}
@ -156,8 +157,9 @@ public class StdLibTest extends NativeTestHelper {
final static MethodHandle gmtime = abi.downcallHandle(abi.defaultLookup().find("gmtime").get(),
FunctionDescriptor.of(C_POINTER.withTargetLayout(Tm.LAYOUT), C_POINTER));
// void qsort( void *ptr, size_t count, size_t size, int (*comp)(const void *, const void *) );
final static MethodHandle qsort = abi.downcallHandle(abi.defaultLookup().find("qsort").get(),
FunctionDescriptor.ofVoid(C_POINTER, C_LONG_LONG, C_LONG_LONG, C_POINTER));
FunctionDescriptor.ofVoid(C_POINTER, C_SIZE_T, C_SIZE_T, C_POINTER));
final static FunctionDescriptor qsortComparFunction = FunctionDescriptor.of(C_INT,
C_POINTER.withTargetLayout(C_INT), C_POINTER.withTargetLayout(C_INT));
@ -187,30 +189,30 @@ public class StdLibTest extends NativeTestHelper {
String strcat(String s1, String s2) throws Throwable {
try (var arena = Arena.ofConfined()) {
MemorySegment buf = arena.allocate(s1.length() + s2.length() + 1);
buf.setUtf8String(0, s1);
MemorySegment other = arena.allocateUtf8String(s2);
return ((MemorySegment)strcat.invokeExact(buf, other)).getUtf8String(0);
buf.setString(0, s1);
MemorySegment other = arena.allocateFrom(s2);
return ((MemorySegment)strcat.invokeExact(buf, other)).getString(0);
}
}
int strcmp(String s1, String s2) throws Throwable {
try (var arena = Arena.ofConfined()) {
MemorySegment ns1 = arena.allocateUtf8String(s1);
MemorySegment ns2 = arena.allocateUtf8String(s2);
MemorySegment ns1 = arena.allocateFrom(s1);
MemorySegment ns2 = arena.allocateFrom(s2);
return (int)strcmp.invokeExact(ns1, ns2);
}
}
int puts(String msg) throws Throwable {
try (var arena = Arena.ofConfined()) {
MemorySegment s = arena.allocateUtf8String(msg);
MemorySegment s = arena.allocateFrom(msg);
return (int)puts.invokeExact(s);
}
}
int strlen(String msg) throws Throwable {
try (var arena = Arena.ofConfined()) {
MemorySegment s = arena.allocateUtf8String(msg);
MemorySegment s = arena.allocateFrom(msg);
return (int)strlen.invokeExact(s);
}
}
@ -277,12 +279,16 @@ public class StdLibTest extends NativeTestHelper {
int[] qsort(int[] arr) throws Throwable {
//init native array
try (var arena = Arena.ofConfined()) {
MemorySegment nativeArr = arena.allocateArray(C_INT, arr);
MemorySegment nativeArr = arena.allocateFrom(C_INT, arr);
//call qsort
MemorySegment qsortUpcallStub = abi.upcallStub(qsortCompar, qsortComparFunction, arena);
qsort.invokeExact(nativeArr, (long)arr.length, C_INT.byteSize(), qsortUpcallStub);
// both of these fit in an int
// automatically widen them to long on x64
int count = arr.length;
int size = (int) C_INT.byteSize();
qsort.invoke(nativeArr, count, size, qsortUpcallStub);
//convert back to Java array
return nativeArr.toArray(C_INT);
@ -300,7 +306,7 @@ public class StdLibTest extends NativeTestHelper {
int printf(String format, List<PrintfArg> args) throws Throwable {
try (var arena = Arena.ofConfined()) {
MemorySegment formatStr = arena.allocateUtf8String(format);
MemorySegment formatStr = arena.allocateFrom(format);
return (int)specializedPrintf(args).invokeExact(formatStr,
args.stream().map(a -> a.nativeValue(arena)).toArray());
}
@ -378,21 +384,24 @@ public class StdLibTest extends NativeTestHelper {
}
enum PrintfArg {
INT(int.class, C_INT, "%d", arena -> 42, 42),
LONG(long.class, C_LONG_LONG, "%d", arena -> 84L, 84L),
DOUBLE(double.class, C_DOUBLE, "%.4f", arena -> 1.2345d, 1.2345d),
STRING(MemorySegment.class, C_POINTER, "%s", arena -> arena.allocateUtf8String("str"), "str");
INT(int.class, C_INT, "%d", "%d", arena -> 42, 42),
LONG(long.class, C_LONG_LONG, "%lld", "%d", arena -> 84L, 84L),
DOUBLE(double.class, C_DOUBLE, "%.4f", "%.4f", arena -> 1.2345d, 1.2345d),
STRING(MemorySegment.class, C_POINTER, "%s", "%s", arena -> arena.allocateFrom("str"), "str");
final Class<?> carrier;
final ValueLayout layout;
final String format;
final String nativeFormat;
final String javaFormat;
final Function<Arena, ?> nativeValueFactory;
final Object javaValue;
<Z, L extends ValueLayout> PrintfArg(Class<?> carrier, L layout, String format, Function<Arena, Z> nativeValueFactory, Object javaValue) {
<Z, L extends ValueLayout> PrintfArg(Class<?> carrier, L layout, String nativeFormat, String javaFormat,
Function<Arena, Z> nativeValueFactory, Object javaValue) {
this.carrier = carrier;
this.layout = layout;
this.format = format;
this.nativeFormat = nativeFormat;
this.javaFormat = javaFormat;
this.nativeValueFactory = nativeValueFactory;
this.javaValue = javaValue;
}

View File

@ -0,0 +1,179 @@
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAccessModes
* @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes
* @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAccessModes
* @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAccessModes
*/
import java.lang.foreign.AddressLayout;
import java.lang.foreign.Arena;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.lang.invoke.VarHandle.AccessMode;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import org.testng.annotations.*;
import static org.testng.Assert.*;
public class TestAccessModes {
@Test(dataProvider = "segmentsAndLayoutsAndModes")
public void testAccessModes(MemorySegment segment, ValueLayout layout, AccessMode mode) throws Throwable {
VarHandle varHandle = layout.varHandle();
MethodHandle methodHandle = varHandle.toMethodHandle(mode);
boolean compatible = AccessModeKind.supportedModes(layout).contains(AccessModeKind.of(mode));
try {
Object o = methodHandle.invokeWithArguments(makeArgs(segment, varHandle.accessModeType(mode)));
assertTrue(compatible);
} catch (UnsupportedOperationException ex) {
assertFalse(compatible);
} catch (IllegalArgumentException ex) {
// access is unaligned, but access mode is supported
assertTrue(compatible);
}
}
Object[] makeArgs(MemorySegment segment, MethodType type) throws Throwable {
List<Object> args = new ArrayList<>();
args.add(segment);
for (Class argType : type.dropParameterTypes(0, 1).parameterList()) {
args.add(defaultValue(argType));
}
return args.toArray();
}
Object defaultValue(Class<?> clazz) throws Throwable {
if (clazz == MemorySegment.class) {
return MemorySegment.NULL;
} else if (clazz.isPrimitive()) {
return MethodHandles.zero(clazz).invoke();
} else {
throw new UnsupportedOperationException();
}
}
/*
* See the javadoc of MemoryLayout::varHandle.
*/
enum AccessModeKind {
PLAIN,
READ_WRITE,
ATOMIC_UPDATE,
ATOMIC_NUMERIC_UPDATE,
ATOMIC_BITWISE_UPDATE;
static AccessModeKind of(AccessMode mode) {
return switch (mode) {
case GET, SET -> PLAIN;
case GET_ACQUIRE, GET_OPAQUE, GET_VOLATILE, SET_VOLATILE,
SET_OPAQUE, SET_RELEASE -> READ_WRITE;
case GET_AND_SET, GET_AND_SET_ACQUIRE, GET_AND_SET_RELEASE,
WEAK_COMPARE_AND_SET, WEAK_COMPARE_AND_SET_RELEASE,
WEAK_COMPARE_AND_SET_ACQUIRE, WEAK_COMPARE_AND_SET_PLAIN,
COMPARE_AND_EXCHANGE, COMPARE_AND_EXCHANGE_ACQUIRE,
COMPARE_AND_EXCHANGE_RELEASE, COMPARE_AND_SET -> ATOMIC_UPDATE;
case GET_AND_ADD, GET_AND_ADD_ACQUIRE, GET_AND_ADD_RELEASE -> ATOMIC_NUMERIC_UPDATE;
default -> ATOMIC_BITWISE_UPDATE;
};
}
static Set<AccessModeKind> supportedModes(ValueLayout layout) {
Set<AccessModeKind> supportedModes = EnumSet.noneOf(AccessModeKind.class);
supportedModes.add(PLAIN);
if (layout.byteAlignment() >= layout.byteSize()) {
supportedModes.add(READ_WRITE);
if (layout instanceof ValueLayout.OfInt || layout instanceof ValueLayout.OfLong ||
layout instanceof ValueLayout.OfFloat || layout instanceof ValueLayout.OfDouble ||
layout instanceof AddressLayout) {
supportedModes.add(ATOMIC_UPDATE);
}
if (layout instanceof ValueLayout.OfInt || layout instanceof ValueLayout.OfLong ||
layout instanceof AddressLayout) {
supportedModes.add(ATOMIC_NUMERIC_UPDATE);
supportedModes.add(ATOMIC_BITWISE_UPDATE);
}
}
return supportedModes;
}
}
static MemoryLayout[] layouts() {
MemoryLayout[] valueLayouts = {
ValueLayout.JAVA_BOOLEAN,
ValueLayout.JAVA_CHAR,
ValueLayout.JAVA_BYTE,
ValueLayout.JAVA_SHORT,
ValueLayout.JAVA_INT,
ValueLayout.JAVA_FLOAT,
ValueLayout.JAVA_LONG,
ValueLayout.JAVA_DOUBLE,
ValueLayout.ADDRESS
};
List<MemoryLayout> layouts = new ArrayList<>();
for (MemoryLayout layout : valueLayouts) {
for (int align : new int[] { 1, 2, 4, 8 }) {
layouts.add(layout.withByteAlignment(align));
}
}
return layouts.toArray(new MemoryLayout[0]);
}
static MemorySegment[] segments() {
return new MemorySegment[]{
Arena.ofAuto().allocate(8),
MemorySegment.ofArray(new byte[8]),
MemorySegment.ofArray(new char[4]),
MemorySegment.ofArray(new short[4]),
MemorySegment.ofArray(new int[2]),
MemorySegment.ofArray(new float[2]),
MemorySegment.ofArray(new long[1]),
MemorySegment.ofArray(new double[1])
};
}
@DataProvider(name = "segmentsAndLayoutsAndModes")
static Object[][] segmentsAndLayoutsAndModes() {
List<Object[]> segmentsAndLayouts = new ArrayList<>();
for (MemorySegment segment : segments()) {
for (MemoryLayout layout : layouts()) {
for (AccessMode mode : AccessMode.values()) {
segmentsAndLayouts.add(new Object[]{segment, layout, mode});
}
}
}
return segmentsAndLayouts.toArray(new Object[0][]);
}
}

View File

@ -24,7 +24,6 @@
/*
* @test
* @enablePreview
* @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAdaptVarHandles
* @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true -Xverify:all TestAdaptVarHandles
* @run testng/othervm -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false -Xverify:all TestAdaptVarHandles
@ -83,11 +82,12 @@ public class TestAdaptVarHandles {
}
}
static final VarHandle intHandleIndexed = ValueLayout.JAVA_INT.arrayElementVarHandle();
static final VarHandle intHandleIndexed = MethodHandles.collectCoordinates(ValueLayout.JAVA_INT.varHandle(),
1, MethodHandles.insertArguments(ValueLayout.JAVA_INT.scaleHandle(), 0, 0L));
static final VarHandle intHandle = ValueLayout.JAVA_INT.varHandle();
static final VarHandle intHandle = MethodHandles.insertCoordinates(ValueLayout.JAVA_INT.varHandle(), 1, 0L);
static final VarHandle floatHandle = ValueLayout.JAVA_FLOAT.varHandle();
static final VarHandle floatHandle = MethodHandles.insertCoordinates(ValueLayout.JAVA_FLOAT.varHandle(), 1, 0L);
@Test
public void testFilterValue() throws Throwable {
@ -96,16 +96,16 @@ public class TestAdaptVarHandles {
MemorySegment segment = scope.allocate(layout);
VarHandle intHandle = layout.varHandle();
VarHandle i2SHandle = MethodHandles.filterValue(intHandle, S2I, I2S);
i2SHandle.set(segment, "1");
String oldValue = (String)i2SHandle.getAndAdd(segment, "42");
i2SHandle.set(segment, 0L, "1");
String oldValue = (String)i2SHandle.getAndAdd(segment, 0L, "42");
assertEquals(oldValue, "1");
String value = (String)i2SHandle.get(segment);
String value = (String)i2SHandle.get(segment, 0L);
assertEquals(value, "43");
boolean swapped = (boolean)i2SHandle.compareAndSet(segment, "43", "12");
boolean swapped = (boolean)i2SHandle.compareAndSet(segment, 0L, "43", "12");
assertTrue(swapped);
oldValue = (String)i2SHandle.compareAndExchange(segment, "12", "42");
oldValue = (String)i2SHandle.compareAndExchange(segment, 0L, "12", "42");
assertEquals(oldValue, "12");
value = (String)i2SHandle.toMethodHandle(VarHandle.AccessMode.GET).invokeExact(segment);
value = (String)i2SHandle.toMethodHandle(VarHandle.AccessMode.GET).invokeExact(segment, 0L);
assertEquals(value, "42");
}
@ -117,17 +117,17 @@ public class TestAdaptVarHandles {
VarHandle intHandle = layout.varHandle();
MethodHandle CTX_S2I = MethodHandles.dropArguments(S2I, 0, String.class, String.class);
VarHandle i2SHandle = MethodHandles.filterValue(intHandle, CTX_S2I, CTX_I2S);
i2SHandle = MethodHandles.insertCoordinates(i2SHandle, 1, "a", "b");
i2SHandle.set(segment, "1");
String oldValue = (String)i2SHandle.getAndAdd(segment, "42");
i2SHandle = MethodHandles.insertCoordinates(i2SHandle, 2, "a", "b");
i2SHandle.set(segment, 0L, "1");
String oldValue = (String)i2SHandle.getAndAdd(segment, 0L, "42");
assertEquals(oldValue, "ab1");
String value = (String)i2SHandle.get(segment);
String value = (String)i2SHandle.get(segment, 0L);
assertEquals(value, "ab43");
boolean swapped = (boolean)i2SHandle.compareAndSet(segment, "43", "12");
boolean swapped = (boolean)i2SHandle.compareAndSet(segment, 0L, "43", "12");
assertTrue(swapped);
oldValue = (String)i2SHandle.compareAndExchange(segment, "12", "42");
oldValue = (String)i2SHandle.compareAndExchange(segment, 0L, "12", "42");
assertEquals(oldValue, "ab12");
value = (String)i2SHandle.toMethodHandle(VarHandle.AccessMode.GET).invokeExact(segment);
value = (String)i2SHandle.toMethodHandle(VarHandle.AccessMode.GET).invokeExact(segment, 0L);
assertEquals(value, "ab42");
}
@ -138,16 +138,16 @@ public class TestAdaptVarHandles {
MemorySegment segment = scope.allocate(layout);
VarHandle intHandle = layout.varHandle();
VarHandle i2SHandle = MethodHandles.filterValue(intHandle, O2I, I2O);
i2SHandle.set(segment, "1");
String oldValue = (String)i2SHandle.getAndAdd(segment, "42");
i2SHandle.set(segment, 0L, "1");
String oldValue = (String)i2SHandle.getAndAdd(segment, 0L, "42");
assertEquals(oldValue, "1");
String value = (String)i2SHandle.get(segment);
String value = (String)i2SHandle.get(segment, 0L);
assertEquals(value, "43");
boolean swapped = (boolean)i2SHandle.compareAndSet(segment, "43", "12");
boolean swapped = (boolean)i2SHandle.compareAndSet(segment, 0L, "43", "12");
assertTrue(swapped);
oldValue = (String)i2SHandle.compareAndExchange(segment, "12", "42");
oldValue = (String)i2SHandle.compareAndExchange(segment, 0L, "12", "42");
assertEquals(oldValue, "12");
value = (String)(Object)i2SHandle.toMethodHandle(VarHandle.AccessMode.GET).invokeExact(segment);
value = (String)(Object)i2SHandle.toMethodHandle(VarHandle.AccessMode.GET).invokeExact(segment, 0L);
assertEquals(value, "42");
}
@ -194,8 +194,8 @@ public class TestAdaptVarHandles {
VarHandle vh = MethodHandles.filterValue(intHandle, S2I, I2S_EX);
try (Arena arena = Arena.ofConfined()) {
MemorySegment seg = arena.allocate(ValueLayout.JAVA_INT);
vh.set(seg, "42");
String x = (String) vh.get(seg); // should throw
vh.set(seg, 0L, "42");
String x = (String) vh.get(seg, 0L); // should throw
}
}
@ -205,7 +205,7 @@ public class TestAdaptVarHandles {
VarHandle vh = MethodHandles.filterValue(intHandle, S2I_EX, I2S);
try (Arena arena = Arena.ofConfined()) {
MemorySegment seg = arena.allocate(ValueLayout.JAVA_INT);
vh.set(seg, "42"); // should throw
vh.set(seg, 0L, "42"); // should throw
}
}

View File

@ -23,9 +23,7 @@
/*
* @test
* @enablePreview
* @library ../ /test/lib
* @requires jdk.foreign.linker != "UNSUPPORTED"
* @run testng/othervm --enable-native-access=ALL-UNNAMED TestAddressDereference
*/
@ -40,6 +38,8 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.testng.annotations.*;
@ -184,18 +184,23 @@ public class TestAddressDereference extends UpcallTestHelper {
this.layout = segment;
}
private static final Pattern LAYOUT_PATTERN = Pattern.compile("^(?<align>\\d+%)?(?<char>[azcsifjdAZCSIFJD])\\d+$");
static LayoutKind parse(String layoutString) {
return switch (layoutString.charAt(0)) {
case 'A','a' -> ADDRESS;
case 'z','Z' -> BOOL;
case 'c','C' -> CHAR;
case 's','S' -> SHORT;
case 'i','I' -> INT;
case 'f','F' -> FLOAT;
case 'j','J' -> LONG;
case 'd','D' -> DOUBLE;
default -> throw new AssertionError("Invalid layout string: " + layoutString);
};
Matcher matcher = LAYOUT_PATTERN.matcher(layoutString);
if (matcher.matches()) {
switch (matcher.group("char")) {
case "A","a": return ADDRESS;
case "z","Z": return BOOL;
case "c","C": return CHAR;
case "s","S": return SHORT;
case "i","I": return INT;
case "f","F": return FLOAT;
case "j","J": return LONG;
case "d","D": return DOUBLE;
};
}
throw new AssertionError("Invalid layout string: " + layoutString);
}
}
}

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
@ -23,12 +23,15 @@
/*
* @test
* @enablePreview
* @run testng TestArrayCopy
*/
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.nio.ByteOrder;
import java.util.ArrayList;
@ -288,9 +291,14 @@ public class TestArrayCopy {
return MemorySegment.ofArray(arr);
}
private static VarHandle arrayVarHandle(ValueLayout layout) {
return MethodHandles.collectCoordinates(layout.varHandle(),
1, MethodHandles.insertArguments(layout.scaleHandle(), 0, 0L));
}
public static MemorySegment truthSegment(MemorySegment srcSeg, CopyHelper<?, ?> helper, int indexShifts, CopyMode mode) {
VarHandle indexedHandleNO = helper.elementLayout.withOrder(NATIVE_ORDER).arrayElementVarHandle();
VarHandle indexedHandleNNO = helper.elementLayout.withOrder(NON_NATIVE_ORDER).arrayElementVarHandle();
VarHandle indexedHandleNO = arrayVarHandle(helper.elementLayout.withOrder(NATIVE_ORDER));
VarHandle indexedHandleNNO = arrayVarHandle(helper.elementLayout.withOrder(NON_NATIVE_ORDER));
MemorySegment dstSeg = MemorySegment.ofArray(srcSeg.toArray(JAVA_BYTE));
int indexLength = (int) dstSeg.byteSize() / (int)helper.elementLayout.byteSize();
if (mode.direction) {

View File

@ -24,13 +24,15 @@
/*
* @test
* @enablePreview
* @run testng/othervm --enable-native-access=ALL-UNNAMED TestArrays
*/
import java.lang.foreign.*;
import java.lang.foreign.MemoryLayout.PathElement;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
@ -144,34 +146,34 @@ public class TestArrays {
@DataProvider(name = "arrays")
public Object[][] nativeAccessOps() {
Consumer<MemorySegment> byteInitializer =
(base) -> initBytes(base, bytes, (addr, pos) -> byteHandle.set(addr, pos, (byte)(long)pos));
(base) -> initBytes(base, bytes, (addr, pos) -> byteHandle.set(addr, 0L, pos, (byte)(long)pos));
Consumer<MemorySegment> charInitializer =
(base) -> initBytes(base, chars, (addr, pos) -> charHandle.set(addr, pos, (char)(long)pos));
(base) -> initBytes(base, chars, (addr, pos) -> charHandle.set(addr, 0L, pos, (char)(long)pos));
Consumer<MemorySegment> shortInitializer =
(base) -> initBytes(base, shorts, (addr, pos) -> shortHandle.set(addr, pos, (short)(long)pos));
(base) -> initBytes(base, shorts, (addr, pos) -> shortHandle.set(addr, 0L, pos, (short)(long)pos));
Consumer<MemorySegment> intInitializer =
(base) -> initBytes(base, ints, (addr, pos) -> intHandle.set(addr, pos, (int)(long)pos));
(base) -> initBytes(base, ints, (addr, pos) -> intHandle.set(addr, 0L, pos, (int)(long)pos));
Consumer<MemorySegment> floatInitializer =
(base) -> initBytes(base, floats, (addr, pos) -> floatHandle.set(addr, pos, (float)(long)pos));
(base) -> initBytes(base, floats, (addr, pos) -> floatHandle.set(addr, 0L, pos, (float)(long)pos));
Consumer<MemorySegment> longInitializer =
(base) -> initBytes(base, longs, (addr, pos) -> longHandle.set(addr, pos, (long)pos));
(base) -> initBytes(base, longs, (addr, pos) -> longHandle.set(addr, 0L, pos, (long)pos));
Consumer<MemorySegment> doubleInitializer =
(base) -> initBytes(base, doubles, (addr, pos) -> doubleHandle.set(addr, pos, (double)(long)pos));
(base) -> initBytes(base, doubles, (addr, pos) -> doubleHandle.set(addr, 0L, pos, (double)(long)pos));
Consumer<MemorySegment> byteChecker =
(base) -> checkBytes(base, bytes, s -> s.toArray(JAVA_BYTE), (addr, pos) -> (byte)byteHandle.get(addr, pos));
(base) -> checkBytes(base, bytes, s -> s.toArray(JAVA_BYTE), (addr, pos) -> (byte)byteHandle.get(addr, 0L, pos));
Consumer<MemorySegment> shortChecker =
(base) -> checkBytes(base, shorts, s -> s.toArray(JAVA_SHORT), (addr, pos) -> (short)shortHandle.get(addr, pos));
(base) -> checkBytes(base, shorts, s -> s.toArray(JAVA_SHORT), (addr, pos) -> (short)shortHandle.get(addr, 0L, pos));
Consumer<MemorySegment> charChecker =
(base) -> checkBytes(base, chars, s -> s.toArray(JAVA_CHAR), (addr, pos) -> (char)charHandle.get(addr, pos));
(base) -> checkBytes(base, chars, s -> s.toArray(JAVA_CHAR), (addr, pos) -> (char)charHandle.get(addr, 0L, pos));
Consumer<MemorySegment> intChecker =
(base) -> checkBytes(base, ints, s -> s.toArray(JAVA_INT), (addr, pos) -> (int)intHandle.get(addr, pos));
(base) -> checkBytes(base, ints, s -> s.toArray(JAVA_INT), (addr, pos) -> (int)intHandle.get(addr, 0L, pos));
Consumer<MemorySegment> floatChecker =
(base) -> checkBytes(base, floats, s -> s.toArray(JAVA_FLOAT), (addr, pos) -> (float)floatHandle.get(addr, pos));
(base) -> checkBytes(base, floats, s -> s.toArray(JAVA_FLOAT), (addr, pos) -> (float)floatHandle.get(addr, 0L, pos));
Consumer<MemorySegment> longChecker =
(base) -> checkBytes(base, longs, s -> s.toArray(JAVA_LONG), (addr, pos) -> (long)longHandle.get(addr, pos));
(base) -> checkBytes(base, longs, s -> s.toArray(JAVA_LONG), (addr, pos) -> (long)longHandle.get(addr, 0L, pos));
Consumer<MemorySegment> doubleChecker =
(base) -> checkBytes(base, doubles, s -> s.toArray(JAVA_DOUBLE), (addr, pos) -> (double)doubleHandle.get(addr, pos));
(base) -> checkBytes(base, doubles, s -> s.toArray(JAVA_DOUBLE), (addr, pos) -> (double)doubleHandle.get(addr, 0L, pos));
return new Object[][]{
{byteInitializer, byteChecker, bytes},

View File

@ -23,7 +23,6 @@
/*
* @test
* @enablePreview
* @modules java.base/sun.nio.ch java.base/jdk.internal.foreign
* @run testng/othervm/timeout=600 --enable-native-access=ALL-UNNAMED TestByteBuffer
*/
@ -122,8 +121,8 @@ public class TestByteBuffer {
static void initTuples(MemorySegment base, long count) {
for (long i = 0; i < count ; i++) {
indexHandle.set(base, i, (int)i);
valueHandle.set(base, i, (float)(i / 500f));
indexHandle.set(base, 0L, i, (int)i);
valueHandle.set(base, 0L, i, (float)(i / 500f));
}
}
@ -131,8 +130,8 @@ public class TestByteBuffer {
for (long i = 0; i < count ; i++) {
int index;
float value;
assertEquals(index = bb.getInt(), (int)indexHandle.get(base, i));
assertEquals(value = bb.getFloat(), (float)valueHandle.get(base, i));
assertEquals(index = bb.getInt(), (int)indexHandle.get(base, 0L, i));
assertEquals(value = bb.getFloat(), (float)valueHandle.get(base, 0L, i));
assertEquals(value, index / 500f);
}
}

View File

@ -23,8 +23,6 @@
/*
* @test
* @enablePreview
* @requires jdk.foreign.linker != "UNSUPPORTED"
* @run testng/othervm --enable-native-access=ALL-UNNAMED TestClassLoaderFindNative
*/

View File

@ -24,7 +24,6 @@
/*
* @test
* @enablePreview
* @run testng TestDereferencePath
*/
@ -73,7 +72,7 @@ public class TestDereferencePath {
b.set(ValueLayout.ADDRESS, 0, c);
c.set(ValueLayout.JAVA_INT, 0, 42);
// dereference
int val = (int) abcx.get(a);
int val = (int) abcx.get(a, 0L);
assertEquals(val, 42);
}
}
@ -98,8 +97,8 @@ public class TestDereferencePath {
try (Arena arena = Arena.ofConfined()) {
// init structs
MemorySegment a = arena.allocate(A);
MemorySegment b = arena.allocateArray(B, 2);
MemorySegment c = arena.allocateArray(C, 4);
MemorySegment b = arena.allocate(B, 2);
MemorySegment c = arena.allocate(C, 4);
// init struct fields
a.set(ValueLayout.ADDRESS, 0, b);
b.set(ValueLayout.ADDRESS, 0, c);
@ -109,13 +108,13 @@ public class TestDereferencePath {
c.setAtIndex(ValueLayout.JAVA_INT, 2, 3);
c.setAtIndex(ValueLayout.JAVA_INT, 3, 4);
// dereference
int val00 = (int) abcx_multi.get(a, 0, 0); // a->b[0]->c[0] = 1
int val00 = (int) abcx_multi.get(a, 0L, 0, 0); // a->b[0]->c[0] = 1
assertEquals(val00, 1);
int val10 = (int) abcx_multi.get(a, 1, 0); // a->b[1]->c[0] = 3
int val10 = (int) abcx_multi.get(a, 0L, 1, 0); // a->b[1]->c[0] = 3
assertEquals(val10, 3);
int val01 = (int) abcx_multi.get(a, 0, 1); // a->b[0]->c[1] = 2
int val01 = (int) abcx_multi.get(a, 0L, 0, 1); // a->b[0]->c[1] = 2
assertEquals(val01, 2);
int val11 = (int) abcx_multi.get(a, 1, 1); // a->b[1]->c[1] = 4
int val11 = (int) abcx_multi.get(a, 0L, 1, 1); // a->b[1]->c[1] = 4
assertEquals(val11, 4);
}
}
@ -152,7 +151,7 @@ public class TestDereferencePath {
try (Arena arena = Arena.ofConfined()) {
MemorySegment segment = arena.allocate(struct.byteSize() + 1).asSlice(1);
VarHandle vhX = struct.varHandle(PathElement.groupElement("x"), PathElement.dereferenceElement());
vhX.set(segment, 42); // should throw
vhX.set(segment, 0L, 42); // should throw
}
}
}

View File

@ -23,8 +23,6 @@
/*
* @test
* @enablePreview
* @requires jdk.foreign.linker != "UNSUPPORTED"
* @modules java.base/jdk.internal.foreign
* @build NativeTestHelper CallGeneratorHelper TestDowncallBase
*

View File

@ -23,8 +23,6 @@
/*
* @test
* @enablePreview
* @requires jdk.foreign.linker != "UNSUPPORTED"
* @modules java.base/jdk.internal.foreign
* @build NativeTestHelper CallGeneratorHelper TestDowncallBase
*

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@ -23,8 +23,6 @@
/*
* @test
* @enablePreview
* @requires jdk.foreign.linker != "UNSUPPORTED"
* @run testng/othervm -Dos.name=Windows --enable-native-access=ALL-UNNAMED TestFallbackLookup
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
@ -23,7 +23,6 @@
/*
* @test
* @enablePreview
* @bug 8248421
* @summary SystemCLinker should have a way to free memory allocated outside Java
* @run testng/othervm --enable-native-access=ALL-UNNAMED TestFree
@ -39,7 +38,7 @@ public class TestFree extends NativeTestHelper {
MemorySegment addr = allocateMemory(str.length() + 1);
addr.copyFrom(MemorySegment.ofArray(str.getBytes()));
addr.set(C_CHAR, str.length(), (byte)0);
assertEquals(str, addr.getUtf8String(0));
assertEquals(str, addr.getString(0));
freeMemory(addr);
}
}

Some files were not shown because too many files have changed in this diff Show More