8282191: Implementation of Foreign Function & Memory API (Preview)

Reviewed-by: erikj, jvernee, psandoz, dholmes, mchung
This commit is contained in:
Maurizio Cimadamore 2022-05-12 16:17:45 +00:00
parent 3be394e160
commit 2c5d136260
303 changed files with 33474 additions and 9186 deletions

View file

@ -0,0 +1,163 @@
/*
* Copyright (c) 2019, 2022, 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 java.lang.foreign;
import java.util.Objects;
import java.util.Optional;
import jdk.internal.foreign.Utils;
import jdk.internal.vm.annotation.Stable;
abstract non-sealed class AbstractLayout implements MemoryLayout {
private final long size;
final long alignment;
private final Optional<String> name;
@Stable
long cachedSize;
public AbstractLayout(long size, long alignment, Optional<String> name) {
this.size = size;
this.alignment = alignment;
this.name = name;
}
@Override
public AbstractLayout withName(String name) {
Objects.requireNonNull(name);
return dup(alignment, Optional.of(name));
}
@Override
public final Optional<String> name() {
return name;
}
abstract AbstractLayout dup(long alignment, Optional<String> name);
@Override
public AbstractLayout withBitAlignment(long alignmentBits) {
checkAlignment(alignmentBits);
return dup(alignmentBits, name);
}
void checkAlignment(long alignmentBitCount) {
if (((alignmentBitCount & (alignmentBitCount - 1)) != 0L) || //alignment must be a power of two
(alignmentBitCount < 8)) { //alignment must be greater than 8
throw new IllegalArgumentException("Invalid alignment: " + alignmentBitCount);
}
}
static void checkSize(long size) {
checkSize(size, false);
}
static void checkSize(long size, boolean includeZero) {
if (size < 0 || (!includeZero && size == 0)) {
throw new IllegalArgumentException("Invalid size for layout: " + size);
}
}
@Override
public final long bitAlignment() {
return alignment;
}
@Override
public long byteSize() {
if (cachedSize == 0) {
cachedSize = Utils.bitsToBytesOrThrow(bitSize(),
() -> new UnsupportedOperationException("Cannot compute byte size; bit size is not a multiple of 8"));
}
return cachedSize;
}
@Override
public long bitSize() {
return size;
}
String decorateLayoutString(String s) {
if (name().isPresent()) {
s = String.format("%s(%s)", s, name().get());
}
if (!hasNaturalAlignment()) {
s = alignment + "%" + s;
}
return s;
}
boolean hasNaturalAlignment() {
return size == alignment;
}
@Override
public boolean isPadding() {
return this instanceof PaddingLayout;
}
/**
* {@return the hash code value for this layout}
*/
@Override
public int hashCode() {
return name.hashCode() << Long.hashCode(alignment);
}
/**
* Compares the specified object with this layout for equality. Returns {@code true} if and only if the specified
* object is also a layout, and it is equal to this layout. Two layouts are considered equal if they are of
* the same kind, have the same size, name and alignment constraints. Furthermore, depending on the layout kind, additional
* conditions must be satisfied:
* <ul>
* <li>two value layouts are considered equal if they have the same byte order (see {@link ValueLayout#order()})</li>
* <li>two sequence layouts are considered equal if they have the same element count (see {@link SequenceLayout#elementCount()}), and
* if their element layouts (see {@link SequenceLayout#elementLayout()}) are also equal</li>
* <li>two group layouts are considered equal if they are of the same kind (see {@link GroupLayout#isStruct()},
* {@link GroupLayout#isUnion()}) and if their member layouts (see {@link GroupLayout#memberLayouts()}) are also equal</li>
* </ul>
*
* @param that the object to be compared for equality with this layout.
* @return {@code true} if the specified object is equal to this layout.
*/
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (!(that instanceof AbstractLayout)) {
return false;
}
return Objects.equals(name, ((AbstractLayout) that).name) &&
Objects.equals(alignment, ((AbstractLayout) that).alignment);
}
/**
* {@return the string representation of this layout}
*/
public abstract String toString();
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2020, 2022, 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 java.lang.foreign;
import jdk.internal.javac.PreviewFeature;
/**
* An object that may be projected down to a {@linkplain #address() memory address}.
* Examples of addressable types are {@link MemorySegment}, {@link MemoryAddress} and {@link VaList}.
* <p>
* The {@link Addressable} type is used by a {@linkplain Linker linker} to model the types of
* {@linkplain Linker#downcallHandle(FunctionDescriptor) downcall handle} parameters that must be passed <em>by reference</em>
* (e.g. memory addresses, variable argument lists and upcall stubs).
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public sealed interface Addressable permits MemorySegment, MemoryAddress, VaList {
/**
* {@return the {@linkplain MemoryAddress memory address} associated with this addressable}
*/
MemoryAddress address();
}

View file

@ -0,0 +1,248 @@
/*
* Copyright (c) 2020, 2022, 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 java.lang.foreign;
import java.lang.invoke.MethodHandle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import jdk.internal.javac.PreviewFeature;
/**
* A function descriptor is made up of zero or more argument layouts and zero or one return layout. A function descriptor
* is used to model the signature of foreign functions when creating
* {@linkplain Linker#downcallHandle(Addressable, FunctionDescriptor) downcall method handles} or
* {@linkplain Linker#upcallStub(MethodHandle, FunctionDescriptor, MemorySession) upcall stubs}.
*
* @implSpec
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @see MemoryLayout
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public sealed class FunctionDescriptor permits FunctionDescriptor.VariadicFunction {
private final MemoryLayout resLayout;
private final List<MemoryLayout> argLayouts;
private FunctionDescriptor(MemoryLayout resLayout, List<MemoryLayout> argLayouts) {
this.resLayout = resLayout;
this.argLayouts = argLayouts;
}
/**
* {@return the return layout (if any) associated with this function descriptor}
*/
public Optional<MemoryLayout> returnLayout() {
return Optional.ofNullable(resLayout);
}
/**
* {@return the argument layouts associated with this function descriptor (as an immutable list)}.
*/
public List<MemoryLayout> argumentLayouts() {
return Collections.unmodifiableList(argLayouts);
}
/**
* Creates a function descriptor with the given return and argument layouts.
* @param resLayout the return layout.
* @param argLayouts the argument layouts.
* @return the new function descriptor.
*/
public static FunctionDescriptor of(MemoryLayout resLayout, MemoryLayout... argLayouts) {
Objects.requireNonNull(resLayout);
Objects.requireNonNull(argLayouts);
Arrays.stream(argLayouts).forEach(Objects::requireNonNull);
return new FunctionDescriptor(resLayout, List.of(argLayouts));
}
/**
* Creates a function descriptor with the given argument layouts and no return layout.
* @param argLayouts the argument layouts.
* @return the new function descriptor.
*/
public static FunctionDescriptor ofVoid(MemoryLayout... argLayouts) {
Objects.requireNonNull(argLayouts);
Arrays.stream(argLayouts).forEach(Objects::requireNonNull);
return new FunctionDescriptor(null, List.of(argLayouts));
}
/**
* Creates a specialized variadic function descriptor, by appending given variadic layouts to this
* function descriptor argument layouts. The resulting function descriptor can report the position
* of the {@linkplain #firstVariadicArgumentIndex() first variadic argument}, and cannot be altered
* in any way: for instance, calling {@link #changeReturnLayout(MemoryLayout)} on the resulting descriptor
* will throw an {@link UnsupportedOperationException}.
* @param variadicLayouts the variadic argument layouts to be appended to this descriptor argument layouts.
* @return a variadic function descriptor, or this descriptor if {@code variadicLayouts.length == 0}.
*/
public FunctionDescriptor asVariadic(MemoryLayout... variadicLayouts) {
Objects.requireNonNull(variadicLayouts);
Arrays.stream(variadicLayouts).forEach(Objects::requireNonNull);
return variadicLayouts.length == 0 ? this : new VariadicFunction(this, variadicLayouts);
}
/**
* The index of the first variadic argument layout (where defined).
* @return The index of the first variadic argument layout, or {@code -1} if this is not a
* {@linkplain #asVariadic(MemoryLayout...) variadic} layout.
*/
public int firstVariadicArgumentIndex() {
return -1;
}
/**
* Returns a function descriptor with the given argument layouts appended to the argument layout array
* of this function descriptor.
* @param addedLayouts the argument layouts to append.
* @return the new function descriptor.
*/
public FunctionDescriptor appendArgumentLayouts(MemoryLayout... addedLayouts) {
return insertArgumentLayouts(argLayouts.size(), addedLayouts);
}
/**
* Returns a function descriptor with the given argument layouts inserted at the given index, into the argument
* layout array of this function descriptor.
* @param index the index at which to insert the arguments
* @param addedLayouts the argument layouts to insert at given index.
* @return the new function descriptor.
* @throws IllegalArgumentException if {@code index < 0 || index > argumentLayouts().size()}.
*/
public FunctionDescriptor insertArgumentLayouts(int index, MemoryLayout... addedLayouts) {
if (index < 0 || index > argLayouts.size())
throw new IllegalArgumentException("Index out of bounds: " + index);
List<MemoryLayout> added = List.of(addedLayouts); // null check on array and its elements
List<MemoryLayout> newLayouts = new ArrayList<>(argLayouts.size() + addedLayouts.length);
newLayouts.addAll(argLayouts.subList(0, index));
newLayouts.addAll(added);
newLayouts.addAll(argLayouts.subList(index, argLayouts.size()));
return new FunctionDescriptor(resLayout, newLayouts);
}
/**
* Returns a function descriptor with the given memory layout as the new return layout.
* @param newReturn the new return layout.
* @return the new function descriptor.
*/
public FunctionDescriptor changeReturnLayout(MemoryLayout newReturn) {
Objects.requireNonNull(newReturn);
return new FunctionDescriptor(newReturn, argLayouts);
}
/**
* Returns a function descriptor with the return layout dropped. This is useful to model functions
* which return no values.
* @return the new function descriptor.
*/
public FunctionDescriptor dropReturnLayout() {
return new FunctionDescriptor(null, argLayouts);
}
/**
* {@return the string representation of this function descriptor}
*/
@Override
public String toString() {
return String.format("(%s)%s",
IntStream.range(0, argLayouts.size())
.mapToObj(i -> (i == firstVariadicArgumentIndex() ?
"..." : "") + argLayouts.get(i))
.collect(Collectors.joining()),
returnLayout().map(Object::toString).orElse("v"));
}
/**
* Compares the specified object with this function descriptor for equality. Returns {@code true} if and only if the specified
* object is also a function descriptor, and all the following conditions are met:
* <ul>
* <li>the two function descriptors have equals return layouts (see {@link MemoryLayout#equals(Object)}), or both have no return layout;</li>
* <li>the two function descriptors have argument layouts that are pair-wise {@linkplain MemoryLayout#equals(Object) equal}; and</li>
* <li>the two function descriptors have the same leading {@linkplain #firstVariadicArgumentIndex() variadic argument index}</li>
* </ul>
*
* @param other the object to be compared for equality with this function descriptor.
* @return {@code true} if the specified object is equal to this function descriptor.
*/
@Override
public boolean equals(Object other) {
return other instanceof FunctionDescriptor f &&
Objects.equals(resLayout, f.resLayout) &&
Objects.equals(argLayouts, f.argLayouts) &&
firstVariadicArgumentIndex() == f.firstVariadicArgumentIndex();
}
/**
* {@return the hash code value for this function descriptor}
*/
@Override
public int hashCode() {
return Objects.hash(argLayouts, resLayout, firstVariadicArgumentIndex());
}
static final class VariadicFunction extends FunctionDescriptor {
private final int firstVariadicIndex;
public VariadicFunction(FunctionDescriptor descriptor, MemoryLayout... argLayouts) {
super(descriptor.returnLayout().orElse(null),
Stream.concat(descriptor.argumentLayouts().stream(), Stream.of(argLayouts)).toList());
this.firstVariadicIndex = descriptor.argumentLayouts().size();
}
@Override
public int firstVariadicArgumentIndex() {
return firstVariadicIndex;
}
@Override
public FunctionDescriptor appendArgumentLayouts(MemoryLayout... addedLayouts) {
throw new UnsupportedOperationException();
}
@Override
public FunctionDescriptor insertArgumentLayouts(int index, MemoryLayout... addedLayouts) {
throw new UnsupportedOperationException();
}
@Override
public FunctionDescriptor changeReturnLayout(MemoryLayout newReturn) {
throw new UnsupportedOperationException();
}
@Override
public FunctionDescriptor dropReturnLayout() {
throw new UnsupportedOperationException();
}
}
}

View file

@ -0,0 +1,188 @@
/*
* Copyright (c) 2019, 2022, 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 java.lang.foreign;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.LongBinaryOperator;
import java.util.stream.Collectors;
import jdk.internal.javac.PreviewFeature;
/**
* A compound layout that aggregates multiple <em>member layouts</em>. There are two ways in which member layouts
* can be combined: if member layouts are laid out one after the other, the resulting group layout is said to be a <em>struct</em>
* (see {@link MemoryLayout#structLayout(MemoryLayout...)}); conversely, if all member layouts are laid out at the same starting offset,
* the resulting group layout is said to be a <em>union</em> (see {@link MemoryLayout#unionLayout(MemoryLayout...)}).
*
* @implSpec
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public final class GroupLayout extends AbstractLayout implements MemoryLayout {
/**
* The group kind.
*/
enum Kind {
/**
* A 'struct' kind.
*/
STRUCT("", Math::addExact),
/**
* A 'union' kind.
*/
UNION("|", Math::max);
final String delimTag;
final LongBinaryOperator sizeOp;
Kind(String delimTag, LongBinaryOperator sizeOp) {
this.delimTag = delimTag;
this.sizeOp = sizeOp;
}
long sizeof(List<MemoryLayout> elems) {
long size = 0;
for (MemoryLayout elem : elems) {
size = sizeOp.applyAsLong(size, elem.bitSize());
}
return size;
}
long alignof(List<MemoryLayout> elems) {
return elems.stream().mapToLong(MemoryLayout::bitAlignment).max() // max alignment in case we have member layouts
.orElse(1); // or minimal alignment if no member layout is given
}
}
private final Kind kind;
private final List<MemoryLayout> elements;
GroupLayout(Kind kind, List<MemoryLayout> elements) {
this(kind, elements, kind.alignof(elements), Optional.empty());
}
GroupLayout(Kind kind, List<MemoryLayout> elements, long alignment, Optional<String> name) {
super(kind.sizeof(elements), alignment, name);
this.kind = kind;
this.elements = elements;
}
/**
* Returns the member layouts associated with this group.
*
* @apiNote the order in which member layouts are returned is the same order in which member layouts have
* been passed to one of the group layout factory methods (see {@link MemoryLayout#structLayout(MemoryLayout...)},
* {@link MemoryLayout#unionLayout(MemoryLayout...)}).
*
* @return the member layouts associated with this group.
*/
public List<MemoryLayout> memberLayouts() {
return Collections.unmodifiableList(elements);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return decorateLayoutString(elements.stream()
.map(Object::toString)
.collect(Collectors.joining(kind.delimTag, "[", "]")));
}
/**
* {@return {@code true}, if this group layout is a struct layout}
*/
public boolean isStruct() {
return kind == Kind.STRUCT;
}
/**
* {@return {@code true}, if this group layout is a union layout}
*/
public boolean isUnion() {
return kind == Kind.UNION;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!super.equals(other)) {
return false;
}
if (!(other instanceof GroupLayout g)) {
return false;
}
return kind.equals(g.kind) && elements.equals(g.elements);
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), kind, elements);
}
@Override
GroupLayout dup(long alignment, Optional<String> name) {
return new GroupLayout(kind, elements, alignment, name);
}
@Override
boolean hasNaturalAlignment() {
return alignment == kind.alignof(elements);
}
//hack: the declarations below are to make javadoc happy; we could have used generics in AbstractLayout
//but that causes issues with javadoc, see JDK-8224052
/**
* {@inheritDoc}
*/
@Override
public GroupLayout withName(String name) {
return (GroupLayout)super.withName(name);
}
/**
* {@inheritDoc}
*/
@Override
public GroupLayout withBitAlignment(long alignmentBits) {
return (GroupLayout)super.withBitAlignment(alignmentBits);
}
}

View file

@ -0,0 +1,307 @@
/*
* Copyright (c) 2020, 2022, 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 java.lang.foreign;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker;
import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker;
import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker;
import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
/**
* A linker provides access to foreign functions from Java code, and access to Java code from foreign functions.
* <p>
* Foreign functions typically reside in libraries that can be loaded on-demand. Each library conforms to
* a specific ABI (Application Binary Interface). An ABI is a set of calling conventions and data types associated with
* the compiler, OS, and processor where the library was built. For example, a C compiler on Linux/x64 usually
* builds libraries that conform to the SystemV ABI.
* <p>
* A linker has detailed knowledge of the calling conventions and data types used by a specific ABI.
* For any library which conforms to that ABI, the linker can mediate between Java code running
* in the JVM and foreign functions in the library. In particular:
* <ul>
* <li>A linker allows Java code to link against foreign functions, via
* {@linkplain #downcallHandle(Addressable, FunctionDescriptor) downcall method handles}; and</li>
* <li>A linker allows foreign functions to call Java method handles,
* via the generation of {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, MemorySession) upcall stubs}.</li>
* </ul>
* In addition, a linker provides a way to look up foreign functions in libraries that conform to the ABI. Each linker
* chooses a set of libraries that are commonly used on the OS and processor combination associated with the ABI.
* For example, a linker for Linux/x64 might choose two libraries: {@code libc} and {@code libm}. The functions in these
* libraries are exposed via a {@linkplain #defaultLookup() symbol lookup}.
* <p>
* The {@link #nativeLinker()} method provides a linker for the ABI associated with the OS and processor where the Java runtime
* is currently executing. This linker also provides access, via its {@linkplain #defaultLookup() default lookup},
* to the native libraries loaded with the Java runtime.
*
* <h2><a id = "downcall-method-handles">Downcall method handles</a></h2>
*
* {@linkplain #downcallHandle(FunctionDescriptor) Linking a foreign function} is a process which requires a function descriptor,
* a set of memory layouts which, together, specify the signature of the foreign function to be linked, and returns,
* when complete, a downcall method handle, that is, a method handle that can be used to invoke the target foreign function.
* <p>
* The Java {@linkplain java.lang.invoke.MethodType method type} associated with the returned method handle is
* {@linkplain #downcallType(FunctionDescriptor) derived} from the argument and return layouts in the function descriptor.
* More specifically, given each layout {@code L} in the function descriptor, a corresponding carrier {@code C} is inferred,
* as described below:
* <ul>
* <li>if {@code L} is a {@link ValueLayout} with carrier {@code E} then there are two cases:
* <ul>
* <li>if {@code L} occurs in a parameter position and {@code E} is {@code MemoryAddress.class},
* then {@code C = Addressable.class};</li>
* <li>otherwise, {@code C = E};
* </ul></li>
* <li>or, if {@code L} is a {@link GroupLayout}, then {@code C} is set to {@code MemorySegment.class}</li>
* </ul>
* <p>
* The downcall method handle type, derived as above, might be decorated by additional leading parameters,
* in the given order if both are present:
* <ul>
* <li>If the downcall method handle is created {@linkplain #downcallHandle(FunctionDescriptor) without specifying a target address},
* the downcall method handle type features a leading parameter of type {@link Addressable}, from which the
* address of the target foreign function can be derived.</li>
* <li>If the function descriptor's return layout is a group layout, the resulting downcall method handle accepts
* an additional leading parameter of type {@link SegmentAllocator}, which is used by the linker runtime to allocate the
* memory region associated with the struct returned by the downcall method handle.</li>
* </ul>
*
* <h2><a id = "upcall-stubs">Upcall stubs</a></h2>
*
* {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, MemorySession) Creating an upcall stub} requires a method
* handle and a function descriptor; in this case, the set of memory layouts in the function descriptor
* specify the signature of the function pointer associated with the upcall stub.
* <p>
* The type of the provided method handle has to {@linkplain #upcallType(FunctionDescriptor) match} the Java
* {@linkplain java.lang.invoke.MethodType method type} associated with the upcall stub, which is derived from the argument
* and return layouts in the function descriptor. More specifically, given each layout {@code L} in the function descriptor,
* a corresponding carrier {@code C} is inferred, as described below:
* <ul>
* <li>If {@code L} is a {@link ValueLayout} with carrier {@code E} then there are two cases:
* <ul>
* <li>If {@code L} occurs in a return position and {@code E} is {@code MemoryAddress.class},
* then {@code C = Addressable.class};</li>
* <li>Otherwise, {@code C = E};
* </ul></li>
* <li>Or, if {@code L} is a {@link GroupLayout}, then {@code C} is set to {@code MemorySegment.class}</li>
* </ul>
* Upcall stubs are modelled by instances of type {@link MemorySegment}; upcall stubs can be passed by reference to other
* downcall method handles (as {@link MemorySegment} implements the {@link Addressable} interface) and,
* when no longer required, they can be {@linkplain MemorySession#close() released}, via their associated {@linkplain MemorySession session}.
*
* <h2>Safety considerations</h2>
*
* Creating a downcall method handle is intrinsically unsafe. A symbol in a foreign library does not, in general,
* contain enough signature information (e.g. arity and types of foreign function parameters). As a consequence,
* the linker runtime cannot validate linkage requests. When a client interacts with a downcall method handle obtained
* through an invalid linkage request (e.g. by specifying a function descriptor featuring too many argument layouts),
* the result of such interaction is unspecified and can lead to JVM crashes. On downcall handle invocation,
* the linker runtime guarantees the following for any argument that is a memory resource {@code R} (of type {@link MemorySegment}
* or {@link VaList}):
* <ul>
* <li>The memory session of {@code R} is {@linkplain MemorySession#isAlive() alive}. Otherwise, the invocation throws
* {@link IllegalStateException};</li>
* <li>The invocation occurs in same thread as the one {@linkplain MemorySession#ownerThread() owning} the memory session of {@code R},
* if said session is confined. Otherwise, the invocation throws {@link IllegalStateException}; and</li>
* <li>The memory session of {@code R} is {@linkplain MemorySession#whileAlive(Runnable) kept alive} (and cannot be closed) during the invocation.</li>
*</ul>
* <p>
* When creating upcall stubs the linker runtime validates the type of the target method handle against the provided
* function descriptor and report an error if any mismatch is detected. As for downcalls, JVM crashes might occur,
* if the foreign code casts the function pointer associated with an upcall stub to a type
* that is incompatible with the provided function descriptor. Moreover, if the target method
* handle associated with an upcall stub returns a {@linkplain MemoryAddress memory address}, clients must ensure
* that this address cannot become invalid after the upcall completes. This can lead to unspecified behavior,
* and even JVM crashes, since an upcall is typically executed in the context of a downcall method handle invocation.
*
* @implSpec
* Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public sealed interface Linker permits Windowsx64Linker, SysVx64Linker, LinuxAArch64Linker, MacOsAArch64Linker {
/**
* Returns a linker for the ABI associated with the underlying native platform. The underlying native platform
* is the combination of OS and processor where the Java runtime is currently executing.
* <p>
* When interacting with the returned linker, clients must describe the signature of a foreign function using a
* {@link FunctionDescriptor function descriptor} whose argument and return layouts are specified as follows:
* <ul>
* <li>Scalar types are modelled by a {@linkplain ValueLayout value layout} instance of a suitable carrier. Example
* of scalar types in C are {@code int}, {@code long}, {@code size_t}, etc. The mapping between a scalar type
* and its corresponding layout is dependent on the ABI of the returned linker;
* <li>Composite types are modelled by a {@linkplain GroupLayout group layout}. Depending on the ABI of the
* returned linker, additional {@linkplain MemoryLayout#paddingLayout(long) padding} member layouts might be required to conform
* to the size and alignment constraints of a composite type definition in C (e.g. using {@code struct} or {@code union}); and</li>
* <li>Pointer types are modelled by a {@linkplain ValueLayout value layout} instance with carrier {@link MemoryAddress}.
* Examples of pointer types in C are {@code int**} and {@code int(*)(size_t*, size_t*)};</li>
* </ul>
* <p>
* Any layout not listed above is <em>unsupported</em>; function descriptors containing unsupported layouts
* will cause an {@link IllegalArgumentException} to be thrown, when used to create a
* {@link #downcallHandle(Addressable, FunctionDescriptor) downcall method handle} or an
* {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, MemorySession) upcall stub}.
* <p>
* Variadic functions (e.g. a C function declared with a trailing ellipses {@code ...} at the end of the formal parameter
* list or with an empty formal parameter list) are not supported directly. However, it is possible to link a
* variadic function by using a {@linkplain FunctionDescriptor#asVariadic(MemoryLayout...) <em>variadic</em>}
* function descriptor, in which the specialized signature of a given variable arity callsite is described in full.
* Alternatively, where the foreign library allows it, clients might be able to interact with variadic functions by
* passing a trailing parameter of type {@link VaList} (e.g. as in {@code vsprintf}).
* <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.
*
* @apiNote It is not currently possible to obtain a linker for a different combination of OS and processor.
* @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}.
*
* @return a linker for the ABI associated with the OS and processor where the Java runtime is currently executing.
* @throws UnsupportedOperationException if the underlying native platform is not supported.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
static Linker nativeLinker() {
Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "nativeLinker");
return SharedUtils.getSystemLinker();
}
/**
* Creates a method handle which can be used to call a target foreign function with the given signature and address.
* <p>
* If the provided method type's return type is {@code MemorySegment}, then the resulting method handle features
* an additional prefix parameter, of type {@link SegmentAllocator}, which will be used by the linker runtime
* to allocate structs returned by-value.
* <p>
* Calling this method is equivalent to the following code:
* {@snippet lang=java :
* linker.downcallHandle(function).bindTo(symbol);
* }
*
* @param symbol the address of the target function.
* @param function the function descriptor of the target function.
* @return a downcall method handle. The method handle type is <a href="CLinker.html#downcall-method-handles"><em>inferred</em></a>
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker.
* or if the symbol is {@link MemoryAddress#NULL}
*/
default MethodHandle downcallHandle(Addressable symbol, FunctionDescriptor function) {
SharedUtils.checkSymbol(symbol);
return downcallHandle(function).bindTo(symbol);
}
/**
* Creates a method handle which can be used to call a target foreign function with the given signature.
* The resulting method handle features a prefix parameter (as the first parameter) corresponding to the foreign function
* entry point, of type {@link Addressable}, which is used to specify the address of the target function
* to be called.
* <p>
* If the provided function descriptor's return layout is a {@link GroupLayout}, then the resulting method handle features an
* additional prefix parameter (inserted immediately after the address parameter), of type {@link SegmentAllocator}),
* which will be used by the linker runtime to allocate structs returned by-value.
* <p>
* The returned method handle will throw an {@link IllegalArgumentException} if the {@link Addressable} parameter passed to it is
* associated with the {@link MemoryAddress#NULL} address, or a {@link NullPointerException} if that parameter is {@code null}.
*
* @param function the function descriptor of the target function.
* @return a downcall method handle. The method handle type is <a href="CLinker.html#downcall-method-handles"><em>inferred</em></a>
* from the provided function descriptor.
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker.
*/
MethodHandle downcallHandle(FunctionDescriptor function);
/**
* Creates a stub which can be passed to other foreign functions as a function pointer, with the given
* memory session. Calling such a function pointer from foreign code will result in the execution of the provided
* method handle.
* <p>
* The returned memory segment's base address points to the newly allocated upcall stub, and is associated with
* the provided memory session. When such session is closed, the corresponding upcall stub will be deallocated.
* <p>
* The target method handle should not throw any exceptions. If the target method handle does throw an exception,
* the VM will exit with a non-zero exit code. To avoid the VM aborting due to an uncaught exception, clients
* could wrap all code in the target method handle in a try/catch block that catches any {@link Throwable}, for
* instance by using the {@link java.lang.invoke.MethodHandles#catchException(MethodHandle, Class, MethodHandle)}
* method handle combinator, and handle exceptions as desired in the corresponding catch block.
*
* @param target the target method handle.
* @param function the upcall stub function descriptor.
* @param session the upcall stub memory session.
* @return a zero-length segment whose base address is the address of the upcall stub.
* @throws IllegalArgumentException if the provided function descriptor is not supported by this linker.
* @throws IllegalArgumentException if it is determined that the target method handle can throw an exception, or if the target method handle
* has a type that does not match the upcall stub <a href="CLinker.html#upcall-stubs"><em>inferred type</em></a>.
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}.
*/
MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, MemorySession session);
/**
* Returns a symbol lookup for symbols in a set of commonly used libraries.
* <p>
* Each {@link Linker} is responsible for choosing libraries that are widely recognized as useful on the OS
* and processor combination supported by the {@link Linker}. Accordingly, the precise set of symbols exposed by the
* symbol lookup is unspecified; it varies from one {@link Linker} to another.
* @implNote It is strongly recommended that the result of {@link #defaultLookup} exposes a set of symbols that is stable over time.
* Clients of {@link #defaultLookup()} are likely to fail if a symbol that was previously exposed by the symbol lookup is no longer exposed.
* <p>If an implementer provides {@link Linker} implementations for multiple OS and processor combinations, then it is strongly
* recommended that the result of {@link #defaultLookup()} exposes, as much as possible, a consistent set of symbols
* across all the OS and processor combinations.
* @return a symbol lookup for symbols in a set of commonly used libraries.
*/
SymbolLookup defaultLookup();
/**
* {@return the downcall method handle {@linkplain MethodType type} associated with the given function descriptor}
* @param functionDescriptor a function descriptor.
* @throws IllegalArgumentException if one or more layouts in the function descriptor are not supported
* (e.g. if they are sequence layouts or padding layouts).
*/
static MethodType downcallType(FunctionDescriptor functionDescriptor) {
return SharedUtils.inferMethodType(functionDescriptor, false);
}
/**
* {@return the method handle {@linkplain MethodType type} associated with an upcall stub with the given function descriptor}
* @param functionDescriptor a function descriptor.
* @throws IllegalArgumentException if one or more layouts in the function descriptor are not supported
* (e.g. if they are sequence layouts or padding layouts).
*/
static MethodType upcallType(FunctionDescriptor functionDescriptor) {
return SharedUtils.inferMethodType(functionDescriptor, true);
}
}

View file

@ -0,0 +1,854 @@
/*
* Copyright (c) 2019, 2022, 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 java.lang.foreign;
import java.nio.ByteOrder;
import jdk.internal.foreign.MemoryAddressImpl;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.reflect.CallerSensitive;
import java.lang.invoke.MethodHandle;
/**
* A memory address models a reference into a memory location. Memory addresses are typically obtained in one of the following ways:
* <ul>
* <li>By calling {@link Addressable#address()} on an instance of type {@link Addressable} (e.g. a memory segment);</li>
* <li>By invoking a {@linkplain Linker#downcallHandle(FunctionDescriptor) downcall method handle} which returns a pointer;</li>
* <li>By reading an address from memory, e.g. via {@link MemorySegment#get(ValueLayout.OfAddress, long)}; and</li>
* <li>By the invocation of an {@linkplain Linker#upcallStub(MethodHandle, FunctionDescriptor, MemorySession) upcall stub} which accepts a pointer.</li>
* </ul>
* A memory address is backed by a raw machine pointer, expressed as a {@linkplain #toRawLongValue() long value}.
*
* <h2>Dereferencing memory addresses</h2>
*
* A memory address can be read or written using various methods provided in this class (e.g. {@link #get(ValueLayout.OfInt, long)}).
* Each dereference method takes a {@linkplain ValueLayout value layout}, which specifies the size,
* alignment constraints, byte order as well as the Java type associated with the dereference operation, and an offset.
* For instance, to read an int from a segment, using {@linkplain ByteOrder#nativeOrder() default endianness}, the following code can be used:
* {@snippet lang=java :
* MemoryAddress address = ...
* int value = address.get(ValueLayout.JAVA_INT, 0);
* }
*
* If the value to be read is stored in memory using {@link ByteOrder#BIG_ENDIAN big-endian} encoding, the dereference operation
* can be expressed as follows:
* {@snippet lang=java :
* MemoryAddress address = ...
* int value = address.get(ValueLayout.JAVA_INT.withOrder(BIG_ENDIAN), 0);
* }
*
* All the dereference methods in this class are <a href="package-summary.html#restricted"><em>restricted</em></a>: since
* a memory address does not feature temporal nor spatial bounds, the runtime has no way to check the correctness
* of the memory dereference operation.
*
* @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
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public sealed interface MemoryAddress extends Addressable permits MemoryAddressImpl {
/**
* {@return the raw long value associated with this memory address}
*/
long toRawLongValue();
/**
* Returns a memory address at given offset from this address.
* @param offset specified offset (in bytes), relative to this address, which should be used to create the new address.
* Might be negative.
* @return a memory address with the given offset from current one.
*/
MemoryAddress addOffset(long offset);
/**
* Reads a UTF-8 encoded, null-terminated string from this address at the given offset.
* <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.
* <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.
*
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return a Java string constructed from the bytes read from the given starting address ({@code toRowLongValue() + offset})
* 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 IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
String getUtf8String(long offset);
/**
* Writes the given string to this address at the given offset, converting it to a null-terminated byte sequence using UTF-8 encoding.
* <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.
* <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.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @param str the Java string to be written at this address.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void setUtf8String(long offset, String str);
/**
* Compares the specified object with this address for equality. Returns {@code true} if and only if the specified
* object is also an address, and it refers to the same memory location as this address.
*
* @param that the object to be compared for equality with this address.
* @return {@code true} if the specified object is equal to this address.
*/
@Override
boolean equals(Object that);
/**
* {@return the hash code value for this address}
*/
@Override
int hashCode();
/**
* The memory address instance modelling the {@code NULL} address.
*/
MemoryAddress NULL = new MemoryAddressImpl(0L);
/**
* Creates a memory address from the given long value.
* @param value the long value representing a raw address.
* @return a memory address with the given raw long value.
*/
static MemoryAddress ofLong(long value) {
return value == 0 ?
NULL :
new MemoryAddressImpl(value);
}
/**
* Reads a byte at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be read.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return a byte value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
byte get(ValueLayout.OfByte layout, long offset);
/**
* Writes a byte at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be written.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the byte value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void set(ValueLayout.OfByte layout, long offset, byte value);
/**
* Reads a boolean at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be read.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return a boolean value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
boolean get(ValueLayout.OfBoolean layout, long offset);
/**
* Writes a boolean at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be written.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the boolean value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void set(ValueLayout.OfBoolean layout, long offset, boolean value);
/**
* Reads a char at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be read.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return a char value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
char get(ValueLayout.OfChar layout, long offset);
/**
* Writes a char at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be written.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the char value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void set(ValueLayout.OfChar layout, long offset, char value);
/**
* Reads a short at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be read.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return a short value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
short get(ValueLayout.OfShort layout, long offset);
/**
* Writes a short at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be written.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the short value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void set(ValueLayout.OfShort layout, long offset, short value);
/**
* Reads an int at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be read.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return an int value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
int get(ValueLayout.OfInt layout, long offset);
/**
* Writes an int at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be written.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the int value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void set(ValueLayout.OfInt layout, long offset, int value);
/**
* Reads a float at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be read.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return a float value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
float get(ValueLayout.OfFloat layout, long offset);
/**
* Writes a float at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be written.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the float value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void set(ValueLayout.OfFloat layout, long offset, float value);
/**
* Reads a long at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be read.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return a long value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
long get(ValueLayout.OfLong layout, long offset);
/**
* Writes a long at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be written.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the long value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void set(ValueLayout.OfLong layout, long offset, long value);
/**
* Reads a double at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be read.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return a double value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
double get(ValueLayout.OfDouble layout, long offset);
/**
* Writes a double at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be written.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the double value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void set(ValueLayout.OfDouble layout, long offset, double value);
/**
* Reads an address at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be read.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return an address value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
MemoryAddress get(ValueLayout.OfAddress layout, long offset);
/**
* Writes an address at the given offset from this address, with the given layout.
* <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.
*
* @param layout the layout of the memory region to be written.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the address value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void set(ValueLayout.OfAddress layout, long offset, Addressable value);
/**
* Reads a char from this address at the given index, scaled by the given layout size.
* <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.
*
* @param layout the layout of the memory region to be read.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @return a char value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
char getAtIndex(ValueLayout.OfChar layout, long index);
/**
* Writes a char to this address at the given index, scaled by the given layout size.
* <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.
*
* @param layout the layout of the memory region to be written.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param value the char value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void setAtIndex(ValueLayout.OfChar layout, long index, char value);
/**
* Reads a short from this address at the given index, scaled by the given layout size.
* <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.
*
* @param layout the layout of the memory region to be read.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @return a short value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
short getAtIndex(ValueLayout.OfShort layout, long index);
/**
* Writes a short to this address at the given index, scaled by the given layout size.
* <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.
*
* @param layout the layout of the memory region to be written.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param value the short value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void setAtIndex(ValueLayout.OfShort layout, long index, short value);
/**
* Reads an int from this address at the given index, scaled by the given layout size.
* <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.
*
* @param layout the layout of the memory region to be read.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @return an int value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
int getAtIndex(ValueLayout.OfInt layout, long index);
/**
* Writes an int to this address at the given index, scaled by the given layout size.
* <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.
*
* @param layout the layout of the memory region to be written.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param value the int value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void setAtIndex(ValueLayout.OfInt layout, long index, int value);
/**
* Reads a float from this address at the given index, scaled by the given layout size.
* <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.
*
* @param layout the layout of the memory region to be read.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @return a float value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
float getAtIndex(ValueLayout.OfFloat layout, long index);
/**
* Writes a float to this address at the given index, scaled by the given layout size.
* <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.
*
* @param layout the layout of the memory region to be written.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param value the float value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void setAtIndex(ValueLayout.OfFloat layout, long index, float value);
/**
* Reads a long from this address at the given index, scaled by the given layout size.
* <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.
*
* @param layout the layout of the memory region to be read.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @return a long value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
long getAtIndex(ValueLayout.OfLong layout, long index);
/**
* Writes a long to this address at the given index, scaled by the given layout size.
* <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.
*
* @param layout the layout of the memory region to be written.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param value the long value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void setAtIndex(ValueLayout.OfLong layout, long index, long value);
/**
* Reads a double from this address at the given index, scaled by the given layout size.
* <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.
*
* @param layout the layout of the memory region to be read.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @return a double value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
double getAtIndex(ValueLayout.OfDouble layout, long index);
/**
* Writes a double to this address at the given index, scaled by the given layout size.
* <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.
*
* @param layout the layout of the memory region to be written.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param value the double value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void setAtIndex(ValueLayout.OfDouble layout, long index, double value);
/**
* Reads an address from this address at the given index, scaled by the given layout size.
* <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.
*
* @param layout the layout of the memory region to be read.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @return an address value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
MemoryAddress getAtIndex(ValueLayout.OfAddress layout, long index);
/**
* Writes an address to this address at the given index, scaled by the given layout size.
* <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.
*
* @param layout the layout of the memory region to be written.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param value the address value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
void setAtIndex(ValueLayout.OfAddress layout, long index, Addressable value);
}

View file

@ -0,0 +1,710 @@
/*
* Copyright (c) 2019, 2022, 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 java.lang.foreign;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.nio.ByteOrder;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.internal.foreign.LayoutPath;
import jdk.internal.foreign.LayoutPath.PathElementImpl.PathKind;
import jdk.internal.foreign.Utils;
import jdk.internal.javac.PreviewFeature;
/**
* A memory layout can be used to describe the contents of a memory segment.
* There are two leaves in the layout hierarchy, <em>value layouts</em>, which are used to represent values of given size and kind (see
* {@link ValueLayout}) and <em>padding layouts</em> 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 (see {@link MemoryLayout#paddingLayout(long)}).
* Some common value layout constants are defined in the {@link ValueLayout} class.
* <p>
* More complex layouts can be derived from simpler ones: a <em>sequence layout</em> denotes a repetition of one or more
* element layout (see {@link SequenceLayout}); a <em>group layout</em> denotes an aggregation of (typically) heterogeneous
* member layouts (see {@link GroupLayout}).
* <p>
* Layouts can be optionally associated with a <em>name</em>. A layout name can be referred to when
* constructing <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>.
* <p>
* Consider the following struct declaration in C:
*
* {@snippet lang=c :
* typedef struct {
* char kind;
* int value;
* } TaggedValues[5];
* }
*
* The above declaration can be modelled using a layout object, as follows:
*
* {@snippet lang=java :
* SequenceLayout taggedValues = MemoryLayout.sequenceLayout(5,
* MemoryLayout.structLayout(
* ValueLayout.JAVA_BYTE.withName("kind"),
* MemoryLayout.paddingLayout(24),
* ValueLayout.JAVA_INT.withName("value")
* )
* ).withName("TaggedValues");
* }
*
* <h2><a id = "layout-align">Size, alignment and byte order</a></h2>
*
* All layouts have a size; layout size for value and padding layouts is always explicitly denoted; this means that a layout description
* always has the same size in bits, regardless of the platform in which it is used. For derived layouts, the size is computed
* as follows:
* <ul>
* <li>for a sequence layout <em>S</em> whose element layout is <em>E</em> and size is <em>L</em>,
* the size of <em>S</em> is that of <em>E</em>, multiplied by <em>L</em></li>
* <li>for a group layout <em>G</em> with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose sizes are
* <em>S1</em>, <em>S2</em>, ... <em>Sn</em>, respectively, the size of <em>G</em> is either <em>S1 + S2 + ... + Sn</em> or
* <em>max(S1, S2, ... Sn)</em> depending on whether the group is a <em>struct</em> or an <em>union</em>, respectively</li>
* </ul>
* <p>
* Furthermore, all layouts feature a <em>natural alignment</em> which can be inferred as follows:
* <ul>
* <li>for a padding layout <em>L</em>, the natural alignment is 1, regardless of its size; that is, in the absence
* of an explicit alignment constraint, a padding layout should not affect the alignment constraint of the group
* layout it is nested into</li>
* <li>for a value layout <em>L</em> whose size is <em>N</em>, the natural alignment of <em>L</em> is <em>N</em></li>
* <li>for a sequence layout <em>S</em> whose element layout is <em>E</em>, the natural alignment of <em>S</em> is that of <em>E</em></li>
* <li>for a group layout <em>G</em> with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose alignments are
* <em>A1</em>, <em>A2</em>, ... <em>An</em>, respectively, the natural alignment of <em>G</em> is <em>max(A1, A2 ... An)</em></li>
* </ul>
* A layout's natural alignment can be overridden if needed (see {@link MemoryLayout#withBitAlignment(long)}), which can be useful to describe
* hyper-aligned layouts.
* <p>
* All value layouts have an <em>explicit</em> byte order (see {@link java.nio.ByteOrder}) which is set when the layout is created.
*
* <h2><a id = "layout-paths">Layout paths</a></h2>
*
* A <em>layout path</em> originates from a <em>root</em> layout (typically a group or a sequence layout) and terminates
* at a layout nested within the root layout - this is the layout <em>selected</em> by the layout path.
* Layout paths are typically expressed as a sequence of one or more {@link PathElement} instances.
* <p>
* Layout paths are for example useful in order to obtain {@linkplain MemoryLayout#bitOffset(PathElement...) offsets} of
* arbitrarily nested layouts inside another layout, to quickly obtain a {@linkplain #varHandle(PathElement...) memory access handle}
* corresponding to the selected layout, or to {@linkplain #select(PathElement...) select} an arbitrarily nested layout inside
* another layout.
* <p>
* Such <em>layout paths</em> can be constructed programmatically using the methods in this class.
* For instance, given the {@code taggedValues} layout instance constructed as above, we can obtain the offset,
* in bits, of the member layout named <code>value</code> in the <em>first</em> sequence element, as follows:
* {@snippet lang=java :
* long valueOffset = taggedValues.bitOffset(PathElement.sequenceElement(0),
* PathElement.groupElement("value")); // yields 32
* }
*
* Similarly, we can select the member layout named {@code value}, as follows:
* {@snippet lang=java :
* MemoryLayout value = taggedValues.select(PathElement.sequenceElement(),
* PathElement.groupElement("value"));
* }
*
* Layout paths can feature one or more <em>free dimensions</em>. For instance, a layout path traversing
* an unspecified sequence element (that is, where one of the path component was obtained with the
* {@link PathElement#sequenceElement()} method) features an additional free dimension, which will have to be bound at runtime.
* This is important when obtaining a {@linkplain MethodHandles#memorySegmentViewVarHandle(ValueLayout) memory segment view var handle}
* from layouts, as in the following code:
*
* {@snippet lang=java :
* VarHandle valueHandle = taggedValues.varHandle(PathElement.sequenceElement(),
* PathElement.groupElement("value"));
* }
*
* Since the layout path constructed in the above example features exactly one free dimension (as it doesn't specify
* <em>which</em> member layout named {@code value} should be selected from the enclosing sequence layout),
* it follows that the var handle {@code valueHandle} will feature an <em>additional</em> {@code long}
* access coordinate.
*
* <p>A layout path with free dimensions can also be used to create an offset-computing method handle, using the
* {@link #bitOffset(PathElement...)} or {@link #byteOffsetHandle(PathElement...)} method. Again, free dimensions are
* translated into {@code long} parameters of the created method handle. The method handle can be used to compute the
* offsets of elements of a sequence at different indices, by supplying these indices when invoking the method handle.
* For instance:
*
* {@snippet lang=java :
* MethodHandle offsetHandle = taggedValues.byteOffsetHandle(PathElement.sequenceElement(),
* PathElement.groupElement("kind"));
* long offset1 = (long) offsetHandle.invokeExact(1L); // 8
* long offset2 = (long) offsetHandle.invokeExact(2L); // 16
* }
*
* @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
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout, GroupLayout, PaddingLayout, ValueLayout {
/**
* {@return the layout size, in bits}
*/
long bitSize();
/**
* {@return the layout size, in bytes}
* @throws UnsupportedOperationException if {@code bitSize()} is not a multiple of 8.
*/
long byteSize();
/**
* {@return the name (if any) associated with this layout}
* @see MemoryLayout#withName(String)
*/
Optional<String> name();
/**
* Returns a memory layout with the same size and alignment constraints as this layout,
* but with the specified name.
*
* @param name the layout name.
* @return a memory layout with the given name.
* @see MemoryLayout#name()
*/
MemoryLayout withName(String name);
/**
* Returns the alignment constraint associated with this layout, expressed in bits. Layout alignment defines a power
* of two {@code A} which is the bit-wise alignment of the layout. If {@code A <= 8} then {@code A/8} is the number of
* bytes that must be aligned for any pointer that correctly points to this layout. Thus:
*
* <ul>
* <li>{@code A=8} means unaligned (in the usual sense), which is common in packets.</li>
* <li>{@code A=64} means word aligned (on LP64), {@code A=32} int aligned, {@code A=16} short aligned, etc.</li>
* <li>{@code A=512} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).</li>
* </ul>
*
* If no explicit alignment constraint was set on this layout (see {@link #withBitAlignment(long)}),
* then this method returns the <a href="#layout-align">natural alignment</a> constraint (in bits) associated with this layout.
*
* @return the layout alignment constraint, in bits.
*/
long bitAlignment();
/**
* Returns the alignment constraint associated with this layout, expressed in bytes. Layout alignment defines a power
* of two {@code A} which is the byte-wise alignment of the layout, where {@code A} is the number of bytes that must be aligned
* for any pointer that correctly points to this layout. Thus:
*
* <ul>
* <li>{@code A=1} means unaligned (in the usual sense), which is common in packets.</li>
* <li>{@code A=8} means word aligned (on LP64), {@code A=4} int aligned, {@code A=2} short aligned, etc.</li>
* <li>{@code A=64} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).</li>
* </ul>
*
* If no explicit alignment constraint was set on this layout (see {@link #withBitAlignment(long)}),
* then this method returns the <a href="#layout-align">natural alignment</a> constraint (in bytes) associated with this layout.
*
* @return the layout alignment constraint, in bytes.
* @throws UnsupportedOperationException if {@code bitAlignment()} is not a multiple of 8.
*/
default long byteAlignment() {
return Utils.bitsToBytesOrThrow(bitAlignment(),
() -> new UnsupportedOperationException("Cannot compute byte alignment; bit alignment is not a multiple of 8"));
}
/**
* Returns a memory layout with the same size and name as this layout,
* but with the specified alignment constraints (in bits).
*
* @param bitAlignment the layout alignment constraint, expressed in bits.
* @return a memory layout with the given alignment constraints.
* @throws IllegalArgumentException if {@code bitAlignment} is not a power of two, or if it's less than 8.
*/
MemoryLayout withBitAlignment(long bitAlignment);
/**
* Computes the offset, in bits, of the layout selected by the given layout path, where the path is considered rooted in this
* layout.
*
* @param elements the layout path elements.
* @return The offset, in bits, of the layout selected by the layout path in {@code elements}.
* @throws IllegalArgumentException if the layout path does not select any layout nested in this layout, or if the
* layout path contains one or more path elements that select multiple sequence element indices
* (see {@link PathElement#sequenceElement()} and {@link PathElement#sequenceElement(long, long)}).
* @throws NullPointerException if either {@code elements == null}, or if any of the elements
* in {@code elements} is {@code null}.
*/
default long bitOffset(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this), LayoutPath::offset,
EnumSet.of(PathKind.SEQUENCE_ELEMENT, PathKind.SEQUENCE_RANGE), elements);
}
/**
* Creates a method handle that can be used to compute the offset, in bits, of the layout selected
* by the given layout path, where the path is considered rooted in this layout.
*
* <p>The returned method handle has a return type of {@code long}, and features as many {@code long}
* parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
* where the order of the parameters corresponds to the order of the path elements.
* The returned method handle can be used to compute a layout offset similar to {@link #bitOffset(PathElement...)},
* but where some sequence indices are specified only when invoking the method handle.
*
* <p>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)
* }</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.
*
* @param elements the layout path elements.
* @return a method handle that can be used to compute the bit offset of the layout element
* specified by the given layout path elements, when supplied with the missing sequence element indices.
* @throws IllegalArgumentException if the layout path contains one or more path elements that select
* multiple sequence element indices (see {@link PathElement#sequenceElement(long, long)}).
*/
default MethodHandle bitOffsetHandle(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this), LayoutPath::offsetHandle,
EnumSet.of(PathKind.SEQUENCE_RANGE), elements);
}
/**
* Computes the offset, in bytes, of the layout selected by the given layout path, where the path is considered rooted in this
* layout.
*
* @param elements the layout path elements.
* @return The offset, in bytes, of the layout selected by the layout path in {@code elements}.
* @throws IllegalArgumentException if the layout path does not select any layout nested in this layout, or if the
* layout path contains one or more path elements that select multiple sequence element indices
* (see {@link PathElement#sequenceElement()} and {@link PathElement#sequenceElement(long, long)}).
* @throws UnsupportedOperationException if {@code bitOffset(elements)} is not a multiple of 8.
* @throws NullPointerException if either {@code elements == null}, or if any of the elements
* in {@code elements} is {@code null}.
*/
default long byteOffset(PathElement... elements) {
return Utils.bitsToBytesOrThrow(bitOffset(elements), Utils.bitsToBytesThrowOffset);
}
/**
* Creates a method handle that can be used to compute the offset, in bytes, of the layout selected
* by the given layout path, where the path is considered rooted in this layout.
*
* <p>The returned method handle has a return type of {@code long}, and features as many {@code long}
* parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
* where the order of the parameters corresponds to the order of the path elements.
* The returned method handle can be used to compute a layout offset similar to {@link #byteOffset(PathElement...)},
* but where some sequence indices are specified only when invoking the method handle.
*
* <p>The final offset returned by the method handle is computed as follows:
*
* <blockquote><pre>{@code
* bitOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
* offset = bitOffset / 8
* }</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.
*
* <p>The method handle will throw an {@link UnsupportedOperationException} if the computed
* offset in bits is not a multiple of 8.
*
* @param elements the layout path elements.
* @return a method handle that can be used to compute the byte offset of the layout element
* specified by the given layout path elements, when supplied with the missing sequence element indices.
* @throws IllegalArgumentException if the layout path contains one or more path elements that select
* multiple sequence element indices (see {@link PathElement#sequenceElement(long, long)}).
*/
default MethodHandle byteOffsetHandle(PathElement... elements) {
MethodHandle mh = bitOffsetHandle(elements);
mh = MethodHandles.filterReturnValue(mh, Utils.MH_bitsToBytesOrThrowForOffset);
return mh;
}
/**
* Creates an access var handle that can be used to dereference memory at the layout selected by the given layout path,
* where the path is considered rooted in this layout.
* <p>
* The final memory location accessed by the returned var handle can be computed as follows:
*
* <blockquote><pre>{@code
* address = base + offset
* }</pre></blockquote>
*
* where {@code base} denotes the base address expressed by the {@link MemorySegment} access coordinate
* (see {@link MemorySegment#address()} and {@link MemoryAddress#toRawLongValue()}) and {@code offset}
* 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.
*
* @apiNote the resulting var handle will feature an additional {@code long} access coordinate for every
* unspecified sequence access component contained in this layout path. Moreover, the resulting var handle
* features certain <em>access mode restrictions</em>, which are common to all memory segment view handles.
*
* @param elements the layout path elements.
* @return a var handle which can be used to dereference memory at the (possibly nested) layout selected by the layout path in {@code elements}.
* @throws UnsupportedOperationException if the layout path has one or more elements with incompatible alignment constraints.
* @throws IllegalArgumentException if the layout path in {@code elements} does not select a value layout (see {@link ValueLayout}).
* @see MethodHandles#memorySegmentViewVarHandle(ValueLayout)
*/
default VarHandle varHandle(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this), LayoutPath::dereferenceHandle,
Set.of(), elements);
}
/**
* Creates a method handle which, given a memory segment, returns a {@linkplain MemorySegment#asSlice(long,long) slice}
* corresponding to the layout selected by the given layout path, where the path is considered rooted in this layout.
*
* <p>The returned method handle has a return type of {@code MemorySegment}, features a {@code MemorySegment}
* parameter as leading parameter representing the segment to be sliced, and features as many trailing {@code long}
* parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
* where the order of the parameters corresponds to the order of the path elements.
* The returned method handle can be used to create a slice similar to using {@link MemorySegment#asSlice(long, long)},
* but where the offset argument is dynamically compute based on indices specified when invoking the method handle.
*
* <p>The offset of the returned segment is computed as follows:
*
* <blockquote><pre>{@code
* bitOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
* offset = bitOffset / 8
* }</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.
*
* <p>After the offset is computed, the returned segment is created as if by calling:
* {@snippet lang=java :
* segment.asSlice(offset, layout.byteSize());
* }
*
* where {@code segment} is the segment to be sliced, and where {@code layout} is the layout selected by the given
* layout path, as per {@link MemoryLayout#select(PathElement...)}.
*
* <p>The method handle will throw an {@link UnsupportedOperationException} if the computed
* offset in bits is not a multiple of 8.
*
* @param elements the layout path elements.
* @return a method handle which can be used to create a slice of the selected layout element, given a segment.
* @throws UnsupportedOperationException if the size of the selected layout in bits is not a multiple of 8.
*/
default MethodHandle sliceHandle(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this), LayoutPath::sliceHandle,
Set.of(), elements);
}
/**
* Selects the layout from a path rooted in this layout.
*
* @param elements the layout path elements.
* @return the layout selected by the layout path in {@code elements}.
* @throws IllegalArgumentException if the layout path does not select any layout nested in this layout,
* or if the layout path contains one or more path elements that select one or more sequence element indices
* (see {@link PathElement#sequenceElement(long)} and {@link PathElement#sequenceElement(long, long)}).
*/
default MemoryLayout select(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this), LayoutPath::layout,
EnumSet.of(PathKind.SEQUENCE_ELEMENT_INDEX, PathKind.SEQUENCE_RANGE), elements);
}
private static <Z> Z computePathOp(LayoutPath path, Function<LayoutPath, Z> finalizer,
Set<PathKind> badKinds, PathElement... elements) {
Objects.requireNonNull(elements);
for (PathElement e : elements) {
LayoutPath.PathElementImpl pathElem = (LayoutPath.PathElementImpl)Objects.requireNonNull(e);
if (badKinds.contains(pathElem.kind())) {
throw new IllegalArgumentException(String.format("Invalid %s selection in layout path", pathElem.kind().description()));
}
path = pathElem.apply(path);
}
return finalizer.apply(path);
}
/**
* {@return true, if this layout is a padding layout}
*/
boolean isPadding();
/**
* An element in a <a href="MemoryLayout.html#layout-paths"><em>layout path</em></a>. There
* are two kinds of path elements: <em>group path elements</em> and <em>sequence path elements</em>. Group
* path elements are used to select a named member layout within a {@link GroupLayout}. Sequence
* path elements are used to select a sequence element layout within a {@link SequenceLayout}; selection
* of sequence element layout can be <em>explicit</em> (see {@link PathElement#sequenceElement(long)}) or
* <em>implicit</em> (see {@link PathElement#sequenceElement()}). When a path uses one or more implicit
* sequence path elements, it acquires additional <em>free dimensions</em>.
*
* @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
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
sealed interface PathElement permits LayoutPath.PathElementImpl {
/**
* Returns a path element which selects a member layout with the given name in a group layout.
* The path element returned by this method does not alter the number of free dimensions of any path
* that is combined with such element.
*
* @implSpec in case multiple group elements with a matching name exist, the path element returned by this
* method will select the first one; that is, the group element with the lowest offset from current path is selected.
*
* @param name the name of the group element to be selected.
* @return a path element which selects the group element with the given name.
*/
static PathElement groupElement(String name) {
Objects.requireNonNull(name);
return new LayoutPath.PathElementImpl(PathKind.GROUP_ELEMENT,
path -> path.groupElement(name));
}
/**
* Returns a path element which selects the element layout at the specified position in a sequence layout.
* The path element returned by this method does not alter the number of free dimensions of any path
* that is combined with such element.
*
* @param index the index of the sequence element to be selected.
* @return a path element which selects the sequence element layout with the given index.
* @throws IllegalArgumentException if {@code index < 0}.
*/
static PathElement sequenceElement(long index) {
if (index < 0) {
throw new IllegalArgumentException("Index must be positive: " + index);
}
return new LayoutPath.PathElementImpl(PathKind.SEQUENCE_ELEMENT_INDEX,
path -> path.sequenceElement(index));
}
/**
* Returns a path element which selects the element layout in a <em>range</em> of positions in a sequence layout.
* The range is expressed as a pair of starting index (inclusive) {@code S} and step factor (which can also be negative)
* {@code F}.
* If a path with free dimensions {@code n} is combined with the path element returned by this method,
* the number of free dimensions of the resulting path will be {@code 1 + n}. If the free dimension associated
* with this path is bound by an index {@code I}, the resulting accessed offset can be obtained with the following
* formula:
*
* <blockquote><pre>{@code
* E * (S + I * F)
* }</pre></blockquote>
*
* where {@code E} is the size (in bytes) of the sequence element layout.
*
* @param start the index of the first sequence element to be selected.
* @param step the step factor at which subsequence sequence elements are to be selected.
* @return a path element which selects the sequence element layout with the given index.
* @throws IllegalArgumentException if {@code start < 0}, or {@code step == 0}.
*/
static PathElement sequenceElement(long start, long step) {
if (start < 0) {
throw new IllegalArgumentException("Start index must be positive: " + start);
}
if (step == 0) {
throw new IllegalArgumentException("Step must be != 0: " + step);
}
return new LayoutPath.PathElementImpl(PathKind.SEQUENCE_RANGE,
path -> path.sequenceElement(start, step));
}
/**
* Returns a path element which selects an unspecified element layout in a sequence layout.
* If a path with free dimensions {@code n} is combined with the path element returned by this method,
* the number of free dimensions of the resulting path will be {@code 1 + n}.
*
* @return a path element which selects an unspecified sequence element layout.
*/
static PathElement sequenceElement() {
return new LayoutPath.PathElementImpl(PathKind.SEQUENCE_ELEMENT,
LayoutPath::sequenceElement);
}
}
/**
* Compares the specified object with this layout for equality. Returns {@code true} if and only if the specified
* object is also a layout, and it is equal to this layout. Two layouts are considered equal if they are of
* the same kind, have the same size, name and alignment constraints. Furthermore, depending on the layout kind, additional
* conditions must be satisfied:
* <ul>
* <li>two value layouts are considered equal if they have the same byte order (see {@link ValueLayout#order()})</li>
* <li>two sequence layouts are considered equal if they have the same element count (see {@link SequenceLayout#elementCount()}), and
* if their element layouts (see {@link SequenceLayout#elementLayout()}) are also equal</li>
* <li>two group layouts are considered equal if they are of the same kind (see {@link GroupLayout#isStruct()},
* {@link GroupLayout#isUnion()}) and if their member layouts (see {@link GroupLayout#memberLayouts()}) are also equal</li>
* </ul>
*
* @param that the object to be compared for equality with this layout.
* @return {@code true} if the specified object is equal to this layout.
*/
boolean equals(Object that);
/**
* {@return the hash code value for this layout}
*/
int hashCode();
/**
* {@return the string representation of this layout}
*/
@Override
String toString();
/**
* Creates a padding layout with the given size.
*
* @param size the padding size in bits.
* @return the new selector layout.
* @throws IllegalArgumentException if {@code size <= 0}.
*/
static MemoryLayout paddingLayout(long size) {
AbstractLayout.checkSize(size);
return new PaddingLayout(size);
}
/**
* Creates a value layout of given Java carrier and byte order. The type of resulting value layout is determined
* by the carrier provided:
* <ul>
* <li>{@link ValueLayout.OfBoolean}, for {@code boolean.class}</li>
* <li>{@link ValueLayout.OfByte}, for {@code byte.class}</li>
* <li>{@link ValueLayout.OfShort}, for {@code short.class}</li>
* <li>{@link ValueLayout.OfChar}, for {@code char.class}</li>
* <li>{@link ValueLayout.OfInt}, for {@code int.class}</li>
* <li>{@link ValueLayout.OfFloat}, for {@code float.class}</li>
* <li>{@link ValueLayout.OfLong}, for {@code long.class}</li>
* <li>{@link ValueLayout.OfDouble}, for {@code double.class}</li>
* <li>{@link ValueLayout.OfAddress}, for {@code MemoryAddress.class}</li>
* </ul>
* @param carrier the value layout carrier.
* @param order the value layout's byte order.
* @return a value layout with the given Java carrier and byte-order.
* @throws IllegalArgumentException if the carrier type is not supported.
*/
static ValueLayout valueLayout(Class<?> carrier, ByteOrder order) {
Objects.requireNonNull(carrier);
Objects.requireNonNull(order);
if (carrier == boolean.class) {
return new ValueLayout.OfBoolean(order);
} else if (carrier == char.class) {
return new ValueLayout.OfChar(order);
} else if (carrier == byte.class) {
return new ValueLayout.OfByte(order);
} else if (carrier == short.class) {
return new ValueLayout.OfShort(order);
} else if (carrier == int.class) {
return new ValueLayout.OfInt(order);
} else if (carrier == float.class) {
return new ValueLayout.OfFloat(order);
} else if (carrier == long.class) {
return new ValueLayout.OfLong(order);
} else if (carrier == double.class) {
return new ValueLayout.OfDouble(order);
} else if (carrier == MemoryAddress.class) {
return new ValueLayout.OfAddress(order);
} else {
throw new IllegalArgumentException("Unsupported carrier: " + carrier.getName());
}
}
/**
* Creates a sequence layout with the given element layout and element count. If the element count has the
* special value {@code -1}, the element count is inferred to be the biggest possible count such that
* the sequence layout size does not overflow, using the following formula:
*
* <blockquote><pre>{@code
* inferredElementCount = Long.MAX_VALUE / elementLayout.bitSize();
* }</pre></blockquote>
*
* @param elementCount the sequence element count; if set to {@code -1}, the sequence element count is inferred.
* @param elementLayout the sequence element layout.
* @return the new sequence layout with the given element layout and size.
* @throws IllegalArgumentException if {@code elementCount < -1}.
* @throws IllegalArgumentException if {@code elementCount != -1} and the computation {@code elementCount * elementLayout.bitSize()} overflows.
*/
static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) {
if (elementCount == -1) {
// inferred element count
long inferredElementCount = Long.MAX_VALUE / elementLayout.bitSize();
return new SequenceLayout(inferredElementCount, elementLayout);
} else {
// explicit element count
AbstractLayout.checkSize(elementCount, true);
return wrapOverflow(() ->
new SequenceLayout(elementCount, Objects.requireNonNull(elementLayout)));
}
}
/**
* Creates a struct layout with the given member layouts.
*
* @param elements The member layouts of the struct layout.
* @return a struct layout with the given member layouts.
* @throws IllegalArgumentException if the sum of the {@linkplain #bitSize() bit sizes} of the member layouts
* overflows.
*/
static GroupLayout structLayout(MemoryLayout... elements) {
Objects.requireNonNull(elements);
return wrapOverflow(() ->
new GroupLayout(GroupLayout.Kind.STRUCT,
Stream.of(elements)
.map(Objects::requireNonNull)
.collect(Collectors.toList())));
}
/**
* Creates a union layout with the given member layouts.
*
* @param elements The member layouts of the union layout.
* @return a union layout with the given member layouts.
*/
static GroupLayout unionLayout(MemoryLayout... elements) {
Objects.requireNonNull(elements);
return new GroupLayout(GroupLayout.Kind.UNION,
Stream.of(elements)
.map(Objects::requireNonNull)
.collect(Collectors.toList()));
}
private static <L extends MemoryLayout> L wrapOverflow(Supplier<L> layoutSupplier) {
try {
return layoutSupplier.get();
} catch (ArithmeticException ex) {
throw new IllegalArgumentException("Layout size exceeds Long.MAX_VALUE");
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,282 @@
/*
* Copyright (c) 2021, 2022, 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 java.lang.foreign;
import java.lang.ref.Cleaner;
import java.util.Objects;
import jdk.internal.foreign.MemorySessionImpl;
import jdk.internal.javac.PreviewFeature;
/**
* A memory session manages the lifecycle of one or more resources. Resources (e.g. {@link MemorySegment}) associated
* with a memory session can only be accessed while the memory session is {@linkplain #isAlive() alive},
* and by the {@linkplain #ownerThread() thread} associated with the memory session (if any).
* <p>
* Memory sessions can be closed. When a memory session is closed, it is no longer {@linkplain #isAlive() alive},
* and subsequent operations on resources associated with that session (e.g. attempting to access a {@link MemorySegment} instance)
* will fail with {@link IllegalStateException}.
* <p>
* A memory session is associated with one or more {@linkplain #addCloseAction(Runnable) close actions}. Close actions
* can be used to specify the cleanup code that must run when a given resource (or set of resources) is no longer in use.
* When a memory session is closed, the {@linkplain #addCloseAction(Runnable) close actions}
* associated with that session are executed (in unspecified order). For instance, closing the memory session associated with
* one or more {@linkplain MemorySegment#allocateNative(long, long, MemorySession) native memory segments} results in releasing
* the off-heap memory associated with said segments.
* <p>
* The {@linkplain #global() global session} is a memory session that cannot be closed.
* As a result, resources associated with the global session are never released. Examples of resources associated with
* the global memory session are {@linkplain MemorySegment#ofArray(int[]) heap segments}.
*
* <h2><a id = "thread-confinement">Thread confinement</a></h2>
*
* Memory sessions can be divided into two categories: <em>thread-confined</em> memory sessions, and <em>shared</em>
* memory sessions.
* <p>
* Confined memory sessions, support strong thread-confinement guarantees. Upon creation,
* they are assigned an {@linkplain #ownerThread() owner thread}, typically the thread which initiated the creation operation.
* After creating a confined memory session, only the owner thread will be allowed to directly manipulate the resources
* associated with this memory session. Any attempt to perform resource access from a thread other than the
* owner thread will fail with {@link IllegalStateException}.
* <p>
* Shared memory sessions, on the other hand, have no owner thread; as such, resources associated with shared memory sessions
* can be accessed by multiple threads. This might be useful when multiple threads need to access the same resource concurrently
* (e.g. in the case of parallel processing).
*
* <h2>Closeable memory sessions</h2>
*
* When a session is associated with off-heap resources, it is often desirable for said resources to be released in a timely fashion,
* rather than waiting for the session to be deemed <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>
* by the garbage collector. In this scenario, a client might consider using a {@linkplain #isCloseable() <em>closeable</em>} memory session.
* Closeable memory sessions are memory sessions that can be {@linkplain MemorySession#close() closed} deterministically, as demonstrated
* in the following example:
*
* {@snippet lang=java :
* try (MemorySession session = MemorySession.openConfined()) {
* MemorySegment segment1 = MemorySegment.allocateNative(100);
* MemorySegment segment1 = MemorySegment.allocateNative(200);
* ...
* } // all memory released here
* }
*
* The above code creates a confined, closeable session. Then it allocates two segments associated with that session.
* When the session is {@linkplain #close() closed} (above, this is done implicitly, using the <em>try-with-resources construct</em>),
* all memory allocated within the session will be released
* <p>
* Closeable memory sessions, while powerful, must be used with caution. Closeable memory sessions must be closed
* when no longer in use, either explicitly (by calling the {@link #close} method), or implicitly (by wrapping the use of
* a closeable memory session in a <em>try-with-resources construct</em>). A failure to do so might result in memory leaks.
* To mitigate this problem, closeable memory sessions can be associated with a {@link Cleaner} instance,
* so that they are also closed automatically, once the session instance becomes <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>.
* This can be useful to allow for predictable, deterministic resource deallocation, while still preventing accidental
* native memory leaks. In case a client closes a memory session managed by a cleaner, no further action will be taken when
* the session becomes unreachable; that is, {@linkplain #addCloseAction(Runnable) close actions} associated with a
* memory session, whether managed or not, are called <em>exactly once</em>.
*
* <h2>Non-closeable views</h2>
*
* There are situations in which it might not be desirable for a memory session to be reachable from one or
* more resources associated with it. For instance, an API might create a private memory session, and allocate
* a memory segment, and then expose one or more slices of this segment to its clients. Since the API's memory session
* would be reachable from the slices (using the {@link MemorySegment#session()} accessor), it might be possible for
* clients to compromise the API (e.g. by closing the session prematurely). To avoid leaking private memory sessions
* to untrusted clients, an API can instead return segments based on a non-closeable view of the session it created, as follows:
*
* {@snippet lang=java :
* MemorySession session = MemorySession.openConfined();
* MemorySession nonCloseableSession = session.asNonCloseable();
* MemorySegment segment = MemorySegment.allocateNative(100, nonCloseableSession);
* segment.session().close(); // throws
* session.close(); //ok
* }
*
* In other words, only the owner of the original {@code session} object can close the session. External clients can only
* access the non-closeable session, and have no access to the underlying API session.
*
* @implSpec
* Implementations of this interface are thread-safe.
*
* @see MemorySegment
* @see SymbolLookup
* @see Linker
* @see VaList
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public sealed interface MemorySession extends AutoCloseable, SegmentAllocator permits MemorySessionImpl, MemorySessionImpl.NonCloseableView {
/**
* {@return {@code true}, if this memory session is alive}
*/
boolean isAlive();
/**
* {@return {@code true}, if this session is a closeable memory session}.
*/
boolean isCloseable();
/**
* {@return the owner thread associated with this memory session, or {@code null} if this session is shared
* across multiple threads}
*/
Thread ownerThread();
/**
* Runs a critical action while this memory session is kept alive.
* @param action the action to be run.
*/
void whileAlive(Runnable action);
/**
* Adds a custom cleanup action which will be executed when the memory session is closed.
* The order in which custom cleanup actions are invoked once the memory session is closed is unspecified.
* @apiNote The provided action should not keep a strong reference to this memory session, so that implicitly
* closed sessions can be handled correctly by a {@link Cleaner} instance.
* @param runnable the custom cleanup action to be associated with this memory session.
* @throws IllegalStateException if this memory session is not {@linkplain #isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain #ownerThread() owning} this memory session.
*/
void addCloseAction(Runnable runnable);
/**
* Closes this memory session. If this operation completes without exceptions, this session
* will be marked as <em>not alive</em>, the {@linkplain #addCloseAction(Runnable) close actions} associated
* with this session will be executed, and all the resources associated with this session will be released.
*
* @apiNote This operation is not idempotent; that is, closing an already closed memory session <em>always</em> results in an
* exception being thrown. This reflects a deliberate design choice: memory session state transitions should be
* manifest in the client code; a failure in any of these transitions reveals a bug in the underlying application
* logic.
*
* @see MemorySession#isAlive()
*
* @throws IllegalStateException if this memory session is not {@linkplain #isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain #ownerThread() owning} this memory session.
* @throws IllegalStateException if this session is {@linkplain #whileAlive(Runnable) kept alive} by another client.
* @throws UnsupportedOperationException if this memory session is not {@linkplain #isCloseable() closeable}.
*/
void close();
/**
* Returns a non-closeable view of this memory session. If this session is {@linkplain #isCloseable() non-closeable},
* this session is returned. Otherwise, this method returns a non-closeable view of this memory session.
* @apiNote a non-closeable view of a memory session {@code S} keeps {@code S} reachable. As such, {@code S}
* cannot be closed implicitly (e.g. by a {@link Cleaner}) as long as one or more non-closeable views of {@code S}
* are reachable.
* @return a non-closeable view of this memory session.
*/
MemorySession asNonCloseable();
/**
* Compares the specified object with this memory session for equality. Returns {@code true} if and only if the specified
* object is also a memory session, and it refers to the same memory session as this memory session.
* {@linkplain #asNonCloseable() A non-closeable view} {@code V} of a memory session {@code S} is considered
* equal to {@code S}.
*
* @param that the object to be compared for equality with this memory session.
* @return {@code true} if the specified object is equal to this memory session.
*/
@Override
boolean equals(Object that);
/**
* {@return the hash code value for this memory session}
*/
@Override
int hashCode();
/**
* Allocates a native segment, using this session. Equivalent to the following code:
* {@snippet lang=java :
* MemorySegment.allocateNative(size, align, this);
* }
*
* @throws IllegalStateException if this memory session is not {@linkplain #isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain #ownerThread() owning} this memory session.
* @return a new native segment, associated with this session.
*/
@Override
default MemorySegment allocate(long bytesSize, long bytesAlignment) {
return MemorySegment.allocateNative(bytesSize, bytesAlignment, this);
}
/**
* Creates a closeable confined memory session.
* @return a new closeable confined memory session.
*/
static MemorySession openConfined() {
return MemorySessionImpl.createConfined(Thread.currentThread(), null);
}
/**
* Creates a closeable confined memory session, managed by the provided cleaner instance.
* @param cleaner the cleaner to be associated with the returned memory session.
* @return a new closeable confined memory session, managed by {@code cleaner}.
*/
static MemorySession openConfined(Cleaner cleaner) {
Objects.requireNonNull(cleaner);
return MemorySessionImpl.createConfined(Thread.currentThread(), cleaner);
}
/**
* Creates a closeable shared memory session.
* @return a new closeable shared memory session.
*/
static MemorySession openShared() {
return MemorySessionImpl.createShared(null);
}
/**
* Creates a closeable shared memory session, managed by the provided cleaner instance.
* @param cleaner the cleaner to be associated with the returned memory session.
* @return a new closeable shared memory session, managed by {@code cleaner}.
*/
static MemorySession openShared(Cleaner cleaner) {
Objects.requireNonNull(cleaner);
return MemorySessionImpl.createShared(cleaner);
}
/**
* Creates a non-closeable shared memory session, managed by a private {@link Cleaner} instance.
* Equivalent to (but likely more efficient than) the following code:
* {@snippet lang=java :
* openShared(Cleaner.create()).asNonCloseable();
* }
* @return a non-closeable shared memory session, managed by a private {@link Cleaner} instance.
*/
static MemorySession openImplicit() {
return MemorySessionImpl.createImplicit();
}
/**
* Returns the global memory session.
* @return the global memory session.
*/
static MemorySession global() {
return MemorySessionImpl.GLOBAL;
}
}

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 2019, 2022, 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 java.lang.foreign;
import java.util.Objects;
import java.util.Optional;
/**
* A padding layout. A padding layout specifies the size of extra space which is typically not accessed by applications,
* and is typically used for aligning member layouts around word boundaries.
*
* @implSpec
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*/
/* package-private */ final class PaddingLayout extends AbstractLayout implements MemoryLayout {
PaddingLayout(long size) {
this(size, 1, Optional.empty());
}
PaddingLayout(long size, long alignment, Optional<String> name) {
super(size, alignment, name);
}
@Override
public String toString() {
return decorateLayoutString("x" + bitSize());
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!super.equals(other)) {
return false;
}
if (!(other instanceof PaddingLayout p)) {
return false;
}
return bitSize() == p.bitSize();
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), bitSize());
}
@Override
PaddingLayout dup(long alignment, Optional<String> name) {
return new PaddingLayout(bitSize(), alignment, name);
}
@Override
public boolean hasNaturalAlignment() {
return true;
}
//hack: the declarations below are to make javadoc happy; we could have used generics in AbstractLayout
//but that causes issues with javadoc, see JDK-8224052
/**
* {@inheritDoc}
*/
@Override
public PaddingLayout withName(String name) {
return (PaddingLayout)super.withName(name);
}
/**
* {@inheritDoc}
*/
@Override
public PaddingLayout withBitAlignment(long alignmentBits) {
return (PaddingLayout)super.withBitAlignment(alignmentBits);
}
}

View file

@ -0,0 +1,459 @@
/*
* Copyright (c) 2021, 2022, 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 java.lang.foreign;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Array;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.function.Function;
import jdk.internal.foreign.AbstractMemorySegmentImpl;
import jdk.internal.foreign.ArenaAllocator;
import jdk.internal.foreign.Utils;
import jdk.internal.javac.PreviewFeature;
/**
* An object that may be used to allocate {@linkplain MemorySegment memory segments}. Clients implementing this interface
* must implement the {@link #allocate(long, long)} method. This interface defines several default methods
* which can be useful to create segments from several kinds of Java values such as primitives and arrays.
* This interface is a {@linkplain FunctionalInterface functional interface}: clients can easily obtain a new segment allocator
* by using either a lambda expression or a method reference.
* <p>
* This interface also defines factories for commonly used allocators:
* <ul>
* <li>{@link #newNativeArena(MemorySession)} creates a more efficient arena-style allocator, where off-heap memory
* is allocated in bigger blocks, which are then sliced accordingly to fit allocation requests;</li>
* <li>{@link #implicitAllocator()} obtains an allocator which allocates native memory segment in independent,
* {@linkplain MemorySession#openImplicit() implicit memory sessions}; and</li>
* <li>{@link #prefixAllocator(MemorySegment)} obtains an allocator which wraps a segment (either on-heap or off-heap)
* and recycles its content upon each new allocation request.</li>
* </ul>
* <p>
* Passing a segment allocator to an API can be especially useful in circumstances where a client wants to communicate <em>where</em>
* the results of a certain operation (performed by the API) should be stored, as a memory segment. For instance,
* {@linkplain Linker#downcallHandle(FunctionDescriptor) downcall method handles} can accept an additional
* {@link SegmentAllocator} parameter if the underlying foreign function is known to return a struct by-value. Effectively,
* the allocator parameter tells the linker runtime where to store the return value of the foreign function.
*/
@FunctionalInterface
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public interface SegmentAllocator {
/**
* Converts a Java string into a UTF-8 encoded, null-terminated C string,
* 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
* {@link java.nio.charset.CharsetEncoder} class should be used when more
* control over the encoding process is required.
*
* @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.
* @return a new native memory segment containing the converted C string.
*/
default MemorySegment allocateUtf8String(String str) {
Objects.requireNonNull(str);
return Utils.toCString(str.getBytes(StandardCharsets.UTF_8), this);
}
/**
* Allocates a memory segment with the given layout and initializes it with the given byte value.
* @implSpec the default implementation for this method calls {@code this.allocate(layout)}.
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set on the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocate(ValueLayout.OfByte layout, byte value) {
Objects.requireNonNull(layout);
VarHandle handle = layout.varHandle();
MemorySegment addr = allocate(layout);
handle.set(addr, value);
return addr;
}
/**
* Allocates a memory segment with the given layout and initializes it with the given char value.
* @implSpec the default implementation for this method calls {@code this.allocate(layout)}.
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set on the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocate(ValueLayout.OfChar layout, char value) {
Objects.requireNonNull(layout);
VarHandle handle = layout.varHandle();
MemorySegment addr = allocate(layout);
handle.set(addr, value);
return addr;
}
/**
* Allocates a memory segment with the given layout and initializes it with the given short value.
* @implSpec the default implementation for this method calls {@code this.allocate(layout)}.
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set on the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocate(ValueLayout.OfShort layout, short value) {
Objects.requireNonNull(layout);
VarHandle handle = layout.varHandle();
MemorySegment addr = allocate(layout);
handle.set(addr, value);
return addr;
}
/**
* Allocates a memory segment with the given layout and initializes it with the given int value.
* @implSpec the default implementation for this method calls {@code this.allocate(layout)}.
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set on the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocate(ValueLayout.OfInt layout, int value) {
Objects.requireNonNull(layout);
VarHandle handle = layout.varHandle();
MemorySegment addr = allocate(layout);
handle.set(addr, value);
return addr;
}
/**
* Allocates a memory segment with the given layout and initializes it with the given float value.
* @implSpec the default implementation for this method calls {@code this.allocate(layout)}.
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set on the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocate(ValueLayout.OfFloat layout, float value) {
Objects.requireNonNull(layout);
VarHandle handle = layout.varHandle();
MemorySegment addr = allocate(layout);
handle.set(addr, value);
return addr;
}
/**
* Allocates a memory segment with the given layout and initializes it with the given long value.
* @implSpec the default implementation for this method calls {@code this.allocate(layout)}.
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set on the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocate(ValueLayout.OfLong layout, long value) {
Objects.requireNonNull(layout);
VarHandle handle = layout.varHandle();
MemorySegment addr = allocate(layout);
handle.set(addr, value);
return addr;
}
/**
* Allocates a memory segment with the given layout and initializes it with the given double value.
* @implSpec the default implementation for this method calls {@code this.allocate(layout)}.
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set on the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocate(ValueLayout.OfDouble layout, double value) {
Objects.requireNonNull(layout);
VarHandle handle = layout.varHandle();
MemorySegment addr = allocate(layout);
handle.set(addr, value);
return addr;
}
/**
* Allocates a memory segment with the given layout and initializes it with the given address value.
* The address value might be narrowed according to the platform address size (see {@link ValueLayout#ADDRESS}).
* @implSpec the default implementation for this method calls {@code this.allocate(layout)}.
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set on the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocate(ValueLayout.OfAddress layout, Addressable value) {
Objects.requireNonNull(value);
Objects.requireNonNull(layout);
MemorySegment segment = allocate(layout);
layout.varHandle().set(segment, value.address());
return segment;
}
/**
* Allocates a memory segment with the given layout and initializes it with the given byte elements.
* @implSpec the default implementation for this method calls {@code this.allocateArray(layout, array.length)}.
* @param elementLayout the element layout of the array to be allocated.
* @param elements the byte elements to be copied to the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocateArray(ValueLayout.OfByte elementLayout, byte... elements) {
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
}
/**
* Allocates a memory segment with the given layout and initializes it with the given short elements.
* @implSpec the default implementation for this method calls {@code this.allocateArray(layout, 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.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocateArray(ValueLayout.OfShort elementLayout, short... elements) {
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
}
/**
* Allocates a memory segment with the given layout and initializes it with the given char elements.
* @implSpec the default implementation for this method calls {@code this.allocateArray(layout, array.length)}.
* @param elementLayout the element layout of the array to be allocated.
* @param elements the char elements to be copied to the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocateArray(ValueLayout.OfChar elementLayout, char... elements) {
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
}
/**
* Allocates a memory segment with the given layout and initializes it with the given int elements.
* @implSpec the default implementation for this method calls {@code this.allocateArray(layout, array.length)}.
* @param elementLayout the element layout of the array to be allocated.
* @param elements the int elements to be copied to the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocateArray(ValueLayout.OfInt elementLayout, int... elements) {
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
}
/**
* Allocates a memory segment with the given layout and initializes it with the given float elements.
* @implSpec the default implementation for this method calls {@code this.allocateArray(layout, array.length)}.
* @param elementLayout the element layout of the array to be allocated.
* @param elements the float elements to be copied to the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocateArray(ValueLayout.OfFloat elementLayout, float... elements) {
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
}
/**
* Allocates a memory segment with the given layout and initializes it with the given long elements.
* @implSpec the default implementation for this method calls {@code this.allocateArray(layout, array.length)}.
* @param elementLayout the element layout of the array to be allocated.
* @param elements the long elements to be copied to the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocateArray(ValueLayout.OfLong elementLayout, long... elements) {
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
}
/**
* Allocates a memory segment with the given layout and initializes it with the given double elements.
* @implSpec the default implementation for this method calls {@code this.allocateArray(layout, 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.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocateArray(ValueLayout.OfDouble elementLayout, double... elements) {
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
}
private <Z> MemorySegment copyArrayWithSwapIfNeeded(Z array, ValueLayout elementLayout,
Function<Z, MemorySegment> heapSegmentFactory) {
Objects.requireNonNull(array);
Objects.requireNonNull(elementLayout);
int size = Array.getLength(array);
MemorySegment addr = allocate(MemoryLayout.sequenceLayout(size, elementLayout));
MemorySegment.copy(heapSegmentFactory.apply(array), elementLayout, 0,
addr, elementLayout.withOrder(ByteOrder.nativeOrder()), 0, size);
return addr;
}
/**
* Allocates a memory segment with the given layout.
* @implSpec the default implementation for this method calls {@code this.allocate(layout.byteSize(), layout.byteAlignment())}.
* @param layout the layout of the block of memory to be allocated.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocate(MemoryLayout layout) {
Objects.requireNonNull(layout);
return allocate(layout.byteSize(), layout.byteAlignment());
}
/**
* Allocates a memory segment with the given element layout and size.
* @implSpec the default implementation for this method calls {@code this.allocate(MemoryLayout.sequenceLayout(count, elementLayout))}.
* @param elementLayout the array element layout.
* @param count the array element count.
* @return a segment for the newly allocated memory block.
* @throws IllegalArgumentException if {@code count < 0}.
*/
default MemorySegment allocateArray(MemoryLayout elementLayout, long count) {
Objects.requireNonNull(elementLayout);
return allocate(MemoryLayout.sequenceLayout(count, elementLayout));
}
/**
* Allocates a memory segment with the given size.
* @implSpec the default implementation for this method calls {@code this.allocate(bytesSize, 1)}.
* @param bytesSize the size (in bytes) of the block of memory to be allocated.
* @return a segment for the newly allocated memory block.
* @throws IllegalArgumentException if {@code bytesSize < 0}
*/
default MemorySegment allocate(long bytesSize) {
return allocate(bytesSize, 1);
}
/**
* Allocates a memory segment with the given size and alignment constraints.
* @param bytesSize the size (in bytes) of the block of memory to be allocated.
* @param bytesAlignment the alignment (in bytes) of the block of memory to be allocated.
* @return a segment for the newly allocated memory block.
* @throws IllegalArgumentException if {@code bytesSize < 0}, {@code alignmentBytes <= 0},
* or if {@code alignmentBytes} is not a power of 2.
*/
MemorySegment allocate(long bytesSize, long bytesAlignment);
/**
* Creates an unbounded arena-based allocator used to allocate native memory segments.
* The returned allocator features a predefined block size and maximum arena size, and the segments it allocates
* are associated with the provided memory session. Equivalent to the following code:
* {@snippet lang=java :
* SegmentAllocator.newNativeArena(Long.MAX_VALUE, predefinedBlockSize, session);
* }
*
* @param session the memory session associated with the segments allocated by the arena-based allocator.
* @return a new unbounded arena-based allocator
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}.
*/
static SegmentAllocator newNativeArena(MemorySession session) {
return newNativeArena(Long.MAX_VALUE, ArenaAllocator.DEFAULT_BLOCK_SIZE, session);
}
/**
* Creates an arena-based allocator used to allocate native memory segments.
* The returned allocator features a block size set to the specified arena size, and the native segments
* it allocates are associated with the provided memory session. Equivalent to the following code:
* {@snippet lang=java :
* SegmentAllocator.newNativeArena(arenaSize, arenaSize, session);
* }
*
* @param arenaSize the size (in bytes) of the allocation arena.
* @param session the memory session associated with the segments allocated by the arena-based allocator.
* @return a new unbounded arena-based allocator
* @throws IllegalArgumentException if {@code arenaSize <= 0}.
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}.
*/
static SegmentAllocator newNativeArena(long arenaSize, MemorySession session) {
return newNativeArena(arenaSize, arenaSize, session);
}
/**
* Creates an arena-based allocator used to allocate native memory segments. The returned allocator features
* the given block size {@code B} and the given arena size {@code A}, and the native segments
* it allocates are associated with the provided memory session.
* <p>
* The allocator arena is first initialized by {@linkplain MemorySegment#allocateNative(long, MemorySession) allocating} a
* native memory segment {@code S} of size {@code B}. The allocator then responds to allocation requests in one of the following ways:
* <ul>
* <li>if the size of the allocation requests is smaller than the size of {@code S}, and {@code S} has a <em>free</em>
* slice {@code S'} which fits that allocation request, return that {@code S'}.
* <li>if the size of the allocation requests is smaller than the size of {@code S}, and {@code S} has no <em>free</em>
* slices which fits that allocation request, allocate a new segment {@code S'}, with size {@code B},
* and set {@code S = S'}; the allocator then tries to respond to the same allocation request again.
* <li>if the size of the allocation requests is bigger than the size of {@code S}, allocate a new segment {@code S'},
* which has a sufficient size to satisfy the allocation request, and return {@code S'}.
* </ul>
* <p>
* This segment allocator can be useful when clients want to perform multiple allocation requests while avoiding the
* cost associated with allocating a new off-heap memory region upon each allocation request.
* <p>
* The returned allocator might throw an {@link OutOfMemoryError} if the total memory allocated with this allocator
* exceeds the arena size {@code A}, or the system capacity. Furthermore, the returned allocator is not thread safe.
* Concurrent allocation needs to be guarded with synchronization primitives.
*
* @param arenaSize the size (in bytes) of the allocation arena.
* @param blockSize the block size associated with the arena-based allocator.
* @param session the memory session associated with the segments returned by the arena-based allocator.
* @return a new unbounded arena-based allocator
* @throws IllegalArgumentException if {@code blockSize <= 0}, if {@code arenaSize <= 0} or if {@code arenaSize < blockSize}.
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}.
*/
static SegmentAllocator newNativeArena(long arenaSize, long blockSize, MemorySession session) {
Objects.requireNonNull(session);
if (blockSize <= 0) {
throw new IllegalArgumentException("Invalid block size: " + blockSize);
}
if (arenaSize <= 0 || arenaSize < blockSize) {
throw new IllegalArgumentException("Invalid arena size: " + arenaSize);
}
return new ArenaAllocator(blockSize, arenaSize, session);
}
/**
* Returns a segment allocator which responds to allocation requests by recycling a single segment. Each
* new allocation request will return a new slice starting at the segment offset {@code 0} (alignment
* constraints are ignored by this allocator), hence the name <em>prefix allocator</em>.
* Equivalent to (but likely more efficient than) the following code:
* {@snippet lang=java :
* MemorySegment segment = ...
* SegmentAllocator prefixAllocator = (size, align) -> segment.asSlice(0, size);
* }
* <p>
* This allocator can be useful to limit allocation requests in case a client
* knows that they have fully processed the contents of the allocated segment before the subsequent allocation request
* takes place.
* <p>
* While the allocator returned by this method is <em>thread-safe</em>, concurrent access on the same recycling
* allocator might cause a thread to overwrite contents written to the underlying segment by a different thread.
*
* @param segment the memory segment to be recycled by the returned allocator.
* @return an allocator which recycles an existing segment upon each new allocation request.
*/
static SegmentAllocator prefixAllocator(MemorySegment segment) {
Objects.requireNonNull(segment);
return (AbstractMemorySegmentImpl)segment;
}
/**
* Returns an allocator which allocates native segments in independent {@linkplain MemorySession#openImplicit() implicit memory sessions}.
* Equivalent to (but likely more efficient than) the following code:
* {@snippet lang=java :
* SegmentAllocator implicitAllocator = (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit());
* }
*
* @return an allocator which allocates native segments in independent {@linkplain MemorySession#openImplicit() implicit memory sessions}.
*/
static SegmentAllocator implicitAllocator() {
class Holder {
static final SegmentAllocator IMPLICIT_ALLOCATOR = (size, align) ->
MemorySegment.allocateNative(size, align, MemorySession.openImplicit());
}
return Holder.IMPLICIT_ALLOCATOR;
}
}

View file

@ -0,0 +1,256 @@
/*
* Copyright (c) 2019, 2022, 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 java.lang.foreign;
import java.util.Objects;
import java.util.Optional;
import jdk.internal.javac.PreviewFeature;
/**
* A compound layout that denotes a repetition of a given <em>element layout</em>.
* The repetition count is said to be the sequence layout's <em>element count</em>. A finite sequence can be thought of as a
* group layout where the sequence layout's element layout is repeated a number of times that is equal to the sequence
* layout's element count. In other words this layout:
*
* {@snippet lang=java :
* MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN));
* }
*
* is equivalent to the following layout:
*
* {@snippet lang=java :
* MemoryLayout.structLayout(
* ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN),
* ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN),
* ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN));
* }
*
* @implSpec
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public final class SequenceLayout extends AbstractLayout implements MemoryLayout {
private final long elemCount;
private final MemoryLayout elementLayout;
SequenceLayout(long elemCount, MemoryLayout elementLayout) {
this(elemCount, elementLayout, elementLayout.bitAlignment(), Optional.empty());
}
SequenceLayout(long elemCount, MemoryLayout elementLayout, long alignment, Optional<String> name) {
super(Math.multiplyExact(elemCount, elementLayout.bitSize()), alignment, name);
this.elemCount = elemCount;
this.elementLayout = elementLayout;
}
/**
* {@return the element layout associated with this sequence layout}
*/
public MemoryLayout elementLayout() {
return elementLayout;
}
/**
* {@return the element count of this sequence layout}
*/
public long elementCount() {
return elemCount;
}
/**
* Returns a sequence layout with the same element layout, alignment constraints and name as this sequence layout,
* but with the specified element count.
* @param elementCount the new element count.
* @return a sequence layout with the given element count.
* @throws IllegalArgumentException if {@code elementCount < 0}.
*/
public SequenceLayout withElementCount(long elementCount) {
AbstractLayout.checkSize(elementCount, true);
return new SequenceLayout(elementCount, elementLayout, alignment, name());
}
/**
* Re-arrange the elements in this sequence layout into a multi-dimensional sequence layout.
* The resulting layout is a sequence layout where element layouts in the flattened projection of this
* sequence layout (see {@link #flatten()}) are re-arranged into one or more nested sequence layouts
* according to the provided element counts. This transformation preserves the layout size;
* that is, multiplying the provided element counts must yield the same element count
* as the flattened projection of this sequence layout.
* <p>
* For instance, given a sequence layout of the kind:
* {@snippet lang=java :
* var seq = MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT));
* }
* calling {@code seq.reshape(2, 6)} will yield the following sequence layout:
* {@snippet lang=java :
* var reshapeSeq = MemoryLayout.sequenceLayout(2, MemoryLayout.sequenceLayout(6, ValueLayout.JAVA_INT));
* }
* <p>
* If one of the provided element count is the special value {@code -1}, then the element
* count in that position will be inferred from the remaining element counts and the
* element count of the flattened projection of this layout. For instance, a layout equivalent to
* the above {@code reshapeSeq} can also be computed in the following ways:
* {@snippet lang=java :
* var reshapeSeqImplicit1 = seq.reshape(-1, 6);
* var reshapeSeqImplicit2 = seq.reshape(2, -1);
* }
* @param elementCounts an array of element counts, of which at most one can be {@code -1}.
* @return a sequence layout where element layouts in the flattened projection of this
* sequence layout (see {@link #flatten()}) are re-arranged into one or more nested sequence layouts.
* @throws UnsupportedOperationException if this sequence layout does not have an element count.
* @throws IllegalArgumentException if two or more element counts are set to {@code -1}, or if one
* or more element count is {@code <= 0} (but other than {@code -1}) or, if, after any required inference,
* multiplying the element counts does not yield the same element count as the flattened projection of this
* sequence layout.
*/
public SequenceLayout reshape(long... elementCounts) {
Objects.requireNonNull(elementCounts);
if (elementCounts.length == 0) {
throw new IllegalArgumentException();
}
SequenceLayout flat = flatten();
long expectedCount = flat.elementCount();
long actualCount = 1;
int inferPosition = -1;
for (int i = 0 ; i < elementCounts.length ; i++) {
if (elementCounts[i] == -1) {
if (inferPosition == -1) {
inferPosition = i;
} else {
throw new IllegalArgumentException("Too many unspecified element counts");
}
} else if (elementCounts[i] <= 0) {
throw new IllegalArgumentException("Invalid element count: " + elementCounts[i]);
} else {
actualCount = elementCounts[i] * actualCount;
}
}
// infer an unspecified element count (if any)
if (inferPosition != -1) {
long inferredCount = expectedCount / actualCount;
elementCounts[inferPosition] = inferredCount;
actualCount = actualCount * inferredCount;
}
if (actualCount != expectedCount) {
throw new IllegalArgumentException("Element counts do not match expected size: " + expectedCount);
}
MemoryLayout res = flat.elementLayout();
for (int i = elementCounts.length - 1 ; i >= 0 ; i--) {
res = MemoryLayout.sequenceLayout(elementCounts[i], res);
}
return (SequenceLayout)res;
}
/**
* Returns a flattened sequence layout. The element layout of the returned sequence layout
* is the first non-sequence element layout found by recursively traversing the element layouts of this sequence layout.
* This transformation preserves the layout size; nested sequence layout in this sequence layout will
* be dropped and their element counts will be incorporated into that of the returned sequence layout.
* For instance, given a sequence layout of the kind:
* {@snippet lang=java :
* var seq = MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT));
* }
* calling {@code seq.flatten()} will yield the following sequence layout:
* {@snippet lang=java :
* var flattenedSeq = MemoryLayout.sequenceLayout(12, ValueLayout.JAVA_INT);
* }
* @return a sequence layout with the same size as this layout (but, possibly, with different
* element count), whose element layout is not a sequence layout.
* @throws UnsupportedOperationException if this sequence layout, or one of the nested sequence layouts being
* flattened, does not have an element count.
*/
public SequenceLayout flatten() {
long count = elementCount();
MemoryLayout elemLayout = elementLayout();
while (elemLayout instanceof SequenceLayout elemSeq) {
count = count * elemSeq.elementCount();
elemLayout = elemSeq.elementLayout();
}
return MemoryLayout.sequenceLayout(count, elemLayout);
}
@Override
public String toString() {
return decorateLayoutString(String.format("[%s:%s]",
elemCount, elementLayout));
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!super.equals(other)) {
return false;
}
if (!(other instanceof SequenceLayout s)) {
return false;
}
return elemCount == s.elemCount && elementLayout.equals(s.elementLayout);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), elemCount, elementLayout);
}
@Override
SequenceLayout dup(long alignment, Optional<String> name) {
return new SequenceLayout(elementCount(), elementLayout, alignment, name);
}
@Override
boolean hasNaturalAlignment() {
return alignment == elementLayout.bitAlignment();
}
//hack: the declarations below are to make javadoc happy; we could have used generics in AbstractLayout
//but that causes issues with javadoc, see JDK-8224052
/**
* {@inheritDoc}
*/
@Override
public SequenceLayout withName(String name) {
return (SequenceLayout)super.withName(name);
}
/**
* {@inheritDoc}
*/
@Override
public SequenceLayout withBitAlignment(long alignmentBits) {
return (SequenceLayout)super.withBitAlignment(alignmentBits);
}
}

View file

@ -0,0 +1,252 @@
/*
* Copyright (c) 2022, 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 java.lang.foreign;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.foreign.MemorySessionImpl;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.loader.BuiltinClassLoader;
import jdk.internal.loader.NativeLibrary;
import jdk.internal.loader.RawNativeLibraries;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import java.lang.invoke.MethodHandles;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
/**
* A <em>symbol lookup</em> is an object that may be used to retrieve the address of a symbol in one or more libraries.
* A symbol is a named entity, such as a function or a global variable.
* <p>
* A symbol lookup is created with respect to a particular library (or libraries). Subsequently, the {@link SymbolLookup#lookup(String)}
* method takes the name of a symbol and returns the address of the symbol in that library.
* <p>
* The address of a symbol is modelled as a zero-length {@linkplain MemorySegment memory segment}. The segment can be used in different ways:
* <ul>
* <li>It can be passed to a {@link Linker} to create a downcall method handle, which can then be used to call the foreign function at the segment's base address.</li>
* <li>It can be passed to an existing {@linkplain Linker#downcallHandle(FunctionDescriptor) downcall method handle}, as an argument to the underlying foreign function.</li>
* <li>It can be {@linkplain MemorySegment#set(ValueLayout.OfAddress, long, Addressable) stored} inside another memory segment.</li>
* <li>It can be used to dereference memory associated with a global variable (this might require
* {@link MemorySegment#ofAddress(MemoryAddress, long, MemorySession) resizing} the segment first).</li>
* </ul>
*
* <h2>Obtaining a symbol lookup</h2>
*
* The factory methods {@link #libraryLookup(String, MemorySession)} and {@link #libraryLookup(Path, MemorySession)}
* create a symbol lookup for a library known to the operating system. The library is specified by either its name or a path.
* The library is loaded if not already loaded. The symbol lookup, which is known as a <em>library lookup</em>, is associated
* with a {@linkplain MemorySession memory session}; when the session is {@linkplain MemorySession#close() closed}, the library is unloaded:
*
* {@snippet lang=java :
* try (MemorySession session = MemorySession.openConfined()) {
* SymbolLookup libGL = SymbolLookup.libraryLookup("libGL.so"); // libGL.so loaded here
* MemorySegment glGetString = libGL.lookup("glGetString").orElseThrow();
* ...
* } // libGL.so unloaded here
* }
* <p>
* If a library was previously loaded through JNI, i.e., by {@link System#load(String)}
* or {@link System#loadLibrary(String)}, then the library was also associated with a particular class loader. The factory
* method {@link #loaderLookup()} creates a symbol lookup for all the libraries associated with the caller's class loader:
*
* {@snippet lang=java :
* System.loadLibrary("GL"); // libGL.so loaded here
* ...
* SymbolLookup libGL = SymbolLookup.loaderLookup();
* MemorySegment glGetString = libGL.lookup("glGetString").orElseThrow();
* }
*
* This symbol lookup, which is known as a <em>loader lookup</em>, is dynamic with respect to the libraries associated
* with the class loader. If other libraries are subsequently loaded through JNI and associated with the class loader,
* then the loader lookup will expose their symbols automatically.
* <p>
* Note that a loader lookup only exposes symbols in libraries that were previously loaded through JNI, i.e.,
* by {@link System#load(String)} or {@link System#loadLibrary(String)}. A loader lookup does not expose symbols in libraries
* that were loaded in the course of creating a library lookup:
*
* {@snippet lang=java :
* libraryLookup("libGL.so", session).lookup("glGetString").isPresent(); // true
* loaderLookup().lookup("glGetString").isPresent(); // false
* }
*
* Note also that a library lookup for library {@code L} exposes symbols in {@code L} even if {@code L} was previously loaded
* through JNI (the association with a class loader is immaterial to the library lookup):
*
* {@snippet lang=java :
* System.loadLibrary("GL"); // libGL.so loaded here
* libraryLookup("libGL.so", session).lookup("glGetString").isPresent(); // true
* }
*
* <p>
* Finally, each {@link Linker} provides a symbol lookup for libraries that are commonly used on the OS and processor
* combination supported by that {@link Linker}. This symbol lookup, which is known as a <em>default lookup</em>,
* helps clients to quickly find addresses of well-known symbols. For example, a {@link Linker} for Linux/x64 might choose to
* expose symbols in {@code libc} through the default lookup:
*
* {@snippet lang=java :
* Linker nativeLinker = Linker.nativeLinker();
* SymbolLookup stdlib = nativeLinker.defaultLookup();
* MemorySegment malloc = stdlib.lookup("malloc").orElseThrow();
* }
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
@FunctionalInterface
public interface SymbolLookup {
/**
* Returns the address of the symbol with the given name.
* @param name the symbol name.
* @return a zero-length memory segment whose base address indicates the address of the symbol, if found.
*/
Optional<MemorySegment> lookup(String name);
/**
* Returns a symbol lookup for symbols in the libraries associated with the caller's class loader.
* <p>
* A library is associated with a class loader {@code CL} when the library is loaded via an invocation of
* {@link System#load(String)} or {@link System#loadLibrary(String)} from code in a class defined by {@code CL}.
* If that code makes further invocations of {@link System#load(String)} or {@link System#loadLibrary(String)},
* then more libraries are loaded and associated with {@code CL}. The symbol lookup returned by this method is always
* current: it reflects all the libraries associated with the relevant class loader, even if they were loaded after
* this method returned.
* <p>
* Libraries associated with a class loader are unloaded when the class loader becomes
* <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>. The symbol lookup
* returned by this method is backed by a {@linkplain MemorySession#asNonCloseable() non-closeable}, shared memory
* session which keeps the caller's class loader reachable. Therefore, libraries associated with the caller's class
* loader are kept loaded (and their symbols available) as long as a loader lookup for that class loader is reachable.
* <p>
* In cases where this method is called from a context where there is no caller frame on the stack
* (e.g. when called directly from a JNI attached thread), the caller's class loader defaults to the
* {@linkplain ClassLoader#getSystemClassLoader system class loader}.
*
* @return a symbol lookup for symbols in the libraries associated with the caller's class loader.
* @see System#load(String)
* @see System#loadLibrary(String)
*/
@CallerSensitive
static SymbolLookup loaderLookup() {
Class<?> caller = Reflection.getCallerClass();
// If there's no caller class, fallback to system loader
ClassLoader loader = caller != null ?
caller.getClassLoader() :
ClassLoader.getSystemClassLoader();
MemorySession loaderSession = (loader == null || loader instanceof BuiltinClassLoader) ?
MemorySession.global() : // builtin loaders never go away
MemorySessionImpl.heapSession(loader);
return name -> {
Objects.requireNonNull(name);
JavaLangAccess javaLangAccess = SharedSecrets.getJavaLangAccess();
// note: ClassLoader::findNative supports a null loader
MemoryAddress addr = MemoryAddress.ofLong(javaLangAccess.findNative(loader, name));
return addr == MemoryAddress.NULL ?
Optional.empty() :
Optional.of(MemorySegment.ofAddress(addr, 0L, loaderSession));
};
}
/**
* Loads a library with the given name (if not already loaded) and creates a symbol lookup for symbols in that library.
* The library will be unloaded when the provided memory session is {@linkplain MemorySession#close() closed},
* if no other library lookup is still using it.
* @implNote The process of resolving a library name is OS-specific. For instance, in a POSIX-compliant OS,
* the library name is resolved according to the specification of the {@code dlopen} function for that OS.
* In Windows, the library name is resolved according to the specification of the {@code LoadLibrary} function.
* <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.
*
* @param name the name of the library in which symbols should be looked up.
* @param session the memory session which controls the library lifecycle.
* @return a new symbol lookup suitable to find symbols in a library with the given name.
* @throws IllegalArgumentException if {@code name} does not identify a valid library.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
static SymbolLookup libraryLookup(String name, MemorySession session) {
Reflection.ensureNativeAccess(Reflection.getCallerClass(), SymbolLookup.class, "libraryLookup");
return libraryLookup(name, RawNativeLibraries::load, session);
}
/**
* Loads a library from the given path (if not already loaded) and creates a symbol lookup for symbols
* in that library. The library will be unloaded when the provided memory session is {@linkplain MemorySession#close() closed},
* if no other library lookup is still using it.
* <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.
*
* @implNote On Linux, the functionalities provided by this factory method and the returned symbol lookup are
* implemented using the {@code dlopen}, {@code dlsym} and {@code dlclose} functions.
* @param path the path of the library in which symbols should be looked up.
* @param session the memory session which controls the library lifecycle.
* @return a new symbol lookup suitable to find symbols in a library with the given path.
* @throws IllegalArgumentException if {@code path} does not point to a valid library.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
static SymbolLookup libraryLookup(Path path, MemorySession session) {
Reflection.ensureNativeAccess(Reflection.getCallerClass(), SymbolLookup.class, "libraryLookup");
return libraryLookup(path, RawNativeLibraries::load, session);
}
private static <Z> SymbolLookup libraryLookup(Z libDesc, BiFunction<RawNativeLibraries, Z, NativeLibrary> loadLibraryFunc, MemorySession session) {
Objects.requireNonNull(libDesc);
Objects.requireNonNull(session);
// attempt to load native library from path or name
RawNativeLibraries nativeLibraries = RawNativeLibraries.newInstance(MethodHandles.lookup());
NativeLibrary library = loadLibraryFunc.apply(nativeLibraries, libDesc);
if (library == null) {
throw new IllegalArgumentException("Cannot open library: " + libDesc);
}
// register hook to unload library when session is closed
MemorySessionImpl.toSessionImpl(session).addOrCleanupIfFail(new MemorySessionImpl.ResourceList.ResourceCleanup() {
@Override
public void cleanup() {
nativeLibraries.unload(library);
}
});
return name -> {
Objects.requireNonNull(name);
MemoryAddress addr = MemoryAddress.ofLong(library.find(name));
return addr == MemoryAddress.NULL
? Optional.empty() :
Optional.of(MemorySegment.ofAddress(addr, 0L, session));
};
}
}

View file

@ -0,0 +1,278 @@
/*
* Copyright (c) 2021, 2022, 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 java.lang.foreign;
import java.util.Objects;
import java.util.function.Consumer;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64VaList;
import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64VaList;
import jdk.internal.foreign.abi.x64.sysv.SysVVaList;
import jdk.internal.foreign.abi.x64.windows.WinVaList;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
/**
* A variable argument list, similar in functionality to a C {@code va_list}.
* <p>
* A variable argument list is a stateful cursor used to iterate over a set of arguments. A variable argument list
* can be passed by reference e.g. to a {@linkplain Linker#downcallHandle(FunctionDescriptor) downcall method handle}.
* <p>
* Per the C specification (see C99 standard 6.5.2.2 Function calls - item 6),
* arguments to variadic calls are erased by way of 'default argument promotions',
* which erases integral types by way of integer promotion (see C99 standard 6.3.1.1 - item 2),
* and which erases all {@code float} arguments to {@code double}.
* <p>
* As such, this interface only supports reading {@code int}, {@code double},
* and any other type that fits into a {@code long}.
*
* This class is not thread safe, and all accesses should occur within a single thread
* (regardless of the memory session associated with the variable arity list).
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
sealed public interface VaList extends Addressable permits WinVaList, SysVVaList, LinuxAArch64VaList, MacOsAArch64VaList, SharedUtils.EmptyVaList {
/**
* {@return the memory session associated with this variable argument list}
*/
MemorySession session();
/**
* Reads the next value as an {@code int} and advances this variable argument list's position. The behavior of this
* method is equivalent to the C {@code va_arg} function.
*
* @param layout the layout of the value to be read.
* @return the {@code int} value read from this variable argument list.
* @throws IllegalStateException if the {@linkplain #session() session} associated with this variable argument list is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
int nextVarg(ValueLayout.OfInt layout);
/**
* Reads the next value as a {@code long} and advances this variable argument list's position. The behavior of this
* method is equivalent to the C {@code va_arg} function.
*
* @param layout the layout of the value to be read.
* @return the {@code long} value read from this variable argument list.
* @throws IllegalStateException if the {@linkplain #session() session} associated with this variable argument list is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
long nextVarg(ValueLayout.OfLong layout);
/**
* Reads the next value as a {@code double} and advances this variable argument list's position. The behavior of this
* method is equivalent to the C {@code va_arg} function.
*
* @param layout the layout of the value
* @return the {@code double} value read from this variable argument list.
* @throws IllegalStateException if the {@linkplain #session() session} associated with this variable argument list is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
double nextVarg(ValueLayout.OfDouble layout);
/**
* Reads the next value as a {@code MemoryAddress} and advances this variable argument list's position. The behavior of this
* method is equivalent to the C {@code va_arg} function.
*
* @param layout the layout of the value to be read.
* @return the {@code MemoryAddress} value read from this variable argument list.
* @throws IllegalStateException if the {@linkplain #session() session} associated with this variable argument list is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
MemoryAddress nextVarg(ValueLayout.OfAddress layout);
/**
* Reads the next value as a {@code MemorySegment}, and advances this variable argument list's position. The behavior of this
* method is equivalent to the C {@code va_arg} function. The provided group layout must correspond to a C struct or union
* type.
* <p>
* How the value is read in the returned segment is ABI-dependent: calling this method on a group layout
* with member layouts {@code L_1, L_2, ... L_n} is not guaranteed to be semantically equivalent to perform distinct
* calls to {@code nextVarg} for each of the layouts in {@code L_1, L_2, ... L_n}.
* <p>
* The memory segment returned by this method will be allocated using the given {@link SegmentAllocator}.
*
* @param layout the layout of the value to be read.
* @param allocator the allocator to be used to create a segment where the contents of the variable argument list
* will be copied.
* @return the {@code MemorySegment} value read from this variable argument list.
* @throws IllegalStateException if the {@linkplain #session() session} associated with this variable argument list is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
MemorySegment nextVarg(GroupLayout layout, SegmentAllocator allocator);
/**
* Skips a number of elements with the given memory layouts, and advances this variable argument list's position.
*
* @param layouts the layouts of the values to be skipped.
* @throws IllegalStateException if the {@linkplain #session() session} associated with this variable argument list is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
void skip(MemoryLayout... layouts);
/**
* Copies this variable argument list at its current position into a new variable argument list associated
* with the same memory session as this variable argument list. The behavior of this method is equivalent to the C
* {@code va_copy} function.
* <p>
* Copying is useful to traverse the variable argument list elements, starting from the current position,
* without affecting the state of the original variable argument list, essentially allowing the elements to be
* traversed multiple times.
*
* @return a copy of this variable argument list.
* @throws IllegalStateException if the {@linkplain #session() session} associated with this variable argument list is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
VaList copy();
/**
* {@return the {@linkplain MemoryAddress memory address} associated with this variable argument list}
* @throws IllegalStateException if the {@linkplain #session() session} associated with this variable argument list is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
@Override
MemoryAddress address();
/**
* Creates a variable argument list from a memory address pointing to an existing variable argument list,
* with the given memory session.
* <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.
*
* @param address a memory address pointing to an existing variable argument list.
* @param session the memory session to be associated with the returned variable argument list.
* @return a new variable argument list backed by the memory region at {@code address}.
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}.
* @throws UnsupportedOperationException if the underlying native platform is not supported.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
static VaList ofAddress(MemoryAddress address, MemorySession session) {
Reflection.ensureNativeAccess(Reflection.getCallerClass(), VaList.class, "ofAddress");
Objects.requireNonNull(address);
Objects.requireNonNull(session);
return SharedUtils.newVaListOfAddress(address, session);
}
/**
* Creates a variable argument list using a builder (see {@link Builder}), with the given
* memory session.
* <p>
* If this method needs to allocate memory, such memory will be managed by the given
* memory session, and will be released when the memory session is {@linkplain MemorySession#close closed}.
* <p>
* Note that when there are no elements added to the created va list,
* this method will return the same as {@link #empty()}.
*
* @param actions a consumer for a builder (see {@link Builder}) which can be used to specify the elements
* of the underlying variable argument list.
* @param session the memory session to be associated with the new variable arity list.
* @return a new variable argument list.
* @throws UnsupportedOperationException if the underlying native platform is not supported.
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}.
*/
static VaList make(Consumer<Builder> actions, MemorySession session) {
Objects.requireNonNull(actions);
Objects.requireNonNull(session);
return SharedUtils.newVaList(actions, session);
}
/**
* Returns an empty variable argument list, associated with the {@linkplain MemorySession#global() global}
* memory session. The resulting variable argument list does not contain any argument, and throws {@link UnsupportedOperationException}
* on all operations, except for {@link VaList#address()}, {@link VaList#copy()} and {@link VaList#session()}.
* @return an empty variable argument list.
* @throws UnsupportedOperationException if the underlying native platform is not supported.
*/
static VaList empty() {
return SharedUtils.emptyVaList();
}
/**
* A builder used to construct a {@linkplain VaList variable argument list}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
sealed interface Builder permits WinVaList.Builder, SysVVaList.Builder, LinuxAArch64VaList.Builder, MacOsAArch64VaList.Builder {
/**
* Writes an {@code int} value to the variable argument list being constructed.
*
* @param layout the layout of the value to be written.
* @param value the {@code int} value to be written.
* @return this builder.
*/
Builder addVarg(ValueLayout.OfInt layout, int value);
/**
* Writes a {@code long} value to the variable argument list being constructed.
*
* @param layout the layout of the value to be written.
* @param value the {@code long} value to be written.
* @return this builder.
*/
Builder addVarg(ValueLayout.OfLong layout, long value);
/**
* Writes a {@code double} value to the variable argument list being constructed.
*
* @param layout the layout of the value to be written.
* @param value the {@code double} value to be written.
* @return this builder.
*/
Builder addVarg(ValueLayout.OfDouble layout, double value);
/**
* Writes an {@code Addressable} value to the variable argument list being constructed.
*
* @param layout the layout of the value to be written.
* @param value the {@code Addressable} value to be written.
* @return this builder.
*/
Builder addVarg(ValueLayout.OfAddress layout, Addressable value);
/**
* Writes a {@code MemorySegment} value, with the given layout, to the variable argument list being constructed.
*
* @param layout the layout of the value to be written.
* @param value the {@code MemorySegment} whose contents will be copied.
* @return this builder.
*/
Builder addVarg(GroupLayout layout, MemorySegment value);
}
}

View file

@ -0,0 +1,678 @@
/*
* Copyright (c) 2019, 2022, 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 java.lang.foreign;
import java.lang.invoke.MethodHandles;
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;
import jdk.internal.foreign.Utils;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.misc.Unsafe;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Stable;
import sun.invoke.util.Wrapper;
/**
* A value layout. A value layout is used to model the memory layout associated with values of basic data types, such as <em>integral</em> types
* (either signed or unsigned) and <em>floating-point</em> types. Each value layout has a size, an alignment (in bits),
* a {@linkplain ByteOrder byte order}, and a <em>carrier</em>, that is, the Java type that should be used when
* {@linkplain MemorySegment#get(OfInt, long) accessing} a memory region using the value layout.
* <p>
* This class defines useful value layout constants for Java primitive types and addresses.
* The layout constants in this class make implicit alignment and byte-ordering assumption: all layout
* constants in this class are byte-aligned, and their byte order is set to the {@linkplain ByteOrder#nativeOrder() platform default},
* thus making it easy to work with other APIs, such as arrays and {@link java.nio.ByteBuffer}.
*
* @implSpec
* This class and its subclasses are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
private final Class<?> carrier;
private final ByteOrder order;
private static final int ADDRESS_SIZE_BITS = Unsafe.ADDRESS_SIZE * 8;
ValueLayout(Class<?> carrier, ByteOrder order, long size) {
this(carrier, order, size, size, Optional.empty());
}
ValueLayout(Class<?> carrier, ByteOrder order, long size, long alignment, Optional<String> name) {
super(size, alignment, name);
this.carrier = carrier;
this.order = order;
checkCarrierSize(carrier, size);
}
/**
* {@return the value's byte order}
*/
public ByteOrder order() {
return order;
}
/**
* Returns a value layout with the same carrier, alignment constraints and name as this value layout,
* but with the specified byte order.
*
* @param order the desired byte order.
* @return a value layout with the given byte order.
*/
public ValueLayout withOrder(ByteOrder order) {
return new ValueLayout(carrier, Objects.requireNonNull(order), bitSize(), alignment, name());
}
@Override
public String toString() {
char descriptor = carrier == MemoryAddress.class ? 'A' : carrier.descriptorString().charAt(0);
if (order == ByteOrder.LITTLE_ENDIAN) {
descriptor = Character.toLowerCase(descriptor);
}
return decorateLayoutString(String.format("%s%d", descriptor, bitSize()));
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!super.equals(other)) {
return false;
}
if (!(other instanceof ValueLayout v)) {
return false;
}
return carrier.equals(v.carrier) &&
order.equals(v.order) &&
bitSize() == v.bitSize() &&
alignment == v.alignment;
}
/**
* Creates a <em>strided</em> access var handle that can be used to dereference a multi-dimensional array. The
* layout of this array is a sequence layout with {@code shape.length} nested sequence layouts. The element
* layout of the sequence layout at depth {@code shape.length} is this value layout.
* As a result, if {@code shape.length == 0}, the array layout will feature only one dimension.
* <p>
* The resulting var handle will feature {@code sizes.length + 1} coordinates of type {@code long}, which are
* used as indices into a multi-dimensional array.
* <p>
* For instance, the following method call:
*
* {@snippet lang=java :
* VarHandle arrayHandle = ValueLayout.JAVA_INT.arrayElementVarHandle(10, 20);
* }
*
* Can be used to access a multi-dimensional array whose layout is as follows:
*
* {@snippet lang=java :
* MemoryLayout arrayLayout = MemoryLayout.sequenceLayout(-1,
* MemoryLayout.sequenceLayout(10,
* MemoryLayout.sequenceLayout(20, ValueLayout.JAVA_INT)));
* }
*
* 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 dereferenced 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>
*
* @param shape the size of each nested array dimension.
* @return a var handle which can be used to dereference 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 the layout path has one or more elements with incompatible alignment constraints.
* @see MethodHandles#memorySegmentViewVarHandle
* @see MemoryLayout#varHandle(PathElement...)
* @see SequenceLayout
*/
public VarHandle arrayElementVarHandle(int... shape) {
Objects.requireNonNull(shape);
MemoryLayout layout = this;
List<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(PathElement.sequenceElement());
}
layout = MemoryLayout.sequenceLayout(-1, layout);
path.add(PathElement.sequenceElement());
return layout.varHandle(path.toArray(new PathElement[0]));
}
/**
* {@return the carrier associated with this value layout}
*/
public Class<?> carrier() {
return carrier;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), order, bitSize(), alignment);
}
@Override
ValueLayout dup(long alignment, Optional<String> name) {
return new ValueLayout(carrier, order, bitSize(), alignment, name());
}
//hack: the declarations below are to make javadoc happy; we could have used generics in AbstractLayout
//but that causes issues with javadoc, see JDK-8224052
/**
* {@inheritDoc}
*/
@Override
public ValueLayout withName(String name) {
return (ValueLayout)super.withName(name);
}
/**
* {@inheritDoc}
*/
@Override
public ValueLayout withBitAlignment(long alignmentBits) {
return (ValueLayout)super.withBitAlignment(alignmentBits);
}
static void checkCarrierSize(Class<?> carrier, long size) {
if (!isValidCarrier(carrier)) {
throw new IllegalArgumentException("Invalid carrier: " + carrier.getName());
}
if (carrier == MemoryAddress.class && size != ADDRESS_SIZE_BITS) {
throw new IllegalArgumentException("Address size mismatch: " + ADDRESS_SIZE_BITS + " != " + size);
}
if (carrier.isPrimitive()) {
int expectedSize = carrier == boolean.class ? 8 : Wrapper.forPrimitiveType(carrier).bitWidth();
if (size != expectedSize) {
throw new IllegalArgumentException("Carrier size mismatch: " + carrier.getName() + " != " + size);
}
}
}
static boolean isValidCarrier(Class<?> carrier) {
return carrier == boolean.class
|| carrier == byte.class
|| carrier == short.class
|| carrier == char.class
|| carrier == int.class
|| carrier == long.class
|| carrier == float.class
|| carrier == double.class
|| carrier == MemoryAddress.class;
}
@Stable
private VarHandle handle;
@ForceInline
VarHandle accessHandle() {
if (handle == null) {
// this store to stable field is safe, because return value of 'makeMemoryAccessVarHandle' has stable identity
handle = Utils.makeSegmentViewVarHandle(this);
}
return handle;
}
/**
* A value layout whose carrier is {@code boolean.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfBoolean extends ValueLayout {
OfBoolean(ByteOrder order) {
super(boolean.class, order, 8);
}
OfBoolean(ByteOrder order, long alignment, Optional<String> name) {
super(boolean.class, order, 8, alignment, name);
}
@Override
OfBoolean dup(long alignment, Optional<String> name) {
return new OfBoolean(order(), alignment, name);
}
@Override
public OfBoolean withName(String name) {
return (OfBoolean)super.withName(name);
}
@Override
public OfBoolean withBitAlignment(long alignmentBits) {
return (OfBoolean)super.withBitAlignment(alignmentBits);
}
@Override
public OfBoolean withOrder(ByteOrder order) {
Objects.requireNonNull(order);
return new OfBoolean(order, alignment, name());
}
}
/**
* A value layout whose carrier is {@code byte.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfByte extends ValueLayout {
OfByte(ByteOrder order) {
super(byte.class, order, 8);
}
OfByte(ByteOrder order, long alignment, Optional<String> name) {
super(byte.class, order, 8, alignment, name);
}
@Override
OfByte dup(long alignment, Optional<String> name) {
return new OfByte(order(), alignment, name);
}
@Override
public OfByte withName(String name) {
return (OfByte)super.withName(name);
}
@Override
public OfByte withBitAlignment(long alignmentBits) {
return (OfByte)super.withBitAlignment(alignmentBits);
}
@Override
public OfByte withOrder(ByteOrder order) {
Objects.requireNonNull(order);
return new OfByte(order, alignment, name());
}
}
/**
* A value layout whose carrier is {@code char.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfChar extends ValueLayout {
OfChar(ByteOrder order) {
super(char.class, order, 16);
}
OfChar(ByteOrder order, long alignment, Optional<String> name) {
super(char.class, order, 16, alignment, name);
}
@Override
OfChar dup(long alignment, Optional<String> name) {
return new OfChar(order(), alignment, name);
}
@Override
public OfChar withName(String name) {
return (OfChar)super.withName(name);
}
@Override
public OfChar withBitAlignment(long alignmentBits) {
return (OfChar)super.withBitAlignment(alignmentBits);
}
@Override
public OfChar withOrder(ByteOrder order) {
Objects.requireNonNull(order);
return new OfChar(order, alignment, name());
}
}
/**
* A value layout whose carrier is {@code short.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfShort extends ValueLayout {
OfShort(ByteOrder order) {
super(short.class, order, 16);
}
OfShort(ByteOrder order, long alignment, Optional<String> name) {
super(short.class, order, 16, alignment, name);
}
@Override
OfShort dup(long alignment, Optional<String> name) {
return new OfShort(order(), alignment, name);
}
@Override
public OfShort withName(String name) {
return (OfShort)super.withName(name);
}
@Override
public OfShort withBitAlignment(long alignmentBits) {
return (OfShort)super.withBitAlignment(alignmentBits);
}
@Override
public OfShort withOrder(ByteOrder order) {
Objects.requireNonNull(order);
return new OfShort(order, alignment, name());
}
}
/**
* A value layout whose carrier is {@code int.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfInt extends ValueLayout {
OfInt(ByteOrder order) {
super(int.class, order, 32);
}
OfInt(ByteOrder order, long alignment, Optional<String> name) {
super(int.class, order, 32, alignment, name);
}
@Override
OfInt dup(long alignment, Optional<String> name) {
return new OfInt(order(), alignment, name);
}
@Override
public OfInt withName(String name) {
return (OfInt)super.withName(name);
}
@Override
public OfInt withBitAlignment(long alignmentBits) {
return (OfInt)super.withBitAlignment(alignmentBits);
}
@Override
public OfInt withOrder(ByteOrder order) {
Objects.requireNonNull(order);
return new OfInt(order, alignment, name());
}
}
/**
* A value layout whose carrier is {@code float.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfFloat extends ValueLayout {
OfFloat(ByteOrder order) {
super(float.class, order, 32);
}
OfFloat(ByteOrder order, long alignment, Optional<String> name) {
super(float.class, order, 32, alignment, name);
}
@Override
OfFloat dup(long alignment, Optional<String> name) {
return new OfFloat(order(), alignment, name);
}
@Override
public OfFloat withName(String name) {
return (OfFloat)super.withName(name);
}
@Override
public OfFloat withBitAlignment(long alignmentBits) {
return (OfFloat)super.withBitAlignment(alignmentBits);
}
@Override
public OfFloat withOrder(ByteOrder order) {
Objects.requireNonNull(order);
return new OfFloat(order, alignment, name());
}
}
/**
* A value layout whose carrier is {@code long.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfLong extends ValueLayout {
OfLong(ByteOrder order) {
super(long.class, order, 64);
}
OfLong(ByteOrder order, long alignment, Optional<String> name) {
super(long.class, order, 64, alignment, name);
}
@Override
OfLong dup(long alignment, Optional<String> name) {
return new OfLong(order(), alignment, name);
}
@Override
public OfLong withName(String name) {
return (OfLong)super.withName(name);
}
@Override
public OfLong withBitAlignment(long alignmentBits) {
return (OfLong)super.withBitAlignment(alignmentBits);
}
@Override
public OfLong withOrder(ByteOrder order) {
Objects.requireNonNull(order);
return new OfLong(order, alignment, name());
}
}
/**
* A value layout whose carrier is {@code double.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfDouble extends ValueLayout {
OfDouble(ByteOrder order) {
super(double.class, order, 64);
}
OfDouble(ByteOrder order, long alignment, Optional<String> name) {
super(double.class, order, 64, alignment, name);
}
@Override
OfDouble dup(long alignment, Optional<String> name) {
return new OfDouble(order(), alignment, name);
}
@Override
public OfDouble withName(String name) {
return (OfDouble)super.withName(name);
}
@Override
public OfDouble withBitAlignment(long alignmentBits) {
return (OfDouble)super.withBitAlignment(alignmentBits);
}
@Override
public OfDouble withOrder(ByteOrder order) {
Objects.requireNonNull(order);
return new OfDouble(order, alignment, name());
}
}
/**
* A value layout whose carrier is {@code MemoryAddress.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfAddress extends ValueLayout {
OfAddress(ByteOrder order) {
super(MemoryAddress.class, order, ADDRESS_SIZE_BITS);
}
OfAddress(ByteOrder order, long size, long alignment, Optional<String> name) {
super(MemoryAddress.class, order, size, alignment, name);
}
@Override
OfAddress dup(long alignment, Optional<String> name) {
return new OfAddress(order(), bitSize(), alignment, name);
}
@Override
public OfAddress withName(String name) {
return (OfAddress)super.withName(name);
}
@Override
public OfAddress withBitAlignment(long alignmentBits) {
return (OfAddress)super.withBitAlignment(alignmentBits);
}
@Override
public OfAddress withOrder(ByteOrder order) {
Objects.requireNonNull(order);
return new OfAddress(order, bitSize(), alignment, name());
}
}
/**
* A value layout constant whose size is the same as that of a machine address ({@code size_t}),
* bit alignment set to {@code sizeof(size_t) * 8}, and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* MemoryLayout.valueLayout(MemoryAddress.class, ByteOrder.nativeOrder())
* .withBitAlignment(<address size>);
* }
*/
public static final OfAddress ADDRESS = new OfAddress(ByteOrder.nativeOrder())
.withBitAlignment(ValueLayout.ADDRESS_SIZE_BITS);
/**
* A value layout constant whose size is the same as that of a Java {@code byte},
* bit alignment set to 8, and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* MemoryLayout.valueLayout(byte.class, ByteOrder.nativeOrder()).withBitAlignment(8);
* }
*/
public static final OfByte JAVA_BYTE = new OfByte(ByteOrder.nativeOrder()).withBitAlignment(8);
/**
* A value layout constant whose size is the same as that of a Java {@code boolean},
* bit alignment set to 8, and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* MemoryLayout.valueLayout(boolean.class, ByteOrder.nativeOrder()).withBitAlignment(8);
* }
*/
public static final OfBoolean JAVA_BOOLEAN = new OfBoolean(ByteOrder.nativeOrder()).withBitAlignment(8);
/**
* A value layout constant whose size is the same as that of a Java {@code char},
* bit alignment set to 16, and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* MemoryLayout.valueLayout(char.class, ByteOrder.nativeOrder()).withBitAlignment(16);
* }
*/
public static final OfChar JAVA_CHAR = new OfChar(ByteOrder.nativeOrder()).withBitAlignment(16);
/**
* A value layout constant whose size is the same as that of a Java {@code short},
* bit alignment set to 16, and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* MemoryLayout.valueLayout(short.class, ByteOrder.nativeOrder()).withBitAlignment(16);
* }
*/
public static final OfShort JAVA_SHORT = new OfShort(ByteOrder.nativeOrder()).withBitAlignment(16);
/**
* A value layout constant whose size is the same as that of a Java {@code int},
* bit alignment set to 32, and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* MemoryLayout.valueLayout(int.class, ByteOrder.nativeOrder()).withBitAlignment(32);
* }
*/
public static final OfInt JAVA_INT = new OfInt(ByteOrder.nativeOrder()).withBitAlignment(32);
/**
* A value layout constant whose size is the same as that of a Java {@code long},
* bit alignment set to 64, and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* MemoryLayout.valueLayout(long.class, ByteOrder.nativeOrder()).withBitAlignment(64);
* }
*/
public static final OfLong JAVA_LONG = new OfLong(ByteOrder.nativeOrder())
.withBitAlignment(64);
/**
* A value layout constant whose size is the same as that of a Java {@code float},
* bit alignment set to 32, and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* MemoryLayout.valueLayout(float.class, ByteOrder.nativeOrder()).withBitAlignment(32);
* }
*/
public static final OfFloat JAVA_FLOAT = new OfFloat(ByteOrder.nativeOrder()).withBitAlignment(32);
/**
* A value layout constant whose size is the same as that of a Java {@code double},
* bit alignment set to 64, and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* MemoryLayout.valueLayout(double.class, ByteOrder.nativeOrder()).withBitAlignment(64);
* }
*/
public static final OfDouble JAVA_DOUBLE = new OfDouble(ByteOrder.nativeOrder()).withBitAlignment(64);
}

View file

