mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8295044: Implementation of Foreign Function and Memory API (Second Preview)
Co-authored-by: Jorn Vernee <jvernee@openjdk.org> Co-authored-by: Per Minborg <pminborg@openjdk.org> Co-authored-by: Maurizio Cimadamore <mcimadamore@openjdk.org> Reviewed-by: jvernee, pminborg, psandoz, alanb, sundar
This commit is contained in:
parent
bd381886e0
commit
73baadceb6
252 changed files with 9221 additions and 7889 deletions
|
@ -52,10 +52,12 @@ import java.util.function.Function;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
import jdk.internal.loader.BuiltinClassLoader;
|
||||
import jdk.internal.loader.BootLoader;
|
||||
import jdk.internal.loader.ClassLoaders;
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.module.ModuleBootstrap;
|
||||
import jdk.internal.module.ModuleLoaderMap;
|
||||
import jdk.internal.module.ServicesCatalog;
|
||||
import jdk.internal.module.Resources;
|
||||
|
@ -256,25 +258,77 @@ public final class Module implements AnnotatedElement {
|
|||
/**
|
||||
* Update this module to allow access to restricted methods.
|
||||
*/
|
||||
Module implAddEnableNativeAccess() {
|
||||
synchronized Module implAddEnableNativeAccess() {
|
||||
enableNativeAccess = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all unnamed modules to allow access to restricted methods.
|
||||
* Returns {@code true} if this module can access
|
||||
* <a href="foreign/package-summary.html#restricted"><em>restricted</em></a> methods.
|
||||
*
|
||||
* @since 20
|
||||
*
|
||||
* @return {@code true} if this module can access <em>restricted</em> methods.
|
||||
*/
|
||||
static void implAddEnableNativeAccessAllUnnamed() {
|
||||
ALL_UNNAMED_MODULE.enableNativeAccess = true;
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public boolean isNativeAccessEnabled() {
|
||||
Module target = moduleForNativeAccess();
|
||||
synchronized(target) {
|
||||
return target.enableNativeAccess;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the Module object that holds the enableNativeAccess
|
||||
// flag for this module.
|
||||
private Module moduleForNativeAccess() {
|
||||
return isNamed() ? this : ALL_UNNAMED_MODULE;
|
||||
}
|
||||
|
||||
// This is invoked from Reflection.ensureNativeAccess
|
||||
void ensureNativeAccess(Class<?> owner, String methodName) {
|
||||
// The target module whose enableNativeAccess flag is ensured
|
||||
Module target = moduleForNativeAccess();
|
||||
// racy read of the enable native access flag
|
||||
boolean isNativeAccessEnabled = target.enableNativeAccess;
|
||||
if (!isNativeAccessEnabled) {
|
||||
synchronized (target) {
|
||||
// safe read of the enableNativeAccess of the target module
|
||||
isNativeAccessEnabled = target.enableNativeAccess;
|
||||
|
||||
// check again with the safely read flag
|
||||
if (isNativeAccessEnabled) {
|
||||
// another thread beat us to it - nothing to do
|
||||
return;
|
||||
} else if (ModuleBootstrap.hasEnableNativeAccessFlag()) {
|
||||
throw new IllegalCallerException("Illegal native access from: " + this);
|
||||
} else {
|
||||
// warn and set flag, so that only one warning is reported per module
|
||||
String cls = owner.getName();
|
||||
String mtd = cls + "::" + methodName;
|
||||
String mod = isNamed() ? "module " + getName() : "the unnamed module";
|
||||
String modflag = isNamed() ? getName() : "ALL-UNNAMED";
|
||||
System.err.printf("""
|
||||
WARNING: A restricted method in %s has been called
|
||||
WARNING: %s has been called by %s
|
||||
WARNING: Use --enable-native-access=%s to avoid a warning for this module
|
||||
%n""", cls, mtd, mod, modflag);
|
||||
|
||||
// set the flag
|
||||
target.enableNativeAccess = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if module m can access restricted methods.
|
||||
* Update all unnamed modules to allow access to restricted methods.
|
||||
*/
|
||||
boolean implIsEnableNativeAccess() {
|
||||
return isNamed() ?
|
||||
enableNativeAccess :
|
||||
ALL_UNNAMED_MODULE.enableNativeAccess;
|
||||
static void implAddEnableNativeAccessToAllUnnamed() {
|
||||
synchronized (ALL_UNNAMED_MODULE) {
|
||||
ALL_UNNAMED_MODULE.enableNativeAccess = true;
|
||||
}
|
||||
}
|
||||
|
||||
// --
|
||||
|
|
|
@ -44,15 +44,17 @@ import java.util.function.Function;
|
|||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
import jdk.internal.loader.ClassLoaderValue;
|
||||
import jdk.internal.loader.Loader;
|
||||
import jdk.internal.loader.LoaderPool;
|
||||
import jdk.internal.module.ServicesCatalog;
|
||||
import jdk.internal.misc.CDS;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
import sun.security.util.SecurityConstants;
|
||||
|
||||
|
||||
/**
|
||||
* A layer of modules in the Java virtual machine.
|
||||
*
|
||||
|
@ -297,6 +299,39 @@ public final class ModuleLayer {
|
|||
source.implAddOpens(pn, target);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables native access for a module in the layer if the caller's module
|
||||
* has native access.
|
||||
*
|
||||
* <p> This method is <a href="foreign/package-summary.html#restricted"><em>restricted</em></a>.
|
||||
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
|
||||
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain
|
||||
* from depending on restricted methods, and use safe and supported functionalities,
|
||||
* where possible.
|
||||
*
|
||||
* @param target
|
||||
* The module to update
|
||||
*
|
||||
* @return This controller
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* If {@code target} is not in the module layer
|
||||
*
|
||||
* @throws IllegalCallerException
|
||||
* If the caller is in a module that does not have native access enabled
|
||||
*
|
||||
* @since 20
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
@CallerSensitive
|
||||
public Controller enableNativeAccess(Module target) {
|
||||
ensureInLayer(target);
|
||||
Reflection.ensureNativeAccess(Reflection.getCallerClass(), Module.class,
|
||||
"enableNativeAccess");
|
||||
target.implAddEnableNativeAccess();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2437,11 +2437,11 @@ public final class System {
|
|||
public Module addEnableNativeAccess(Module m) {
|
||||
return m.implAddEnableNativeAccess();
|
||||
}
|
||||
public void addEnableNativeAccessAllUnnamed() {
|
||||
Module.implAddEnableNativeAccessAllUnnamed();
|
||||
public void addEnableNativeAccessToAllUnnamed() {
|
||||
Module.implAddEnableNativeAccessToAllUnnamed();
|
||||
}
|
||||
public boolean isEnableNativeAccess(Module m) {
|
||||
return m.implIsEnableNativeAccess();
|
||||
public void ensureNativeAccess(Module m, Class<?> owner, String methodName) {
|
||||
m.ensureNativeAccess(owner, methodName);
|
||||
}
|
||||
public ServicesCatalog getServicesCatalog(ModuleLayer layer) {
|
||||
return layer.getServicesCatalog();
|
||||
|
|
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
* 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.ForceInline;
|
||||
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
|
||||
@ForceInline
|
||||
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;
|
||||
}
|
||||
|
||||
// the following methods have to copy the same Javadoc as in MemoryLayout, or subclasses will just show
|
||||
// the Object methods javadoc
|
||||
|
||||
/**
|
||||
* {@return the hash code value for this layout}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, size, 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 {@linkplain ValueLayout#order() order},
|
||||
* and {@linkplain ValueLayout#carrier() carrier}</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 other 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 other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return other instanceof AbstractLayout otherLayout &&
|
||||
name.equals(otherLayout.name) &&
|
||||
size == otherLayout.size &&
|
||||
alignment == otherLayout.alignment;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the string representation of this layout}
|
||||
*/
|
||||
public abstract String toString();
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* 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();
|
||||
}
|
166
src/java.base/share/classes/java/lang/foreign/Arena.java
Normal file
166
src/java.base/share/classes/java/lang/foreign/Arena.java
Normal file
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* 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.foreign.MemorySessionImpl;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
* An arena controls the lifecycle of memory segments, providing both flexible allocation and timely deallocation.
|
||||
* <p>
|
||||
* An arena has a {@linkplain #scope() scope}, called the arena scope. When the arena is {@linkplain #close() closed},
|
||||
* the arena scope is no longer {@linkplain SegmentScope#isAlive() alive}. As a result, all the
|
||||
* segments associated with the arena scope are invalidated, safely and atomically, their backing memory regions are
|
||||
* deallocated (where applicable) and can no longer be accessed after the arena is closed:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* try (Arena arena = Arena.openConfined()) {
|
||||
* MemorySegment segment = MemorySegment.allocateNative(100, arena.scope());
|
||||
* ...
|
||||
* } // memory released here
|
||||
*}
|
||||
*
|
||||
* Furthermore, an arena is a {@link SegmentAllocator}. All the segments {@linkplain #allocate(long, long) allocated} by the
|
||||
* arena are associated with the arena scope. This makes arenas extremely useful when interacting with foreign code, as shown below:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* try (Arena arena = Arena.openConfined()) {
|
||||
* MemorySegment nativeArray = arena.allocateArray(ValueLayout.JAVA_INT, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
|
||||
* MemorySegment nativeString = arena.allocateUtf8String("Hello!");
|
||||
* MemorySegment upcallStub = linker.upcallStub(handle, desc, arena.scope());
|
||||
* ...
|
||||
* } // memory released here
|
||||
*}
|
||||
*
|
||||
* <h2 id = "thread-confinement">Safety and thread-confinement</h2>
|
||||
*
|
||||
* Arenas provide strong temporal safety guarantees: a memory segment allocated by an arena cannot be accessed
|
||||
* <em>after</em> the arena has been closed. The cost of providing this guarantee varies based on the
|
||||
* number of threads that have access to the memory segments allocated by the arena. For instance, if an arena
|
||||
* is always created and closed by one thread, and the memory segments associated with the arena's scope are always
|
||||
* accessed by that same thread, then ensuring correctness is trivial.
|
||||
* <p>
|
||||
* Conversely, if an arena allocates segments that can be accessed by multiple threads, or if the arena can be closed
|
||||
* by a thread other than the accessing thread, then ensuring correctness is much more complex. For example, a segment
|
||||
* allocated with the arena might be accessed <em>while</em> another thread attempts, concurrently, to close the arena.
|
||||
* To provide the strong temporal safety guarantee without forcing every client, even simple ones, to incur a performance
|
||||
* impact, arenas are divided into <em>thread-confined</em> arenas, and <em>shared</em> arenas.
|
||||
* <p>
|
||||
* Confined arenas, support strong thread-confinement guarantees. Upon creation, they are assigned an
|
||||
* {@linkplain #isCloseableBy(Thread) owner thread}, typically the thread which initiated the creation operation.
|
||||
* The segments created by a confined arena can only be {@linkplain SegmentScope#isAccessibleBy(Thread) accessed}
|
||||
* by the owner thread. Moreover, any attempt to close the confined arena from a thread other than the owner thread will
|
||||
* fail with {@link WrongThreadException}.
|
||||
* <p>
|
||||
* Shared arenas, on the other hand, have no owner thread. The segments created by a shared arena
|
||||
* can be {@linkplain SegmentScope#isAccessibleBy(Thread) accessed} by any thread. This might be useful when
|
||||
* multiple threads need to access the same memory segment concurrently (e.g. in the case of parallel processing).
|
||||
* Moreover, a shared arena {@linkplain #isCloseableBy(Thread) can be closed} by any thread.
|
||||
*
|
||||
* @since 20
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public interface Arena extends SegmentAllocator, AutoCloseable {
|
||||
|
||||
/**
|
||||
* Returns a native memory segment with the given size (in bytes) and alignment constraint (in bytes).
|
||||
* The returned segment is associated with the arena scope.
|
||||
* The segment's {@link MemorySegment#address() address} is the starting address of the
|
||||
* allocated off-heap memory region backing the segment, and the address is
|
||||
* aligned according the provided alignment constraint.
|
||||
*
|
||||
* @implSpec
|
||||
* The default implementation of this method is equivalent to the following code:
|
||||
* {@snippet lang = java:
|
||||
* MemorySegment.allocateNative(bytesSize, byteAlignment, scope());
|
||||
*}
|
||||
* More generally implementations of this method must return a native segment featuring the requested size,
|
||||
* and that is compatible with the provided alignment constraint. Furthermore, for any two segments
|
||||
* {@code S1, S2} returned by this method, the following invariant must hold:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* S1.overlappingSlice(S2).isEmpty() == true
|
||||
*}
|
||||
*
|
||||
* @param byteSize the size (in bytes) of the off-heap memory block backing the native memory segment.
|
||||
* @param byteAlignment the alignment constraint (in bytes) of the off-heap region of memory backing the native memory segment.
|
||||
* @return a new native memory segment.
|
||||
* @throws IllegalArgumentException if {@code bytesSize < 0}, {@code alignmentBytes <= 0}, or if {@code alignmentBytes}
|
||||
* is not a power of 2.
|
||||
* @throws IllegalStateException if the arena has already been {@linkplain #close() closed}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code scope().isAccessibleBy(T) == false}.
|
||||
* @see MemorySegment#allocateNative(long, long, SegmentScope)
|
||||
*/
|
||||
@Override
|
||||
default MemorySegment allocate(long byteSize, long byteAlignment) {
|
||||
return MemorySegment.allocateNative(byteSize, byteAlignment, scope());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the arena scope}
|
||||
*/
|
||||
SegmentScope scope();
|
||||
|
||||
/**
|
||||
* Closes this arena. If this method completes normally, the arena scope is no longer {@linkplain SegmentScope#isAlive() alive},
|
||||
* and all the memory segments associated with it can no longer be accessed. Furthermore, any off-heap region of memory backing the
|
||||
* segments associated with that scope are also released.
|
||||
*
|
||||
* @apiNote This operation is not idempotent; that is, closing an already closed arena <em>always</em> results in an
|
||||
* exception being thrown. This reflects a deliberate design choice: failure to close an arena might reveal a bug
|
||||
* in the underlying application logic.
|
||||
*
|
||||
* @see SegmentScope#isAlive()
|
||||
*
|
||||
* @throws IllegalStateException if the arena has already been closed.
|
||||
* @throws IllegalStateException if the arena scope is {@linkplain SegmentScope#whileAlive(Runnable) kept alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isCloseableBy(T) == false}.
|
||||
*/
|
||||
@Override
|
||||
void close();
|
||||
|
||||
/**
|
||||
* {@return {@code true} if the provided thread can close this arena}
|
||||
* @param thread the thread to be tested.
|
||||
*/
|
||||
boolean isCloseableBy(Thread thread);
|
||||
|
||||
/**
|
||||
* {@return a new confined arena, owned by the current thread}
|
||||
*/
|
||||
static Arena openConfined() {
|
||||
return MemorySessionImpl.createConfined(Thread.currentThread()).asArena();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return a new shared arena}
|
||||
*/
|
||||
static Arena openShared() {
|
||||
return MemorySessionImpl.createShared().asArena();
|
||||
}
|
||||
}
|
|
@ -25,101 +25,38 @@
|
|||
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.lang.invoke.MethodType;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.internal.foreign.FunctionDescriptorImpl;
|
||||
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}.
|
||||
* A function descriptor models the signature of foreign functions. A function descriptor is made up of zero or more
|
||||
* argument layouts and zero or one return layout. A function descriptor is typically used when creating
|
||||
* {@linkplain Linker#downcallHandle(MemorySegment, FunctionDescriptor, Linker.Option...) downcall method handles} or
|
||||
* {@linkplain Linker#upcallStub(MethodHandle, FunctionDescriptor, SegmentScope) upcall stubs}.
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
* Implementing classes are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @see MemoryLayout
|
||||
* @since 19
|
||||
*/
|
||||
@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;
|
||||
}
|
||||
public sealed interface FunctionDescriptor permits FunctionDescriptorImpl {
|
||||
|
||||
/**
|
||||
* {@return the return layout (if any) associated with this function descriptor}
|
||||
*/
|
||||
public Optional<MemoryLayout> returnLayout() {
|
||||
return Optional.ofNullable(resLayout);
|
||||
}
|
||||
Optional<MemoryLayout> returnLayout();
|
||||
|
||||
/**
|
||||
* {@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;
|
||||
}
|
||||
List<MemoryLayout> argumentLayouts();
|
||||
|
||||
/**
|
||||
* Returns a function descriptor with the given argument layouts appended to the argument layout array
|
||||
|
@ -127,9 +64,7 @@ public sealed class FunctionDescriptor permits FunctionDescriptor.VariadicFuncti
|
|||
* @param addedLayouts the argument layouts to append.
|
||||
* @return the new function descriptor.
|
||||
*/
|
||||
public FunctionDescriptor appendArgumentLayouts(MemoryLayout... addedLayouts) {
|
||||
return insertArgumentLayouts(argLayouts.size(), addedLayouts);
|
||||
}
|
||||
FunctionDescriptor appendArgumentLayouts(MemoryLayout... addedLayouts);
|
||||
|
||||
/**
|
||||
* Returns a function descriptor with the given argument layouts inserted at the given index, into the argument
|
||||
|
@ -139,110 +74,57 @@ public sealed class FunctionDescriptor permits FunctionDescriptor.VariadicFuncti
|
|||
* @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);
|
||||
}
|
||||
FunctionDescriptor insertArgumentLayouts(int index, MemoryLayout... addedLayouts);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
FunctionDescriptor changeReturnLayout(MemoryLayout newReturn);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
FunctionDescriptor dropReturnLayout();
|
||||
|
||||
/**
|
||||
* {@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:
|
||||
* Returns the method type consisting of the carrier types of the layouts in this function descriptor.
|
||||
* <p>
|
||||
* The carrier type of a layout is determined as follows:
|
||||
* <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>
|
||||
* <li>If the layout is a {@link ValueLayout} the carrier type is determined through {@link ValueLayout#carrier()}.</li>
|
||||
* <li>If the layout is a {@link GroupLayout} the carrier type is {@link MemorySegment}.</li>
|
||||
* <li>If the layout is a {@link PaddingLayout}, or {@link SequenceLayout} an {@link IllegalArgumentException} is thrown.</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.
|
||||
* @return the method type consisting of the carrier types of the layouts in this function descriptor
|
||||
* @throws IllegalArgumentException if one or more layouts in the function descriptor can not be mapped to carrier
|
||||
* types (e.g. if they are sequence layouts or padding layouts).
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other instanceof FunctionDescriptor f &&
|
||||
Objects.equals(resLayout, f.resLayout) &&
|
||||
Objects.equals(argLayouts, f.argLayouts) &&
|
||||
firstVariadicArgumentIndex() == f.firstVariadicArgumentIndex();
|
||||
MethodType toMethodType();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
static FunctionDescriptor of(MemoryLayout resLayout, MemoryLayout... argLayouts) {
|
||||
Objects.requireNonNull(resLayout);
|
||||
// Null checks are implicit in List.of(argLayouts)
|
||||
return FunctionDescriptorImpl.of(resLayout, List.of(argLayouts));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the hash code value for this function descriptor}
|
||||
* Creates a function descriptor with the given argument layouts and no return layout.
|
||||
* @param argLayouts the argument layouts.
|
||||
* @return the new 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();
|
||||
}
|
||||
static FunctionDescriptor ofVoid(MemoryLayout... argLayouts) {
|
||||
// Null checks are implicit in List.of(argLayouts)
|
||||
return FunctionDescriptorImpl.ofVoid(List.of(argLayouts));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,19 +25,14 @@
|
|||
*/
|
||||
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>
|
||||
* can be combined: if member layouts are laid out one after the other, the resulting group layout is said to be a <em>struct layout</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...)}).
|
||||
* the resulting group layout is said to be a <em>union layout</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>.
|
||||
|
@ -45,55 +40,7 @@ import jdk.internal.javac.PreviewFeature;
|
|||
* @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;
|
||||
}
|
||||
public sealed interface GroupLayout extends MemoryLayout permits StructLayout, UnionLayout {
|
||||
|
||||
/**
|
||||
* Returns the member layouts associated with this group.
|
||||
|
@ -104,84 +51,17 @@ public final class GroupLayout extends AbstractLayout implements MemoryLayout {
|
|||
*
|
||||
* @return the member layouts associated with this group.
|
||||
*/
|
||||
public List<MemoryLayout> memberLayouts() {
|
||||
return Collections.unmodifiableList(elements);
|
||||
}
|
||||
List<MemoryLayout> memberLayouts();
|
||||
|
||||
/**
|
||||
* {@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;
|
||||
}
|
||||
GroupLayout withName(String name);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!super.equals(other)) {
|
||||
return false;
|
||||
}
|
||||
return other instanceof GroupLayout otherGroup &&
|
||||
kind == otherGroup.kind &&
|
||||
elements.equals(otherGroup.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);
|
||||
}
|
||||
GroupLayout withBitAlignment(long bitAlignment);
|
||||
}
|
||||
|
|
|
@ -26,13 +26,13 @@
|
|||
package java.lang.foreign;
|
||||
|
||||
import jdk.internal.foreign.abi.AbstractLinker;
|
||||
import jdk.internal.foreign.abi.LinkerOptions;
|
||||
import jdk.internal.foreign.abi.SharedUtils;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
/**
|
||||
* A linker provides access to foreign functions from Java code, and access to Java code from foreign functions.
|
||||
|
@ -47,9 +47,9 @@ import java.lang.invoke.MethodType;
|
|||
* 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>
|
||||
* {@linkplain #downcallHandle(MemorySegment, FunctionDescriptor, Option...) 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>
|
||||
* via the generation of {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, SegmentScope) 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.
|
||||
|
@ -62,29 +62,16 @@ import java.lang.invoke.MethodType;
|
|||
*
|
||||
* <h2 id="downcall-method-handles">Downcall method handles</h2>
|
||||
*
|
||||
* {@linkplain #downcallHandle(FunctionDescriptor) Linking a foreign function} is a process which requires a function descriptor,
|
||||
* {@linkplain #downcallHandle(FunctionDescriptor, Option...) 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:
|
||||
* {@linkplain FunctionDescriptor#toMethodType() derived} from the argument and return layouts in the function descriptor.
|
||||
* The downcall method handle type, might then be decorated by additional leading parameters, in the given order if both are present:
|
||||
* <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
|
||||
* <li>If the downcall method handle is created {@linkplain #downcallHandle(FunctionDescriptor, Option...) without specifying a target address},
|
||||
* the downcall method handle type features a leading parameter of type {@link MemorySegment}, 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
|
||||
|
@ -93,26 +80,15 @@ import java.lang.invoke.MethodType;
|
|||
*
|
||||
* <h2 id="upcall-stubs">Upcall stubs</h2>
|
||||
*
|
||||
* {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, MemorySession) Creating an upcall stub} requires a method
|
||||
* {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, SegmentScope) 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>
|
||||
* The type of the provided method handle's type has to match the method type associated with the upcall stub,
|
||||
* which is {@linkplain FunctionDescriptor#toMethodType() derived} from the provided function descriptor.
|
||||
* <p>
|
||||
* 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}.
|
||||
* downcall method handles and, they are released via their associated {@linkplain SegmentScope scope}.
|
||||
*
|
||||
* <h2 id="safety">Safety considerations</h2>
|
||||
*
|
||||
|
@ -121,23 +97,34 @@ import java.lang.invoke.MethodType;
|
|||
* 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}):
|
||||
* the linker runtime guarantees the following for any argument {@code A} of type {@link MemorySegment} whose corresponding
|
||||
* layout is {@link ValueLayout#ADDRESS}:
|
||||
* <ul>
|
||||
* <li>The memory session of {@code R} is {@linkplain MemorySession#isAlive() alive}. Otherwise, the invocation throws
|
||||
* <li>The scope of {@code A} is {@linkplain SegmentScope#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 WrongThreadException}; and</li>
|
||||
* <li>The memory session of {@code R} is {@linkplain MemorySession#whileAlive(Runnable) kept alive} (and cannot be closed) during the invocation.</li>
|
||||
* <li>The invocation occurs in a thread {@code T} such that {@code A.scope().isAccessibleBy(T) == true}.
|
||||
* Otherwise, the invocation throws {@link WrongThreadException}; and</li>
|
||||
* <li>The scope of {@code A} is {@linkplain SegmentScope#whileAlive(Runnable) kept alive} during the invocation.</li>
|
||||
*</ul>
|
||||
* A downcall method handle created from a function descriptor whose return layout is an
|
||||
* {@linkplain ValueLayout.OfAddress address layout} returns a native segment associated with
|
||||
* the {@linkplain SegmentScope#global() global scope}. Under normal conditions, the size of the returned segment is {@code 0}.
|
||||
* However, if the return layout is an {@linkplain ValueLayout.OfAddress#asUnbounded() unbounded} address layout,
|
||||
* then the size of the returned segment is {@code Long.MAX_VALUE}.
|
||||
* <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
|
||||
* handle associated with an upcall stub returns a {@linkplain MemorySegment memory segment}, 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.
|
||||
* <p>
|
||||
* An upcall stub argument whose corresponding layout is an {@linkplain ValueLayout.OfAddress address layout}
|
||||
* is a native segment associated with the {@linkplain SegmentScope#global() global scope}.
|
||||
* Under normal conditions, the size of this segment argument is {@code 0}. However, if the layout associated with
|
||||
* the upcall stub argument is an {@linkplain ValueLayout.OfAddress#asUnbounded() unbounded} address layout,
|
||||
* then the size of the segment argument is {@code Long.MAX_VALUE}.
|
||||
*
|
||||
* @implSpec
|
||||
* Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
|
@ -159,22 +146,22 @@ public sealed interface Linker permits AbstractLinker {
|
|||
* 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}.
|
||||
* to the size and alignment constraint 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 MemorySegment}.
|
||||
* 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}.
|
||||
* {@link #downcallHandle(MemorySegment, FunctionDescriptor, Option...) downcall method handle} or an
|
||||
* {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, SegmentScope) 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}).
|
||||
* variadic function by using {@linkplain Linker.Option#firstVariadicArg(int) a linker option} to indicate
|
||||
* the start of the list of variadic arguments, together with a specialized function descriptor describing a
|
||||
* given variable arity callsite. 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
|
||||
|
@ -199,55 +186,60 @@ public sealed interface Linker permits AbstractLinker {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a method handle which can be used to call a target foreign function with the given signature and address.
|
||||
* Creates a method handle which can be used to call a 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.
|
||||
* an additional prefix parameter, of type {@link SegmentAllocator}, which will be used by the linker 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 symbol the address of the target function.
|
||||
* @param function the function descriptor of the target function.
|
||||
* @param options any linker options.
|
||||
* @return a downcall method handle. The method handle type is <a href="Linker.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}
|
||||
* or if the symbol is {@link MemorySegment#NULL}
|
||||
* @throws IllegalArgumentException if an invalid combination of linker options is given.
|
||||
*/
|
||||
default MethodHandle downcallHandle(Addressable symbol, FunctionDescriptor function) {
|
||||
default MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Option... options) {
|
||||
SharedUtils.checkSymbol(symbol);
|
||||
return downcallHandle(function).bindTo(symbol);
|
||||
return downcallHandle(function, options).bindTo(symbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a method handle which can be used to call a target foreign function with the given signature.
|
||||
* Creates a method handle which can be used to call a 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
|
||||
* entry point, of type {@link MemorySegment}, 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.
|
||||
* which will be used by the linker 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}.
|
||||
* The returned method handle will throw an {@link IllegalArgumentException} if the {@link MemorySegment} parameter passed to it is
|
||||
* associated with the {@link MemorySegment#NULL} address, or a {@link NullPointerException} if that parameter is {@code null}.
|
||||
*
|
||||
* @param function the function descriptor of the target function.
|
||||
* @param options any linker options.
|
||||
* @return a downcall method handle. The method handle type is <a href="Linker.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.
|
||||
* @throws IllegalArgumentException if an invalid combination of linker options is given.
|
||||
*/
|
||||
MethodHandle downcallHandle(FunctionDescriptor function);
|
||||
MethodHandle downcallHandle(FunctionDescriptor function, Option... options);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Creates a stub which can be passed to other foreign functions as a function pointer, associated with the given
|
||||
* scope. 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.
|
||||
* The returned memory segment's address points to the newly allocated upcall stub, and is associated with
|
||||
* the provided scope. As such, the corresponding upcall stub will be deallocated
|
||||
* when the scope becomes not {@linkplain SegmentScope#isAlive() alive}.
|
||||
* <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
|
||||
|
@ -257,16 +249,16 @@ public sealed interface Linker permits AbstractLinker {
|
|||
*
|
||||
* @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.
|
||||
* @param scope the scope associated with the returned upcall stub segment.
|
||||
* @return a zero-length segment whose 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="Linker.html#upcall-stubs"><em>inferred type</em></a>.
|
||||
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread other than the thread
|
||||
* {@linkplain MemorySession#ownerThread() owning} {@code session}.
|
||||
* @throws IllegalStateException if {@code scope} is not {@linkplain SegmentScope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code scope.isAccessibleBy(T) == false}.
|
||||
*/
|
||||
MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, MemorySession session);
|
||||
MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, SegmentScope scope);
|
||||
|
||||
/**
|
||||
* Returns a symbol lookup for symbols in a set of commonly used libraries.
|
||||
|
@ -284,22 +276,21 @@ public sealed interface Linker permits AbstractLinker {
|
|||
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).
|
||||
* A linker option is used to indicate additional linking requirements to the linker,
|
||||
* besides what is described by a function descriptor.
|
||||
* @since 20
|
||||
*/
|
||||
static MethodType downcallType(FunctionDescriptor functionDescriptor) {
|
||||
return SharedUtils.inferMethodType(functionDescriptor, false);
|
||||
}
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface Option
|
||||
permits LinkerOptions.FirstVariadicArg {
|
||||
|
||||
/**
|
||||
* {@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);
|
||||
/**
|
||||
* {@return a linker option used to denote the index of the first variadic argument layout in a
|
||||
* foreign function call}
|
||||
* @param index the index of the first variadic argument in a downcall handle linkage request.
|
||||
*/
|
||||
static Option firstVariadicArg(int index) {
|
||||
return new LinkerOptions.FirstVariadicArg(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,854 +0,0 @@
|
|||
/*
|
||||
* 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 id="dereferencing">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 toRawLongValue() + offset}.
|
||||
* @return a Java string constructed from the bytes read from the given starting address ({@code toRawLongValue() + 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 toRawLongValue() + 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 from this address at the given offset, 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 toRawLongValue() + 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 into this address at the given offset, 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 toRawLongValue() + 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 from this address at the given offset, 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 toRawLongValue() + 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 into this address at the given offset, 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 toRawLongValue() + 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 from this address at the given offset, 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 toRawLongValue() + 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 into this address at the given offset, 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 toRawLongValue() + 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 from this address at the given offset, 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 toRawLongValue() + 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 into this address at the given offset, 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 toRawLongValue() + 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 from this address at the given offset, 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 toRawLongValue() + 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 into this address at the given offset, 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 toRawLongValue() + 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 from this address at the given offset, 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 toRawLongValue() + 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 into this address at the given offset, 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 toRawLongValue() + 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 from this address at the given offset, 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 toRawLongValue() + 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 into this address at the given offset, 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 toRawLongValue() + 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 from this address at the given offset, 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 toRawLongValue() + 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 into this address at the given offset, 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 toRawLongValue() + 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 from this address at the given offset, 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 toRawLongValue() + 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 into this address at the given offset, 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 toRawLongValue() + 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 toRawLongValue() + (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 into 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 toRawLongValue() + (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 toRawLongValue() + (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 into 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 toRawLongValue() + (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 toRawLongValue() + (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 into 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 toRawLongValue() + (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 toRawLongValue() + (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 into 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 toRawLongValue() + (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 toRawLongValue() + (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 into 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 toRawLongValue() + (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 toRawLongValue() + (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 into 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 toRawLongValue() + (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 toRawLongValue() + (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 into 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 toRawLongValue() + (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);
|
||||
}
|
|
@ -35,15 +35,20 @@ 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.foreign.layout.MemoryLayoutUtil;
|
||||
import jdk.internal.foreign.layout.PaddingLayoutImpl;
|
||||
import jdk.internal.foreign.layout.SequenceLayoutImpl;
|
||||
import jdk.internal.foreign.layout.StructLayoutImpl;
|
||||
import jdk.internal.foreign.layout.UnionLayoutImpl;
|
||||
import jdk.internal.foreign.layout.ValueLayouts;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
* A memory layout can be used to describe the contents of a memory segment.
|
||||
* A memory layout describes 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)}).
|
||||
|
@ -162,10 +167,11 @@ import jdk.internal.javac.PreviewFeature;
|
|||
* @implSpec
|
||||
* Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @sealedGraph
|
||||
* @since 19
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout, GroupLayout, PaddingLayout, ValueLayout {
|
||||
public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, PaddingLayout, ValueLayout {
|
||||
|
||||
/**
|
||||
* {@return the layout size, in bits}
|
||||
|
@ -185,7 +191,7 @@ public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout, Gro
|
|||
Optional<String> name();
|
||||
|
||||
/**
|
||||
* Returns a memory layout with the same size and alignment constraints as this layout,
|
||||
* Returns a memory layout of the same type with the same size and alignment constraint as this layout,
|
||||
* but with the specified name.
|
||||
*
|
||||
* @param name the layout name.
|
||||
|
@ -235,11 +241,11 @@ public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout, Gro
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a memory layout with the same size and name as this layout,
|
||||
* but with the specified alignment constraints (in bits).
|
||||
* Returns a memory layout of the same type with the same size and name as this layout,
|
||||
* but with the specified alignment constraint (in bits).
|
||||
*
|
||||
* @param bitAlignment the layout alignment constraint, expressed in bits.
|
||||
* @return a memory layout with the given alignment constraints.
|
||||
* @return a memory layout with the given alignment constraint.
|
||||
* @throws IllegalArgumentException if {@code bitAlignment} is not a power of two, or if it's less than 8.
|
||||
*/
|
||||
MemoryLayout withBitAlignment(long bitAlignment);
|
||||
|
@ -307,7 +313,7 @@ public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout, Gro
|
|||
* in {@code elements} is {@code null}.
|
||||
*/
|
||||
default long byteOffset(PathElement... elements) {
|
||||
return Utils.bitsToBytesOrThrow(bitOffset(elements), Utils.bitsToBytesThrowOffset);
|
||||
return Utils.bitsToBytesOrThrow(bitOffset(elements), Utils.BITS_TO_BYTES_THROW_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -343,23 +349,24 @@ public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout, Gro
|
|||
*/
|
||||
default MethodHandle byteOffsetHandle(PathElement... elements) {
|
||||
MethodHandle mh = bitOffsetHandle(elements);
|
||||
mh = MethodHandles.filterReturnValue(mh, Utils.MH_bitsToBytesOrThrowForOffset);
|
||||
mh = MethodHandles.filterReturnValue(mh, Utils.MH_BITS_TO_BYTES_OR_THROW_FOR_OFFSET);
|
||||
return mh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an access var handle that can be used to dereference memory at the layout selected by the given layout path,
|
||||
* Creates a var handle that can be used to access a memory segment 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:
|
||||
* The final address accessed by the returned var handle can be computed as follows:
|
||||
*
|
||||
* <blockquote><pre>{@code
|
||||
* address = base + offset
|
||||
* address = base(segment) + 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:
|
||||
* Where {@code base(segment)} denotes a function that returns the physical base address of the accessed
|
||||
* memory segment. For native segments, this function just returns the native segment's
|
||||
* {@linkplain MemorySegment#address() address}. For heap segments, this function is more complex, as the address
|
||||
* of heap segments is virtualized. The {@code offset} coordinate 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)
|
||||
|
@ -378,8 +385,8 @@ public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout, Gro
|
|||
* 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.
|
||||
* @return a var handle which can be used to access a memory segment 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 constraint.
|
||||
* @throws IllegalArgumentException if the layout path in {@code elements} does not select a value layout (see {@link ValueLayout}).
|
||||
* @see MethodHandles#memorySegmentViewVarHandle(ValueLayout)
|
||||
*/
|
||||
|
@ -458,11 +465,6 @@ public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout, Gro
|
|||
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
|
||||
|
@ -581,15 +583,15 @@ public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout, Gro
|
|||
/**
|
||||
* 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
|
||||
* the same kind, have the same size, name and alignment constraint. Furthermore, depending on the layout kind, additional
|
||||
* conditions must be satisfied:
|
||||
* <ul>
|
||||
* <li>two value layouts are considered equal if they have the same {@linkplain ValueLayout#order() order},
|
||||
* and {@linkplain ValueLayout#carrier() carrier}</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>
|
||||
* <li>two group layouts are considered equal if they are of the same type (see {@link StructLayout},
|
||||
* {@link UnionLayout}) and if their member layouts (see {@link GroupLayout#memberLayouts()}) are also equal</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param other the object to be compared for equality with this layout.
|
||||
|
@ -615,9 +617,9 @@ public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout, Gro
|
|||
* @return the new selector layout.
|
||||
* @throws IllegalArgumentException if {@code size <= 0}.
|
||||
*/
|
||||
static MemoryLayout paddingLayout(long size) {
|
||||
AbstractLayout.checkSize(size);
|
||||
return new PaddingLayout(size);
|
||||
static PaddingLayout paddingLayout(long size) {
|
||||
MemoryLayoutUtil.checkSize(size);
|
||||
return PaddingLayoutImpl.of(size);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -632,7 +634,7 @@ public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout, Gro
|
|||
* <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>
|
||||
* <li>{@link ValueLayout.OfAddress}, for {@code MemorySegment.class}</li>
|
||||
* </ul>
|
||||
* @param carrier the value layout carrier.
|
||||
* @param order the value layout's byte order.
|
||||
|
@ -643,54 +645,58 @@ public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout, Gro
|
|||
Objects.requireNonNull(carrier);
|
||||
Objects.requireNonNull(order);
|
||||
if (carrier == boolean.class) {
|
||||
return new ValueLayout.OfBoolean(order);
|
||||
return ValueLayouts.OfBooleanImpl.of(order);
|
||||
} else if (carrier == char.class) {
|
||||
return new ValueLayout.OfChar(order);
|
||||
return ValueLayouts.OfCharImpl.of(order);
|
||||
} else if (carrier == byte.class) {
|
||||
return new ValueLayout.OfByte(order);
|
||||
return ValueLayouts.OfByteImpl.of(order);
|
||||
} else if (carrier == short.class) {
|
||||
return new ValueLayout.OfShort(order);
|
||||
return ValueLayouts.OfShortImpl.of(order);
|
||||
} else if (carrier == int.class) {
|
||||
return new ValueLayout.OfInt(order);
|
||||
return ValueLayouts.OfIntImpl.of(order);
|
||||
} else if (carrier == float.class) {
|
||||
return new ValueLayout.OfFloat(order);
|
||||
return ValueLayouts.OfFloatImpl.of(order);
|
||||
} else if (carrier == long.class) {
|
||||
return new ValueLayout.OfLong(order);
|
||||
return ValueLayouts.OfLongImpl.of(order);
|
||||
} else if (carrier == double.class) {
|
||||
return new ValueLayout.OfDouble(order);
|
||||
} else if (carrier == MemoryAddress.class) {
|
||||
return new ValueLayout.OfAddress(order);
|
||||
return ValueLayouts.OfDoubleImpl.of(order);
|
||||
} else if (carrier == MemorySegment.class) {
|
||||
return ValueLayouts.OfAddressImpl.of(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:
|
||||
* Creates a sequence layout with the given element layout and element count.
|
||||
*
|
||||
* <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 elementCount the sequence element count.
|
||||
* @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.
|
||||
* @throws IllegalArgumentException if {@code elementCount } is negative.
|
||||
*/
|
||||
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)));
|
||||
}
|
||||
MemoryLayoutUtil.checkSize(elementCount, true);
|
||||
Objects.requireNonNull(elementLayout);
|
||||
return wrapOverflow(() ->
|
||||
SequenceLayoutImpl.of(elementCount, elementLayout));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a sequence layout with the given element layout and the maximum element
|
||||
* count such that it does not overflow a {@code long}.
|
||||
*
|
||||
* This is equivalent to the following code:
|
||||
* {@snippet lang = java:
|
||||
* sequenceLayout(Long.MAX_VALUE / elementLayout.bitSize(), elementLayout);
|
||||
* }
|
||||
*
|
||||
* @param elementLayout the sequence element layout.
|
||||
* @return a new sequence layout with the given element layout and maximum element count.
|
||||
*/
|
||||
static SequenceLayout sequenceLayout(MemoryLayout elementLayout) {
|
||||
Objects.requireNonNull(elementLayout);
|
||||
return sequenceLayout(Long.MAX_VALUE / elementLayout.bitSize(), elementLayout);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -701,13 +707,12 @@ public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout, Gro
|
|||
* @throws IllegalArgumentException if the sum of the {@linkplain #bitSize() bit sizes} of the member layouts
|
||||
* overflows.
|
||||
*/
|
||||
static GroupLayout structLayout(MemoryLayout... elements) {
|
||||
static StructLayout structLayout(MemoryLayout... elements) {
|
||||
Objects.requireNonNull(elements);
|
||||
return wrapOverflow(() ->
|
||||
new GroupLayout(GroupLayout.Kind.STRUCT,
|
||||
Stream.of(elements)
|
||||
.map(Objects::requireNonNull)
|
||||
.collect(Collectors.toList())));
|
||||
StructLayoutImpl.of(Stream.of(elements)
|
||||
.map(Objects::requireNonNull)
|
||||
.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -716,12 +721,11 @@ public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout, Gro
|
|||
* @param elements The member layouts of the union layout.
|
||||
* @return a union layout with the given member layouts.
|
||||
*/
|
||||
static GroupLayout unionLayout(MemoryLayout... elements) {
|
||||
static UnionLayout unionLayout(MemoryLayout... elements) {
|
||||
Objects.requireNonNull(elements);
|
||||
return new GroupLayout(GroupLayout.Kind.UNION,
|
||||
Stream.of(elements)
|
||||
.map(Objects::requireNonNull)
|
||||
.collect(Collectors.toList()));
|
||||
return UnionLayoutImpl.of(Stream.of(elements)
|
||||
.map(Objects::requireNonNull)
|
||||
.toList());
|
||||
}
|
||||
|
||||
private static <L extends MemoryLayout> L wrapOverflow(Supplier<L> layoutSupplier) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,285 +0,0 @@
|
|||
/*
|
||||
* 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 id = "thread-confinement">Thread confinement</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 WrongThreadException}.
|
||||
* <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 id="closeable">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 id="non-closeable">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}.
|
||||
* @throws WrongThreadException if this method is called 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}.
|
||||
* @throws IllegalStateException if this session is {@linkplain #whileAlive(Runnable) kept alive} by another client.
|
||||
* @throws WrongThreadException if this method is called from a thread other than the thread
|
||||
* {@linkplain #ownerThread() owning} this memory session.
|
||||
* @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}.
|
||||
* @throws WrongThreadException if this method is called 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;
|
||||
}
|
||||
}
|
|
@ -25,76 +25,30 @@
|
|||
*/
|
||||
package java.lang.foreign;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import jdk.internal.foreign.layout.PaddingLayoutImpl;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
* A padding layout. A padding layout specifies the size of extra space which is typically not accessed by applications,
|
||||
* 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>.
|
||||
* Implementing classes are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @since 20
|
||||
*/
|
||||
/* 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
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public sealed interface PaddingLayout extends MemoryLayout permits PaddingLayoutImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public PaddingLayout withName(String name) {
|
||||
return (PaddingLayout)super.withName(name);
|
||||
}
|
||||
PaddingLayout withName(String name);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public PaddingLayout withBitAlignment(long alignmentBits) {
|
||||
return (PaddingLayout)super.withBitAlignment(alignmentBits);
|
||||
}
|
||||
PaddingLayout withBitAlignment(long bitAlignment);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,8 @@ 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.MemorySessionImpl;
|
||||
import jdk.internal.foreign.SlicingAllocator;
|
||||
import jdk.internal.foreign.Utils;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
|
@ -45,17 +46,17 @@ import jdk.internal.javac.PreviewFeature;
|
|||
* <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 #nativeAllocator(SegmentScope)} obtains a simple allocator which can
|
||||
* be used to allocate native segments;</li>
|
||||
* <li>{@link #slicingAllocator(MemorySegment)} obtains an efficient slicing allocator, where memory
|
||||
* is allocated by repeatedly slicing the provided memory segment;</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
|
||||
* {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) 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.
|
||||
*/
|
||||
|
@ -80,7 +81,7 @@ public interface SegmentAllocator {
|
|||
* @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.
|
||||
* @return a new native segment containing the converted C string.
|
||||
*/
|
||||
default MemorySegment allocateUtf8String(String str) {
|
||||
Objects.requireNonNull(str);
|
||||
|
@ -200,11 +201,11 @@ public interface SegmentAllocator {
|
|||
* @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) {
|
||||
default MemorySegment allocate(ValueLayout.OfAddress layout, MemorySegment value) {
|
||||
Objects.requireNonNull(value);
|
||||
Objects.requireNonNull(layout);
|
||||
MemorySegment segment = allocate(layout);
|
||||
layout.varHandle().set(segment, value.address());
|
||||
layout.varHandle().set(segment, value);
|
||||
return segment;
|
||||
}
|
||||
|
||||
|
@ -287,10 +288,8 @@ public interface SegmentAllocator {
|
|||
|
||||
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 = allocateArray(elementLayout, size);
|
||||
int size = Array.getLength(Objects.requireNonNull(array));
|
||||
MemorySegment addr = allocateArray(Objects.requireNonNull(elementLayout), size);
|
||||
if (size > 0) {
|
||||
MemorySegment.copy(heapSegmentFactory.apply(array), elementLayout, 0,
|
||||
addr, elementLayout.withOrder(ByteOrder.nativeOrder()), 0, size);
|
||||
|
@ -327,105 +326,39 @@ public interface SegmentAllocator {
|
|||
|
||||
/**
|
||||
* 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.
|
||||
* @implSpec the default implementation for this method calls {@code this.allocate(byteSize, 1)}.
|
||||
* @param byteSize 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}
|
||||
* @throws IllegalArgumentException if {@code byteSize < 0}
|
||||
*/
|
||||
default MemorySegment allocate(long bytesSize) {
|
||||
return allocate(bytesSize, 1);
|
||||
default MemorySegment allocate(long byteSize) {
|
||||
return allocate(byteSize, 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.
|
||||
* Allocates a memory segment with the given size and alignment constraint.
|
||||
* @param byteSize the size (in bytes) of the block of memory to be allocated.
|
||||
* @param byteAlignment 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},
|
||||
* @throws IllegalArgumentException if {@code byteSize < 0}, {@code byteAlignment <= 0},
|
||||
* or if {@code alignmentBytes} is not a power of 2.
|
||||
*/
|
||||
MemorySegment allocate(long bytesSize, long bytesAlignment);
|
||||
MemorySegment allocate(long byteSize, long byteAlignment);
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
* @throws WrongThreadException if this method is called 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}.
|
||||
* @throws WrongThreadException if this method is called 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.
|
||||
* Returns a segment allocator which responds to allocation requests by returning consecutive slices
|
||||
* obtained from the provided segment. Each new allocation request will return a new slice starting at the
|
||||
* current offset (modulo additional padding to satisfy alignment constraint), with given size.
|
||||
* <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.
|
||||
* When the returned allocator cannot satisfy an allocation request, e.g. because a slice of the provided
|
||||
* segment with the requested size cannot be found, an {@link IndexOutOfBoundsException} is thrown.
|
||||
*
|
||||
* @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}.
|
||||
* @throws WrongThreadException if this method is called from a thread other than the thread
|
||||
* {@linkplain MemorySession#ownerThread() owning} {@code session}.
|
||||
* @param segment the segment which the returned allocator should slice from.
|
||||
* @return a new slicing allocator
|
||||
*/
|
||||
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);
|
||||
static SegmentAllocator slicingAllocator(MemorySegment segment) {
|
||||
Objects.requireNonNull(segment);
|
||||
return new SlicingAllocator(segment);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -449,24 +382,33 @@ public interface SegmentAllocator {
|
|||
* @return an allocator which recycles an existing segment upon each new allocation request.
|
||||
*/
|
||||
static SegmentAllocator prefixAllocator(MemorySegment segment) {
|
||||
Objects.requireNonNull(segment);
|
||||
return (AbstractMemorySegmentImpl)segment;
|
||||
return (AbstractMemorySegmentImpl)Objects.requireNonNull(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());
|
||||
* Simple allocator used to allocate native segments. The returned allocator responds to an allocation request by
|
||||
* returning a native segment backed by a fresh off-heap region of memory, with given byte size and alignment constraint.
|
||||
* <p>
|
||||
* Each native segment obtained by the returned allocator is associated with the provided scope. As such,
|
||||
* the off-heap region which backs the returned segment is freed when the scope becomes not
|
||||
* {@linkplain SegmentScope#isAlive() alive}.
|
||||
* <p>
|
||||
* The {@link MemorySegment#address()} of the native segments obtained by the returned allocator is the starting address of
|
||||
* the newly allocated off-heap memory region backing the segment. Moreover, the {@linkplain MemorySegment#address() address}
|
||||
* of the native segment will be aligned according the provided alignment constraint.
|
||||
* <p>
|
||||
* The off-heap region of memory backing a native segment obtained by the returned allocator is initialized to zero.
|
||||
* <p>
|
||||
* This is equivalent to the following code:
|
||||
* {@snippet lang = java:
|
||||
* SegmentAllocator nativeAllocator = (byteSize, byteAlignment) ->
|
||||
* MemorySegment.allocateNative(byteSize, byteAlignment, scope);
|
||||
* }
|
||||
*
|
||||
* @return an allocator which allocates native segments in independent {@linkplain MemorySession#openImplicit() implicit memory sessions}.
|
||||
* @param scope the scope associated with the segments returned by the native allocator.
|
||||
* @return a simple allocator used to allocate native segments.
|
||||
*/
|
||||
static SegmentAllocator implicitAllocator() {
|
||||
class Holder {
|
||||
static final SegmentAllocator IMPLICIT_ALLOCATOR = (size, align) ->
|
||||
MemorySegment.allocateNative(size, align, MemorySession.openImplicit());
|
||||
}
|
||||
return Holder.IMPLICIT_ALLOCATOR;
|
||||
static SegmentAllocator nativeAllocator(SegmentScope scope) {
|
||||
Objects.requireNonNull(scope);
|
||||
return (MemorySessionImpl)scope;
|
||||
}
|
||||
}
|
||||
|
|
132
src/java.base/share/classes/java/lang/foreign/SegmentScope.java
Normal file
132
src/java.base/share/classes/java/lang/foreign/SegmentScope.java
Normal file
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* 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.foreign.MemorySessionImpl;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
import jdk.internal.ref.CleanerFactory;
|
||||
|
||||
/**
|
||||
* A segment scope controls access to memory segments.
|
||||
* <p>
|
||||
* A memory segment can only be accessed while its scope is {@linkplain #isAlive() alive}. Moreover,
|
||||
* depending on how the segment scope has been obtained, access might additionally be
|
||||
* <a href="Arena.html#thread-confinement">restricted to specific threads</a>.
|
||||
* <p>
|
||||
* The simplest segment scope is the {@linkplain SegmentScope#global() global scope}. The global scope
|
||||
* is always alive. As a result, segments associated with the global scope are always accessible and their backing
|
||||
* regions of memory are never deallocated. Moreover, memory segments associated with the global scope
|
||||
* can be {@linkplain #isAccessibleBy(Thread) accessed} from any thread.
|
||||
* {@snippet lang = java:
|
||||
* MemorySegment segment = MemorySegment.allocateNative(100, SegmentScope.global());
|
||||
* ...
|
||||
* // segment is never deallocated!
|
||||
*}
|
||||
* <p>
|
||||
* Alternatively, clients can obtain an {@linkplain SegmentScope#auto() automatic scope}, that is a segment
|
||||
* scope that is managed, automatically, by the garbage collector. The regions of memory backing memory segments associated
|
||||
* with an automatic scope are deallocated at some unspecified time <em>after</em> they become
|
||||
* <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>, as shown below:
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* MemorySegment segment = MemorySegment.allocateNative(100, SegmentScope.auto());
|
||||
* ...
|
||||
* segment = null; // the segment region becomes available for deallocation after this point
|
||||
*}
|
||||
* Memory segments associated with an automatic scope can also be {@linkplain #isAccessibleBy(Thread) accessed} from any thread.
|
||||
* <p>
|
||||
* Finally, clients can obtain a segment scope from an existing {@linkplain Arena arena}, the arena scope. The regions of memory
|
||||
* backing memory segments associated with an arena scope are deallocated when the arena is {@linkplain Arena#close() closed}.
|
||||
* When this happens, the arena scope becomes not {@linkplain #isAlive() alive} and subsequent access operations on segments
|
||||
* associated with the arena scope will fail {@link IllegalStateException}.
|
||||
*
|
||||
* {@snippet lang = java:
|
||||
* MemorySegment segment = null;
|
||||
* try (Arena arena = Arena.openConfined()) {
|
||||
* segment = MemorySegment.allocateNative(100, arena.scope());
|
||||
* ...
|
||||
* } // segment region deallocated here
|
||||
* segment.get(ValueLayout.JAVA_BYTE, 0); // throws IllegalStateException
|
||||
* }
|
||||
*
|
||||
* Which threads can {@link #isAccessibleBy(Thread) access} memory segments associated with an arena scope depends
|
||||
* on the arena kind. For instance, segments associated with the scope of a {@linkplain Arena#openConfined() confined arena}
|
||||
* can only be accessed by the thread that created the arena. Conversely, segments associated with the scope of
|
||||
* {@linkplain Arena#openConfined() shared arena} can be accessed by any thread.
|
||||
*
|
||||
* @implSpec
|
||||
* Implementations of this interface are thread-safe.
|
||||
*
|
||||
* @see Arena
|
||||
* @see MemorySegment
|
||||
*
|
||||
* @since 20
|
||||
*/
|
||||
@PreviewFeature(feature =PreviewFeature.Feature.FOREIGN)
|
||||
sealed public interface SegmentScope permits MemorySessionImpl {
|
||||
|
||||
/**
|
||||
* Creates a new scope that is managed, automatically, by the garbage collector.
|
||||
* Segments associated with the returned scope can be
|
||||
* {@linkplain SegmentScope#isAccessibleBy(Thread) accessed} by any thread.
|
||||
*
|
||||
* @return a new scope that is managed, automatically, by the garbage collector.
|
||||
*/
|
||||
static SegmentScope auto() {
|
||||
return MemorySessionImpl.createImplicit(CleanerFactory.cleaner());
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the global scope. Segments associated with the global scope can be
|
||||
* {@linkplain SegmentScope#isAccessibleBy(Thread) accessed} by any thread.
|
||||
*
|
||||
* @return the global scope.
|
||||
*/
|
||||
static SegmentScope global() {
|
||||
return MemorySessionImpl.GLOBAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return {@code true}, if this scope is alive}
|
||||
*/
|
||||
boolean isAlive();
|
||||
|
||||
/**
|
||||
* {@return {@code true} if the provided thread can access and/or associate segments with this scope}
|
||||
* @param thread the thread to be tested.
|
||||
*/
|
||||
boolean isAccessibleBy(Thread thread);
|
||||
|
||||
/**
|
||||
* Runs a critical action while this scope is kept alive.
|
||||
* @param action the action to be run.
|
||||
* @throws IllegalStateException if this scope is not {@linkplain SegmentScope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code isAccessibleBy(T) == false}.
|
||||
*/
|
||||
void whileAlive(Runnable action);
|
||||
|
||||
}
|
|
@ -25,9 +25,7 @@
|
|||
*/
|
||||
package java.lang.foreign;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import jdk.internal.foreign.layout.SequenceLayoutImpl;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
|
@ -55,46 +53,27 @@ import jdk.internal.javac.PreviewFeature;
|
|||
* @since 19
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public final class SequenceLayout extends AbstractLayout implements MemoryLayout {
|
||||
public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayoutImpl {
|
||||
|
||||
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;
|
||||
}
|
||||
MemoryLayout elementLayout();
|
||||
|
||||
/**
|
||||
* {@return the element count of this sequence layout}
|
||||
*/
|
||||
public long elementCount() {
|
||||
return elemCount;
|
||||
}
|
||||
long elementCount();
|
||||
|
||||
/**
|
||||
* Returns a sequence layout with the same element layout, alignment constraints and name as this sequence layout,
|
||||
* Returns a sequence layout with the same element layout, alignment constraint 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());
|
||||
}
|
||||
SequenceLayout withElementCount(long elementCount);
|
||||
|
||||
/**
|
||||
* Re-arrange the elements in this sequence layout into a multi-dimensional sequence layout.
|
||||
|
@ -129,47 +108,7 @@ public final class SequenceLayout extends AbstractLayout implements MemoryLayout
|
|||
* 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;
|
||||
}
|
||||
SequenceLayout reshape(long... elementCounts);
|
||||
|
||||
/**
|
||||
* Returns a flattened sequence layout. The element layout of the returned sequence layout
|
||||
|
@ -187,66 +126,11 @@ public final class SequenceLayout extends AbstractLayout implements MemoryLayout
|
|||
* @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.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
SequenceLayout flatten();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return decorateLayoutString(String.format("[%s:%s]",
|
||||
elemCount, elementLayout));
|
||||
}
|
||||
SequenceLayout withName(String name);
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!super.equals(other)) {
|
||||
return false;
|
||||
}
|
||||
return other instanceof SequenceLayout otherSeq &&
|
||||
elemCount == otherSeq.elemCount &&
|
||||
elementLayout.equals(otherSeq.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);
|
||||
}
|
||||
SequenceLayout withBitAlignment(long bitAlignment);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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 jdk.internal.foreign.layout.StructLayoutImpl;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
* A group layout whose member layouts are laid out one after the other.
|
||||
*
|
||||
* @implSpec
|
||||
* Implementing classes are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @since 20
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public sealed interface StructLayout extends GroupLayout permits StructLayoutImpl {
|
||||
|
||||
@Override
|
||||
StructLayout withName(String name);
|
||||
|
||||
@Override
|
||||
StructLayout withBitAlignment(long bitAlignment);
|
||||
}
|
|
@ -42,35 +42,35 @@ 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 <em>symbol lookup</em> retrieves 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)}
|
||||
* A symbol lookup is created with respect to a particular library (or libraries). Subsequently, the {@link SymbolLookup#find(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>
|
||||
* <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 address.</li>
|
||||
* <li>It can be passed to an existing {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle}, as an argument to the underlying foreign function.</li>
|
||||
* <li>It can be {@linkplain MemorySegment#set(ValueLayout.OfAddress, long, MemorySegment) stored} inside another memory segment.</li>
|
||||
* <li>It can be used to access the region of memory backing a global variable (this might require
|
||||
* {@link MemorySegment#ofAddress(long, long, SegmentScope) resizing} the segment first).</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2 id="obtaining">Obtaining a symbol lookup</h2>
|
||||
*
|
||||
* The factory methods {@link #libraryLookup(String, MemorySession)} and {@link #libraryLookup(Path, MemorySession)}
|
||||
* The factory methods {@link #libraryLookup(String, SegmentScope)} and {@link #libraryLookup(Path, SegmentScope)}
|
||||
* 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:
|
||||
* with a {@linkplain SegmentScope scope}; when the scope becomes not {@link SegmentScope#isAlive()}, 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();
|
||||
* {@snippet lang = java:
|
||||
* try (Arena arena = Arena.openConfined()) {
|
||||
* SymbolLookup libGL = SymbolLookup.libraryLookup("libGL.so", arena.scope()); // libGL.so loaded here
|
||||
* MemorySegment glGetString = libGL.find("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
|
||||
|
@ -80,7 +80,7 @@ import java.util.function.BiFunction;
|
|||
* System.loadLibrary("GL"); // libGL.so loaded here
|
||||
* ...
|
||||
* SymbolLookup libGL = SymbolLookup.loaderLookup();
|
||||
* MemorySegment glGetString = libGL.lookup("glGetString").orElseThrow();
|
||||
* MemorySegment glGetString = libGL.find("glGetString").orElseThrow();
|
||||
* }
|
||||
*
|
||||
* This symbol lookup, which is known as a <em>loader lookup</em>, is dynamic with respect to the libraries associated
|
||||
|
@ -91,18 +91,18 @@ import java.util.function.BiFunction;
|
|||
* 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
|
||||
* }
|
||||
* {@snippet lang = java:
|
||||
* libraryLookup("libGL.so", scope).find("glGetString").isPresent(); // true
|
||||
* loaderLookup().find("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 :
|
||||
* {@snippet lang = java:
|
||||
* System.loadLibrary("GL"); // libGL.so loaded here
|
||||
* libraryLookup("libGL.so", session).lookup("glGetString").isPresent(); // true
|
||||
* }
|
||||
* libraryLookup("libGL.so", scope).find("glGetString").isPresent(); // true
|
||||
*}
|
||||
*
|
||||
* <p>
|
||||
* Finally, each {@link Linker} provides a symbol lookup for libraries that are commonly used on the OS and processor
|
||||
|
@ -110,11 +110,11 @@ import java.util.function.BiFunction;
|
|||
* 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 :
|
||||
* {@snippet lang = java:
|
||||
* Linker nativeLinker = Linker.nativeLinker();
|
||||
* SymbolLookup stdlib = nativeLinker.defaultLookup();
|
||||
* MemorySegment malloc = stdlib.lookup("malloc").orElseThrow();
|
||||
* }
|
||||
* MemorySegment malloc = stdlib.find("malloc").orElseThrow();
|
||||
*}
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
@FunctionalInterface
|
||||
|
@ -123,9 +123,9 @@ 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.
|
||||
* @return a zero-length memory segment whose address indicates the address of the symbol, if found.
|
||||
*/
|
||||
Optional<MemorySegment> lookup(String name);
|
||||
Optional<MemorySegment> find(String name);
|
||||
|
||||
/**
|
||||
* Returns a symbol lookup for symbols in the libraries associated with the caller's class loader.
|
||||
|
@ -139,8 +139,8 @@ public interface SymbolLookup {
|
|||
* <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
|
||||
* returned by this method is backed by a scope that is always alive and 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
|
||||
|
@ -158,24 +158,24 @@ public interface SymbolLookup {
|
|||
ClassLoader loader = caller != null ?
|
||||
caller.getClassLoader() :
|
||||
ClassLoader.getSystemClassLoader();
|
||||
MemorySession loaderSession = (loader == null || loader instanceof BuiltinClassLoader) ?
|
||||
MemorySession.global() : // builtin loaders never go away
|
||||
SegmentScope loaderScope = (loader == null || loader instanceof BuiltinClassLoader) ?
|
||||
SegmentScope.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 ?
|
||||
long addr = javaLangAccess.findNative(loader, name);
|
||||
return addr == 0L ?
|
||||
Optional.empty() :
|
||||
Optional.of(MemorySegment.ofAddress(addr, 0L, loaderSession));
|
||||
Optional.of(MemorySegment.ofAddress(addr, 0L, loaderScope));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* The library will be unloaded when the provided scope becomes
|
||||
* not {@linkplain SegmentScope#isAlive() alive}, 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.
|
||||
|
@ -186,7 +186,7 @@ public interface SymbolLookup {
|
|||
* 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.
|
||||
* @param scope the scope associated with symbols obtained from the returned lookup.
|
||||
* @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
|
||||
|
@ -194,15 +194,15 @@ public interface SymbolLookup {
|
|||
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
|
||||
*/
|
||||
@CallerSensitive
|
||||
static SymbolLookup libraryLookup(String name, MemorySession session) {
|
||||
static SymbolLookup libraryLookup(String name, SegmentScope scope) {
|
||||
Reflection.ensureNativeAccess(Reflection.getCallerClass(), SymbolLookup.class, "libraryLookup");
|
||||
return libraryLookup(name, RawNativeLibraries::load, session);
|
||||
return libraryLookup(name, RawNativeLibraries::load, scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* in that library. The library will be unloaded when the provided scope becomes
|
||||
* not {@linkplain SegmentScope#isAlive() alive}, 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
|
||||
|
@ -212,7 +212,7 @@ public interface SymbolLookup {
|
|||
* @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.
|
||||
* @param scope the scope associated with symbols obtained from the returned lookup.
|
||||
* @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
|
||||
|
@ -220,22 +220,22 @@ public interface SymbolLookup {
|
|||
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
|
||||
*/
|
||||
@CallerSensitive
|
||||
static SymbolLookup libraryLookup(Path path, MemorySession session) {
|
||||
static SymbolLookup libraryLookup(Path path, SegmentScope scope) {
|
||||
Reflection.ensureNativeAccess(Reflection.getCallerClass(), SymbolLookup.class, "libraryLookup");
|
||||
return libraryLookup(path, RawNativeLibraries::load, session);
|
||||
return libraryLookup(path, RawNativeLibraries::load, scope);
|
||||
}
|
||||
|
||||
private static <Z> SymbolLookup libraryLookup(Z libDesc, BiFunction<RawNativeLibraries, Z, NativeLibrary> loadLibraryFunc, MemorySession session) {
|
||||
private static <Z> SymbolLookup libraryLookup(Z libDesc, BiFunction<RawNativeLibraries, Z, NativeLibrary> loadLibraryFunc, SegmentScope libScope) {
|
||||
Objects.requireNonNull(libDesc);
|
||||
Objects.requireNonNull(session);
|
||||
Objects.requireNonNull(libScope);
|
||||
// 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() {
|
||||
// register hook to unload library when 'libScope' becomes not alive
|
||||
((MemorySessionImpl) libScope).addOrCleanupIfFail(new MemorySessionImpl.ResourceList.ResourceCleanup() {
|
||||
@Override
|
||||
public void cleanup() {
|
||||
nativeLibraries.unload(library);
|
||||
|
@ -243,10 +243,10 @@ public interface SymbolLookup {
|
|||
});
|
||||
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));
|
||||
long addr = library.find(name);
|
||||
return addr == 0L ?
|
||||
Optional.empty() :
|
||||
Optional.of(MemorySegment.ofAddress(addr, 0, libScope));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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 jdk.internal.foreign.layout.UnionLayoutImpl;
|
||||
import jdk.internal.javac.PreviewFeature;
|
||||
|
||||
/**
|
||||
* A group layout whose member layouts are laid out at the same starting offset.
|
||||
*
|
||||
* @implSpec
|
||||
* Implementing classes are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
|
||||
*
|
||||
* @since 20
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public sealed interface UnionLayout extends GroupLayout permits UnionLayoutImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
UnionLayout withName(String name);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
UnionLayout withBitAlignment(long bitAlignment);
|
||||
}
|
|
@ -39,10 +39,40 @@ import jdk.internal.reflect.CallerSensitive;
|
|||
import jdk.internal.reflect.Reflection;
|
||||
|
||||
/**
|
||||
* A variable argument list, similar in functionality to a C {@code va_list}.
|
||||
* Helper class to create and manipulate variable argument lists, 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}.
|
||||
* A variable argument list can be created using the {@link #make(Consumer, SegmentScope)} factory, as follows:
|
||||
* {@snippet lang = java:
|
||||
* VaList vaList = VaList.make(builder ->
|
||||
* builder.addVarg(C_INT, 42)
|
||||
* .addVarg(C_DOUBLE, 3.8d));
|
||||
*}
|
||||
* Once created, clients can obtain the platform-dependent {@linkplain #segment() memory segment} associated with a variable
|
||||
* argument list, which can then be passed to {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handles}
|
||||
* targeting native functions using the C {@code va_list} type.
|
||||
* <p>
|
||||
* The contents of a foreign memory segment modelling a variable argument list can be accessed by <em>unsafely</em> creating
|
||||
* a variable argument list, as follows:
|
||||
* {@snippet lang = java:
|
||||
* void upcall(int n, MemorySegment vaListSegment) {
|
||||
* try (Arena arena = Arena.openConfined()) {
|
||||
* VaList vaList = VaList.ofAddress(vaListSegment.address(), arena.scope());
|
||||
* VaList copy = vaList.copy();
|
||||
* int i = vaList.nextVarg(C_INT);
|
||||
* double d = vaList.nextVarg(C_DOUBLE);
|
||||
* // and again
|
||||
* int i = copy.nextVarg(C_INT);
|
||||
* double d = copy.nextVarg(C_DOUBLE);
|
||||
* }
|
||||
* }
|
||||
*}
|
||||
* The above method receives a foreign segment modelling a variable argument list; the contents of the segment are accessed by creating
|
||||
* a new variable argument list, from the segment address. Note that the variable argument list is first copied into
|
||||
* a second list before any element is accessed: this will allow us to iterate through the elements twice. Elements in
|
||||
* the variable argument list are accessed using {@link #nextVarg(ValueLayout.OfInt)} and
|
||||
* {@link #nextVarg(ValueLayout.OfDouble)}. These methods (as well as other access methods in the {@link VaList} class)
|
||||
* take the layout of the element that needs to be accessed and perform all the necessary alignment checks as well
|
||||
* as endianness conversions.
|
||||
* <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',
|
||||
|
@ -64,22 +94,17 @@ import jdk.internal.reflect.Reflection;
|
|||
* <p>
|
||||
* Whether this detection succeeds depends on the factory method used to create the variable argument list:
|
||||
* <ul>
|
||||
* <li>Variable argument lists created <em>safely</em>, using {@link #make(Consumer, MemorySession)} are capable of detecting out-of-bounds reads;</li>
|
||||
* <li>Variable argument lists created <em>unsafely</em>, using {@link #ofAddress(MemoryAddress, MemorySession)} are not capable of detecting out-of-bounds reads</li>
|
||||
* <li>Variable argument lists created <em>safely</em>, using {@link #make(Consumer, SegmentScope)} are capable of detecting out-of-bounds reads;</li>
|
||||
* <li>Variable argument lists created <em>unsafely</em>, using {@link #ofAddress(long, SegmentScope)} are not capable of detecting out-of-bounds reads</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 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).
|
||||
* (regardless of the scope used to obtain 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();
|
||||
public sealed interface VaList permits WinVaList, SysVVaList, LinuxAArch64VaList, MacOsAArch64VaList, SharedUtils.EmptyVaList {
|
||||
|
||||
/**
|
||||
* Reads the next value as an {@code int} and advances this variable argument list's position. The behavior of this
|
||||
|
@ -87,10 +112,10 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
|
|||
*
|
||||
* @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}.
|
||||
* @throws WrongThreadException if this method is called from a thread other than the thread owning
|
||||
* the {@linkplain #session() session} associated with this variable argument list.
|
||||
* @throws IllegalStateException if the scope associated with this variable argument list is not
|
||||
* {@linkplain SegmentScope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code segment().scope().isAccessibleBy(T) == false}.
|
||||
* @throws NoSuchElementException if an <a href=VaList.html#safety>out-of-bounds</a> read is detected.
|
||||
*/
|
||||
int nextVarg(ValueLayout.OfInt layout);
|
||||
|
@ -101,10 +126,10 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
|
|||
*
|
||||
* @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}.
|
||||
* @throws WrongThreadException if this method is called from a thread other than the thread owning
|
||||
* the {@linkplain #session() session} associated with this variable argument list.
|
||||
* @throws IllegalStateException if the scope associated with this variable argument list is not
|
||||
* {@linkplain SegmentScope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code segment().scope().isAccessibleBy(T) == false}.
|
||||
* @throws NoSuchElementException if an <a href=VaList.html#safety>out-of-bounds</a> read is detected.
|
||||
*/
|
||||
long nextVarg(ValueLayout.OfLong layout);
|
||||
|
@ -115,32 +140,37 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
|
|||
*
|
||||
* @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}.
|
||||
* @throws WrongThreadException if this method is called from a thread other than the thread owning
|
||||
* the {@linkplain #session() session} associated with this variable argument list.
|
||||
* @throws IllegalStateException if the scope associated with this variable argument list is not
|
||||
* {@linkplain SegmentScope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code segment().scope().isAccessibleBy(T) == false}.
|
||||
* @throws NoSuchElementException if an <a href=VaList.html#safety>out-of-bounds</a> read is detected.
|
||||
*/
|
||||
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.
|
||||
* Reads the next address value, wraps it into a native segment, and advances this variable argument list's position.
|
||||
* The behavior of this method is equivalent to the C {@code va_arg} function. The returned segment's base
|
||||
* {@linkplain MemorySegment#address()} is set to the value read from the variable argument list, and the segment
|
||||
* is associated with the {@linkplain SegmentScope#global() global scope}. Under normal conditions, the size of the returned
|
||||
* segment is {@code 0}. However, if the provided layout is an {@linkplain ValueLayout.OfAddress#asUnbounded() unbounded}
|
||||
* address layout, then the size of the returned segment is {@code Long.MAX_VALUE}.
|
||||
*
|
||||
* @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}.
|
||||
* @throws WrongThreadException if this method is called from a thread other than the thread owning
|
||||
* the {@linkplain #session() session} associated with this variable argument list.
|
||||
* @return a native segment whose {@linkplain MemorySegment#address() address} is the value read from
|
||||
* this variable argument list.
|
||||
* @throws IllegalStateException if the scope associated with this variable argument list is not
|
||||
* {@linkplain SegmentScope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code segment().scope().isAccessibleBy(T) == false}.
|
||||
* @throws NoSuchElementException if an <a href=VaList.html#safety>out-of-bounds</a> read is detected.
|
||||
*/
|
||||
MemoryAddress nextVarg(ValueLayout.OfAddress layout);
|
||||
MemorySegment 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.
|
||||
* Reads the next composite value into a new {@code MemorySegment}, allocated with the provided allocator,
|
||||
* 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
|
||||
|
@ -152,10 +182,10 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
|
|||
* @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}.
|
||||
* @throws WrongThreadException if this method is called from a thread other than the thread owning
|
||||
* the {@linkplain #session() session} associated with this variable argument list.
|
||||
* @throws IllegalStateException if the scope associated with this variable argument list is not
|
||||
* {@linkplain SegmentScope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code segment().scope().isAccessibleBy(T) == false}.
|
||||
* @throws NoSuchElementException if an <a href=VaList.html#safety>out-of-bounds</a> read is detected.
|
||||
*/
|
||||
MemorySegment nextVarg(GroupLayout layout, SegmentAllocator allocator);
|
||||
|
@ -164,17 +194,17 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
|
|||
* 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}.
|
||||
* @throws WrongThreadException if this method is called from a thread other than the thread owning
|
||||
* the {@linkplain #session() session} associated with this variable argument list.
|
||||
* @throws IllegalStateException if the scope associated with this variable argument list is not
|
||||
* {@linkplain SegmentScope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code segment().scope().isAccessibleBy(T) == false}.
|
||||
* @throws NoSuchElementException if an <a href=VaList.html#safety>out-of-bounds</a> read is detected.
|
||||
*/
|
||||
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
|
||||
* with the same scope 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,
|
||||
|
@ -182,59 +212,57 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
|
|||
* 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}.
|
||||
* @throws WrongThreadException if this method is called from a thread other than the thread owning
|
||||
* the {@linkplain #session() session} associated with this variable argument list.
|
||||
* @throws IllegalStateException if the scope associated with this variable argument list is not
|
||||
* {@linkplain SegmentScope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code segment().scope().isAccessibleBy(T) == false}.
|
||||
*/
|
||||
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}.
|
||||
* @throws WrongThreadException if this method is called from a thread other than the thread owning
|
||||
* the {@linkplain #session() session} associated with this variable argument list.
|
||||
* Returns a zero-length {@linkplain MemorySegment memory segment} associated with this variable argument list.
|
||||
* The contents of the returned memory segment are platform-dependent. Whether and how the contents of
|
||||
* the returned segment are updated when iterating the contents of a variable argument list is also
|
||||
* platform-dependent.
|
||||
* @return a zero-length {@linkplain MemorySegment memory segment} associated with this variable argument list.
|
||||
*/
|
||||
@Override
|
||||
MemoryAddress address();
|
||||
MemorySegment segment();
|
||||
|
||||
/**
|
||||
* Creates a variable argument list from a memory address pointing to an existing variable argument list,
|
||||
* with the given memory session.
|
||||
* Creates a variable argument list from the give address value and scope. The address is typically obtained
|
||||
* by calling {@link MemorySegment#address()} on a foreign memory segment instance. The provided scope determines
|
||||
* the lifecycle of the returned variable argument list: the returned variable argument list will no longer be accessible,
|
||||
* and its associated off-heap memory region will be deallocated when the scope becomes not
|
||||
* {@linkplain SegmentScope#isAlive() alive}.
|
||||
* <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 variable argument lists created using this method can not detect <a href=VaList.html#safety>out-of-bounds</a> reads.
|
||||
*
|
||||
* @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}.
|
||||
* @throws WrongThreadException if this method is called from a thread other than the thread
|
||||
* {@linkplain MemorySession#ownerThread() owning} {@code session}.
|
||||
* @param address the address of the variable argument list.
|
||||
* @param scope the scope associated with the returned variable argument list.
|
||||
* @return a new variable argument list backed by an off-heap region of memory starting at the given address value.
|
||||
* @throws IllegalStateException if {@code scope} is not {@linkplain SegmentScope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code scope.isAccessibleBy(T) == false}.
|
||||
* @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) {
|
||||
static VaList ofAddress(long address, SegmentScope scope) {
|
||||
Reflection.ensureNativeAccess(Reflection.getCallerClass(), VaList.class, "ofAddress");
|
||||
Objects.requireNonNull(address);
|
||||
Objects.requireNonNull(session);
|
||||
return SharedUtils.newVaListOfAddress(address, session);
|
||||
Objects.requireNonNull(scope);
|
||||
return SharedUtils.newVaListOfAddress(address, scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
* scope. The provided scope determines the lifecycle of the returned variable argument list: the
|
||||
* returned variable argument list will no longer be accessible, and its associated off-heap memory region will be
|
||||
* deallocated when the scope becomes not {@linkplain SegmentScope#isAlive() alive}.
|
||||
* <p>
|
||||
* Note that when there are no elements added to the created va list,
|
||||
* this method will return the same as {@link #empty()}.
|
||||
|
@ -243,23 +271,23 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
|
|||
*
|
||||
* @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.
|
||||
* @param scope the scope 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}.
|
||||
* @throws WrongThreadException if this method is called from a thread other than the thread
|
||||
* {@linkplain MemorySession#ownerThread() owning} {@code session}.
|
||||
* @throws IllegalStateException if {@code scope} is not {@linkplain SegmentScope#isAlive() alive}.
|
||||
* @throws WrongThreadException if this method is called from a thread {@code T},
|
||||
* such that {@code scope.isAccessibleBy(T) == false}.
|
||||
*/
|
||||
static VaList make(Consumer<Builder> actions, MemorySession session) {
|
||||
static VaList make(Consumer<Builder> actions, SegmentScope scope) {
|
||||
Objects.requireNonNull(actions);
|
||||
Objects.requireNonNull(session);
|
||||
return SharedUtils.newVaList(actions, session);
|
||||
Objects.requireNonNull(scope);
|
||||
return SharedUtils.newVaList(actions, scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()}.
|
||||
* Returns an empty variable argument list, associated with the {@linkplain SegmentScope#global() global scope}.
|
||||
* The resulting variable argument list does not contain any argument, and throws {@link UnsupportedOperationException}
|
||||
* on all operations, except for {@link VaList#segment()}, {@link VaList#copy()}.
|
||||
* @return an empty variable argument list.
|
||||
* @throws UnsupportedOperationException if the underlying native platform is not supported.
|
||||
*/
|
||||
|
@ -303,16 +331,17 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
|
|||
Builder addVarg(ValueLayout.OfDouble layout, double value);
|
||||
|
||||
/**
|
||||
* Writes an {@code Addressable} value to the variable argument list being constructed.
|
||||
* Writes the {@linkplain MemorySegment#address() address} of the provided native segment
|
||||
* 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.
|
||||
* @param segment the segment whose {@linkplain MemorySegment#address() address} is to be written.
|
||||
* @return this builder.
|
||||
*/
|
||||
Builder addVarg(ValueLayout.OfAddress layout, Addressable value);
|
||||
Builder addVarg(ValueLayout.OfAddress layout, MemorySegment segment);
|
||||
|
||||
/**
|
||||
* Writes a {@code MemorySegment} value, with the given layout, to the variable argument list being constructed.
|
||||
* Writes a {@code MemorySegment}, 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.
|
||||
|
|
|
@ -28,102 +28,49 @@ 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.foreign.layout.ValueLayouts;
|
||||
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;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
|
||||
/**
|
||||
* 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 layout that models values of basic data types. Examples of values modelled by a value layout are
|
||||
* <em>integral</em> values (either signed or unsigned), <em>floating-point</em> values and
|
||||
* <em>address</em> values.
|
||||
* <p>
|
||||
* 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.
|
||||
* {@linkplain MemorySegment#get(OfInt, long) accessing} a region of memory 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>.
|
||||
* @implSpec implementing classes and 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);
|
||||
}
|
||||
public sealed interface ValueLayout extends MemoryLayout {
|
||||
|
||||
/**
|
||||
* {@return the value's byte order}
|
||||
*/
|
||||
public ByteOrder order() {
|
||||
return order;
|
||||
}
|
||||
ByteOrder order();
|
||||
|
||||
/**
|
||||
* Returns a value layout with the same carrier, alignment constraints and name as this value layout,
|
||||
* Returns a value layout with the same carrier, alignment constraint 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());
|
||||
}
|
||||
ValueLayout withOrder(ByteOrder order);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@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()));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (!super.equals(other)) {
|
||||
return false;
|
||||
}
|
||||
return other instanceof ValueLayout otherValue &&
|
||||
carrier.equals(otherValue.carrier) &&
|
||||
order.equals(otherValue.order);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Creates a <em>strided</em> var handle that can be used to access a memory segment as 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>
|
||||
|
@ -138,15 +85,15 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
|
|||
*
|
||||
* Can be used to access a multi-dimensional array whose layout is as follows:
|
||||
*
|
||||
* {@snippet lang=java :
|
||||
* SequenceLayout arrayLayout = MemoryLayout.sequenceLayout(-1,
|
||||
* {@snippet lang = java:
|
||||
* SequenceLayout arrayLayout = MemoryLayout.sequenceLayout(
|
||||
* 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
|
||||
* to right, as {@code x}, {@code y} and {@code z} respectively, the final offset accessed by the var handle can be
|
||||
* computed with the following formula:
|
||||
*
|
||||
* <blockquote><pre>{@code
|
||||
|
@ -170,7 +117,8 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
|
|||
* as the value for {@code z} is outside its specified bounds.
|
||||
*
|
||||
* @param shape the size of each nested array dimension.
|
||||
* @return a var handle which can be used to dereference a multi-dimensional array, featuring {@code shape.length + 1}
|
||||
* @return a var handle which can be used to access a memory segment as a multi-dimensional array,
|
||||
* featuring {@code shape.length + 1}
|
||||
* {@code long} coordinates.
|
||||
* @throws IllegalArgumentException if {@code shape[i] < 0}, for at least one index {@code i}.
|
||||
* @throws UnsupportedOperationException if {@code bitAlignment() > bitSize()}.
|
||||
|
@ -178,504 +126,385 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
|
|||
* @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]));
|
||||
}
|
||||
VarHandle arrayElementVarHandle(int... shape);
|
||||
|
||||
/**
|
||||
* {@return the carrier associated with this value layout}
|
||||
*/
|
||||
public Class<?> carrier() {
|
||||
return carrier;
|
||||
}
|
||||
Class<?> carrier();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(super.hashCode(), order, carrier);
|
||||
}
|
||||
|
||||
@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
|
||||
ValueLayout withName(String name);
|
||||
|
||||
/**
|
||||
* {@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;
|
||||
}
|
||||
ValueLayout withBitAlignment(long bitAlignment);
|
||||
|
||||
/**
|
||||
* A value layout whose carrier is {@code boolean.class}.
|
||||
*
|
||||
* @see #JAVA_BOOLEAN
|
||||
* @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);
|
||||
}
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfBoolean extends ValueLayout permits ValueLayouts.OfBooleanImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
OfBoolean dup(long alignment, Optional<String> name) {
|
||||
return new OfBoolean(order(), alignment, name);
|
||||
}
|
||||
OfBoolean withName(String name);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfBoolean withName(String name) {
|
||||
return (OfBoolean)super.withName(name);
|
||||
}
|
||||
OfBoolean withBitAlignment(long bitAlignment);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfBoolean withBitAlignment(long alignmentBits) {
|
||||
return (OfBoolean)super.withBitAlignment(alignmentBits);
|
||||
}
|
||||
OfBoolean withOrder(ByteOrder order);
|
||||
|
||||
@Override
|
||||
public OfBoolean withOrder(ByteOrder order) {
|
||||
Objects.requireNonNull(order);
|
||||
return new OfBoolean(order, alignment, name());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A value layout whose carrier is {@code byte.class}.
|
||||
*
|
||||
* @see #JAVA_BYTE
|
||||
* @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);
|
||||
}
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfByte extends ValueLayout permits ValueLayouts.OfByteImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
OfByte dup(long alignment, Optional<String> name) {
|
||||
return new OfByte(order(), alignment, name);
|
||||
}
|
||||
OfByte withName(String name);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfByte withName(String name) {
|
||||
return (OfByte)super.withName(name);
|
||||
}
|
||||
OfByte withBitAlignment(long bitAlignment);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfByte withBitAlignment(long alignmentBits) {
|
||||
return (OfByte)super.withBitAlignment(alignmentBits);
|
||||
}
|
||||
OfByte withOrder(ByteOrder order);
|
||||
|
||||
@Override
|
||||
public OfByte withOrder(ByteOrder order) {
|
||||
Objects.requireNonNull(order);
|
||||
return new OfByte(order, alignment, name());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A value layout whose carrier is {@code char.class}.
|
||||
*
|
||||
* @see #JAVA_CHAR
|
||||
* @see #JAVA_CHAR_UNALIGNED
|
||||
* @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);
|
||||
}
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfChar extends ValueLayout permits ValueLayouts.OfCharImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
OfChar dup(long alignment, Optional<String> name) {
|
||||
return new OfChar(order(), alignment, name);
|
||||
}
|
||||
OfChar withName(String name);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfChar withName(String name) {
|
||||
return (OfChar)super.withName(name);
|
||||
}
|
||||
OfChar withBitAlignment(long bitAlignment);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfChar withBitAlignment(long alignmentBits) {
|
||||
return (OfChar)super.withBitAlignment(alignmentBits);
|
||||
}
|
||||
OfChar withOrder(ByteOrder order);
|
||||
|
||||
@Override
|
||||
public OfChar withOrder(ByteOrder order) {
|
||||
Objects.requireNonNull(order);
|
||||
return new OfChar(order, alignment, name());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A value layout whose carrier is {@code short.class}.
|
||||
*
|
||||
* @see #JAVA_SHORT
|
||||
* @see #JAVA_SHORT_UNALIGNED
|
||||
* @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);
|
||||
}
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfShort extends ValueLayout permits ValueLayouts.OfShortImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
OfShort dup(long alignment, Optional<String> name) {
|
||||
return new OfShort(order(), alignment, name);
|
||||
}
|
||||
OfShort withName(String name);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfShort withName(String name) {
|
||||
return (OfShort)super.withName(name);
|
||||
}
|
||||
OfShort withBitAlignment(long bitAlignment);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfShort withBitAlignment(long alignmentBits) {
|
||||
return (OfShort)super.withBitAlignment(alignmentBits);
|
||||
}
|
||||
OfShort withOrder(ByteOrder order);
|
||||
|
||||
@Override
|
||||
public OfShort withOrder(ByteOrder order) {
|
||||
Objects.requireNonNull(order);
|
||||
return new OfShort(order, alignment, name());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A value layout whose carrier is {@code int.class}.
|
||||
*
|
||||
* @see #JAVA_INT
|
||||
* @see #JAVA_INT_UNALIGNED
|
||||
* @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);
|
||||
}
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfInt extends ValueLayout permits ValueLayouts.OfIntImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
OfInt dup(long alignment, Optional<String> name) {
|
||||
return new OfInt(order(), alignment, name);
|
||||
}
|
||||
OfInt withName(String name);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfInt withName(String name) {
|
||||
return (OfInt)super.withName(name);
|
||||
}
|
||||
OfInt withBitAlignment(long bitAlignment);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfInt withBitAlignment(long alignmentBits) {
|
||||
return (OfInt)super.withBitAlignment(alignmentBits);
|
||||
}
|
||||
OfInt withOrder(ByteOrder order);
|
||||
|
||||
@Override
|
||||
public OfInt withOrder(ByteOrder order) {
|
||||
Objects.requireNonNull(order);
|
||||
return new OfInt(order, alignment, name());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A value layout whose carrier is {@code float.class}.
|
||||
*
|
||||
* @see #JAVA_FLOAT
|
||||
* @see #JAVA_FLOAT_UNALIGNED
|
||||
* @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);
|
||||
}
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfFloat extends ValueLayout permits ValueLayouts.OfFloatImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
OfFloat dup(long alignment, Optional<String> name) {
|
||||
return new OfFloat(order(), alignment, name);
|
||||
}
|
||||
OfFloat withName(String name);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfFloat withName(String name) {
|
||||
return (OfFloat)super.withName(name);
|
||||
}
|
||||
OfFloat withBitAlignment(long bitAlignment);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfFloat withBitAlignment(long alignmentBits) {
|
||||
return (OfFloat)super.withBitAlignment(alignmentBits);
|
||||
}
|
||||
OfFloat withOrder(ByteOrder order);
|
||||
|
||||
@Override
|
||||
public OfFloat withOrder(ByteOrder order) {
|
||||
Objects.requireNonNull(order);
|
||||
return new OfFloat(order, alignment, name());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A value layout whose carrier is {@code long.class}.
|
||||
*
|
||||
* @see #JAVA_LONG
|
||||
* @see #JAVA_LONG_UNALIGNED
|
||||
* @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);
|
||||
}
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfLong extends ValueLayout permits ValueLayouts.OfLongImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
OfLong dup(long alignment, Optional<String> name) {
|
||||
return new OfLong(order(), alignment, name);
|
||||
}
|
||||
OfLong withName(String name);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfLong withName(String name) {
|
||||
return (OfLong)super.withName(name);
|
||||
}
|
||||
OfLong withBitAlignment(long bitAlignment);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfLong withBitAlignment(long alignmentBits) {
|
||||
return (OfLong)super.withBitAlignment(alignmentBits);
|
||||
}
|
||||
OfLong withOrder(ByteOrder order);
|
||||
|
||||
@Override
|
||||
public OfLong withOrder(ByteOrder order) {
|
||||
Objects.requireNonNull(order);
|
||||
return new OfLong(order, alignment, name());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A value layout whose carrier is {@code double.class}.
|
||||
*
|
||||
* @see #JAVA_DOUBLE
|
||||
* @see #JAVA_DOUBLE_UNALIGNED
|
||||
* @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);
|
||||
}
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfDouble extends ValueLayout permits ValueLayouts.OfDoubleImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
OfDouble dup(long alignment, Optional<String> name) {
|
||||
return new OfDouble(order(), alignment, name);
|
||||
}
|
||||
OfDouble withName(String name);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfDouble withName(String name) {
|
||||
return (OfDouble)super.withName(name);
|
||||
}
|
||||
OfDouble withBitAlignment(long bitAlignment);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfDouble withBitAlignment(long alignmentBits) {
|
||||
return (OfDouble)super.withBitAlignment(alignmentBits);
|
||||
}
|
||||
OfDouble withOrder(ByteOrder order);
|
||||
|
||||
@Override
|
||||
public OfDouble withOrder(ByteOrder order) {
|
||||
Objects.requireNonNull(order);
|
||||
return new OfDouble(order, alignment, name());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A value layout whose carrier is {@code MemoryAddress.class}.
|
||||
* A value layout whose carrier is {@code MemorySegment.class}.
|
||||
*
|
||||
* @see #ADDRESS
|
||||
* @see #ADDRESS_UNALIGNED
|
||||
* @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);
|
||||
}
|
||||
@PreviewFeature(feature = PreviewFeature.Feature.FOREIGN)
|
||||
sealed interface OfAddress extends ValueLayout permits ValueLayouts.OfAddressImpl {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
OfAddress dup(long alignment, Optional<String> name) {
|
||||
return new OfAddress(order(), bitSize(), alignment, name);
|
||||
}
|
||||
OfAddress withName(String name);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfAddress withName(String name) {
|
||||
return (OfAddress)super.withName(name);
|
||||
}
|
||||
OfAddress withBitAlignment(long bitAlignment);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public OfAddress withBitAlignment(long alignmentBits) {
|
||||
return (OfAddress)super.withBitAlignment(alignmentBits);
|
||||
}
|
||||
OfAddress withOrder(ByteOrder order);
|
||||
|
||||
/**
|
||||
* Returns an <em>unbounded</em> address layout with the same carrier, alignment constraint, name and order as this address layout,
|
||||
* but with the specified pointee layout. An unbounded address layout allow raw addresses to be accessed
|
||||
* as {@linkplain MemorySegment memory segments} whose size is set to {@link Long#MAX_VALUE}. As such,
|
||||
* these segments can be used in subsequent access operations.
|
||||
* <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.
|
||||
*
|
||||
* @return an unbounded address layout with same characteristics as this layout.
|
||||
* @see #isUnbounded()
|
||||
*/
|
||||
@CallerSensitive
|
||||
OfAddress asUnbounded();
|
||||
|
||||
/**
|
||||
* {@return {@code true}, if this address layout is an {@linkplain #asUnbounded() unbounded address layout}}.
|
||||
*/
|
||||
boolean isUnbounded();
|
||||
|
||||
@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()}.
|
||||
* bit alignment set to {@code sizeof(size_t) * 8}, byte order set to {@link ByteOrder#nativeOrder()}.
|
||||
* Equivalent to the following code:
|
||||
* {@snippet lang=java :
|
||||
* MemoryLayout.valueLayout(MemoryAddress.class, ByteOrder.nativeOrder())
|
||||
* .withBitAlignment(<address size>);
|
||||
* MemoryLayout.valueLayout(MemorySegment.class, ByteOrder.nativeOrder());
|
||||
* }
|
||||
*/
|
||||
public static final OfAddress ADDRESS = new OfAddress(ByteOrder.nativeOrder())
|
||||
.withBitAlignment(ValueLayout.ADDRESS_SIZE_BITS);
|
||||
OfAddress ADDRESS = ValueLayouts.OfAddressImpl.of(ByteOrder.nativeOrder());
|
||||
|
||||
/**
|
||||
* 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);
|
||||
* MemoryLayout.valueLayout(byte.class, ByteOrder.nativeOrder());
|
||||
* }
|
||||
*/
|
||||
public static final OfByte JAVA_BYTE = new OfByte(ByteOrder.nativeOrder()).withBitAlignment(8);
|
||||
OfByte JAVA_BYTE = ValueLayouts.OfByteImpl.of(ByteOrder.nativeOrder());
|
||||
|
||||
/**
|
||||
* 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);
|
||||
* MemoryLayout.valueLayout(boolean.class, ByteOrder.nativeOrder());
|
||||
* }
|
||||
*/
|
||||
public static final OfBoolean JAVA_BOOLEAN = new OfBoolean(ByteOrder.nativeOrder()).withBitAlignment(8);
|
||||
OfBoolean JAVA_BOOLEAN = ValueLayouts.OfBooleanImpl.of(ByteOrder.nativeOrder());
|
||||
|
||||
/**
|
||||
* 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);
|
||||
* MemoryLayout.valueLayout(char.class, ByteOrder.nativeOrder());
|
||||
* }
|
||||
*/
|
||||
public static final OfChar JAVA_CHAR = new OfChar(ByteOrder.nativeOrder()).withBitAlignment(16);
|
||||
OfChar JAVA_CHAR = ValueLayouts.OfCharImpl.of(ByteOrder.nativeOrder());
|
||||
|
||||
/**
|
||||
* 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);
|
||||
* MemoryLayout.valueLayout(short.class, ByteOrder.nativeOrder());
|
||||
* }
|
||||
*/
|
||||
public static final OfShort JAVA_SHORT = new OfShort(ByteOrder.nativeOrder()).withBitAlignment(16);
|
||||
OfShort JAVA_SHORT = ValueLayouts.OfShortImpl.of(ByteOrder.nativeOrder());
|
||||
|
||||
/**
|
||||
* 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);
|
||||
* MemoryLayout.valueLayout(int.class, ByteOrder.nativeOrder());
|
||||
* }
|
||||
*/
|
||||
public static final OfInt JAVA_INT = new OfInt(ByteOrder.nativeOrder()).withBitAlignment(32);
|
||||
OfInt JAVA_INT = ValueLayouts.OfIntImpl.of(ByteOrder.nativeOrder());
|
||||
|
||||
/**
|
||||
* 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);
|
||||
* MemoryLayout.valueLayout(long.class, ByteOrder.nativeOrder());
|
||||
* }
|
||||
*/
|
||||
public static final OfLong JAVA_LONG = new OfLong(ByteOrder.nativeOrder())
|
||||
.withBitAlignment(64);
|
||||
OfLong JAVA_LONG = ValueLayouts.OfLongImpl.of(ByteOrder.nativeOrder());
|
||||
|
||||
/**
|
||||
* A value layout constant whose size is the same as that of a Java {@code float},
|
||||
|
@ -685,15 +514,100 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
|
|||
* MemoryLayout.valueLayout(float.class, ByteOrder.nativeOrder()).withBitAlignment(32);
|
||||
* }
|
||||
*/
|
||||
public static final OfFloat JAVA_FLOAT = new OfFloat(ByteOrder.nativeOrder()).withBitAlignment(32);
|
||||
OfFloat JAVA_FLOAT = ValueLayouts.OfFloatImpl.of(ByteOrder.nativeOrder());
|
||||
|
||||
/**
|
||||
* 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);
|
||||
* MemoryLayout.valueLayout(double.class, ByteOrder.nativeOrder());
|
||||
* }
|
||||
*/
|
||||
public static final OfDouble JAVA_DOUBLE = new OfDouble(ByteOrder.nativeOrder()).withBitAlignment(64);
|
||||
OfDouble JAVA_DOUBLE = ValueLayouts.OfDoubleImpl.of(ByteOrder.nativeOrder());
|
||||
|
||||
/**
|
||||
* An unaligned value layout constant whose size is the same as that of a machine address ({@code size_t}),
|
||||
* and byte order set to {@link ByteOrder#nativeOrder()}.
|
||||
* Equivalent to the following code:
|
||||
* {@snippet lang=java :
|
||||
* ADDRESS.withBitAlignment(8);
|
||||
* }
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may induce
|
||||
* performance and portability issues.
|
||||
*/
|
||||
OfAddress ADDRESS_UNALIGNED = ADDRESS.withBitAlignment(8);
|
||||
|
||||
/**
|
||||
* An unaligned value layout constant whose size is the same as that of a Java {@code char}
|
||||
* and byte order set to {@link ByteOrder#nativeOrder()}.
|
||||
* Equivalent to the following code:
|
||||
* {@snippet lang=java :
|
||||
* JAVA_CHAR.withBitAlignment(8);
|
||||
* }
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may induce
|
||||
* performance and portability issues.
|
||||
*/
|
||||
OfChar JAVA_CHAR_UNALIGNED = JAVA_CHAR.withBitAlignment(8);
|
||||
|
||||
/**
|
||||
* An unaligned value layout constant whose size is the same as that of a Java {@code short}
|
||||
* and byte order set to {@link ByteOrder#nativeOrder()}.
|
||||
* Equivalent to the following code:
|
||||
* {@snippet lang=java :
|
||||
* JAVA_SHORT.withBitAlignment(8);
|
||||
* }
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may induce
|
||||
* performance and portability issues.
|
||||
*/
|
||||
OfShort JAVA_SHORT_UNALIGNED = JAVA_SHORT.withBitAlignment(8);
|
||||
|
||||
/**
|
||||
* An unaligned value layout constant whose size is the same as that of a Java {@code int}
|
||||
* and byte order set to {@link ByteOrder#nativeOrder()}.
|
||||
* Equivalent to the following code:
|
||||
* {@snippet lang=java :
|
||||
* JAVA_INT.withBitAlignment(8);
|
||||
* }
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may induce
|
||||
* performance and portability issues.
|
||||
*/
|
||||
OfInt JAVA_INT_UNALIGNED = JAVA_INT.withBitAlignment(8);
|
||||
|
||||
/**
|
||||
* An unaligned value layout constant whose size is the same as that of a Java {@code long}
|
||||
* and byte order set to {@link ByteOrder#nativeOrder()}.
|
||||
* Equivalent to the following code:
|
||||
* {@snippet lang=java :
|
||||
* JAVA_LONG.withBitAlignment(8);
|
||||
* }
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may induce
|
||||
* performance and portability issues.
|
||||
*/
|
||||
OfLong JAVA_LONG_UNALIGNED = JAVA_LONG.withBitAlignment(8);
|
||||
|
||||
/**
|
||||
* An unaligned value layout constant whose size is the same as that of a Java {@code float}
|
||||
* and byte order set to {@link ByteOrder#nativeOrder()}.
|
||||
* Equivalent to the following code:
|
||||
* {@snippet lang=java :
|
||||
* JAVA_FLOAT.withBitAlignment(8);
|
||||
* }
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may induce
|
||||
* performance and portability issues.
|
||||
*/
|
||||
OfFloat JAVA_FLOAT_UNALIGNED = JAVA_FLOAT.withBitAlignment(8);
|
||||
|
||||
/**
|
||||
* An unaligned value layout constant whose size is the same as that of a Java {@code double}
|
||||
* and byte order set to {@link ByteOrder#nativeOrder()}.
|
||||
* Equivalent to the following code:
|
||||
* {@snippet lang=java :
|
||||
* JAVA_DOUBLE.withBitAlignment(8);
|
||||
* }
|
||||
* @apiNote Care should be taken when using unaligned value layouts as they may induce
|
||||
* performance and portability issues.
|
||||
*/
|
||||
OfDouble JAVA_DOUBLE_UNALIGNED = JAVA_DOUBLE.withBitAlignment(8);
|
||||
|
||||
}
|
||||
|
|
|
@ -31,29 +31,36 @@
|
|||
*
|
||||
* <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
|
||||
* models a contiguous region of memory, 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},
|
||||
* an alternate, more abstract way, to <a href=MemorySegment.html#segment-deref>access memory segments</a>
|
||||
* using {@linkplain java.lang.foreign.MemoryLayout#varHandle(java.lang.foreign.MemoryLayout.PathElement...) 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:
|
||||
* For example, to allocate an off-heap region of memory 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());
|
||||
* {@snippet lang = java:
|
||||
* MemorySegment segment = MemorySegment.allocateNative(10 * 4, SegmentScope.auto());
|
||||
* 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}.
|
||||
* The segment is associated with an {@linkplain java.lang.foreign.SegmentScope#auto() automatic scope}. This
|
||||
* means that the off-heap region of memory backing the segment is managed, automatically, by the garbage collector.
|
||||
* As such, the off-heap memory backing the native segment will be released at some unspecified
|
||||
* point <em>after</em> the segment becomes <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>.
|
||||
* This is similar to what happens with direct buffers created via {@link java.nio.ByteBuffer#allocateDirect(int)}.
|
||||
* It is also possible to manage the lifecycle of allocated native segments more directly, as shown in a later section.
|
||||
* <p>
|
||||
* 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,
|
||||
* {@linkplain java.lang.foreign.MemorySegment#setAtIndex(ValueLayout.OfInt, long, int) access method}
|
||||
* accepts a {@linkplain java.lang.foreign.ValueLayout value layout}, which specifies the size, alignment constraint,
|
||||
* byte order as well as the Java type ({@code int}, in this case) associated with the access 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}.
|
||||
|
@ -64,35 +71,37 @@
|
|||
* 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:
|
||||
* Clients that operate under these assumptions might want to programmatically release the memory backing a memory segment.
|
||||
* This can be done, using the {@link java.lang.foreign.Arena} abstraction, as shown below:
|
||||
*
|
||||
* {@snippet lang=java :
|
||||
* try (MemorySession session = MemorySession.openConfined()) {
|
||||
* MemorySegment segment = MemorySegment.allocateNative(10 * 4, session);
|
||||
* {@snippet lang = java:
|
||||
* try (Arena arena = Arena.openConfined()) {
|
||||
* MemorySegment segment = arena.allocate(10 * 4);
|
||||
* 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>.
|
||||
* This example is almost identical to the prior one; this time we first create an arena
|
||||
* which is used to allocate multiple native segments which share the same life-cycle. That is, all the segments
|
||||
* allocated by the arena will be associated with the same {@linkplain java.lang.foreign.SegmentScope scope}.
|
||||
* Note the use of the <em>try-with-resources</em> construct: this idiom ensures that the off-heap region of memory backing the
|
||||
* native 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 id="safety">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>;
|
||||
* <em>outside</em> the boundaries of the memory segment used by the access 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.
|
||||
* Since memory segments created with an arena can become invalid (see above), segments are also validated (upon access) to make sure that
|
||||
* the scope associated with the segment being accessed is still alive.
|
||||
* 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.
|
||||
* operation either succeeds - and accesses a valid location within the region of memory backing the memory segment - or fails.
|
||||
*
|
||||
* <h2 id="ffa">Foreign function access</h2>
|
||||
* The key abstractions introduced to support foreign function access are {@link java.lang.foreign.SymbolLookup},
|
||||
|
@ -105,134 +114,118 @@
|
|||
* 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 :
|
||||
* {@snippet lang = java:
|
||||
* Linker linker = Linker.nativeLinker();
|
||||
* SymbolLookup stdlib = linker.defaultLookup();
|
||||
* MethodHandle strlen = linker.downcallHandle(
|
||||
* stdlib.lookup("strlen").get(),
|
||||
* stdlib.find("strlen").get(),
|
||||
* FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)
|
||||
* );
|
||||
*
|
||||
* try (MemorySession session = MemorySession.openConfined()) {
|
||||
* MemorySegment cString = MemorySegment.allocateNative(5 + 1, session);
|
||||
* cString.setUtf8String(0, "Hello");
|
||||
* try (Arena arena = Arena.openConfined()) {
|
||||
* MemorySegment cString = arena.allocateUtf8String("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
|
||||
* to {@linkplain java.lang.foreign.SymbolLookup#find(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}.
|
||||
* {@linkplain java.lang.foreign.Linker#downcallHandle(FunctionDescriptor, Linker.Option...) 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 id="addresses">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);
|
||||
* }
|
||||
* The {@link java.lang.foreign.Arena} class also provides many useful methods for
|
||||
* interacting with foreign code, such as
|
||||
* {@linkplain java.lang.foreign.SegmentAllocator#allocateUtf8String(java.lang.String) converting} Java strings into
|
||||
* zero-terminated, UTF-8 strings, as demonstrated in the above example.
|
||||
*
|
||||
* <h3 id="upcalls">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.
|
||||
* to a Java method) into a memory segment, 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);
|
||||
* static int intCompare(MemorySegment addr1, MemorySegment 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
|
||||
* The above method accesses two foreign memory segments 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);
|
||||
* {@snippet lang = java:
|
||||
* FunctionDescriptor intCompareDescriptor = FunctionDescriptor.of(ValueLayout.JAVA_INT,
|
||||
* ValueLayout.ADDRESS.asUnbounded(),
|
||||
* ValueLayout.ADDRESS.asUnbounded());
|
||||
* MethodHandle intCompareHandle = MethodHandles.lookup().findStatic(IntComparator.class,
|
||||
* "intCompare",
|
||||
* Linker.upcallType(comparFunction));
|
||||
* }
|
||||
* intCompareDescriptor.toMethodType());
|
||||
*}
|
||||
*
|
||||
* 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
|
||||
* {@linkplain java.lang.foreign.FunctionDescriptor#toMethodType() 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 = Linker.nativeLinker().upcallStub(
|
||||
* intCompareHandle, intCompareDescriptor, session);
|
||||
* {@snippet lang = java:
|
||||
* SegmentScope scope = ...
|
||||
* MemorySegment comparFunc = Linker.nativeLinker().upcallStub(
|
||||
* intCompareHandle, intCompareDescriptor, scope);
|
||||
* );
|
||||
* }
|
||||
*}
|
||||
*
|
||||
* 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}
|
||||
* {@linkplain java.lang.foreign.Linker#upcallStub(java.lang.invoke.MethodHandle, FunctionDescriptor, SegmentScope) 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}
|
||||
* The lifecycle of the upcall stub is tied to the {@linkplain java.lang.foreign.SegmentScope scope}
|
||||
* provided when the upcall stub is created. This same scope is made available by the {@link java.lang.foreign.MemorySegment}
|
||||
* instance returned by that method.
|
||||
*
|
||||
* <h2 id="restricted">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)}
|
||||
* the restricted method {@link java.lang.foreign.MemorySegment#ofAddress(long, long, SegmentScope)}
|
||||
* 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
|
||||
* 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(long, long, SegmentScope)}, 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 access 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.
|
||||
* Given the potential danger of restricted methods, the Java runtime issues a warning on the standard error stream
|
||||
* every time a restricted method is invoked. Such warnings can be disabled by granting access to restricted methods
|
||||
* to selected modules. This can be done either via implementation-specific command line options, or programmatically, e.g. by calling
|
||||
* {@link java.lang.ModuleLayer.Controller#enableNativeAccess(java.lang.Module)}.
|
||||
* <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.
|
||||
*
|
||||
* @apiNote Usual memory model guarantees, for example stated in {@jls 6.6} and {@jls 10.4}, do not apply
|
||||
* when accessing native memory segments as these segments are backed by off-heap regions of memory.
|
||||
*
|
||||
* @implNote
|
||||
* In the reference implementation, access to restricted methods can be granted to specific modules 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.
|
||||
*
|
||||
*/
|
||||
package java.lang.foreign;
|
||||
|
||||
|
|
|
@ -45,8 +45,8 @@ 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.MemorySegment;
|
||||
import java.lang.foreign.ValueLayout;
|
||||
import java.lang.invoke.LambdaForm.BasicType;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
@ -7910,21 +7910,21 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
|
|||
* 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}.
|
||||
* {@code float}, {@code double} or {@link MemorySegment}.
|
||||
* (Future major platform releases of the JDK may support additional
|
||||
* types for certain currently unsupported access modes.)
|
||||
* <li>numeric atomic update access modes for {@code int}, {@code long} and {@link MemoryAddress}.
|
||||
* <li>numeric atomic update access modes for {@code int}, {@code long} and {@link MemorySegment}.
|
||||
* (Future major platform releases of the JDK may support additional
|
||||
* numeric types for certain currently unsupported access modes.)
|
||||
* <li>bitwise atomic update access modes for {@code int}, {@code long} and {@link MemoryAddress}.
|
||||
* <li>bitwise atomic update access modes for {@code int}, {@code long} and {@link MemorySegment}.
|
||||
* (Future major platform releases of the JDK may support additional
|
||||
* numeric types for certain currently unsupported access modes.)
|
||||
* </ul>
|
||||
*
|
||||
* If {@code T} is {@code float}, {@code double} or {@link MemoryAddress} then atomic
|
||||
* If {@code T} is {@code float}, {@code double} or {@link MemorySegment} then atomic
|
||||
* update access modes compare values using their bitwise representation
|
||||
* (see {@link Float#floatToRawIntBits},
|
||||
* {@link Double#doubleToRawLongBits} and {@link MemoryAddress#toRawLongValue()}, respectively).
|
||||
* {@link Double#doubleToRawLongBits} and {@link MemorySegment#address()}, respectively).
|
||||
* <p>
|
||||
* Alternatively, a memory access operation is <em>partially aligned</em> if it occurs at a memory address {@code A}
|
||||
* which is only compatible with the alignment constraint {@code B}; in such cases, access for anything other than the
|
||||
|
|
|
@ -52,24 +52,32 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError;
|
|||
*/
|
||||
public static MethodHandle make(NativeEntryPoint nep) {
|
||||
MethodType type = nep.type();
|
||||
if (!allTypesPrimitive(type))
|
||||
throw new IllegalArgumentException("Type must only contain primitives: " + type);
|
||||
if (hasIllegalType(type))
|
||||
throw new IllegalArgumentException("Illegal type(s) found: " + type);
|
||||
|
||||
|
||||
LambdaForm lform = preparedLambdaForm(type);
|
||||
return new NativeMethodHandle(type, lform, nep);
|
||||
}
|
||||
|
||||
private static boolean allTypesPrimitive(MethodType type) {
|
||||
if (!type.returnType().isPrimitive())
|
||||
return false;
|
||||
private static boolean hasIllegalType(MethodType type) {
|
||||
if (isIllegalType(type.returnType()))
|
||||
return true;
|
||||
|
||||
for (Class<?> pType : type.parameterArray()) {
|
||||
if (!pType.isPrimitive())
|
||||
return false;
|
||||
if (isIllegalType(pType))
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isIllegalType(Class<?> pType) {
|
||||
return !(pType == long.class
|
||||
|| pType == int.class
|
||||
|| pType == float.class
|
||||
|| pType == double.class
|
||||
|| pType == void.class);
|
||||
}
|
||||
|
||||
private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
|
||||
|
|
|
@ -34,7 +34,6 @@ 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;
|
||||
|
|
|
@ -29,7 +29,6 @@ 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.foreign.MemorySessionImpl;
|
||||
|
|
|
@ -27,7 +27,7 @@ package java.nio.channels;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.lang.foreign.MemorySegment;
|
||||
import java.lang.foreign.MemorySession;
|
||||
import java.lang.foreign.SegmentScope;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.spi.AbstractInterruptibleChannel;
|
||||
|
@ -1001,6 +1001,9 @@ public abstract class FileChannel
|
|||
/**
|
||||
* Maps a region of this channel's file into a new mapped memory segment,
|
||||
* with the given offset, size and memory session.
|
||||
* The {@linkplain MemorySegment#address() address} of the returned memory
|
||||
* segment is the starting address of the mapped off-heap region backing
|
||||
* the segment.
|
||||
*
|
||||
* <p> If the specified mapping mode is
|
||||
* {@linkplain FileChannel.MapMode#READ_ONLY READ_ONLY}, the resulting
|
||||
|
@ -1053,11 +1056,11 @@ public abstract class FileChannel
|
|||
*
|
||||
* @throws IllegalStateException
|
||||
* If the {@code session} is not
|
||||
* {@linkplain MemorySession#isAlive() alive}.
|
||||
* {@linkplain SegmentScope#isAlive() alive}.
|
||||
*
|
||||
* @throws WrongThreadException
|
||||
* If this method is called from a thread other than the thread
|
||||
* {@linkplain MemorySession#ownerThread() owning} the
|
||||
* {@linkplain SegmentScope#isAccessibleBy(Thread) owning} the
|
||||
* {@code session}.
|
||||
*
|
||||
* @throws NonReadableChannelException
|
||||
|
@ -1080,7 +1083,7 @@ public abstract class FileChannel
|
|||
* @since 19
|
||||
*/
|
||||
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
|
||||
public MemorySegment map(MapMode mode, long offset, long size, MemorySession session)
|
||||
public MemorySegment map(MapMode mode, long offset, long size, SegmentScope session)
|
||||
throws IOException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue