mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8282191: Implementation of Foreign Function & Memory API (Preview)
Reviewed-by: erikj, jvernee, psandoz, dholmes, mchung
This commit is contained in:
parent
3be394e160
commit
2c5d136260
303 changed files with 33474 additions and 9186 deletions
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
188
src/java.base/share/classes/java/lang/foreign/GroupLayout.java
Normal file
188
src/java.base/share/classes/java/lang/foreign/GroupLayout.java
Normal 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);
|
||||
}
|
||||
}
|
307
src/java.base/share/classes/java/lang/foreign/Linker.java
Normal file
307
src/java.base/share/classes/java/lang/foreign/Linker.java
Normal 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);
|
||||
}
|
||||
}
|
854
src/java.base/share/classes/java/lang/foreign/MemoryAddress.java
Normal file
854
src/java.base/share/classes/java/lang/foreign/MemoryAddress.java
Normal 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);
|
||||
}
|
710
src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
Normal file
710
src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
1849
src/java.base/share/classes/java/lang/foreign/MemorySegment.java
Normal file
1849
src/java.base/share/classes/java/lang/foreign/MemorySegment.java
Normal file
File diff suppressed because it is too large
Load diff
282
src/java.base/share/classes/java/lang/foreign/MemorySession.java
Normal file
282
src/java.base/share/classes/java/lang/foreign/MemorySession.java
Normal 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;
|
||||
}
|
||||
}
|
100
src/java.base/share/classes/java/lang/foreign/PaddingLayout.java
Normal file
100
src/java.base/share/classes/java/lang/foreign/PaddingLayout.java
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
252
src/java.base/share/classes/java/lang/foreign/SymbolLookup.java
Normal file
252
src/java.base/share/classes/java/lang/foreign/SymbolLookup.java
Normal 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));
|
||||
};
|
||||
}
|
||||
}
|
278
src/java.base/share/classes/java/lang/foreign/VaList.java
Normal file
278
src/java.base/share/classes/java/lang/foreign/VaList.java
Normal 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);
|
||||
}
|
||||
}
|
678
src/java.base/share/classes/java/lang/foreign/ValueLayout.java
Normal file
678
src/java.base/share/classes/java/lang/foreign/ValueLayout.java
Normal 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);
|
||||
}
|
238
src/java.base/share/classes/java/lang/foreign/package-info.java
Normal file
238
src/java.base/share/classes/java/lang/foreign/package-info.java
Normal 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;
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 --
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue