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