@ -0,0 +1,238 @@
/*
* Copyright (c) 2019, 2022, 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.
*
*/
/**
* <p>Provides low-level access to memory and functions outside the Java runtime.
*
* <h2>Foreign memory access</h2>
*
* <p>
* The main abstraction introduced to support foreign memory access is {@link java.lang.foreign.MemorySegment}, which
* models a contiguous memory region, residing either inside or outside the Java heap. The contents of a memory
* segment can be described using a {@link java.lang.foreign.MemoryLayout memory layout}, which provides
* basic operations to query sizes, offsets and alignment constraints. Memory layouts also provide
* an alternate, more abstract way, to <a href=MemorySegment.html#segment-deref>dereference memory segments</a>
* using {@linkplain java.lang.foreign.MemoryLayout#varHandle(java.lang.foreign.MemoryLayout.PathElement...) access var handles},
* which can be computed using <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>.
*
* For example, to allocate an off-heap memory region big enough to hold 10 values of the primitive type {@code int}, and fill it with values
* ranging from {@code 0} to {@code 9}, we can use the following code:
*
* {@snippet lang=java :
* MemorySegment segment = MemorySegment.allocateNative(10 * 4, MemorySession.openImplicit());
* for (int i = 0 ; i < 10 ; i++) {
* segment.setAtIndex(ValueLayout.JAVA_INT, i, i);
* }
* }
*
* This code creates a <em>native</em> memory segment, that is, a memory segment backed by
* off-heap memory; the size of the segment is 40 bytes, enough to store 10 values of the primitive type {@code int}.
* Inside a loop, we then initialize the contents of the memory segment; note how the
* {@linkplain java.lang.foreign.MemorySegment#setAtIndex(ValueLayout.OfInt, long, int) dereference method}
* accepts a {@linkplain java.lang.foreign.ValueLayout value layout}, which specifies the size, alignment constraints,
* byte order as well as the Java type ({@code int}, in this case) associated with the dereference operation. More specifically,
* if we view the memory segment as a set of 10 adjacent slots, {@code s[i]}, where {@code 0 <= i < 10},
* where the size of each slot is exactly 4 bytes, the initialization logic above will set each slot
* so that {@code s[i] = i}, again where {@code 0 <= i < 10}.
*
* <h3><a id="deallocation"></a>Deterministic deallocation</h3>
*
* When writing code that manipulates memory segments, especially if backed by memory which resides outside the Java heap, it is
* often crucial that the resources associated with a memory segment are released when the segment is no longer in use,
* and in a timely fashion. For this reason, there might be cases where waiting for the garbage collector to determine that a segment
* is <a href="../../../java/lang/ref/package.html#reachability">unreachable</a> is not optimal.
* Clients that operate under these assumptions might want to programmatically release the memory associated
* with a memory segment. This can be done, using the {@link java.lang.foreign.MemorySession} abstraction, as shown below:
*
* {@snippet lang=java :
* try (MemorySession session = MemorySession.openConfined()) {
* MemorySegment segment = MemorySegment.allocateNative(10 * 4, session);
* for (int i = 0 ; i < 10 ; i++) {
* segment.setAtIndex(ValueLayout.JAVA_INT, i, i);
* }
* }
* }
*
* This example is almost identical to the prior one; this time we first create a so called <em>memory session</em>,
* which is used to <em>bind</em> the life-cycle of the segment created immediately afterwards. Note the use of the
* <em>try-with-resources</em> construct: this idiom ensures that all the memory resources associated with the segment will be released
* at the end of the block, according to the semantics described in Section {@jls 14.20.3} of <cite>The Java Language Specification</cite>.
*
* <h3><a id="safety"></a>Safety</h3>
*
* This API provides strong safety guarantees when it comes to memory access. First, when dereferencing a memory segment,
* the access coordinates are validated (upon access), to make sure that access does not occur at any address which resides
* <em>outside</em> the boundaries of the memory segment used by the dereference operation. We call this guarantee <em>spatial safety</em>;
* in other words, access to memory segments is bounds-checked, in the same way as array access is, as described in
* Section {@jls 15.10.4} of <cite>The Java Language Specification</cite>.
* <p>
* Since memory segments can be closed (see above), segments are also validated (upon access) to make sure that
* the memory session associated with the segment being accessed has not been closed prematurely.
* We call this guarantee <em>temporal safety</em>. Together, spatial and temporal safety ensure that each memory access
* operation either succeeds - and accesses a valid memory location - or fails.
*
* <h2>Foreign function access</h2>
* The key abstractions introduced to support foreign function access are {@link java.lang.foreign.SymbolLookup},
* {@link java.lang.foreign.FunctionDescriptor} and {@link java.lang.foreign.Linker}. The first is used to look up symbols
* inside libraries; the second is used to model the signature of foreign functions, while the third provides
* linking capabilities which allows modelling foreign functions as {@link java.lang.invoke.MethodHandle} instances,
* so that clients can perform foreign function calls directly in Java, without the need for intermediate layers of C/C++
* code (as is the case with the <a href="{@docRoot}/../specs/jni/index.html">Java Native Interface (JNI)</a>).
* <p>
* For example, to compute the length of a string using the C standard library function {@code strlen} on a Linux x64 platform,
* we can use the following code:
*
* {@snippet lang=java :
* var linker = Linker.nativeLinker();
* MethodHandle strlen = linker.downcallHandle(
* linker.lookup("strlen").get(),
* FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)
* );
*
* try (var session = MemorySession.openConfined()) {
* var cString = MemorySegment.allocateNative(5 + 1, session);
* cString.setUtf8String("Hello");
* long len = (long)strlen.invoke(cString); // 5
* }
* }
*
* Here, we obtain a {@linkplain java.lang.foreign.Linker#nativeLinker() native linker} and we use it
* to {@linkplain java.lang.foreign.SymbolLookup#lookup(java.lang.String) look up} the {@code strlen} symbol in the
* standard C library; a <em>downcall method handle</em> targeting said symbol is subsequently
* {@linkplain java.lang.foreign.Linker#downcallHandle(java.lang.foreign.FunctionDescriptor) obtained}.
* To complete the linking successfully, we must provide a {@link java.lang.foreign.FunctionDescriptor} instance,
* describing the signature of the {@code strlen} function.
* From this information, the linker will uniquely determine the sequence of steps which will turn
* the method handle invocation (here performed using {@link java.lang.invoke.MethodHandle#invoke(java.lang.Object...)})
* into a foreign function call, according to the rules specified by the ABI of the underlying platform.
* The {@link java.lang.foreign.MemorySegment} class also provides many useful methods for
* interacting with foreign code, such as converting Java strings
* {@linkplain java.lang.foreign.MemorySegment#setUtf8String(long, java.lang.String) into} zero-terminated, UTF-8 strings and
* {@linkplain java.lang.foreign.MemorySegment#getUtf8String(long) back}, as demonstrated in the above example.
*
* <h3>Foreign addresses</h3>
*
* When a memory segment is created from Java code, the segment properties (spatial bounds, temporal bounds and confinement)
* are fully known at segment creation. But when interacting with foreign functions, clients will often receive <em>raw</em> pointers.
* Such pointers have no spatial bounds. For example, the C type {@code char*} can refer to a single {@code char} value,
* or an array of {@code char} values, of given size. Nor do said pointers have any notion of temporal bounds or thread-confinement.
* <p>
* Raw pointers are modelled using the {@link java.lang.foreign.MemoryAddress} class. When clients receive a
* memory address instance from a foreign function call, they can perform memory dereference on it directly,
* using one of the many <em>unsafe</em>
* {@linkplain java.lang.foreign.MemoryAddress#get(java.lang.foreign.ValueLayout.OfInt, long) dereference methods}
* provided:
*
* {@snippet lang=java :
* MemoryAddress addr = ... // obtain address from foreign function call
* int x = addr.get(ValueLayout.JAVA_INT, 0);
* }
*
* Alternatively, the client can
* {@linkplain java.lang.foreign.MemorySegment#ofAddress(java.lang.foreign.MemoryAddress, long, java.lang.foreign.MemorySession) create}
* a memory segment <em>unsafely</em>. This allows the client to inject extra knowledge about spatial bounds which might,
* for instance, be available in the documentation of the foreign function which produced the native address.
* Here is how an unsafe segment can be created from a memory address:
*
* {@snippet lang=java :
* MemorySession session = ... // initialize a memory session object
* MemoryAddress addr = ... // obtain address from foreign function call
* MemorySegment segment = MemorySegment.ofAddress(addr, 4, session); // segment is 4 bytes long
* int x = segment.get(ValueLayout.JAVA_INT, 0);
* }
*
* <h3>Upcalls</h3>
* The {@link java.lang.foreign.Linker} interface also allows clients to turn an existing method handle (which might point
* to a Java method) into a memory address, so that Java code can effectively be passed to other foreign functions.
* For instance, we can write a method that compares two integer values, as follows:
*
* {@snippet lang=java :
* class IntComparator {
* static int intCompare(MemoryAddress addr1, MemoryAddress addr2) {
* return addr1.get(ValueLayout.JAVA_INT, 0) - addr2.get(ValueLayout.JAVA_INT, 0);
* }
* }
* }
*
* The above method dereferences two memory addresses containing an integer value, and performs a simple comparison
* by returning the difference between such values. We can then obtain a method handle which targets the above static
* method, as follows:
*
* {@snippet lang=java :
* FunctionDescriptor intCompareDescriptor = FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.ADDRESS, ValueLayout.ADDRESS);
* MethodHandle intCompareHandle = MethodHandles.lookup().findStatic(IntComparator.class,
* "intCompare",
* CLinker.upcallType(comparFunction));
* }
*
* As before, we need to create a {@link java.lang.foreign.FunctionDescriptor} instance, this time describing the signature
* of the function pointer we want to create. The descriptor can be used to
* {@linkplain java.lang.foreign.Linker#upcallType(java.lang.foreign.FunctionDescriptor) derive} a method type
* that can be used to look up the method handle for {@code IntComparator.intCompare}.
* <p>
* Now that we have a method handle instance, we can turn it into a fresh function pointer,
* using the {@link java.lang.foreign.Linker} interface, as follows:
*
* {@snippet lang=java :
* MemorySession session = ...
* Addressable comparFunc = CLinker.nativeLinker().upcallStub(
* intCompareHandle, intCompareDescriptor, session);
* );
* }
*
* The {@link java.lang.foreign.FunctionDescriptor} instance created in the previous step is then used to
* {@linkplain java.lang.foreign.Linker#upcallStub(java.lang.invoke.MethodHandle, java.lang.foreign.FunctionDescriptor, java.lang.foreign.MemorySession) create}
* a new upcall stub; the layouts in the function descriptors allow the linker to determine the sequence of steps which
* allow foreign code to call the stub for {@code intCompareHandle} according to the rules specified by the ABI of the
* underlying platform.
* The lifecycle of the upcall stub is tied to the {@linkplain java.lang.foreign.MemorySession memory session}
* provided when the upcall stub is created. This same session is made available by the {@link java.lang.foreign.MemorySegment}
* instance returned by that method.
*
* <a id="restricted"></a>
* <h2>Restricted methods</h2>
* Some methods in this package are considered <em>restricted</em>. Restricted methods are typically used to bind native
* foreign data and/or functions to first-class Java API elements which can then be used directly by clients. For instance
* the restricted method {@link java.lang.foreign.MemorySegment#ofAddress(MemoryAddress, long, MemorySession)}
* can be used to create a fresh segment with the given spatial bounds out of a native address.
* <p>
* Binding foreign data and/or functions is generally unsafe and, if done incorrectly, can result in VM crashes, or memory corruption when the bound Java API element is accessed.
* For instance, in the case of {@link java.lang.foreign.MemorySegment#ofAddress(MemoryAddress, long, MemorySession)},
* if the provided spatial bounds are incorrect, a client of the segment returned by that method might crash the VM, or corrupt
* memory when attempting to dereference said segment. For these reasons, it is crucial for code that calls a restricted method
* to never pass arguments that might cause incorrect binding of foreign data and/or functions to a Java API.
* <p>
* Access to restricted methods can be controlled using the command line option {@code --enable-native-access=M1,M2, ... Mn},
* where {@code M1}, {@code M2}, {@code ... Mn} are module names (for the unnamed module, the special value {@code ALL-UNNAMED}
* can be used). If this option is specified, access to restricted methods is only granted to the modules listed by that
* option. If this option is not specified, access to restricted methods is enabled for all modules, but
* access to restricted methods will result in runtime warnings.
* <p>
* For every class in this package, unless specified otherwise, any method arguments of reference
* type must not be null, and any null argument will elicit a {@code NullPointerException}. This fact is not individually
* documented for methods of this API.
*/
package java.lang.foreign;

View file

@ -29,7 +29,6 @@ import jdk.internal.access.JavaLangInvokeAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.invoke.NativeEntryPoint;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.vm.annotation.ForceInline;
@ -1586,9 +1585,8 @@ abstract class MethodHandleImpl {
}
@Override
public VarHandle memoryAccessVarHandle(Class<?> carrier, boolean skipAlignmentMaskCheck, long alignmentMask,
ByteOrder order) {
return VarHandles.makeMemoryAddressViewHandle(carrier, skipAlignmentMaskCheck, alignmentMask, order);
public VarHandle memorySegmentViewHandle(Class<?> carrier, long alignmentMask, ByteOrder order) {
return VarHandles.memorySegmentViewHandle(carrier, alignmentMask, order);
}
@Override

View file

@ -26,6 +26,8 @@
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;
@ -42,13 +44,16 @@ import sun.reflect.misc.ReflectUtil;
import sun.security.util.SecurityConstants;
import java.lang.constant.ConstantDescs;
import java.lang.foreign.GroupLayout;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.LambdaForm.BasicType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ReflectPermission;
import java.nio.ByteOrder;
import java.security.ProtectionDomain;
import java.util.ArrayList;
@ -7863,4 +7868,299 @@ 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}
* by viewing its contents as a sequence of 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 returned var handle's type is {@code carrier} and the list of coordinate types is
* {@code (MemorySegment, long)}, where the {@code long} coordinate type corresponds to byte offset into
* a given memory segment. The returned var handle accesses bytes at an offset in a given
* memory segment, composing bytes to or from a value of the type {@code carrier} according to the given endianness;
* the alignment constraint (in bytes) for the resulting var handle is given by {@code alignmentBytes}.
*
* <p>As an example, consider the memory layout expressed by a {@link GroupLayout} instance constructed as follows:
* <blockquote><pre>{@code
* GroupLayout seq = java.lang.foreign.MemoryLayout.structLayout(
* MemoryLayout.paddingLayout(32),
* ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value")
* );
* }</pre></blockquote>
* To access the member layout named {@code value}, we can construct a memory segment view var handle as follows:
* <blockquote><pre>{@code
* VarHandle handle = MethodHandles.memorySegmentViewVarHandle(ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN)); //(MemorySegment, long) -> int
* handle = MethodHandles.insertCoordinates(handle, 1, 4); //(MemorySegment) -> int
* }</pre></blockquote>
*
* @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 MemoryAddress}.
* (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 MemoryAddress}.
* (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 MemoryAddress}.
* (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 MemoryAddress} then atomic
* update access modes compare values using their bitwise representation
* (see {@link Float#floatToRawIntBits},
* {@link Double#doubleToRawLongBits} and {@link MemoryAddress#toRawLongValue()}, 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>
* Finally, 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.
*
* @param layout the value layout for which a memory access handle is to be obtained.
* @return the new memory segment view var handle.
* @throws IllegalArgumentException if an illegal carrier type is used, or if {@code alignmentBytes} is not a power of two.
* @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>
* When calling e.g. {@link VarHandle#set(Object...)} on the resulting var handle, the incoming value (of type {@code T}, where
* {@code T} is the <em>last</em> parameter type of the first filter function) is processed using the first filter and then passed
* to the target var handle.
* Conversely, when calling e.g. {@link VarHandle#get(Object...)} on the resulting var handle, the return value obtained from
* the target var handle (of type {@code T}, where {@code T} is the <em>last</em> parameter type of the second filter function)
* is processed using the second filter and returned to the caller. More advanced access mode types, such as
* {@link VarHandle.AccessMode#COMPARE_AND_EXCHANGE} might apply both filters at the same time.
* <p>
* For the boxing and unboxing filters to be well-formed, their types must be of the form {@code (A... , S) -> T} and
* {@code (A... , T) -> S}, respectively, where {@code T} is the type of the target var handle. If this is the case,
* the resulting var handle will have type {@code S} and will feature the additional coordinates {@code A...} (which
* will be appended to the coordinates of the target var handle).
* <p>
* If the boxing and unboxing filters throw any checked exceptions when invoked, the resulting var handle will
* throw an {@link IllegalStateException}.
* <p>
* The resulting var handle will feature the same access modes (see {@link VarHandle.AccessMode}) and
* atomic access guarantees as those featured by the target var handle.
*
* @param target the target var handle
* @param filterToTarget a filter to convert some type {@code S} into the type of {@code target}
* @param filterFromTarget a filter to convert the type of {@code target} to some type {@code S}
* @return an adapter var handle which accepts a new type, performing the provided boxing/unboxing conversions.
* @throws IllegalArgumentException if {@code filterFromTarget} and {@code filterToTarget} are not well-formed, that is, they have types
* 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
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget) {
return VarHandles.filterValue(target, filterToTarget, filterFromTarget);
}
/**
* Adapts a target var handle by pre-processing incoming coordinate values using unary filter functions.
* <p>
* When calling e.g. {@link VarHandle#get(Object...)} on the resulting var handle, the incoming coordinate values
* starting at position {@code pos} (of type {@code C1, C2 ... Cn}, where {@code C1, C2 ... Cn} are the return types
* of the unary filter functions) are transformed into new values (of type {@code S1, S2 ... Sn}, where {@code S1, S2 ... Sn} are the
* parameter types of the unary filter functions), and then passed (along with any coordinate that was left unaltered
* by the adaptation) to the target var handle.
* <p>
* For the coordinate filters to be well-formed, their types must be of the form {@code S1 -> T1, S2 -> T1 ... Sn -> Tn},
* where {@code T1, T2 ... Tn} are the coordinate types starting at position {@code pos} of the target var handle.
* <p>
* If any of the filters throws a checked exception when invoked, the resulting var handle will
* throw an {@link IllegalStateException}.
* <p>
* The resulting var handle will feature the same access modes (see {@link VarHandle.AccessMode}) and
* atomic access guarantees as those featured by the target var handle.
*
* @param target the target var handle
* @param pos the position of the first coordinate to be transformed
* @param filters the unary functions which are used to transform coordinates starting at position {@code pos}
* @return an adapter var handle which accepts new coordinate types, applying the provided transformation
* to the new coordinate values.
* @throws IllegalArgumentException if the handles in {@code filters} are not well-formed, that is, they have types
* other than {@code S1 -> T1, S2 -> T2, ... Sn -> Tn} where {@code T1, T2 ... Tn} are the coordinate types starting
* at position {@code pos} of the target var handle, if {@code pos} is not between 0 and the target var handle coordinate arity, inclusive,
* 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
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static VarHandle filterCoordinates(VarHandle target, int pos, MethodHandle... filters) {
return VarHandles.filterCoordinates(target, pos, filters);
}
/**
* Provides a target var handle with one or more <em>bound coordinates</em>
* in advance of the var handle's invocation. As a consequence, the resulting var handle will feature less
* coordinate types than the target var handle.
* <p>
* When calling e.g. {@link VarHandle#get(Object...)} on the resulting var handle, incoming coordinate values
* are joined with bound coordinate values, and then passed to the target var handle.
* <p>
* For the bound coordinates to be well-formed, their types must be {@code T1, T2 ... Tn },
* where {@code T1, T2 ... Tn} are the coordinate types starting at position {@code pos} of the target var handle.
* <p>
* The resulting var handle will feature the same access modes (see {@link VarHandle.AccessMode}) and
* atomic access guarantees as those featured by the target var handle.
*
* @param target the var handle to invoke after the bound coordinates are inserted
* @param pos the position of the first coordinate to be inserted
* @param values the series of bound coordinates to insert
* @return an adapter var handle which inserts additional coordinates,
* before calling the target var handle
* @throws IllegalArgumentException if {@code pos} is not between 0 and the target var handle coordinate arity, inclusive,
* or if more values are provided than the actual number of coordinate types available starting at {@code pos}.
* @throws ClassCastException if the bound coordinates in {@code values} are not well-formed, that is, they have types
* 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
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static VarHandle insertCoordinates(VarHandle target, int pos, Object... values) {
return VarHandles.insertCoordinates(target, pos, values);
}
/**
* Provides a var handle which adapts the coordinate values of the target var handle, by re-arranging them
* so that the new coordinates match the provided ones.
* <p>
* The given array controls the reordering.
* Call {@code #I} the number of incoming coordinates (the value
* {@code newCoordinates.size()}), and call {@code #O} the number
* of outgoing coordinates (the number of coordinates associated with the target var handle).
* Then the length of the reordering array must be {@code #O},
* and each element must be a non-negative number less than {@code #I}.
* For every {@code N} less than {@code #O}, the {@code N}-th
* outgoing coordinate will be taken from the {@code I}-th incoming
* coordinate, where {@code I} is {@code reorder[N]}.
* <p>
* No coordinate value conversions are applied.
* The type of each incoming coordinate, as determined by {@code newCoordinates},
* must be identical to the type of the corresponding outgoing coordinate
* in the target var handle.
* <p>
* The reordering array need not specify an actual permutation.
* An incoming coordinate will be duplicated if its index appears
* more than once in the array, and an incoming coordinate will be dropped
* if its index does not appear in the array.
* <p>
* The resulting var handle will feature the same access modes (see {@link VarHandle.AccessMode}) and
* atomic access guarantees as those featured by the target var handle.
* @param target the var handle to invoke after the coordinates have been reordered
* @param newCoordinates the new coordinate types
* @param reorder an index array which controls the reordering
* @return an adapter var handle which re-arranges the incoming coordinate values,
* before calling the target var handle
* @throws IllegalArgumentException if the index array length is not equal to
* the number of coordinates of the target var handle, or if any index array element is not a valid index for
* 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
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static VarHandle permuteCoordinates(VarHandle target, List<Class<?>> newCoordinates, int... reorder) {
return VarHandles.permuteCoordinates(target, newCoordinates, reorder);
}
/**
* Adapts a target var handle by pre-processing
* a sub-sequence of its coordinate values with a filter (a method handle).
* The pre-processed coordinates are replaced by the result (if any) of the
* filter function and the target var handle is then called on the modified (usually shortened)
* coordinate list.
* <p>
* If {@code R} is the return type of the filter (which cannot be void), the target var handle must accept a value of
* type {@code R} as its coordinate in position {@code pos}, preceded and/or followed by
* any coordinate not passed to the filter.
* No coordinates are reordered, and the result returned from the filter
* replaces (in order) the whole subsequence of coordinates originally
* passed to the adapter.
* <p>
* The argument types (if any) of the filter
* replace zero or one coordinate types of the target var handle, at position {@code pos},
* in the resulting adapted var handle.
* The return type of the filter must be identical to the
* coordinate type of the target var handle at position {@code pos}, and that target var handle
* coordinate is supplied by the return value of the filter.
* <p>
* If any of the filters throws a checked exception when invoked, the resulting var handle will
* throw an {@link IllegalStateException}.
* <p>
* The resulting var handle will feature the same access modes (see {@link VarHandle.AccessMode}) and
* atomic access guarantees as those featured by the target var handle.
*
* @param target the var handle to invoke after the coordinates have been filtered
* @param pos the position of the coordinate to be filtered
* @param filter the filter method handle
* @return an adapter var handle which filters the incoming coordinate values,
* before calling the target var handle
* @throws IllegalArgumentException if the return type of {@code filter}
* is void, or it is not the same as the {@code pos} coordinate of the target var handle,
* if {@code pos} is not between 0 and the target var handle coordinate arity, inclusive,
* 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
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle filter) {
return VarHandles.collectCoordinates(target, pos, filter);
}
/**
* Returns a var handle which will discard some dummy coordinates before delegating to the
* target var handle. As a consequence, the resulting var handle will feature more
* coordinate types than the target var handle.
* <p>
* The {@code pos} argument may range between zero and <i>N</i>, where <i>N</i> is the arity of the
* target var handle's coordinate types. If {@code pos} is zero, the dummy coordinates will precede
* the target's real arguments; if {@code pos} is <i>N</i> they will come after.
* <p>
* The resulting var handle will feature the same access modes (see {@link VarHandle.AccessMode}) and
* atomic access guarantees as those featured by the target var handle.
*
* @param target the var handle to invoke after the dummy coordinates are dropped
* @param pos position of the first coordinate to drop (zero for the leftmost)
* @param valueTypes the type(s) of the coordinate(s) to drop
* @return an adapter var handle which drops some dummy coordinates,
* 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
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static VarHandle dropCoordinates(VarHandle target, int pos, Class<?>... valueTypes) {
return VarHandles.dropCoordinates(target, pos, valueTypes);
}
}

View file

@ -472,7 +472,7 @@ import static java.lang.invoke.MethodHandleStatics.UNSAFE;
* @since 9
*/
public abstract sealed class VarHandle implements Constable
permits IndirectVarHandle, MemoryAccessVarHandleBase,
permits IndirectVarHandle, VarHandleSegmentViewBase,
VarHandleByteArrayAsChars.ByteArrayViewVarHandle,
VarHandleByteArrayAsDoubles.ByteArrayViewVarHandle,
VarHandleByteArrayAsFloats.ByteArrayViewVarHandle,

View file

@ -26,17 +26,16 @@
package java.lang.invoke;
/**
* Base class for memory access var handle implementations.
* Base class for memory segment var handle view implementations.
*/
abstract sealed class MemoryAccessVarHandleBase extends VarHandle permits
MemoryAccessVarHandleByteHelper,
MemoryAccessVarHandleCharHelper,
MemoryAccessVarHandleDoubleHelper,
MemoryAccessVarHandleFloatHelper,
MemoryAccessVarHandleIntHelper,
MemoryAccessVarHandleLongHelper,
MemoryAccessVarHandleShortHelper
{
abstract sealed class VarHandleSegmentViewBase extends VarHandle permits
VarHandleSegmentAsBytes,
VarHandleSegmentAsChars,
VarHandleSegmentAsDoubles,
VarHandleSegmentAsFloats,
VarHandleSegmentAsInts,
VarHandleSegmentAsLongs,
VarHandleSegmentAsShorts {
/** endianness **/
final boolean be;
@ -47,12 +46,8 @@ abstract sealed class MemoryAccessVarHandleBase extends VarHandle permits
/** alignment constraint (in bytes, expressed as a bit mask) **/
final long alignmentMask;
/** if true, only the base part of the address will be checked for alignment **/
final boolean skipAlignmentMaskCheck;
MemoryAccessVarHandleBase(VarForm form, boolean skipAlignmentMaskCheck, boolean be, long length, long alignmentMask, boolean exact) {
VarHandleSegmentViewBase(VarForm form, boolean be, long length, long alignmentMask, boolean exact) {
super(form, exact);
this.skipAlignmentMaskCheck = skipAlignmentMaskCheck;
this.be = be;
this.length = length;
this.alignmentMask = alignmentMask;

View file

@ -300,23 +300,18 @@ final class VarHandles {
}
/**
* Creates a memory access VarHandle.
* Creates a memory segment view var handle.
*
* Resulting VarHandle will take a memory address as first argument,
* and a certain number of coordinate {@code long} parameters, depending on the length
* of the {@code strides} argument array.
*
* Coordinates are multiplied with corresponding scale factors ({@code strides}) and added
* to a single fixed offset to compute an effective offset from the given MemoryAddress for the access.
* The resulting var handle will take a memory segment as first argument (the segment to be dereferenced),
* and a {@code long} as second argument (the offset into the segment).
*
* @param carrier the Java carrier type.
* @param skipAlignmentMaskCheck if true, only the base part of the address will be checked for alignment.
* @param alignmentMask alignment requirement to be checked upon access. In bytes. Expressed as a mask.
* @param byteOrder the byte order.
* @return the created VarHandle.
*/
static VarHandle makeMemoryAddressViewHandle(Class<?> carrier, boolean skipAlignmentMaskCheck, long alignmentMask,
ByteOrder byteOrder) {
static VarHandle memorySegmentViewHandle(Class<?> carrier, long alignmentMask,
ByteOrder byteOrder) {
if (!carrier.isPrimitive() || carrier == void.class || carrier == boolean.class) {
throw new IllegalArgumentException("Invalid carrier: " + carrier.getName());
}
@ -325,19 +320,19 @@ final class VarHandles {
boolean exact = false;
if (carrier == byte.class) {
return maybeAdapt(new MemoryAccessVarHandleByteHelper(skipAlignmentMaskCheck, be, size, alignmentMask, exact));
return maybeAdapt(new VarHandleSegmentAsBytes(be, size, alignmentMask, exact));
} else if (carrier == char.class) {
return maybeAdapt(new MemoryAccessVarHandleCharHelper(skipAlignmentMaskCheck, be, size, alignmentMask, exact));
return maybeAdapt(new VarHandleSegmentAsChars(be, size, alignmentMask, exact));
} else if (carrier == short.class) {
return maybeAdapt(new MemoryAccessVarHandleShortHelper(skipAlignmentMaskCheck, be, size, alignmentMask, exact));
return maybeAdapt(new VarHandleSegmentAsShorts(be, size, alignmentMask, exact));
} else if (carrier == int.class) {
return maybeAdapt(new MemoryAccessVarHandleIntHelper(skipAlignmentMaskCheck, be, size, alignmentMask, exact));
return maybeAdapt(new VarHandleSegmentAsInts(be, size, alignmentMask, exact));
} else if (carrier == float.class) {
return maybeAdapt(new MemoryAccessVarHandleFloatHelper(skipAlignmentMaskCheck, be, size, alignmentMask, exact));
return maybeAdapt(new VarHandleSegmentAsFloats(be, size, alignmentMask, exact));
} else if (carrier == long.class) {
return maybeAdapt(new MemoryAccessVarHandleLongHelper(skipAlignmentMaskCheck, be, size, alignmentMask, exact));
return maybeAdapt(new VarHandleSegmentAsLongs(be, size, alignmentMask, exact));
} else if (carrier == double.class) {
return maybeAdapt(new MemoryAccessVarHandleDoubleHelper(skipAlignmentMaskCheck, be, size, alignmentMask, exact));
return maybeAdapt(new VarHandleSegmentAsDoubles(be, size, alignmentMask, exact));
} else {
throw new IllegalStateException("Cannot get here");
}

View file

@ -26,13 +26,15 @@ package java.lang.invoke;
import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.foreign.AbstractMemorySegmentImpl;
import jdk.internal.foreign.MemorySessionImpl;
import jdk.internal.misc.ScopedMemoryAccess;
import jdk.internal.misc.ScopedMemoryAccess.Scope;
import jdk.internal.misc.Unsafe;
import jdk.internal.util.Preconditions;
import jdk.internal.vm.annotation.ForceInline;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.nio.ByteBuffer;
import java.nio.ReadOnlyBufferException;
import java.util.List;
@ -607,15 +609,15 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
@ForceInline
static int index(ByteBuffer bb, int index) {
MemorySegmentProxy segmentProxy = NIO_ACCESS.bufferSegment(bb);
MemorySegment segment = NIO_ACCESS.bufferSegment(bb);
return Preconditions.checkIndex(index, UNSAFE.getInt(bb, BUFFER_LIMIT) - ALIGN, null);
}
@ForceInline
static Scope scope(ByteBuffer bb) {
MemorySegmentProxy segmentProxy = NIO_ACCESS.bufferSegment(bb);
return segmentProxy != null ?
segmentProxy.scope() : null;
static MemorySessionImpl session(ByteBuffer bb) {
MemorySegment segment = NIO_ACCESS.bufferSegment(bb);
return segment != null ?
((AbstractMemorySegmentImpl)segment).sessionImpl() : null;
}
@ForceInline
@ -638,13 +640,13 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
#if[floatingPoint]
$rawType$ rawValue = SCOPED_MEMORY_ACCESS.get$RawType$Unaligned(scope(bb),
$rawType$ rawValue = SCOPED_MEMORY_ACCESS.get$RawType$Unaligned(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
((long) index(bb, index)) + UNSAFE.getLong(bb, BUFFER_ADDRESS),
handle.be);
return $Type$.$rawType$BitsTo$Type$(rawValue);
#else[floatingPoint]
return SCOPED_MEMORY_ACCESS.get$Type$Unaligned(scope(bb),
return SCOPED_MEMORY_ACCESS.get$Type$Unaligned(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
((long) index(bb, index)) + UNSAFE.getLong(bb, BUFFER_ADDRESS),
handle.be);
@ -656,13 +658,13 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
#if[floatingPoint]
SCOPED_MEMORY_ACCESS.put$RawType$Unaligned(scope(bb),
SCOPED_MEMORY_ACCESS.put$RawType$Unaligned(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
((long) indexRO(bb, index)) + UNSAFE.getLong(bb, BUFFER_ADDRESS),
$Type$.$type$ToRaw$RawType$Bits(value),
handle.be);
#else[floatingPoint]
SCOPED_MEMORY_ACCESS.put$Type$Unaligned(scope(bb),
SCOPED_MEMORY_ACCESS.put$Type$Unaligned(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
((long) indexRO(bb, index)) + UNSAFE.getLong(bb, BUFFER_ADDRESS),
value,
@ -675,7 +677,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.get$RawType$Volatile(scope(bb),
SCOPED_MEMORY_ACCESS.get$RawType$Volatile(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, index(bb, index))));
}
@ -684,7 +686,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
static void setVolatile(VarHandle ob, Object obb, int index, $type$ value) {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
SCOPED_MEMORY_ACCESS.put$RawType$Volatile(scope(bb),
SCOPED_MEMORY_ACCESS.put$RawType$Volatile(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
convEndian(handle.be, value));
@ -695,7 +697,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.get$RawType$Acquire(scope(bb),
SCOPED_MEMORY_ACCESS.get$RawType$Acquire(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, index(bb, index))));
}
@ -704,7 +706,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
static void setRelease(VarHandle ob, Object obb, int index, $type$ value) {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
SCOPED_MEMORY_ACCESS.put$RawType$Release(scope(bb),
SCOPED_MEMORY_ACCESS.put$RawType$Release(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
convEndian(handle.be, value));
@ -715,7 +717,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.get$RawType$Opaque(scope(bb),
SCOPED_MEMORY_ACCESS.get$RawType$Opaque(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, index(bb, index))));
}
@ -724,7 +726,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
static void setOpaque(VarHandle ob, Object obb, int index, $type$ value) {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
SCOPED_MEMORY_ACCESS.put$RawType$Opaque(scope(bb),
SCOPED_MEMORY_ACCESS.put$RawType$Opaque(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
convEndian(handle.be, value));
@ -736,12 +738,12 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
#if[Object]
return SCOPED_MEMORY_ACCESS.compareAndSetReference(scope(bb),
return SCOPED_MEMORY_ACCESS.compareAndSetReference(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
convEndian(handle.be, expected), convEndian(handle.be, value));
#else[Object]
return SCOPED_MEMORY_ACCESS.compareAndSet$RawType$(scope(bb),
return SCOPED_MEMORY_ACCESS.compareAndSet$RawType$(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
convEndian(handle.be, expected), convEndian(handle.be, value));
@ -753,7 +755,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$(scope(bb),
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
convEndian(handle.be, expected), convEndian(handle.be, value)));
@ -764,7 +766,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Acquire(scope(bb),
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Acquire(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
convEndian(handle.be, expected), convEndian(handle.be, value)));
@ -775,7 +777,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Release(scope(bb),
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Release(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
convEndian(handle.be, expected), convEndian(handle.be, value)));
@ -785,7 +787,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
static boolean weakCompareAndSetPlain(VarHandle ob, Object obb, int index, $type$ expected, $type$ value) {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Plain(scope(bb),
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Plain(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
convEndian(handle.be, expected), convEndian(handle.be, value));
@ -795,7 +797,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
static boolean weakCompareAndSet(VarHandle ob, Object obb, int index, $type$ expected, $type$ value) {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(scope(bb),
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
convEndian(handle.be, expected), convEndian(handle.be, value));
@ -805,7 +807,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
static boolean weakCompareAndSetAcquire(VarHandle ob, Object obb, int index, $type$ expected, $type$ value) {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Acquire(scope(bb),
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Acquire(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
convEndian(handle.be, expected), convEndian(handle.be, value));
@ -815,7 +817,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
static boolean weakCompareAndSetRelease(VarHandle ob, Object obb, int index, $type$ expected, $type$ value) {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Release(scope(bb),
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Release(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
convEndian(handle.be, expected), convEndian(handle.be, value));
@ -827,13 +829,13 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
#if[Object]
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.getAndSetReference(scope(bb),
SCOPED_MEMORY_ACCESS.getAndSetReference(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
convEndian(handle.be, value)));
#else[Object]
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.getAndSet$RawType$(scope(bb),
SCOPED_MEMORY_ACCESS.getAndSet$RawType$(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
convEndian(handle.be, value)));
@ -845,7 +847,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.getAndSet$RawType$Acquire(scope(bb),
SCOPED_MEMORY_ACCESS.getAndSet$RawType$Acquire(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
convEndian(handle.be, value)));
@ -856,7 +858,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.getAndSet$RawType$Release(scope(bb),
SCOPED_MEMORY_ACCESS.getAndSet$RawType$Release(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
convEndian(handle.be, value)));
@ -869,7 +871,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$(scope(bb),
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
delta);
@ -883,7 +885,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Acquire(scope(bb),
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Acquire(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
delta);
@ -897,7 +899,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Release(scope(bb),
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Release(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
delta);
@ -912,7 +914,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
Object base = UNSAFE.getReference(bb, BYTE_BUFFER_HB);
long offset = address(bb, indexRO(bb, index));
do {
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(scope(bb), base, offset);
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(session(bb), base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
} while (!UNSAFE.weakCompareAndSet$RawType$(base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue + delta)));
@ -926,7 +928,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$(scope(bb),
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
value);
@ -940,7 +942,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Release(scope(bb),
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Release(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
value);
@ -954,7 +956,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Acquire(scope(bb),
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Acquire(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
value);
@ -969,7 +971,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
Object base = UNSAFE.getReference(bb, BYTE_BUFFER_HB);
long offset = address(bb, indexRO(bb, index));
do {
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(scope(bb), base, offset);
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(session(bb), base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
} while (!UNSAFE.weakCompareAndSet$RawType$(base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue | value)));
@ -981,7 +983,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$(scope(bb),
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
value);
@ -995,7 +997,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Release(scope(bb),
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Release(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
value);
@ -1009,7 +1011,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Acquire(scope(bb),
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Acquire(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
value);
@ -1024,7 +1026,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
Object base = UNSAFE.getReference(bb, BYTE_BUFFER_HB);
long offset = address(bb, indexRO(bb, index));
do {
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(scope(bb), base, offset);
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(session(bb), base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
} while (!UNSAFE.weakCompareAndSet$RawType$(base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue & value)));
@ -1037,7 +1039,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$(scope(bb),
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
value);
@ -1051,7 +1053,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Release(scope(bb),
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Release(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
value);
@ -1065,7 +1067,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
ByteBufferHandle handle = (ByteBufferHandle)ob;
ByteBuffer bb = (ByteBuffer) Objects.requireNonNull(obb);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Acquire(scope(bb),
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Acquire(session(bb),
UNSAFE.getReference(bb, BYTE_BUFFER_HB),
address(bb, indexRO(bb, index)),
value);
@ -1080,7 +1082,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
Object base = UNSAFE.getReference(bb, BYTE_BUFFER_HB);
long offset = address(bb, indexRO(bb, index));
do {
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(scope(bb), base, offset);
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(session(bb), base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
} while (!UNSAFE.weakCompareAndSet$RawType$(base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue ^ value)));

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, 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
@ -24,10 +24,11 @@
*/
package java.lang.invoke;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.foreign.AbstractMemorySegmentImpl;
import jdk.internal.misc.ScopedMemoryAccess;
import jdk.internal.vm.annotation.ForceInline;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Reference;
import java.util.Objects;
@ -36,7 +37,7 @@ import static java.lang.invoke.MethodHandleStatics.UNSAFE;
#warn
final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase {
final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
static final boolean BE = UNSAFE.isBigEndian();
@ -44,29 +45,29 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
static final int VM_ALIGN = $BoxType$.BYTES - 1;
static final VarForm FORM = new VarForm(MemoryAccessVarHandle$Type$Helper.class, MemorySegmentProxy.class, $type$.class, long.class);
static final VarForm FORM = new VarForm(VarHandleSegmentAs$Type$s.class, MemorySegment.class, $type$.class, long.class);
MemoryAccessVarHandle$Type$Helper(boolean skipAlignmentMaskCheck, boolean be, long length, long alignmentMask, boolean exact) {
super(FORM, skipAlignmentMaskCheck, be, length, alignmentMask, exact);
VarHandleSegmentAs$Type$s(boolean be, long length, long alignmentMask, boolean exact) {
super(FORM, be, length, alignmentMask, exact);
}
@Override
final MethodType accessModeTypeUncached(VarHandle.AccessType accessType) {
return accessType.accessModeType(MemorySegmentProxy.class, $type$.class, long.class);
return accessType.accessModeType(MemorySegment.class, $type$.class, long.class);
}
@Override
public MemoryAccessVarHandle$Type$Helper withInvokeExactBehavior() {
public VarHandleSegmentAs$Type$s withInvokeExactBehavior() {
return hasInvokeExactBehavior() ?
this :
new MemoryAccessVarHandle$Type$Helper(skipAlignmentMaskCheck, be, length, alignmentMask, true);
new VarHandleSegmentAs$Type$s(be, length, alignmentMask, true);
}
@Override
public MemoryAccessVarHandle$Type$Helper withInvokeBehavior() {
public VarHandleSegmentAs$Type$s withInvokeBehavior() {
return !hasInvokeExactBehavior() ?
this :
new MemoryAccessVarHandle$Type$Helper(skipAlignmentMaskCheck, be, length, alignmentMask, false);
new VarHandleSegmentAs$Type$s(be, length, alignmentMask, false);
}
#if[floatingPoint]
@ -96,58 +97,51 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
#end[floatingPoint]
@ForceInline
static MemorySegmentProxy checkAddress(Object obb, long offset, long length, boolean ro) {
MemorySegmentProxy oo = (MemorySegmentProxy)Objects.requireNonNull(obb);
static AbstractMemorySegmentImpl checkAddress(Object obb, long offset, long length, boolean ro) {
AbstractMemorySegmentImpl oo = (AbstractMemorySegmentImpl)Objects.requireNonNull(obb);
oo.checkAccess(offset, length, ro);
return oo;
}
@ForceInline
static long offset(boolean skipAlignmentMaskCheck, MemorySegmentProxy bb, long offset, long alignmentMask) {
long address = offsetNoVMAlignCheck(skipAlignmentMaskCheck, bb, offset, alignmentMask);
static long offset(AbstractMemorySegmentImpl bb, long offset, long alignmentMask) {
long address = offsetNoVMAlignCheck(bb, offset, alignmentMask);
if ((address & VM_ALIGN) != 0) {
throw MemoryAccessVarHandleBase.newIllegalArgumentExceptionForMisalignedAccess(address);
throw VarHandleSegmentViewBase.newIllegalArgumentExceptionForMisalignedAccess(address);
}
return address;
}
@ForceInline
static long offsetNoVMAlignCheck(boolean skipAlignmentMaskCheck, MemorySegmentProxy bb, long offset, long alignmentMask) {
static long offsetNoVMAlignCheck(AbstractMemorySegmentImpl bb, long offset, long alignmentMask) {
long base = bb.unsafeGetOffset();
long address = base + offset;
long maxAlignMask = bb.maxAlignMask();
if (skipAlignmentMaskCheck) {
//note: the offset portion has already been aligned-checked, by construction
if (((base | maxAlignMask) & alignmentMask) != 0) {
throw MemoryAccessVarHandleBase.newIllegalArgumentExceptionForMisalignedAccess(address);
}
} else {
if (((address | maxAlignMask) & alignmentMask) != 0) {
throw MemoryAccessVarHandleBase.newIllegalArgumentExceptionForMisalignedAccess(address);
}
if (((address | maxAlignMask) & alignmentMask) != 0) {
throw VarHandleSegmentViewBase.newIllegalArgumentExceptionForMisalignedAccess(address);
}
return address;
}
@ForceInline
static $type$ get(VarHandle ob, Object obb, long base) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, true);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, true);
#if[floatingPoint]
$rawType$ rawValue = SCOPED_MEMORY_ACCESS.get$RawType$Unaligned(bb.scope(),
$rawType$ rawValue = SCOPED_MEMORY_ACCESS.get$RawType$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetNoVMAlignCheck(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
handle.be);
return $Type$.$rawType$BitsTo$Type$(rawValue);
#else[floatingPoint]
#if[byte]
return SCOPED_MEMORY_ACCESS.get$Type$(bb.scope(),
return SCOPED_MEMORY_ACCESS.get$Type$(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetNoVMAlignCheck(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask));
offsetNoVMAlignCheck(bb, base, handle.alignmentMask));
#else[byte]
return SCOPED_MEMORY_ACCESS.get$Type$Unaligned(bb.scope(),
return SCOPED_MEMORY_ACCESS.get$Type$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetNoVMAlignCheck(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
handle.be);
#end[byte]
#end[floatingPoint]
@ -155,24 +149,24 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
@ForceInline
static void set(VarHandle ob, Object obb, long base, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
#if[floatingPoint]
SCOPED_MEMORY_ACCESS.put$RawType$Unaligned(bb.scope(),
SCOPED_MEMORY_ACCESS.put$RawType$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetNoVMAlignCheck(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
$Type$.$type$ToRaw$RawType$Bits(value),
handle.be);
#else[floatingPoint]
#if[byte]
SCOPED_MEMORY_ACCESS.put$Type$(bb.scope(),
SCOPED_MEMORY_ACCESS.put$Type$(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetNoVMAlignCheck(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
value);
#else[byte]
SCOPED_MEMORY_ACCESS.put$Type$Unaligned(bb.scope(),
SCOPED_MEMORY_ACCESS.put$Type$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetNoVMAlignCheck(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
value,
handle.be);
#end[byte]
@ -181,178 +175,178 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
@ForceInline
static $type$ getVolatile(VarHandle ob, Object obb, long base) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, true);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, true);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.scope(),
SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask)));
offset(bb, base, handle.alignmentMask)));
}
@ForceInline
static void setVolatile(VarHandle ob, Object obb, long base, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
SCOPED_MEMORY_ACCESS.put$RawType$Volatile(bb.scope(),
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
SCOPED_MEMORY_ACCESS.put$RawType$Volatile(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value));
}
@ForceInline
static $type$ getAcquire(VarHandle ob, Object obb, long base) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, true);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, true);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.get$RawType$Acquire(bb.scope(),
SCOPED_MEMORY_ACCESS.get$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask)));
offset(bb, base, handle.alignmentMask)));
}
@ForceInline
static void setRelease(VarHandle ob, Object obb, long base, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
SCOPED_MEMORY_ACCESS.put$RawType$Release(bb.scope(),
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
SCOPED_MEMORY_ACCESS.put$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value));
}
@ForceInline
static $type$ getOpaque(VarHandle ob, Object obb, long base) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, true);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, true);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.get$RawType$Opaque(bb.scope(),
SCOPED_MEMORY_ACCESS.get$RawType$Opaque(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask)));
offset(bb, base, handle.alignmentMask)));
}
@ForceInline
static void setOpaque(VarHandle ob, Object obb, long base, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
SCOPED_MEMORY_ACCESS.put$RawType$Opaque(bb.scope(),
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
SCOPED_MEMORY_ACCESS.put$RawType$Opaque(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value));
}
#if[CAS]
@ForceInline
static boolean compareAndSet(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
return SCOPED_MEMORY_ACCESS.compareAndSet$RawType$(bb.scope(),
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return SCOPED_MEMORY_ACCESS.compareAndSet$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ForceInline
static $type$ compareAndExchange(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$(bb.scope(),
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value)));
}
@ForceInline
static $type$ compareAndExchangeAcquire(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Acquire(bb.scope(),
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value)));
}
@ForceInline
static $type$ compareAndExchangeRelease(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Release(bb.scope(),
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value)));
}
@ForceInline
static boolean weakCompareAndSetPlain(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Plain(bb.scope(),
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Plain(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ForceInline
static boolean weakCompareAndSet(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.scope(),
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ForceInline
static boolean weakCompareAndSetAcquire(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Acquire(bb.scope(),
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ForceInline
static boolean weakCompareAndSetRelease(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Release(bb.scope(),
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ForceInline
static $type$ getAndSet(VarHandle ob, Object obb, long base, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.getAndSet$RawType$(bb.scope(),
SCOPED_MEMORY_ACCESS.getAndSet$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value)));
}
@ForceInline
static $type$ getAndSetAcquire(VarHandle ob, Object obb, long base, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.getAndSet$RawType$Acquire(bb.scope(),
SCOPED_MEMORY_ACCESS.getAndSet$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value)));
}
@ForceInline
static $type$ getAndSetRelease(VarHandle ob, Object obb, long base, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.getAndSet$RawType$Release(bb.scope(),
SCOPED_MEMORY_ACCESS.getAndSet$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value)));
}
#end[CAS]
@ -360,54 +354,54 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
@ForceInline
static $type$ getAndAdd(VarHandle ob, Object obb, long base, $type$ delta) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$(bb.scope(),
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
delta);
} else {
return getAndAddConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), delta);
return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta);
}
}
@ForceInline
static $type$ getAndAddAcquire(VarHandle ob, Object obb, long base, $type$ delta) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Acquire(bb.scope(),
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
delta);
} else {
return getAndAddConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), delta);
return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta);
}
}
@ForceInline
static $type$ getAndAddRelease(VarHandle ob, Object obb, long base, $type$ delta) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Release(bb.scope(),
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
delta);
} else {
return getAndAddConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), delta);
return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta);
}
}
@ForceInline
static $type$ getAndAddConvEndianWithCAS(MemorySegmentProxy bb, long offset, $type$ delta) {
static $type$ getAndAddConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ delta) {
$type$ nativeExpectedValue, expectedValue;
Object base = bb.unsafeGetBase();
do {
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.scope(),base, offset);
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
} while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.scope(),base, offset,
} while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue + delta)));
return expectedValue;
}
@ -416,108 +410,108 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
@ForceInline
static $type$ getAndBitwiseOr(VarHandle ob, Object obb, long base, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$(bb.scope(),
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseOrConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseOrRelease(VarHandle ob, Object obb, long base, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Release(bb.scope(),
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseOrConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseOrAcquire(VarHandle ob, Object obb, long base, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Acquire(bb.scope(),
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseOrConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseOrConvEndianWithCAS(MemorySegmentProxy bb, long offset, $type$ value) {
static $type$ getAndBitwiseOrConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ value) {
$type$ nativeExpectedValue, expectedValue;
Object base = bb.unsafeGetBase();
do {
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.scope(),base, offset);
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
} while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.scope(),base, offset,
} while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue | value)));
return expectedValue;
}
@ForceInline
static $type$ getAndBitwiseAnd(VarHandle ob, Object obb, long base, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$(bb.scope(),
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseAndConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseAndRelease(VarHandle ob, Object obb, long base, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Release(bb.scope(),
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseAndConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseAndAcquire(VarHandle ob, Object obb, long base, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Acquire(bb.scope(),
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseAndConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseAndConvEndianWithCAS(MemorySegmentProxy bb, long offset, $type$ value) {
static $type$ getAndBitwiseAndConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ value) {
$type$ nativeExpectedValue, expectedValue;
Object base = bb.unsafeGetBase();
do {
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.scope(),base, offset);
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
} while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.scope(),base, offset,
} while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue & value)));
return expectedValue;
}
@ -525,54 +519,54 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
@ForceInline
static $type$ getAndBitwiseXor(VarHandle ob, Object obb, long base, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$(bb.scope(),
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseXorConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseXorRelease(VarHandle ob, Object obb, long base, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Release(bb.scope(),
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseXorConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseXorAcquire(VarHandle ob, Object obb, long base, $type$ value) {
MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Acquire(bb.scope(),
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseXorConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseXorConvEndianWithCAS(MemorySegmentProxy bb, long offset, $type$ value) {
static $type$ getAndBitwiseXorConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ value) {
$type$ nativeExpectedValue, expectedValue;
Object base = bb.unsafeGetBase();
do {
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.scope(),base, offset);
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
} while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.scope(),base, offset,
} while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue ^ value)));
return expectedValue;
}

View file

@ -27,15 +27,17 @@ package java.nio;
import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.access.foreign.UnmapperProxy;
import jdk.internal.foreign.AbstractMemorySegmentImpl;
import jdk.internal.foreign.MemorySessionImpl;
import jdk.internal.misc.ScopedMemoryAccess;
import jdk.internal.misc.ScopedMemoryAccess.Scope;
import jdk.internal.misc.Unsafe;
import jdk.internal.misc.VM.BufferPool;
import jdk.internal.vm.annotation.ForceInline;
import java.io.FileDescriptor;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.util.Objects;
import java.util.Spliterator;
@ -225,12 +227,12 @@ public abstract sealed class Buffer
long address;
// Used by buffers generated by the memory access API (JEP-370)
final MemorySegmentProxy segment;
final MemorySegment segment;
// Creates a new buffer with given address and capacity.
//
Buffer(long addr, int cap, MemorySegmentProxy segment) {
Buffer(long addr, int cap, MemorySegment segment) {
this.address = addr;
this.capacity = cap;
this.segment = segment;
@ -239,7 +241,7 @@ public abstract sealed class Buffer
// Creates a new buffer with the given mark, position, limit, and capacity,
// after checking invariants.
//
Buffer(int mark, int pos, int lim, int cap, MemorySegmentProxy segment) { // package-private
Buffer(int mark, int pos, int lim, int cap, MemorySegment segment) { // package-private
if (cap < 0)
throw createCapacityException(cap);
this.capacity = cap;
@ -758,20 +760,20 @@ public abstract sealed class Buffer
}
@ForceInline
final ScopedMemoryAccess.Scope scope() {
final MemorySessionImpl session() {
if (segment != null) {
return segment.scope();
return ((AbstractMemorySegmentImpl)segment).sessionImpl();
} else {
return null;
}
}
final void checkScope() {
ScopedMemoryAccess.Scope scope = scope();
if (scope != null) {
final void checkSession() {
MemorySessionImpl session = session();
if (session != null) {
try {
scope.checkValidState();
} catch (ScopedMemoryAccess.Scope.ScopedAccessError e) {
session.checkValidState();
} catch (ScopedMemoryAccess.ScopedAccessError e) {
throw new IllegalStateException("This segment is already closed");
}
}
@ -787,17 +789,17 @@ public abstract sealed class Buffer
}
@Override
public ByteBuffer newDirectByteBuffer(long addr, int cap, Object obj, MemorySegmentProxy segment) {
public ByteBuffer newDirectByteBuffer(long addr, int cap, Object obj, MemorySegment segment) {
return new DirectByteBuffer(addr, cap, obj, segment);
}
@Override
public ByteBuffer newMappedByteBuffer(UnmapperProxy unmapperProxy, long address, int cap, Object obj, MemorySegmentProxy segment) {
public ByteBuffer newMappedByteBuffer(UnmapperProxy unmapperProxy, long address, int cap, Object obj, MemorySegment segment) {
return new DirectByteBuffer(address, cap, obj, unmapperProxy.fileDescriptor(), unmapperProxy.isSync(), segment);
}
@Override
public ByteBuffer newHeapByteBuffer(byte[] hb, int offset, int capacity, MemorySegmentProxy segment) {
public ByteBuffer newHeapByteBuffer(byte[] hb, int offset, int capacity, MemorySegment segment) {
return new HeapByteBuffer(hb, -1, 0, capacity, capacity, offset, segment);
}
@ -821,21 +823,21 @@ public abstract sealed class Buffer
}
@Override
public MemorySegmentProxy bufferSegment(Buffer buffer) {
public MemorySegment bufferSegment(Buffer buffer) {
return buffer.segment;
}
@Override
public Runnable acquireScope(Buffer buffer, boolean async) {
var scope = buffer.scope();
if (scope == null) {
public Runnable acquireSession(Buffer buffer, boolean async) {
var session = buffer.session();
if (session == null) {
return null;
}
if (async && scope.ownerThread() != null) {
throw new IllegalStateException("Confined scope not supported");
if (async && session.ownerThread() != null) {
throw new IllegalStateException("Confined session not supported");
}
scope.acquire0();
return scope::release0;
session.acquire0();
return session::release0;
}
@Override

View file

@ -39,7 +39,7 @@ final class BufferMismatch {
if (length > 7) {
if (a.get(aOff) != b.get(bOff))
return 0;
i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(a.scope(), b.scope(),
i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(a.session(), b.session(),
a.base(), a.address + aOff,
b.base(), b.address + bOff,
length,
@ -63,7 +63,7 @@ final class BufferMismatch {
&& a.charRegionOrder() != null && b.charRegionOrder() != null) {
if (a.get(aOff) != b.get(bOff))
return 0;
i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(a.scope(), b.scope(),
i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(a.session(), b.session(),
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_CHAR_INDEX_SCALE),
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_CHAR_INDEX_SCALE),
length,
@ -83,7 +83,7 @@ final class BufferMismatch {
if (length > 3 && a.order() == b.order()) {
if (a.get(aOff) != b.get(bOff))
return 0;
i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(a.scope(), b.scope(),
i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(a.session(), b.session(),
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_SHORT_INDEX_SCALE),
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_SHORT_INDEX_SCALE),
length,
@ -103,7 +103,7 @@ final class BufferMismatch {
if (length > 1 && a.order() == b.order()) {
if (a.get(aOff) != b.get(bOff))
return 0;
i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(a.scope(), b.scope(),
i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(a.session(), b.session(),
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_INT_INDEX_SCALE),
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_INT_INDEX_SCALE),
length,
@ -122,7 +122,7 @@ final class BufferMismatch {
int i = 0;
if (length > 1 && a.order() == b.order()) {
if (Float.floatToRawIntBits(a.get(aOff)) == Float.floatToRawIntBits(b.get(bOff))) {
i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(a.scope(), b.scope(),
i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(a.session(), b.session(),
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_FLOAT_INDEX_SCALE),
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_FLOAT_INDEX_SCALE),
length,
@ -161,7 +161,7 @@ final class BufferMismatch {
if (length > 0 && a.order() == b.order()) {
if (a.get(aOff) != b.get(bOff))
return 0;
i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(a.scope(), b.scope(),
i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(a.session(), b.session(),
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_LONG_INDEX_SCALE),
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_LONG_INDEX_SCALE),
length,
@ -179,7 +179,7 @@ final class BufferMismatch {
int i = 0;
if (length > 0 && a.order() == b.order()) {
if (Double.doubleToRawLongBits(a.get(aOff)) == Double.doubleToRawLongBits(b.get(bOff))) {
i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(a.scope(), b.scope(),
i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(a.session(), b.session(),
a.base(), a.address + (aOff << ArraysSupport.LOG2_ARRAY_DOUBLE_INDEX_SCALE),
b.base(), b.address + (bOff << ArraysSupport.LOG2_ARRAY_DOUBLE_INDEX_SCALE),
length,

View file

@ -27,8 +27,8 @@
package java.nio;
import java.lang.foreign.MemorySegment;
import java.util.Objects;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.misc.Unsafe;
#if[rw]
@ -49,7 +49,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
#end[rw]
ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb, MemorySegmentProxy segment) { // package-private
ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb, MemorySegment segment) { // package-private
#if[rw]
super(-1, 0,
bb.remaining() >> $LG_BYTES_PER_VALUE$,
@ -68,7 +68,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb,
int mark, int pos, int lim, int cap,
long addr, MemorySegmentProxy segment)
long addr, MemorySegment segment)
{
#if[rw]
super(mark, pos, lim, cap, segment);
@ -138,13 +138,13 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
}
public $type$ get() {
$memtype$ x = SCOPED_MEMORY_ACCESS.get$Memtype$Unaligned(scope(), bb.hb, byteOffset(nextGetIndex()),
$memtype$ x = SCOPED_MEMORY_ACCESS.get$Memtype$Unaligned(session(), bb.hb, byteOffset(nextGetIndex()),
{#if[boB]?true:false});
return $fromBits$(x);
}
public $type$ get(int i) {
$memtype$ x = SCOPED_MEMORY_ACCESS.get$Memtype$Unaligned(scope(), bb.hb, byteOffset(checkIndex(i)),
$memtype$ x = SCOPED_MEMORY_ACCESS.get$Memtype$Unaligned(session(), bb.hb, byteOffset(checkIndex(i)),
{#if[boB]?true:false});
return $fromBits$(x);
}
@ -162,7 +162,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
public $Type$Buffer put($type$ x) {
#if[rw]
$memtype$ y = $toBits$(x);
SCOPED_MEMORY_ACCESS.put$Memtype$Unaligned(scope(), bb.hb, byteOffset(nextPutIndex()), y,
SCOPED_MEMORY_ACCESS.put$Memtype$Unaligned(session(), bb.hb, byteOffset(nextPutIndex()), y,
{#if[boB]?true:false});
return this;
#else[rw]
@ -173,7 +173,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
public $Type$Buffer put(int i, $type$ x) {
#if[rw]
$memtype$ y = $toBits$(x);
SCOPED_MEMORY_ACCESS.put$Memtype$Unaligned(scope(), bb.hb, byteOffset(checkIndex(i)), y,
SCOPED_MEMORY_ACCESS.put$Memtype$Unaligned(session(), bb.hb, byteOffset(checkIndex(i)), y,
{#if[boB]?true:false});
return this;
#else[rw]

View file

@ -33,7 +33,7 @@ class XXX {
private $type$ get$Type$(long a) {
try {
$memtype$ x = SCOPED_MEMORY_ACCESS.get$Memtype$Unaligned(scope(), null, a, bigEndian);
$memtype$ x = SCOPED_MEMORY_ACCESS.get$Memtype$Unaligned(session(), null, a, bigEndian);
return $fromBits$(x);
} finally {
Reference.reachabilityFence(this);
@ -62,7 +62,7 @@ class XXX {
#if[rw]
try {
$memtype$ y = $toBits$(x);
SCOPED_MEMORY_ACCESS.put$Memtype$Unaligned(scope(), null, a, y, bigEndian);
SCOPED_MEMORY_ACCESS.put$Memtype$Unaligned(session(), null, a, y, bigEndian);
} finally {
Reference.reachabilityFence(this);
}

View file

@ -28,10 +28,12 @@
package java.nio;
import java.io.FileDescriptor;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.ref.Reference;
import java.util.Objects;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.misc.ScopedMemoryAccess.Scope;
import jdk.internal.foreign.MemorySessionImpl;
import jdk.internal.misc.ScopedMemoryAccess.ScopedAccessError;
import jdk.internal.misc.VM;
import jdk.internal.ref.Cleaner;
import sun.nio.ch.DirectBuffer;
@ -152,7 +154,7 @@ class Direct$Type$Buffer$RW$$BO$
// Invoked to construct a direct ByteBuffer referring to the block of
// memory. A given arbitrary object may also be attached to the buffer.
//
Direct$Type$Buffer(long addr, int cap, Object ob, MemorySegmentProxy segment) {
Direct$Type$Buffer(long addr, int cap, Object ob, MemorySegment segment) {
super(-1, 0, cap, cap, segment);
address = addr;
cleaner = null;
@ -162,7 +164,7 @@ class Direct$Type$Buffer$RW$$BO$
// Invoked to construct a direct ByteBuffer referring to the block of
// memory. A given arbitrary object may also be attached to the buffer.
//
Direct$Type$Buffer(long addr, int cap, Object ob, FileDescriptor fd, boolean isSync, MemorySegmentProxy segment) {
Direct$Type$Buffer(long addr, int cap, Object ob, FileDescriptor fd, boolean isSync, MemorySegment segment) {
super(-1, 0, cap, cap, fd, isSync, segment);
address = addr;
cleaner = null;
@ -185,7 +187,7 @@ class Direct$Type$Buffer$RW$$BO$
protected Direct$Type$Buffer$RW$(int cap, long addr,
FileDescriptor fd,
Runnable unmapper,
boolean isSync, MemorySegmentProxy segment)
boolean isSync, MemorySegment segment)
{
#if[rw]
super(-1, 0, cap, cap, fd, isSync, segment);
@ -207,7 +209,7 @@ class Direct$Type$Buffer$RW$$BO$
#if[byte]
FileDescriptor fd, boolean isSync,
#end[byte]
MemorySegmentProxy segment)
MemorySegment segment)
{
#if[rw]
super(mark, pos, lim, cap,
@ -306,14 +308,14 @@ class Direct$Type$Buffer$RW$$BO$
#if[rw]
public long address() {
Scope scope = scope();
if (scope != null) {
if (scope.ownerThread() == null) {
throw new UnsupportedOperationException("ByteBuffer derived from shared segments not supported");
MemorySessionImpl session = session();
if (session != null) {
if (session.ownerThread() == null && session.isCloseable()) {
throw new UnsupportedOperationException("ByteBuffer derived from closeable shared sessions not supported");
}
try {
scope.checkValidState();
} catch (Scope.ScopedAccessError e) {
session.checkValidState();
} catch (ScopedAccessError e) {
throw new IllegalStateException("This segment is already closed");
}
}
@ -326,7 +328,7 @@ class Direct$Type$Buffer$RW$$BO$
public $type$ get() {
try {
return $fromBits$($swap$(SCOPED_MEMORY_ACCESS.get$Swaptype$(scope(), null, ix(nextGetIndex()))));
return $fromBits$($swap$(SCOPED_MEMORY_ACCESS.get$Swaptype$(session(), null, ix(nextGetIndex()))));
} finally {
Reference.reachabilityFence(this);
}
@ -334,7 +336,7 @@ class Direct$Type$Buffer$RW$$BO$
public $type$ get(int i) {
try {
return $fromBits$($swap$(SCOPED_MEMORY_ACCESS.get$Swaptype$(scope(), null, ix(checkIndex(i)))));
return $fromBits$($swap$(SCOPED_MEMORY_ACCESS.get$Swaptype$(session(), null, ix(checkIndex(i)))));
} finally {
Reference.reachabilityFence(this);
}
@ -354,7 +356,7 @@ class Direct$Type$Buffer$RW$$BO$
public $Type$Buffer put($type$ x) {
#if[rw]
try {
SCOPED_MEMORY_ACCESS.put$Swaptype$(scope(), null, ix(nextPutIndex()), $swap$($toBits$(x)));
SCOPED_MEMORY_ACCESS.put$Swaptype$(session(), null, ix(nextPutIndex()), $swap$($toBits$(x)));
} finally {
Reference.reachabilityFence(this);
}
@ -367,7 +369,7 @@ class Direct$Type$Buffer$RW$$BO$
public $Type$Buffer put(int i, $type$ x) {
#if[rw]
try {
SCOPED_MEMORY_ACCESS.put$Swaptype$(scope(), null, ix(checkIndex(i)), $swap$($toBits$(x)));
SCOPED_MEMORY_ACCESS.put$Swaptype$(session(), null, ix(checkIndex(i)), $swap$($toBits$(x)));
} finally {
Reference.reachabilityFence(this);
}
@ -384,8 +386,8 @@ class Direct$Type$Buffer$RW$$BO$
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
try {
// null is passed as destination Scope to avoid checking scope() twice
SCOPED_MEMORY_ACCESS.copyMemory(scope(), null, null,
// null is passed as destination MemorySession to avoid checking session() twice
SCOPED_MEMORY_ACCESS.copyMemory(session(), null, null,
ix(pos), null, ix(0), (long)rem << $LG_BYTES_PER_VALUE$);
} finally {
Reference.reachabilityFence(this);

View file

@ -27,8 +27,8 @@
package java.nio;
import java.lang.foreign.MemorySegment;
import java.util.Objects;
import jdk.internal.access.foreign.MemorySegmentProxy;
/**
#if[rw]
@ -66,7 +66,7 @@ class Heap$Type$Buffer$RW$
*/
#end[rw]
Heap$Type$Buffer$RW$(int cap, int lim, MemorySegmentProxy segment) { // package-private
Heap$Type$Buffer$RW$(int cap, int lim, MemorySegment segment) { // package-private
#if[rw]
super(-1, 0, lim, cap, new $type$[cap], 0, segment);
/*
@ -80,7 +80,7 @@ class Heap$Type$Buffer$RW$
#end[rw]
}
Heap$Type$Buffer$RW$($type$[] buf, int off, int len, MemorySegmentProxy segment) { // package-private
Heap$Type$Buffer$RW$($type$[] buf, int off, int len, MemorySegment segment) { // package-private
#if[rw]
super(-1, off, off + len, buf.length, buf, 0, segment);
/*
@ -96,7 +96,7 @@ class Heap$Type$Buffer$RW$
protected Heap$Type$Buffer$RW$($type$[] buf,
int mark, int pos, int lim, int cap,
int off, MemorySegmentProxy segment)
int off, MemorySegment segment)
{
#if[rw]
super(mark, pos, lim, cap, buf, off, segment);
@ -183,7 +183,7 @@ class Heap$Type$Buffer$RW$
#end[streamableType]
public $Type$Buffer get($type$[] dst, int offset, int length) {
checkScope();
checkSession();
Objects.checkFromIndexSize(offset, length, dst.length);
int pos = position();
if (length > limit() - pos)
@ -194,7 +194,7 @@ class Heap$Type$Buffer$RW$
}
public $Type$Buffer get(int index, $type$[] dst, int offset, int length) {
checkScope();
checkSession();
Objects.checkFromIndexSize(index, length, limit());
Objects.checkFromIndexSize(offset, length, dst.length);
System.arraycopy(hb, ix(index), dst, offset, length);
@ -231,7 +231,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer put($type$[] src, int offset, int length) {
#if[rw]
checkScope();
checkSession();
Objects.checkFromIndexSize(offset, length, src.length);
int pos = position();
if (length > limit() - pos)
@ -246,7 +246,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer put($Type$Buffer src) {
#if[rw]
checkScope();
checkSession();
super.put(src);
return this;
#else[rw]
@ -256,7 +256,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer put(int index, $Type$Buffer src, int offset, int length) {
#if[rw]
checkScope();
checkSession();
super.put(index, src, offset, length);
return this;
#else[rw]
@ -266,7 +266,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer put(int index, $type$[] src, int offset, int length) {
#if[rw]
checkScope();
checkSession();
Objects.checkFromIndexSize(index, length, limit());
Objects.checkFromIndexSize(offset, length, src.length);
System.arraycopy(src, offset, hb, ix(index), length);
@ -280,7 +280,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer put(String src, int start, int end) {
#if[rw]
checkScope();
checkSession();
int length = end - start;
Objects.checkFromIndexSize(start, length, src.length());
int pos = position();
@ -335,18 +335,18 @@ class Heap$Type$Buffer$RW$
#if[rw]
public char getChar() {
return SCOPED_MEMORY_ACCESS.getCharUnaligned(scope(), hb, byteOffset(nextGetIndex(2)), bigEndian);
return SCOPED_MEMORY_ACCESS.getCharUnaligned(session(), hb, byteOffset(nextGetIndex(2)), bigEndian);
}
public char getChar(int i) {
return SCOPED_MEMORY_ACCESS.getCharUnaligned(scope(), hb, byteOffset(checkIndex(i, 2)), bigEndian);
return SCOPED_MEMORY_ACCESS.getCharUnaligned(session(), hb, byteOffset(checkIndex(i, 2)), bigEndian);
}
#end[rw]
public $Type$Buffer putChar(char x) {
#if[rw]
SCOPED_MEMORY_ACCESS.putCharUnaligned(scope(), hb, byteOffset(nextPutIndex(2)), x, bigEndian);
SCOPED_MEMORY_ACCESS.putCharUnaligned(session(), hb, byteOffset(nextPutIndex(2)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -355,7 +355,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putChar(int i, char x) {
#if[rw]
SCOPED_MEMORY_ACCESS.putCharUnaligned(scope(), hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
SCOPED_MEMORY_ACCESS.putCharUnaligned(session(), hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -387,18 +387,18 @@ class Heap$Type$Buffer$RW$
#if[rw]
public short getShort() {
return SCOPED_MEMORY_ACCESS.getShortUnaligned(scope(), hb, byteOffset(nextGetIndex(2)), bigEndian);
return SCOPED_MEMORY_ACCESS.getShortUnaligned(session(), hb, byteOffset(nextGetIndex(2)), bigEndian);
}
public short getShort(int i) {
return SCOPED_MEMORY_ACCESS.getShortUnaligned(scope(), hb, byteOffset(checkIndex(i, 2)), bigEndian);
return SCOPED_MEMORY_ACCESS.getShortUnaligned(session(), hb, byteOffset(checkIndex(i, 2)), bigEndian);
}
#end[rw]
public $Type$Buffer putShort(short x) {
#if[rw]
SCOPED_MEMORY_ACCESS.putShortUnaligned(scope(), hb, byteOffset(nextPutIndex(2)), x, bigEndian);
SCOPED_MEMORY_ACCESS.putShortUnaligned(session(), hb, byteOffset(nextPutIndex(2)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -407,7 +407,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putShort(int i, short x) {
#if[rw]
SCOPED_MEMORY_ACCESS.putShortUnaligned(scope(), hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
SCOPED_MEMORY_ACCESS.putShortUnaligned(session(), hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -439,18 +439,18 @@ class Heap$Type$Buffer$RW$
#if[rw]
public int getInt() {
return SCOPED_MEMORY_ACCESS.getIntUnaligned(scope(), hb, byteOffset(nextGetIndex(4)), bigEndian);
return SCOPED_MEMORY_ACCESS.getIntUnaligned(session(), hb, byteOffset(nextGetIndex(4)), bigEndian);
}
public int getInt(int i) {
return SCOPED_MEMORY_ACCESS.getIntUnaligned(scope(), hb, byteOffset(checkIndex(i, 4)), bigEndian);
return SCOPED_MEMORY_ACCESS.getIntUnaligned(session(), hb, byteOffset(checkIndex(i, 4)), bigEndian);
}
#end[rw]
public $Type$Buffer putInt(int x) {
#if[rw]
SCOPED_MEMORY_ACCESS.putIntUnaligned(scope(), hb, byteOffset(nextPutIndex(4)), x, bigEndian);
SCOPED_MEMORY_ACCESS.putIntUnaligned(session(), hb, byteOffset(nextPutIndex(4)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -459,7 +459,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putInt(int i, int x) {
#if[rw]
SCOPED_MEMORY_ACCESS.putIntUnaligned(scope(), hb, byteOffset(checkIndex(i, 4)), x, bigEndian);
SCOPED_MEMORY_ACCESS.putIntUnaligned(session(), hb, byteOffset(checkIndex(i, 4)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -491,18 +491,18 @@ class Heap$Type$Buffer$RW$
#if[rw]
public long getLong() {
return SCOPED_MEMORY_ACCESS.getLongUnaligned(scope(), hb, byteOffset(nextGetIndex(8)), bigEndian);
return SCOPED_MEMORY_ACCESS.getLongUnaligned(session(), hb, byteOffset(nextGetIndex(8)), bigEndian);
}
public long getLong(int i) {
return SCOPED_MEMORY_ACCESS.getLongUnaligned(scope(), hb, byteOffset(checkIndex(i, 8)), bigEndian);
return SCOPED_MEMORY_ACCESS.getLongUnaligned(session(), hb, byteOffset(checkIndex(i, 8)), bigEndian);
}
#end[rw]
public $Type$Buffer putLong(long x) {
#if[rw]
SCOPED_MEMORY_ACCESS.putLongUnaligned(scope(), hb, byteOffset(nextPutIndex(8)), x, bigEndian);
SCOPED_MEMORY_ACCESS.putLongUnaligned(session(), hb, byteOffset(nextPutIndex(8)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -511,7 +511,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putLong(int i, long x) {
#if[rw]
SCOPED_MEMORY_ACCESS.putLongUnaligned(scope(), hb, byteOffset(checkIndex(i, 8)), x, bigEndian);
SCOPED_MEMORY_ACCESS.putLongUnaligned(session(), hb, byteOffset(checkIndex(i, 8)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -543,12 +543,12 @@ class Heap$Type$Buffer$RW$
#if[rw]
public float getFloat() {
int x = SCOPED_MEMORY_ACCESS.getIntUnaligned(scope(), hb, byteOffset(nextGetIndex(4)), bigEndian);
int x = SCOPED_MEMORY_ACCESS.getIntUnaligned(session(), hb, byteOffset(nextGetIndex(4)), bigEndian);
return Float.intBitsToFloat(x);
}
public float getFloat(int i) {
int x = SCOPED_MEMORY_ACCESS.getIntUnaligned(scope(), hb, byteOffset(checkIndex(i, 4)), bigEndian);
int x = SCOPED_MEMORY_ACCESS.getIntUnaligned(session(), hb, byteOffset(checkIndex(i, 4)), bigEndian);
return Float.intBitsToFloat(x);
}
@ -557,7 +557,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putFloat(float x) {
#if[rw]
int y = Float.floatToRawIntBits(x);
SCOPED_MEMORY_ACCESS.putIntUnaligned(scope(), hb, byteOffset(nextPutIndex(4)), y, bigEndian);
SCOPED_MEMORY_ACCESS.putIntUnaligned(session(), hb, byteOffset(nextPutIndex(4)), y, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -567,7 +567,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putFloat(int i, float x) {
#if[rw]
int y = Float.floatToRawIntBits(x);
SCOPED_MEMORY_ACCESS.putIntUnaligned(scope(), hb, byteOffset(checkIndex(i, 4)), y, bigEndian);
SCOPED_MEMORY_ACCESS.putIntUnaligned(session(), hb, byteOffset(checkIndex(i, 4)), y, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -599,12 +599,12 @@ class Heap$Type$Buffer$RW$
#if[rw]
public double getDouble() {
long x = SCOPED_MEMORY_ACCESS.getLongUnaligned(scope(), hb, byteOffset(nextGetIndex(8)), bigEndian);
long x = SCOPED_MEMORY_ACCESS.getLongUnaligned(session(), hb, byteOffset(nextGetIndex(8)), bigEndian);
return Double.longBitsToDouble(x);
}
public double getDouble(int i) {
long x = SCOPED_MEMORY_ACCESS.getLongUnaligned(scope(), hb, byteOffset(checkIndex(i, 8)), bigEndian);
long x = SCOPED_MEMORY_ACCESS.getLongUnaligned(session(), hb, byteOffset(checkIndex(i, 8)), bigEndian);
return Double.longBitsToDouble(x);
}
@ -613,7 +613,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putDouble(double x) {
#if[rw]
long y = Double.doubleToRawLongBits(x);
SCOPED_MEMORY_ACCESS.putLongUnaligned(scope(), hb, byteOffset(nextPutIndex(8)), y, bigEndian);
SCOPED_MEMORY_ACCESS.putLongUnaligned(session(), hb, byteOffset(nextPutIndex(8)), y, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -623,7 +623,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putDouble(int i, double x) {
#if[rw]
long y = Double.doubleToRawLongBits(x);
SCOPED_MEMORY_ACCESS.putLongUnaligned(scope(), hb, byteOffset(checkIndex(i, 8)), y, bigEndian);
SCOPED_MEMORY_ACCESS.putLongUnaligned(session(), hb, byteOffset(checkIndex(i, 8)), y, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2022, 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
@ -27,10 +27,10 @@ package java.nio;
import java.io.FileDescriptor;
import java.io.UncheckedIOException;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Reference;
import java.util.Objects;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.access.foreign.UnmapperProxy;
import jdk.internal.misc.ScopedMemoryAccess;
import jdk.internal.misc.Unsafe;
@ -96,20 +96,20 @@ public abstract sealed class MappedByteBuffer
// This should only be invoked by the DirectByteBuffer constructors
//
MappedByteBuffer(int mark, int pos, int lim, int cap, // package-private
FileDescriptor fd, boolean isSync, MemorySegmentProxy segment) {
FileDescriptor fd, boolean isSync, MemorySegment segment) {
super(mark, pos, lim, cap, segment);
this.fd = fd;
this.isSync = isSync;
}
MappedByteBuffer(int mark, int pos, int lim, int cap, // package-private
boolean isSync, MemorySegmentProxy segment) {
boolean isSync, MemorySegment segment) {
super(mark, pos, lim, cap, segment);
this.fd = null;
this.isSync = isSync;
}
MappedByteBuffer(int mark, int pos, int lim, int cap, MemorySegmentProxy segment) { // package-private
MappedByteBuffer(int mark, int pos, int lim, int cap, MemorySegment segment) { // package-private
super(mark, pos, lim, cap, segment);
this.fd = null;
this.isSync = false;
@ -189,7 +189,7 @@ public abstract sealed class MappedByteBuffer
if (fd == null) {
return true;
}
return SCOPED_MEMORY_ACCESS.isLoaded(scope(), address, isSync, capacity());
return SCOPED_MEMORY_ACCESS.isLoaded(session(), address, isSync, capacity());
}
/**
@ -207,7 +207,7 @@ public abstract sealed class MappedByteBuffer
return this;
}
try {
SCOPED_MEMORY_ACCESS.load(scope(), address, isSync, capacity());
SCOPED_MEMORY_ACCESS.load(session(), address, isSync, capacity());
} finally {
Reference.reachabilityFence(this);
}
@ -307,7 +307,7 @@ public abstract sealed class MappedByteBuffer
if ((address != 0) && (capacity != 0)) {
// check inputs
Objects.checkFromIndexSize(index, length, capacity);
SCOPED_MEMORY_ACCESS.force(scope(), fd, address, isSync, index, length);
SCOPED_MEMORY_ACCESS.force(session(), fd, address, isSync, index, length);
}
return this;
}

View file

@ -37,8 +37,8 @@ import java.util.stream.StreamSupport;
import java.util.stream.$Streamtype$Stream;
#end[streamableType]
import java.lang.foreign.MemorySegment;
import java.util.Objects;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.util.ArraysSupport;
/**
@ -293,7 +293,7 @@ public abstract sealed class $Type$Buffer
// backing array, and array offset
//
$Type$Buffer(int mark, int pos, int lim, int cap, // package-private
$type$[] hb, int offset, MemorySegmentProxy segment)
$type$[] hb, int offset, MemorySegment segment)
{
super(mark, pos, lim, cap, segment);
this.hb = hb;
@ -302,13 +302,13 @@ public abstract sealed class $Type$Buffer
// Creates a new buffer with the given mark, position, limit, and capacity
//
$Type$Buffer(int mark, int pos, int lim, int cap, MemorySegmentProxy segment) { // package-private
$Type$Buffer(int mark, int pos, int lim, int cap, MemorySegment segment) { // package-private
this(mark, pos, lim, cap, null, 0, segment);
}
// Creates a new buffer with given base, address and capacity
//
$Type$Buffer($type$[] hb, long addr, int cap, MemorySegmentProxy segment) { // package-private
$Type$Buffer($type$[] hb, long addr, int cap, MemorySegment segment) { // package-private
super(addr, cap, segment);
this.hb = hb;
this.offset = 0;
@ -935,12 +935,12 @@ public abstract sealed class $Type$Buffer
#if[!byte]
if (order() != ByteOrder.nativeOrder())
SCOPED_MEMORY_ACCESS.copySwapMemory(
scope(), null, base(), bufAddr,
session(), null, base(), bufAddr,
dst, dstOffset, len, $Fulltype$.BYTES);
else
#end[!byte]
SCOPED_MEMORY_ACCESS.copyMemory(
scope(), null, base(), bufAddr,
session(), null, base(), bufAddr,
dst, dstOffset, len);
} finally {
Reference.reachabilityFence(this);
@ -1105,12 +1105,12 @@ public abstract sealed class $Type$Buffer
#if[!byte]
if (this.order() != src.order())
SCOPED_MEMORY_ACCESS.copySwapMemory(
src.scope(), scope(), srcBase, srcAddr,
src.session(), session(), srcBase, srcAddr,
base, addr, len, $Fulltype$.BYTES);
else
#end[!byte]
SCOPED_MEMORY_ACCESS.copyMemory(
src.scope(), scope(), srcBase, srcAddr,
src.session(), session(), srcBase, srcAddr,
base, addr, len);
} finally {
Reference.reachabilityFence(src);
@ -1325,12 +1325,12 @@ public abstract sealed class $Type$Buffer
#if[!byte]
if (order() != ByteOrder.nativeOrder())
SCOPED_MEMORY_ACCESS.copySwapMemory(
null, scope(), src, srcOffset,
null, session(), src, srcOffset,
base(), bufAddr, len, $Fulltype$.BYTES);
else
#end[!byte]
SCOPED_MEMORY_ACCESS.copyMemory(
null, scope(), src, srcOffset,
null, session(), src, srcOffset,
base(), bufAddr, len);
} finally {
Reference.reachabilityFence(this);

View file

@ -26,6 +26,8 @@
package java.nio.channels;
import java.io.IOException;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.spi.AbstractInterruptibleChannel;
@ -38,6 +40,7 @@ import java.nio.file.spi.FileSystemProvider;
import java.util.Set;
import java.util.HashSet;
import java.util.Collections;
import jdk.internal.javac.PreviewFeature;
/**
* A channel for reading, writing, mapping, and manipulating a file.
@ -943,13 +946,13 @@ public abstract class FileChannel
*
* @throws NonReadableChannelException
* If the {@code mode} is {@link MapMode#READ_ONLY READ_ONLY} or
* an implementation specific map mode requiring read access
* an implementation specific map mode requiring read access,
* but this channel was not opened for reading
*
* @throws NonWritableChannelException
* If the {@code mode} is {@link MapMode#READ_WRITE READ_WRITE}.
* If the {@code mode} is {@link MapMode#READ_WRITE READ_WRITE},
* {@link MapMode#PRIVATE PRIVATE} or an implementation specific
* map mode requiring write access but this channel was not
* map mode requiring write access, but this channel was not
* opened for both reading and writing
*
* @throws IllegalArgumentException
@ -967,6 +970,89 @@ public abstract class FileChannel
public abstract MappedByteBuffer map(MapMode mode, long position, long size)
throws IOException;
/**
* Maps a region of this channel's file into a new mapped memory segment,
* with the given offset, size and memory session.
*
* <p> If the specified mapping mode is
* {@linkplain FileChannel.MapMode#READ_ONLY READ_ONLY}, the resulting
* segment will be read-only (see {@link MemorySegment#isReadOnly()}).
*
* <p> The content of a mapped memory segment can change at any time, for
* example if the content of the corresponding region of the mapped file is
* changed by this (or another) program. Whether such changes occur, and
* when they occur, is operating-system dependent and therefore unspecified.
*
* <p> All or part of a mapped memory segment may become inaccessible at any
* time, for example if the backing mapped file is truncated. An attempt to
* access an inaccessible region of a mapped memory segment will not change
* the segment's content and will cause an unspecified exception to be
* thrown either at the time of the access or at some later time. It is
* therefore strongly recommended that appropriate precautions be taken to
* avoid the manipulation of a mapped file by this (or another) program,
* except to read or write the file's content.
*
* @implNote When obtaining a mapped segment from a newly created file
* channel, the initialization state of the contents of the block
* of mapped memory associated with the returned mapped memory
* segment is unspecified and should not be relied upon.
*
* @param mode
* The file mapping mode, see
* {@link FileChannel#map(FileChannel.MapMode, long, long)};
* the mapping mode might affect the behavior of the returned memory
* mapped segment (see {@link MemorySegment#force()}).
*
* @param offset
* The offset (expressed in bytes) within the file at which the
* mapped segment is to start.
*
* @param size
* The size (in bytes) of the mapped memory backing the memory
* segment.
* @param session
* The segment memory session.
*
* @return A new mapped memory segment.
*
* @throws IllegalArgumentException
* If {@code offset < 0}, {@code size < 0} or
* {@code offset + size} overflows the range of {@code long}.
*
* @throws IllegalStateException
* If the {@code session} is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs
* from a thread other than the thread
* {@linkplain MemorySession#ownerThread() owning} the
* {@code session}.
*
* @throws NonReadableChannelException
* If the {@code mode} is {@link MapMode#READ_ONLY READ_ONLY} or
* an implementation specific map mode requiring read access,
* but this channel was not opened for reading.
*
* @throws NonWritableChannelException
* If the {@code mode} is {@link MapMode#READ_WRITE READ_WRITE},
* {@link MapMode#PRIVATE PRIVATE} or an implementation specific
* map mode requiring write access, but this channel was not
* opened for both reading and writing.
*
* @throws IOException
* If some other I/O error occurs.
*
* @throws UnsupportedOperationException
* If an unsupported map mode is specified.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public MemorySegment map(MapMode mode, long offset, long size,
MemorySession session)
throws IOException
{
throw new UnsupportedOperationException();
}
// -- Locks --