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

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

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2014, 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
@ -55,7 +55,6 @@ DOCS_MODULES= \
jdk.jsobject \
jdk.jshell \
jdk.jstatd \
jdk.incubator.foreign \
jdk.localedata \
jdk.management \
jdk.management.agent \

View file

@ -43,7 +43,6 @@ BOOT_MODULES= \
java.rmi \
java.security.sasl \
java.xml \
jdk.incubator.foreign \
jdk.incubator.vector \
jdk.internal.vm.ci \
jdk.jfr \

View file

@ -1,5 +1,5 @@
#
# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2011, 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
@ -203,3 +203,18 @@ ifeq ($(call isTargetOs, windows), true)
))
TARGETS += $(COPY_TZMAPPINGS)
endif
################################################################################
# Create system lookup
$(eval $(call SetupJdkLibrary, BUILD_SYSLOOKUPLIB, \
NAME := syslookup, \
CFLAGS := $(CFLAGS_JDKLIB), \
CXXFLAGS := $(CXXFLAGS_JDKLIB), \
LDFLAGS := $(LDFLAGS_JDKLIB), \
LDFLAGS_linux := -Wl$(COMMA)--no-as-needed, \
LIBS := $(LIBCXX), \
LIBS_linux := -lc -lm -ldl, \
))
TARGETS += $(BUILD_SYSLOOKUPLIB)

View file

@ -160,14 +160,14 @@ endef
################################################################################
################################################################################
# Setup a rule for generating a memory access var handle helper classes
# Setup a rule for generating a memory segment var handle view class
# Param 1 - Variable declaration prefix
# Param 2 - Type with first letter capitalized
define GenerateVarHandleMemoryAccess
define GenerateVarHandleMemorySegment
$1_Type := $2
$1_FILENAME := $(VARHANDLES_GENSRC_DIR)/MemoryAccessVarHandle$$($1_Type)Helper.java
$1_FILENAME := $(VARHANDLES_GENSRC_DIR)/VarHandleSegmentAs$$($1_Type)s.java
ifeq ($$($1_Type), Byte)
$1_type := byte
@ -248,7 +248,7 @@ define GenerateVarHandleMemoryAccess
$1_ARGS += -KfloatingPoint
endif
$$($1_FILENAME): $(VARHANDLES_SRC_DIR)/X-VarHandleMemoryAccess.java.template $(BUILD_TOOLS_JDK)
$$($1_FILENAME): $(VARHANDLES_SRC_DIR)/X-VarHandleSegmentView.java.template $(BUILD_TOOLS_JDK)
$$(call MakeDir, $$(@D))
$(RM) $$@
$(TOOL_SPP) -nel -K$$($1_type) \
@ -272,8 +272,8 @@ $(foreach t, $(VARHANDLES_BYTE_ARRAY_TYPES), \
$(eval $(call GenerateVarHandleByteArray,VAR_HANDLE_BYTE_ARRAY_$t,$t)))
# List the types to generate source for, with capitalized first letter
VARHANDLES_MEMORY_ADDRESS_TYPES := Byte Short Char Int Long Float Double
$(foreach t, $(VARHANDLES_MEMORY_ADDRESS_TYPES), \
$(eval $(call GenerateVarHandleMemoryAccess,VAR_HANDLE_MEMORY_ADDRESS_$t,$t)))
VARHANDLES_MEMORY_SEGMENT_TYPES := Byte Short Char Int Long Float Double
$(foreach t, $(VARHANDLES_MEMORY_SEGMENT_TYPES), \
$(eval $(call GenerateVarHandleMemorySegment,VAR_HANDLE_MEMORY_SEGMENT_$t,$t)))
TARGETS += $(GENSRC_VARHANDLES)

View file

@ -1,62 +0,0 @@
#
# Copyright (c) 2021, 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.
#
include LibCommon.gmk
ifeq ($(call isTargetOs, linux), true)
$(eval $(call SetupJdkLibrary, BUILD_SYSLOOKUPLIB, \
NAME := syslookup, \
CFLAGS := $(CFLAGS_JDKLIB), \
CXXFLAGS := $(CXXFLAGS_JDKLIB), \
LDFLAGS := $(LDFLAGS_JDKLIB) -Wl$(COMMA)--no-as-needed, \
LIBS := $(LIBCXX) -lc -lm -ldl, \
))
else ifeq ($(call isTargetOs, windows), false)
$(eval $(call SetupJdkLibrary, BUILD_SYSLOOKUPLIB, \
NAME := syslookup, \
CFLAGS := $(CFLAGS_JDKLIB), \
CXXFLAGS := $(CXXFLAGS_JDKLIB), \
LDFLAGS := $(LDFLAGS_JDKLIB), \
LIBS := $(LIBCXX), \
))
else # windows
$(eval $(call SetupJdkLibrary, BUILD_SYSLOOKUPLIB, \
NAME := WinFallbackLookup, \
CFLAGS := $(CFLAGS_JDKLIB), \
CXXFLAGS := $(CXXFLAGS_JDKLIB), \
LDFLAGS := $(LDFLAGS_JDKLIB), \
LIBS := $(LIBCXX), \
))
endif
TARGETS += $(BUILD_SYSLOOKUPLIB)
################################################################################

View file

@ -91,7 +91,7 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \
TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \
SMALL_JAVA := false, \
CLASSPATH := $(MICROBENCHMARK_CLASSPATH), \
DISABLED_WARNINGS := processing rawtypes cast serial, \
DISABLED_WARNINGS := processing rawtypes cast serial preview, \
SRC := $(MICROBENCHMARK_SRC), \
BIN := $(MICROBENCHMARK_CLASSES), \
JAVAC_FLAGS := --add-exports java.base/sun.security.util=ALL-UNNAMED \

View file

@ -69,14 +69,23 @@ ifeq ($(call isTargetOs, windows), true)
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exerevokeall := advapi32.lib
BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libAsyncStackWalk := /EHsc
BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libAsyncInvokers := /EHsc
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libLinkerInvokerUnnamed := /EHsc
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libLinkerInvokerModule := /EHsc
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libLoaderLookupInvoker := /EHsc
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncStackWalk := $(LIBCXX)
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncInvokers := $(LIBCXX)
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libLinkerInvokerUnnamed := $(LIBCXX)
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libLinkerInvokerModule := $(LIBCXX)
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libLoaderLookupInvoker := $(LIBCXX)
else
BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava
BUILD_JDK_JTREG_LIBRARIES_LIBS_libDirectIO := -ljava
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libNativeThread := -pthread
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncStackWalk := $(LIBCXX) -pthread
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncInvokers := $(LIBCXX) -pthread
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libLinkerInvokerUnnamed := $(LIBCXX) -pthread
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libLinkerInvokerModule := $(LIBCXX) -pthread
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libLoaderLookupInvoker := $(LIBCXX) -pthread
BUILD_JDK_JTREG_EXCLUDE += exerevokeall.c
ifeq ($(call isTargetOs, linux), true)
BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava

View file

@ -225,7 +225,7 @@ static bool trust_final_non_static_fields(ciInstanceKlass* holder) {
// Even if general trusting is disabled, trust system-built closures in these packages.
if (holder->is_in_package("java/lang/invoke") || holder->is_in_package("sun/invoke") ||
holder->is_in_package("java/lang/reflect") || holder->is_in_package("jdk/internal/reflect") ||
holder->is_in_package("jdk/internal/foreign") || holder->is_in_package("jdk/incubator/foreign") ||
holder->is_in_package("jdk/internal/foreign") || holder->is_in_package("java/lang/foreign") ||
holder->is_in_package("jdk/internal/vm/vector") || holder->is_in_package("jdk/incubator/vector") ||
holder->is_in_package("java/lang"))
return true;

View file

@ -764,7 +764,6 @@ class OptimizedEntryBlob: public BufferBlob {
JavaThread* thread;
JNIHandleBlock* old_handles;
JNIHandleBlock* new_handles;
bool should_detach;
};
// defined in frame_ARCH.cpp

View file

@ -70,7 +70,6 @@ public:
class CloseScopedMemoryClosure : public HandshakeClosure {
jobject _deopt;
jobject _exception;
public:
jboolean _found;
@ -78,7 +77,6 @@ public:
CloseScopedMemoryClosure(jobject deopt, jobject exception)
: HandshakeClosure("CloseScopedMemory")
, _deopt(deopt)
, _exception(exception)
, _found(false) {}
void do_thread(Thread* thread) {
@ -140,12 +138,11 @@ public:
};
/*
* This function issues a global handshake operation with all
* Java threads. This is useful for implementing asymmetric
* dekker synchronization schemes, where expensive synchronization
* in performance sensitive common paths, may be shifted to
* a less common slow path instead.
* Top frames containing obj will be deoptimized.
* This function performs a thread-local handshake against all threads running at the time
* the given session (deopt) was closed. If the handshake for a given thread is processed while
* one or more threads is found inside a scoped method (that is, a method inside the ScopedMemoryAccess
* class annotated with the '@Scoped' annotation), and whose local variables mention the session being
* closed (deopt), this method returns false, signalling that the session cannot be closed safely.
*/
JVM_ENTRY(jboolean, ScopedMemoryAccess_closeScope(JNIEnv *env, jobject receiver, jobject deopt, jobject exception))
CloseScopedMemoryClosure cl(deopt, exception);
@ -155,26 +152,26 @@ JVM_END
/// JVM_RegisterUnsafeMethods
#define PKG "Ljdk/internal/misc/"
#define PKG_MISC "Ljdk/internal/misc/"
#define PKG_FOREIGN "Ljdk/internal/foreign/"
#define MEMACCESS "ScopedMemoryAccess"
#define SCOPE PKG MEMACCESS "$Scope;"
#define SCOPED_ERR PKG MEMACCESS "$Scope$ScopedAccessError;"
#define SCOPE PKG_FOREIGN "MemorySessionImpl;"
#define CC (char*) /*cast a literal from (const char*)*/
#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
static JNINativeMethod jdk_internal_misc_ScopedMemoryAccess_methods[] = {
{CC "closeScope0", CC "(" SCOPE SCOPED_ERR ")Z", FN_PTR(ScopedMemoryAccess_closeScope)},
{CC "closeScope0", CC "(" SCOPE ")Z", FN_PTR(ScopedMemoryAccess_closeScope)},
};
#undef CC
#undef FN_PTR
#undef PKG
#undef PKG_MISC
#undef PKG_FOREIGN
#undef MEMACCESS
#undef SCOPE
#undef SCOPED_EXC
// This function is exported, used by NativeLookup.

View file

@ -36,6 +36,26 @@
extern struct JavaVM_ main_vm;
// When an upcall is invoked from a thread that is not attached to the VM, we need to attach it,
// and then to detach it at some point later. Detaching a thread as soon as the upcall completes
// is suboptimal, as the same thread could later upcall to Java again, at which point the VM would
// create multiple Java views of the same native thread. For this reason, we use thread local storage
// to keep track of the fact that we have attached a native thread to the VM. When the thread local
// storage is destroyed (which happens when the native threads is terminated), we check if the
// storage has an attached thread and, if so, we detach it from the VM.
struct UpcallContext {
Thread* attachedThread;
~UpcallContext() {
if (attachedThread != NULL) {
JavaVM_ *vm = (JavaVM *)(&main_vm);
vm->functions->DetachCurrentThread(vm);
}
}
};
APPROVED_CPP_THREAD_LOCAL UpcallContext threadContext;
void ProgrammableUpcallHandler::upcall_helper(JavaThread* thread, jobject rec, address buff) {
JavaThread* THREAD = thread; // For exception macros.
ThreadInVMfromNative tiv(THREAD);
@ -51,30 +71,23 @@ void ProgrammableUpcallHandler::upcall_helper(JavaThread* thread, jobject rec, a
JavaCalls::call_static(&result, upcall_method.klass, upcall_method.name, upcall_method.sig, &args, CATCH);
}
JavaThread* ProgrammableUpcallHandler::maybe_attach_and_get_thread(bool* should_detach) {
JavaThread* ProgrammableUpcallHandler::maybe_attach_and_get_thread() {
JavaThread* thread = JavaThread::current_or_null();
if (thread == nullptr) {
JavaVM_ *vm = (JavaVM *)(&main_vm);
JNIEnv* p_env = nullptr; // unused
jint result = vm->functions->AttachCurrentThread(vm, (void**) &p_env, nullptr);
jint result = vm->functions->AttachCurrentThreadAsDaemon(vm, (void**) &p_env, nullptr);
guarantee(result == JNI_OK, "Could not attach thread for upcall. JNI error code: %d", result);
*should_detach = true;
thread = JavaThread::current();
threadContext.attachedThread = thread;
assert(!thread->has_last_Java_frame(), "newly-attached thread not expected to have last Java frame");
} else {
*should_detach = false;
}
return thread;
}
void ProgrammableUpcallHandler::detach_current_thread() {
JavaVM_ *vm = (JavaVM *)(&main_vm);
vm->functions->DetachCurrentThread(vm);
}
// modelled after JavaCallWrapper::JavaCallWrapper
JavaThread* ProgrammableUpcallHandler::on_entry(OptimizedEntryBlob::FrameData* context) {
JavaThread* thread = maybe_attach_and_get_thread(&context->should_detach);
JavaThread* thread = maybe_attach_and_get_thread();
context->thread = thread;
assert(thread->can_call_java(), "must be able to call Java");
@ -132,24 +145,15 @@ void ProgrammableUpcallHandler::on_exit(OptimizedEntryBlob::FrameData* context)
JNIHandleBlock::release_block(context->new_handles, thread);
assert(!thread->has_pending_exception(), "Upcall can not throw an exception");
if (context->should_detach) {
detach_current_thread();
}
}
void ProgrammableUpcallHandler::attach_thread_and_do_upcall(jobject rec, address buff) {
bool should_detach = false;
JavaThread* thread = maybe_attach_and_get_thread(&should_detach);
JavaThread* thread = maybe_attach_and_get_thread();
{
MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, thread));
upcall_helper(thread, rec, buff);
}
if (should_detach) {
detach_current_thread();
}
}
const ProgrammableUpcallHandler& ProgrammableUpcallHandler::instance() {

View file

@ -48,8 +48,7 @@ private:
static void attach_thread_and_do_upcall(jobject rec, address buff);
static void handle_uncaught_exception(oop exception);
static JavaThread* maybe_attach_and_get_thread(bool* should_detach);
static void detach_current_thread();
static JavaThread* maybe_attach_and_get_thread();
static JavaThread* on_entry(OptimizedEntryBlob::FrameData* context);
static void on_exit(OptimizedEntryBlob::FrameData* context);

View file

@ -0,0 +1,163 @@
/*
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package java.lang.foreign;
import java.util.Objects;
import java.util.Optional;
import jdk.internal.foreign.Utils;
import jdk.internal.vm.annotation.Stable;
abstract non-sealed class AbstractLayout implements MemoryLayout {
private final long size;
final long alignment;
private final Optional<String> name;
@Stable
long cachedSize;
public AbstractLayout(long size, long alignment, Optional<String> name) {
this.size = size;
this.alignment = alignment;
this.name = name;
}
@Override
public AbstractLayout withName(String name) {
Objects.requireNonNull(name);
return dup(alignment, Optional.of(name));
}
@Override
public final Optional<String> name() {
return name;
}
abstract AbstractLayout dup(long alignment, Optional<String> name);
@Override
public AbstractLayout withBitAlignment(long alignmentBits) {
checkAlignment(alignmentBits);
return dup(alignmentBits, name);
}
void checkAlignment(long alignmentBitCount) {
if (((alignmentBitCount & (alignmentBitCount - 1)) != 0L) || //alignment must be a power of two
(alignmentBitCount < 8)) { //alignment must be greater than 8
throw new IllegalArgumentException("Invalid alignment: " + alignmentBitCount);
}
}
static void checkSize(long size) {
checkSize(size, false);
}
static void checkSize(long size, boolean includeZero) {
if (size < 0 || (!includeZero && size == 0)) {
throw new IllegalArgumentException("Invalid size for layout: " + size);
}
}
@Override
public final long bitAlignment() {
return alignment;
}
@Override
public long byteSize() {
if (cachedSize == 0) {
cachedSize = Utils.bitsToBytesOrThrow(bitSize(),
() -> new UnsupportedOperationException("Cannot compute byte size; bit size is not a multiple of 8"));
}
return cachedSize;
}
@Override
public long bitSize() {
return size;
}
String decorateLayoutString(String s) {
if (name().isPresent()) {
s = String.format("%s(%s)", s, name().get());
}
if (!hasNaturalAlignment()) {
s = alignment + "%" + s;
}
return s;
}
boolean hasNaturalAlignment() {
return size == alignment;
}
@Override
public boolean isPadding() {
return this instanceof PaddingLayout;
}
/**
* {@return the hash code value for this layout}
*/
@Override
public int hashCode() {
return name.hashCode() << Long.hashCode(alignment);
}
/**
* Compares the specified object with this layout for equality. Returns {@code true} if and only if the specified
* object is also a layout, and it is equal to this layout. Two layouts are considered equal if they are of
* the same kind, have the same size, name and alignment constraints. Furthermore, depending on the layout kind, additional
* conditions must be satisfied:
* <ul>
* <li>two value layouts are considered equal if they have the same byte order (see {@link ValueLayout#order()})</li>
* <li>two sequence layouts are considered equal if they have the same element count (see {@link SequenceLayout#elementCount()}), and
* if their element layouts (see {@link SequenceLayout#elementLayout()}) are also equal</li>
* <li>two group layouts are considered equal if they are of the same kind (see {@link GroupLayout#isStruct()},
* {@link GroupLayout#isUnion()}) and if their member layouts (see {@link GroupLayout#memberLayouts()}) are also equal</li>
* </ul>
*
* @param that the object to be compared for equality with this layout.
* @return {@code true} if the specified object is equal to this layout.
*/
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (!(that instanceof AbstractLayout)) {
return false;
}
return Objects.equals(name, ((AbstractLayout) that).name) &&
Objects.equals(alignment, ((AbstractLayout) that).alignment);
}
/**
* {@return the string representation of this layout}
*/
public abstract String toString();
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* 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
@ -23,21 +23,22 @@
* questions.
*/
package jdk.incubator.foreign;
package java.lang.foreign;
import jdk.internal.javac.PreviewFeature;
/**
* Represents a type which is <em>addressable</em>. An addressable type is one which can be projected down to
* a {@linkplain #address() memory address}. Examples of addressable types are {@link MemorySegment},
* {@link MemoryAddress}, {@link VaList} and {@link NativeSymbol}.
* 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 the {@link CLinker C linker} to model the types of
* {@link CLinker#downcallHandle(FunctionDescriptor) downcall handle} parameters that must be passed <em>by reference</em>
* (e.g. memory addresses, va lists and upcall stubs).
* 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).
*
* @implSpec
* Implementations of this interface are <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
* @since 19
*/
public sealed interface Addressable permits MemorySegment, MemoryAddress, NativeSymbol, VaList {
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public sealed interface Addressable permits MemorySegment, MemoryAddress, VaList {
/**
* {@return the {@linkplain MemoryAddress memory address} associated with this addressable}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* 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
@ -22,28 +22,34 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.incubator.foreign;
package java.lang.foreign;
import java.lang.constant.Constable;
import java.lang.constant.ConstantDesc;
import java.lang.constant.ConstantDescs;
import java.lang.constant.DynamicConstantDesc;
import java.lang.invoke.MethodHandle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import jdk.internal.javac.PreviewFeature;
/**
* A function descriptor is made up of zero or more argument layouts and zero or one return layout. A function descriptor
* is used to model the signature of foreign functions.
* 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}.
*
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
* @implSpec
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @see MemoryLayout
* @since 19
*/
public sealed class FunctionDescriptor implements Constable permits FunctionDescriptor.VariadicFunction {
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public sealed class FunctionDescriptor permits FunctionDescriptor.VariadicFunction {
private final MemoryLayout resLayout;
private final List<MemoryLayout> argLayouts;
@ -61,14 +67,14 @@ public sealed class FunctionDescriptor implements Constable permits FunctionDesc
}
/**
* {@return the argument layouts associated with this function descriptor}.
* {@return the argument layouts associated with this function descriptor (as an immutable list)}.
*/
public List<MemoryLayout> argumentLayouts() {
return argLayouts;
return Collections.unmodifiableList(argLayouts);
}
/**
* Create a function descriptor with given return and argument layouts.
* 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.
@ -81,7 +87,7 @@ public sealed class FunctionDescriptor implements Constable permits FunctionDesc
}
/**
* Create a function descriptor with given argument layouts and no return layout.
* Creates a function descriptor with the given argument layouts and no return layout.
* @param argLayouts the argument layouts.
* @return the new function descriptor.
*/
@ -92,13 +98,13 @@ public sealed class FunctionDescriptor implements Constable permits FunctionDesc
}
/**
* Obtain a specialized variadic function descriptor, by appending given variadic layouts to this
* 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 new variadic function descriptor, or this descriptor if {@code variadicLayouts.length == 0}.
* @return a variadic function descriptor, or this descriptor if {@code variadicLayouts.length == 0}.
*/
public FunctionDescriptor asVariadic(MemoryLayout... variadicLayouts) {
Objects.requireNonNull(variadicLayouts);
@ -116,7 +122,7 @@ public sealed class FunctionDescriptor implements Constable permits FunctionDesc
}
/**
* Create a new function descriptor with the given argument layouts appended to the argument layout array
* Returns a function descriptor with the given argument layouts appended to the argument layout array
* of this function descriptor.
* @param addedLayouts the argument layouts to append.
* @return the new function descriptor.
@ -126,7 +132,7 @@ public sealed class FunctionDescriptor implements Constable permits FunctionDesc
}
/**
* Create a new function descriptor with the given argument layouts inserted at the given index, into the argument
* Returns a function descriptor with the given argument layouts inserted at the given index, into the argument
* layout array of this function descriptor.
* @param index the index at which to insert the arguments
* @param addedLayouts the argument layouts to insert at given index.
@ -145,7 +151,7 @@ public sealed class FunctionDescriptor implements Constable permits FunctionDesc
}
/**
* Create a new function descriptor with the given memory layout as the new return layout.
* 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.
*/
@ -155,7 +161,7 @@ public sealed class FunctionDescriptor implements Constable permits FunctionDesc
}
/**
* Create a new function descriptor with the return layout dropped. This is useful to model functions
* Returns a function descriptor with the return layout dropped. This is useful to model functions
* which return no values.
* @return the new function descriptor.
*/
@ -169,8 +175,9 @@ public sealed class FunctionDescriptor implements Constable permits FunctionDesc
@Override
public String toString() {
return String.format("(%s)%s",
Stream.of(argLayouts)
.map(Object::toString)
IntStream.range(0, argLayouts.size())
.mapToObj(i -> (i == firstVariadicArgumentIndex() ?
"..." : "") + argLayouts.get(i))
.collect(Collectors.joining()),
returnLayout().map(Object::toString).orElse("v"));
}
@ -179,8 +186,9 @@ public sealed class FunctionDescriptor implements Constable permits FunctionDesc
* Compares the specified object with this function descriptor for equality. Returns {@code true} if and only if the specified
* object is also a function descriptor, and all the following conditions are met:
* <ul>
* <li>the two function descriptors have equals return layouts (see {@link MemoryLayout#equals(Object)}), or both have no return layout</li>
* <li>the two function descriptors have argument layouts that are pair-wise equal (see {@link MemoryLayout#equals(Object)})
* <li>the two function descriptors have equals return layouts (see {@link MemoryLayout#equals(Object)}), or both have no return layout;</li>
* <li>the two function descriptors have argument layouts that are pair-wise {@linkplain MemoryLayout#equals(Object) equal}; and</li>
* <li>the two function descriptors have the same leading {@linkplain #firstVariadicArgumentIndex() variadic argument index}</li>
* </ul>
*
* @param other the object to be compared for equality with this function descriptor.
@ -188,13 +196,10 @@ public sealed class FunctionDescriptor implements Constable permits FunctionDesc
*/
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof FunctionDescriptor f)) {
return false;
}
return Objects.equals(resLayout, f.resLayout) && Objects.equals(argLayouts, f.argLayouts);
return other instanceof FunctionDescriptor f &&
Objects.equals(resLayout, f.resLayout) &&
Objects.equals(argLayouts, f.argLayouts) &&
firstVariadicArgumentIndex() == f.firstVariadicArgumentIndex();
}
/**
@ -202,30 +207,7 @@ public sealed class FunctionDescriptor implements Constable permits FunctionDesc
*/
@Override
public int hashCode() {
int hashCode = Objects.hashCode(argLayouts);
return resLayout == null ? hashCode : resLayout.hashCode() ^ hashCode;
}
/**
* Returns an {@link Optional} containing the nominal descriptor for this
* function descriptor, if one can be constructed, or an empty {@link Optional}
* if one cannot be constructed.
*
* @return An {@link Optional} containing the resulting nominal descriptor,
* or an empty {@link Optional} if one cannot be constructed.
*/
@Override
public Optional<DynamicConstantDesc<FunctionDescriptor>> describeConstable() {
List<ConstantDesc> constants = new ArrayList<>();
constants.add(resLayout == null ? AbstractLayout.MH_VOID_FUNCTION : AbstractLayout.MH_FUNCTION);
if (resLayout != null) {
constants.add(resLayout.describeConstable().get());
}
for (MemoryLayout argLayout : argLayouts) {
constants.add(argLayout.describeConstable().get());
}
return Optional.of(DynamicConstantDesc.ofNamed(
ConstantDescs.BSM_INVOKE, "function", AbstractLayout.CD_FUNCTION_DESC, constants.toArray(new ConstantDesc[0])));
return Objects.hash(argLayouts, resLayout, firstVariadicArgumentIndex());
}
static final class VariadicFunction extends FunctionDescriptor {
@ -262,10 +244,5 @@ public sealed class FunctionDescriptor implements Constable permits FunctionDesc
public FunctionDescriptor dropReturnLayout() {
throw new UnsupportedOperationException();
}
@Override
public Optional<DynamicConstantDesc<FunctionDescriptor>> describeConstable() {
return Optional.empty();
}
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,39 +23,28 @@
* questions.
*
*/
package jdk.incubator.foreign;
package java.lang.foreign;
import java.lang.constant.ConstantDesc;
import java.lang.constant.ConstantDescs;
import java.lang.constant.DynamicConstantDesc;
import java.lang.constant.MethodHandleDesc;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalLong;
import java.util.function.LongBinaryOperator;
import java.util.stream.Collectors;
import jdk.internal.javac.PreviewFeature;
/**
* A group layout is used to combine multiple <em>member layouts</em>. There are two ways in which member layouts
* A compound layout that aggregates multiple <em>member layouts</em>. There are two ways in which member layouts
* can be combined: if member layouts are laid out one after the other, the resulting group layout is said to be a <em>struct</em>
* (see {@link MemoryLayout#structLayout(MemoryLayout...)}); conversely, if all member layouts are laid out at the same starting offset,
* the resulting group layout is said to be a <em>union</em> (see {@link MemoryLayout#unionLayout(MemoryLayout...)}).
* <p>
* This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
* class; programmers should treat instances that are
* {@linkplain #equals(Object) equal} as interchangeable and should not
* use instances for synchronization, or unpredictable behavior may
* occur. For example, in a future release, synchronization may fail.
* The {@code equals} method should be used for comparisons.
*
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
*
* @implSpec
* This class is immutable and thread-safe.
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public final class GroupLayout extends AbstractLayout implements MemoryLayout {
/**
@ -65,32 +54,26 @@ public final class GroupLayout extends AbstractLayout implements MemoryLayout {
/**
* A 'struct' kind.
*/
STRUCT("", MH_STRUCT, Long::sum),
STRUCT("", Math::addExact),
/**
* A 'union' kind.
*/
UNION("|", MH_UNION, Math::max);
UNION("|", Math::max);
final String delimTag;
final MethodHandleDesc mhDesc;
final LongBinaryOperator sizeOp;
Kind(String delimTag, MethodHandleDesc mhDesc, LongBinaryOperator sizeOp) {
Kind(String delimTag, LongBinaryOperator sizeOp) {
this.delimTag = delimTag;
this.mhDesc = mhDesc;
this.sizeOp = sizeOp;
}
OptionalLong sizeof(List<MemoryLayout> elems) {
long sizeof(List<MemoryLayout> elems) {
long size = 0;
for (MemoryLayout elem : elems) {
if (AbstractLayout.optSize(elem).isPresent()) {
size = sizeOp.applyAsLong(size, elem.bitSize());
} else {
return OptionalLong.empty();
}
}
return OptionalLong.of(size);
return size;
}
long alignof(List<MemoryLayout> elems) {
@ -125,6 +108,9 @@ public final class GroupLayout extends AbstractLayout implements MemoryLayout {
return Collections.unmodifiableList(elements);
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return decorateLayoutString(elements.stream()
@ -133,19 +119,22 @@ public final class GroupLayout extends AbstractLayout implements MemoryLayout {
}
/**
* {@return {@code true}, if this group layout is a <em>struct</em>}
* {@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 <em>union</em>}
* {@return {@code true}, if this group layout is a union layout}
*/
public boolean isUnion() {
return kind == Kind.UNION;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object other) {
if (this == other) {
@ -160,6 +149,9 @@ public final class GroupLayout extends AbstractLayout implements MemoryLayout {
return kind.equals(g.kind) && elements.equals(g.elements);
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), kind, elements);
@ -175,18 +167,6 @@ public final class GroupLayout extends AbstractLayout implements MemoryLayout {
return alignment == kind.alignof(elements);
}
@Override
public Optional<DynamicConstantDesc<GroupLayout>> describeConstable() {
ConstantDesc[] constants = new ConstantDesc[1 + elements.size()];
constants[0] = kind.mhDesc;
for (int i = 0 ; i < elements.size() ; i++) {
constants[i + 1] = elements.get(i).describeConstable().get();
}
return Optional.of(decorateLayoutConstant(DynamicConstantDesc.ofNamed(
ConstantDescs.BSM_INVOKE, kind.name().toLowerCase(),
CD_GROUP_LAYOUT, constants)));
}
//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

View file

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

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,30 +24,32 @@
*
*/
package jdk.incubator.foreign;
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;
import java.nio.ByteOrder;
/**
* 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 CLinker#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)}.</li>
* <li>By the invocation of an {@linkplain CLinker#upcallStub(MethodHandle, FunctionDescriptor, ResourceScope) upcall stub} which accepts a pointer.
* <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>Dereference</h2>
* <h2>Dereferencing memory addresses</h2>
*
* A memory address can be read or written using various methods provided in this class (e.g. {@link #get(ValueLayout.OfInt, long)}).
* Each dereference method takes a {@linkplain jdk.incubator.foreign.ValueLayout value layout}, which specifies the size,
* 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 {@link ByteOrder#nativeOrder() default endianness}, the following code can be used:
* 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);
@ -63,18 +65,13 @@ import java.nio.ByteOrder;
* 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.
* <p>
* All implementations of this interface must be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>;
* programmers should treat instances that are {@linkplain #equals(Object) equal} as interchangeable and should not
* use instances for synchronization, or unpredictable behavior may occur. For example, in a future release,
* synchronization may fail. The {@code equals} method should be used for comparisons.
*
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
*
* @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 {
/**
@ -83,14 +80,15 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
long toRawLongValue();
/**
* Creates a new memory address with given offset (in bytes), which might be negative, from current one.
* 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.
* @return a new memory address with given offset from current one.
* 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 and 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
@ -102,28 +100,35 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return a Java string constructed from the bytes read from the given starting address ({@code toRowLongValue() + offset})
* up to (but not including) the first {@code '\0'} terminator character (assuming one is found).
* @throws IllegalArgumentException if the size of the native string is greater than the largest string supported by the platform.
* @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 either absent, or does not mention the module name {@code M}, or
* {@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 given offset, converting it to a null-terminated byte sequence using UTF-8 encoding.
* 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.
* @param offset offset in bytes (relative to this address). The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
* restricted methods, and use safe and supported functionalities, where possible.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @param str the Java string to be written at this address.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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
@ -146,14 +151,14 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
int hashCode();
/**
* The native memory address instance modelling the {@code NULL} address.
* The memory address instance modelling the {@code NULL} address.
*/
MemoryAddress NULL = new MemoryAddressImpl(0L);
/**
* Obtain a native memory address instance from given long address.
* @param value the long address.
* @return the new memory address instance.
* 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 ?
@ -162,7 +167,7 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
}
/**
* Reads a byte from this address and offset with given layout.
* Reads a byte at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -170,19 +175,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return a byte value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 to this address instance and offset with given layout.
* Writes a byte at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -190,19 +196,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the byte value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 and offset with given layout.
* Reads a boolean at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -210,19 +217,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return a boolean value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 to this address instance and offset with given layout.
* Writes a boolean at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -230,19 +238,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the boolean value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 and offset with given layout.
* Reads a char at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -250,19 +259,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return a char value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 to this address instance and offset with given layout.
* Writes a char at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -270,19 +280,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the char value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 and offset with given layout.
* Reads a short at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -290,19 +301,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return a short value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 to this address instance and offset with given layout.
* Writes a short at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -310,19 +322,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the short value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 and offset with given layout.
* Reads an int at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -330,19 +343,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return an int value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 to this address instance and offset with given layout.
* Writes an int at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -350,19 +364,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the int value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 and offset with given layout.
* Reads a float at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -370,19 +385,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return a float value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 to this address instance and offset with given layout.
* Writes a float at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -390,19 +406,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the float value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 and offset with given layout.
* Reads a long at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -410,19 +427,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return a long value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 to this address instance and offset with given layout.
* Writes a long at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -430,19 +448,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the long value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 and offset with given layout.
* Reads a double at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -450,19 +469,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return a double value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 to this address instance and offset with given layout.
* Writes a double at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -470,19 +490,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the double value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 and offset with given layout.
* Reads an address at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -490,19 +511,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @return an address value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 to this address instance and offset with given layout.
* Writes an address at the given offset from this address, with the given layout.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -510,19 +532,20 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + offset}.
* @param value the address value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 and index, scaled by given layout size.
* 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
@ -530,20 +553,21 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @return a char value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
char getAtIndex(ValueLayout.OfChar layout, long index);
/**
* Writes a char to this address instance and index, scaled by given layout size.
* Writes a char to this address at the given index, scaled by the given layout size.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -551,20 +575,21 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param value the char value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 and index, scaled by given layout size.
* 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
@ -572,20 +597,21 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @return a short value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
short getAtIndex(ValueLayout.OfShort layout, long index);
/**
* Writes a short to this address instance and index, scaled by given layout size.
* Writes a short to this address at the given index, scaled by the given layout size.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -593,20 +619,21 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param value the short value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 and index, scaled by given layout size.
* 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
@ -614,20 +641,21 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @return an int value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
int getAtIndex(ValueLayout.OfInt layout, long index);
/**
* Writes an int to this address instance and index, scaled by given layout size.
* Writes an int to this address at the given index, scaled by the given layout size.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -635,20 +663,21 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param value the int value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 and index, scaled by given layout size.
* 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
@ -656,20 +685,21 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @return a float value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
float getAtIndex(ValueLayout.OfFloat layout, long index);
/**
* Writes a float to this address instance and index, scaled by given layout size.
* Writes a float to this address at the given index, scaled by the given layout size.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -677,20 +707,21 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param value the float value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 and index, scaled by given layout size.
* 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
@ -698,20 +729,21 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @return a long value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
long getAtIndex(ValueLayout.OfLong layout, long index);
/**
* Writes a long to this address instance and index, scaled by given layout size.
* Writes a long to this address at the given index, scaled by the given layout size.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -719,20 +751,21 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param value the long value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 and index, scaled by given layout size.
* 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
@ -740,20 +773,21 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @return a double value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
double getAtIndex(ValueLayout.OfDouble layout, long index);
/**
* Writes a double to this address instance and index, scaled by given layout size.
* Writes a double to this address at the given index, scaled by the given layout size.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -761,20 +795,21 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param value the double value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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 and index, scaled by given layout size.
* 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
@ -782,20 +817,21 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @return an address value read from this address.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@code --enable-native-access} is specified, but does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
MemoryAddress getAtIndex(ValueLayout.OfAddress layout, long index);
/**
* Writes an address to this address instance and index, scaled by given layout size.
* Writes an address to this address at the given index, scaled by the given layout size.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -803,13 +839,14 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
* 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). The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param index index in bytes (relative to this address). Might be negative.
* The final address of this write operation can be expressed as {@code toRowLongValue() + (index * layout.byteSize())}.
* @param value the address value to be written.
* @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,14 +23,8 @@
* questions.
*
*/
package jdk.incubator.foreign;
package java.lang.foreign;
import jdk.internal.foreign.LayoutPath;
import jdk.internal.foreign.LayoutPath.PathElementImpl.PathKind;
import jdk.internal.foreign.Utils;
import java.lang.constant.Constable;
import java.lang.constant.DynamicConstantDesc;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
@ -38,12 +32,15 @@ import java.nio.ByteOrder;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalLong;
import java.util.Set;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.internal.foreign.LayoutPath;
import jdk.internal.foreign.LayoutPath.PathElementImpl.PathKind;
import jdk.internal.foreign.Utils;
import jdk.internal.javac.PreviewFeature;
/**
* A memory layout can be used to describe the contents of a memory segment.
@ -56,7 +53,10 @@ import java.util.stream.Stream;
* element layout (see {@link SequenceLayout}); a <em>group layout</em> denotes an aggregation of (typically) heterogeneous
* member layouts (see {@link GroupLayout}).
* <p>
* For instance, consider the following struct declaration in C:
* Layouts can be optionally associated with a <em>name</em>. A layout name can be referred to when
* constructing <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>.
* <p>
* Consider the following struct declaration in C:
*
* {@snippet lang=c :
* typedef struct {
@ -76,14 +76,6 @@ import java.util.stream.Stream;
* )
* ).withName("TaggedValues");
* }
* <p>
* All implementations of this interface must be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>;
* programmers should treat instances that are {@linkplain #equals(Object) equal} as interchangeable and should not
* use instances for synchronization, or unpredictable behavior may occur. For example, in a future release,
* synchronization may fail. The {@code equals} method should be used for comparisons.
*
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
*
* <h2><a id = "layout-align">Size, alignment and byte order</a></h2>
*
@ -91,9 +83,8 @@ import java.util.stream.Stream;
* always has the same size in bits, regardless of the platform in which it is used. For derived layouts, the size is computed
* as follows:
* <ul>
* <li>for a <em>finite</em> sequence layout <em>S</em> whose element layout is <em>E</em> and size is L,
* <li>for a sequence layout <em>S</em> whose element layout is <em>E</em> and size is <em>L</em>,
* the size of <em>S</em> is that of <em>E</em>, multiplied by <em>L</em></li>
* <li>the size of an <em>unbounded</em> sequence layout is <em>unknown</em></li>
* <li>for a group layout <em>G</em> with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose sizes are
* <em>S1</em>, <em>S2</em>, ... <em>Sn</em>, respectively, the size of <em>G</em> is either <em>S1 + S2 + ... + Sn</em> or
* <em>max(S1, S2, ... Sn)</em> depending on whether the group is a <em>struct</em> or an <em>union</em>, respectively</li>
@ -122,8 +113,7 @@ import java.util.stream.Stream;
* <p>
* Layout paths are for example useful in order to obtain {@linkplain MemoryLayout#bitOffset(PathElement...) offsets} of
* arbitrarily nested layouts inside another layout, to quickly obtain a {@linkplain #varHandle(PathElement...) memory access handle}
* corresponding to the selected layout, to {@linkplain #select(PathElement...) select} an arbitrarily nested layout inside
* another layout, or to {@link #map(UnaryOperator, PathElement...) transform} a nested layout element inside
* corresponding to the selected layout, or to {@linkplain #select(PathElement...) select} an arbitrarily nested layout inside
* another layout.
* <p>
* Such <em>layout paths</em> can be constructed programmatically using the methods in this class.
@ -140,26 +130,11 @@ import java.util.stream.Stream;
* PathElement.groupElement("value"));
* }
*
* And, we can also replace the layout named {@code value} with another layout, as follows:
* {@snippet lang=java :
* MemoryLayout taggedValuesWithHole = taggedValues.map(l -> MemoryLayout.paddingLayout(32),
* PathElement.sequenceElement(), PathElement.groupElement("value"));
* }
*
* That is, the above declaration is identical to the following, more verbose one:
* {@snippet lang=java :
* MemoryLayout taggedValuesWithHole = MemoryLayout.sequenceLayout(5,
* MemoryLayout.structLayout(
* ValueLayout.JAVA_BYTE.withName("kind"),
* MemoryLayout.paddingLayout(32),
* MemoryLayout.paddingLayout(32)
* ));
* }
*
* Layout paths can feature one or more <em>free dimensions</em>. For instance, a layout path traversing
* an unspecified sequence element (that is, where one of the path component was obtained with the
* {@link PathElement#sequenceElement()} method) features an additional free dimension, which will have to be bound at runtime.
* This is important when obtaining memory access var handle from layouts, as in the following code:
* This is important when obtaining a {@linkplain MethodHandles#memorySegmentViewVarHandle(ValueLayout) memory segment view var handle}
* from layouts, as in the following code:
*
* {@snippet lang=java :
* VarHandle valueHandle = taggedValues.varHandle(PathElement.sequenceElement(),
@ -168,7 +143,7 @@ import java.util.stream.Stream;
*
* Since the layout path constructed in the above example features exactly one free dimension (as it doesn't specify
* <em>which</em> member layout named {@code value} should be selected from the enclosing sequence layout),
* it follows that the memory access var handle {@code valueHandle} will feature an <em>additional</em> {@code long}
* it follows that the var handle {@code valueHandle} will feature an <em>additional</em> {@code long}
* access coordinate.
*
* <p>A layout path with free dimensions can also be used to create an offset-computing method handle, using the
@ -184,59 +159,37 @@ import java.util.stream.Stream;
* long offset2 = (long) offsetHandle.invokeExact(2L); // 16
* }
*
* <h2>Layout attributes</h2>
*
* Layouts can be optionally associated with a <em>name</em>. A layout name can be referred to when
* constructing <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>.
*
* @implSpec
* Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*/
public sealed interface MemoryLayout extends Constable permits AbstractLayout, SequenceLayout, GroupLayout, PaddingLayout, ValueLayout {
/**
* {@return an {@link Optional} containing the nominal descriptor for this
* layout, if one can be constructed, or an empty {@link Optional}
* if one cannot be constructed}
*/
@Override
Optional<? extends DynamicConstantDesc<? extends MemoryLayout>> describeConstable();
/**
* Returns {@code true} if this layout has a specified size. A layout does not have a specified size if it is (or contains) a sequence layout whose
* size is unspecified (see {@link SequenceLayout#elementCount()}).
*
* Value layouts (see {@link ValueLayout}) and padding layouts (see {@link MemoryLayout#paddingLayout(long)})
* <em>always</em> have a specified size, therefore this method always returns {@code true} in these cases.
*
* @return {@code true}, if this layout has a specified size.
* @since 19
*/
boolean hasSize();
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public sealed interface MemoryLayout permits AbstractLayout, SequenceLayout, GroupLayout, PaddingLayout, ValueLayout {
/**
* {@return the layout size, in bits}
* @throws UnsupportedOperationException if the layout is, or contains, a sequence layout with unspecified size (see {@link SequenceLayout}).
*/
long bitSize();
/**
* {@return the layout size, in bytes}
* @throws UnsupportedOperationException if the layout is, or contains, a sequence layout with unspecified size (see {@link SequenceLayout}),
* or if {@code bitSize()} is not a multiple of 8.
* @throws UnsupportedOperationException if {@code bitSize()} is not a multiple of 8.
*/
long byteSize();
/**
* {@return the <em>name</em> (if any) associated with this layout}
* {@return the name (if any) associated with this layout}
* @see MemoryLayout#withName(String)
*/
Optional<String> name();
/**
* Creates a new layout which features the desired layout <em>name</em>.
* Returns a memory layout with the same size and alignment constraints as this layout,
* but with the specified name.
*
* @param name the layout name.
* @return a new layout which is the same as this layout, except for the <em>name</em> associated with it.
* @return a memory layout with the given name.
* @see MemoryLayout#name()
*/
MemoryLayout withName(String name);
@ -282,16 +235,17 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
}
/**
* Creates a new layout which features the desired alignment constraint.
* Returns a memory layout with the same size and name as this layout,
* but with the specified alignment constraints (in bits).
*
* @param bitAlignment the layout alignment constraint, expressed in bits.
* @return a new layout which is the same as this layout, except for the alignment constraint associated with it.
* @return a memory layout with the given alignment constraints.
* @throws IllegalArgumentException if {@code bitAlignment} is not a power of two, or if it's less than 8.
*/
MemoryLayout withBitAlignment(long bitAlignment);
/**
* Computes the offset, in bits, of the layout selected by a given layout path, where the path is considered rooted in this
* Computes the offset, in bits, of the layout selected by the given layout path, where the path is considered rooted in this
* layout.
*
* @param elements the layout path elements.
@ -299,18 +253,17 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
* @throws IllegalArgumentException if the layout path does not select any layout nested in this layout, or if the
* layout path contains one or more path elements that select multiple sequence element indices
* (see {@link PathElement#sequenceElement()} and {@link PathElement#sequenceElement(long, long)}).
* @throws UnsupportedOperationException if one of the layouts traversed by the layout path has unspecified size.
* @throws NullPointerException if either {@code elements == null}, or if any of the elements
* in {@code elements} is {@code null}.
*/
default long bitOffset(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), LayoutPath::offset,
return computePathOp(LayoutPath.rootPath(this), LayoutPath::offset,
EnumSet.of(PathKind.SEQUENCE_ELEMENT, PathKind.SEQUENCE_RANGE), elements);
}
/**
* Creates a method handle that can be used to compute the offset, in bits, of the layout selected
* by a given layout path, where the path is considered rooted in this layout.
* by the given layout path, where the path is considered rooted in this layout.
*
* <p>The returned method handle has a return type of {@code long}, and features as many {@code long}
* parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
@ -334,15 +287,14 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
* specified by the given layout path elements, when supplied with the missing sequence element indices.
* @throws IllegalArgumentException if the layout path contains one or more path elements that select
* multiple sequence element indices (see {@link PathElement#sequenceElement(long, long)}).
* @throws UnsupportedOperationException if one of the layouts traversed by the layout path has unspecified size.
*/
default MethodHandle bitOffsetHandle(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), LayoutPath::offsetHandle,
return computePathOp(LayoutPath.rootPath(this), LayoutPath::offsetHandle,
EnumSet.of(PathKind.SEQUENCE_RANGE), elements);
}
/**
* Computes the offset, in bytes, of the layout selected by a given layout path, where the path is considered rooted in this
* Computes the offset, in bytes, of the layout selected by the given layout path, where the path is considered rooted in this
* layout.
*
* @param elements the layout path elements.
@ -350,8 +302,7 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
* @throws IllegalArgumentException if the layout path does not select any layout nested in this layout, or if the
* layout path contains one or more path elements that select multiple sequence element indices
* (see {@link PathElement#sequenceElement()} and {@link PathElement#sequenceElement(long, long)}).
* @throws UnsupportedOperationException if one of the layouts traversed by the layout path has unspecified size,
* or if {@code bitOffset(elements)} is not a multiple of 8.
* @throws UnsupportedOperationException if {@code bitOffset(elements)} is not a multiple of 8.
* @throws NullPointerException if either {@code elements == null}, or if any of the elements
* in {@code elements} is {@code null}.
*/
@ -361,7 +312,7 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
/**
* Creates a method handle that can be used to compute the offset, in bytes, of the layout selected
* by a given layout path, where the path is considered rooted in this layout.
* by the given layout path, where the path is considered rooted in this layout.
*
* <p>The returned method handle has a return type of {@code long}, and features as many {@code long}
* parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
@ -389,7 +340,6 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
* specified by the given layout path elements, when supplied with the missing sequence element indices.
* @throws IllegalArgumentException if the layout path contains one or more path elements that select
* multiple sequence element indices (see {@link PathElement#sequenceElement(long, long)}).
* @throws UnsupportedOperationException if one of the layouts traversed by the layout path has unspecified size.
*/
default MethodHandle byteOffsetHandle(PathElement... elements) {
MethodHandle mh = bitOffsetHandle(elements);
@ -398,10 +348,10 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
}
/**
* Creates a memory access var handle that can be used to dereference memory at the layout selected by a given layout path,
* Creates an access var handle that can be used to dereference memory at the layout selected by the given layout path,
* where the path is considered rooted in this layout.
* <p>
* The final memory location accessed by the returned memory access var handle can be computed as follows:
* The final memory location accessed by the returned var handle can be computed as follows:
*
* <blockquote><pre>{@code
* address = base + offset
@ -417,27 +367,27 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
*
* where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
* arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
* and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
* and {@code s_1}, {@code s_2}, ... {@code s_n} are <em>static</em> stride constants which are derived from
* the layout path.
*
* @apiNote the resulting var handle will feature an additional {@code long} access coordinate for every
* unspecified sequence access component contained in this layout path. Moreover, the resulting var handle
* features certain <a href="MemoryHandles.html#memaccess-mode">access mode restrictions</a>, which are common to all memory access var handles.
* 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,
* or if one of the layouts traversed by the layout path has unspecified size.
* @throws UnsupportedOperationException if the layout path has one or more elements with incompatible alignment constraints.
* @throws IllegalArgumentException if the layout path in {@code elements} does not select a value layout (see {@link ValueLayout}).
* @see MethodHandles#memorySegmentViewVarHandle(ValueLayout)
*/
default VarHandle varHandle(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), LayoutPath::dereferenceHandle,
return computePathOp(LayoutPath.rootPath(this), LayoutPath::dereferenceHandle,
Set.of(), elements);
}
/**
* Creates a method handle which, given a memory segment, returns a {@linkplain MemorySegment#asSlice(long,long) slice}
* corresponding to the layout selected by a given layout path, where the path is considered rooted in this layout.
* corresponding to the layout selected by the given layout path, where the path is considered rooted in this layout.
*
* <p>The returned method handle has a return type of {@code MemorySegment}, features a {@code MemorySegment}
* parameter as leading parameter representing the segment to be sliced, and features as many trailing {@code long}
@ -455,7 +405,7 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
*
* where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
* arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
* and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
* and {@code s_1}, {@code s_2}, ... {@code s_n} are <em>static</em> stride constants which are derived from
* the layout path.
*
* <p>After the offset is computed, the returned segment is created as if by calling:
@ -474,11 +424,10 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
* @throws UnsupportedOperationException if the size of the selected layout in bits is not a multiple of 8.
*/
default MethodHandle sliceHandle(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), LayoutPath::sliceHandle,
return computePathOp(LayoutPath.rootPath(this), LayoutPath::sliceHandle,
Set.of(), elements);
}
/**
* Selects the layout from a path rooted in this layout.
*
@ -489,30 +438,12 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
* (see {@link PathElement#sequenceElement(long)} and {@link PathElement#sequenceElement(long, long)}).
*/
default MemoryLayout select(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this, l -> 0L), LayoutPath::layout,
EnumSet.of(PathKind.SEQUENCE_ELEMENT_INDEX, PathKind.SEQUENCE_RANGE), elements);
}
/**
* Creates a transformed copy of this layout where a selected layout, from a path rooted in this layout,
* is replaced with the result of applying the given operation.
*
* @param op the unary operation to be applied to the selected layout.
* @param elements the layout path elements.
* @return a new layout where the layout selected by the layout path in {@code elements},
* has been replaced by the result of applying {@code op} to the selected layout.
* @throws IllegalArgumentException if the layout path does not select any layout nested in this layout,
* or if the layout path contains one or more path elements that select one or more sequence element indices
* (see {@link PathElement#sequenceElement(long)} and {@link PathElement#sequenceElement(long, long)}).
*/
default MemoryLayout map(UnaryOperator<MemoryLayout> op, PathElement... elements) {
Objects.requireNonNull(op);
return computePathOp(LayoutPath.rootPath(this, l -> 0L), path -> path.map(op),
return computePathOp(LayoutPath.rootPath(this), LayoutPath::layout,
EnumSet.of(PathKind.SEQUENCE_ELEMENT_INDEX, PathKind.SEQUENCE_RANGE), elements);
}
private static <Z> Z computePathOp(LayoutPath path, Function<LayoutPath, Z> finalizer,
Set<LayoutPath.PathElementImpl.PathKind> badKinds, PathElement... elements) {
Set<PathKind> badKinds, PathElement... elements) {
Objects.requireNonNull(elements);
for (PathElement e : elements) {
LayoutPath.PathElementImpl pathElem = (LayoutPath.PathElementImpl)Objects.requireNonNull(e);
@ -530,24 +461,24 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
boolean isPadding();
/**
* Instances of this class are used to form <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>. There
* An element in a <a href="MemoryLayout.html#layout-paths"><em>layout path</em></a>. There
* are two kinds of path elements: <em>group path elements</em> and <em>sequence path elements</em>. Group
* path elements are used to select a given named member layout within a {@link GroupLayout}. Sequence
* path elements are used to select a named member layout within a {@link GroupLayout}. Sequence
* path elements are used to select a sequence element layout within a {@link SequenceLayout}; selection
* of sequence element layout can be <em>explicit</em> (see {@link PathElement#sequenceElement(long)}) or
* <em>implicit</em> (see {@link PathElement#sequenceElement()}). When a path uses one or more implicit
* sequence path elements, it acquires additional <em>free dimensions</em>.
*
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
*
* @implSpec
* Implementations of this interface are immutable and thread-safe.
* Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
sealed interface PathElement permits LayoutPath.PathElementImpl {
/**
* Returns a path element which selects a member layout with given name from a given group layout.
* Returns a path element which selects a member layout with the given name in a group layout.
* The path element returned by this method does not alter the number of free dimensions of any path
* that is combined with such element.
*
@ -555,47 +486,49 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
* method will select the first one; that is, the group element with the lowest offset from current path is selected.
*
* @param name the name of the group element to be selected.
* @return a path element which selects the group element with given name.
* @return a path element which selects the group element with the given name.
*/
static PathElement groupElement(String name) {
Objects.requireNonNull(name);
return new LayoutPath.PathElementImpl(LayoutPath.PathElementImpl.PathKind.GROUP_ELEMENT,
return new LayoutPath.PathElementImpl(PathKind.GROUP_ELEMENT,
path -> path.groupElement(name));
}
/**
* Returns a path element which selects the element layout at the specified position in a given the sequence layout.
* Returns a path element which selects the element layout at the specified position in a sequence layout.
* The path element returned by this method does not alter the number of free dimensions of any path
* that is combined with such element.
*
* @param index the index of the sequence element to be selected.
* @return a path element which selects the sequence element layout with given index.
* @return a path element which selects the sequence element layout with the given index.
* @throws IllegalArgumentException if {@code index < 0}.
*/
static PathElement sequenceElement(long index) {
if (index < 0) {
throw new IllegalArgumentException("Index must be positive: " + index);
}
return new LayoutPath.PathElementImpl(LayoutPath.PathElementImpl.PathKind.SEQUENCE_ELEMENT_INDEX,
return new LayoutPath.PathElementImpl(PathKind.SEQUENCE_ELEMENT_INDEX,
path -> path.sequenceElement(index));
}
/**
* Returns a path element which selects the element layout in a <em>range</em> of positions in a given the sequence layout,
* where the range is expressed as a pair of starting index (inclusive) {@code S} and step factor (which can also be negative)
* Returns a path element which selects the element layout in a <em>range</em> of positions in a sequence layout.
* The range is expressed as a pair of starting index (inclusive) {@code S} and step factor (which can also be negative)
* {@code F}.
* If a path with free dimensions {@code n} is combined with the path element returned by this method,
* the number of free dimensions of the resulting path will be {@code 1 + n}. If the free dimension associated
* with this path is bound by an index {@code I}, the resulting accessed offset can be obtained with the following
* formula:
*
* <blockquote><pre>{@code
* E * (S + I * F)
* }</pre></blockquote>
*
* where {@code E} is the size (in bytes) of the sequence element layout.
*
* @param start the index of the first sequence element to be selected.
* @param step the step factor at which subsequence sequence elements are to be selected.
* @return a path element which selects the sequence element layout with given index.
* @return a path element which selects the sequence element layout with the given index.
* @throws IllegalArgumentException if {@code start < 0}, or {@code step == 0}.
*/
static PathElement sequenceElement(long start, long step) {
@ -605,19 +538,19 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
if (step == 0) {
throw new IllegalArgumentException("Step must be != 0: " + step);
}
return new LayoutPath.PathElementImpl(LayoutPath.PathElementImpl.PathKind.SEQUENCE_RANGE,
return new LayoutPath.PathElementImpl(PathKind.SEQUENCE_RANGE,
path -> path.sequenceElement(start, step));
}
/**
* Returns a path element which selects an unspecified element layout from a given sequence layout.
* Returns a path element which selects an unspecified element layout in a sequence layout.
* If a path with free dimensions {@code n} is combined with the path element returned by this method,
* the number of free dimensions of the resulting path will be {@code 1 + n}.
*
* @return a path element which selects an unspecified sequence element layout.
*/
static PathElement sequenceElement() {
return new LayoutPath.PathElementImpl(LayoutPath.PathElementImpl.PathKind.SEQUENCE_ELEMENT,
return new LayoutPath.PathElementImpl(PathKind.SEQUENCE_ELEMENT,
LayoutPath::sequenceElement);
}
}
@ -652,7 +585,7 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
String toString();
/**
* Create a new padding layout with given size.
* Creates a padding layout with the given size.
*
* @param size the padding size in bits.
* @return the new selector layout.
@ -679,7 +612,7 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
* </ul>
* @param carrier the value layout carrier.
* @param order the value layout's byte order.
* @return a new value layout.
* @return a value layout with the given Java carrier and byte-order.
* @throws IllegalArgumentException if the carrier type is not supported.
*/
static ValueLayout valueLayout(Class<?> carrier, ByteOrder order) {
@ -709,48 +642,55 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
}
/**
* Create a new sequence layout with given element layout and element count.
* 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:
*
* @param elementCount the sequence 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 elementLayout the sequence element layout.
* @return the new sequence layout with given element layout and size.
* @throws IllegalArgumentException if {@code elementCount < 0}.
* @return the new sequence layout with the given element layout and size.
* @throws IllegalArgumentException if {@code elementCount < -1}.
* @throws IllegalArgumentException if {@code elementCount != -1} and the computation {@code elementCount * elementLayout.bitSize()} overflows.
*/
static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) {
if (elementCount == -1) {
// inferred element count
long inferredElementCount = Long.MAX_VALUE / elementLayout.bitSize();
return new SequenceLayout(inferredElementCount, elementLayout);
} else {
// explicit element count
AbstractLayout.checkSize(elementCount, true);
OptionalLong size = OptionalLong.of(elementCount);
return new SequenceLayout(size, Objects.requireNonNull(elementLayout));
return wrapOverflow(() ->
new SequenceLayout(elementCount, Objects.requireNonNull(elementLayout)));
}
}
/**
* Create a new sequence layout, with unbounded element count and given element layout.
* Creates a struct layout with the given member layouts.
*
* @param elementLayout the element layout of the sequence layout.
* @return the new sequence layout with given element layout.
*/
static SequenceLayout sequenceLayout(MemoryLayout elementLayout) {
return new SequenceLayout(OptionalLong.empty(), Objects.requireNonNull(elementLayout));
}
/**
* Create a new <em>struct</em> group layout with given member layouts.
*
* @param elements The member layouts of the <em>struct</em> group layout.
* @return a new <em>struct</em> group layout with given member layouts.
* @param elements The member layouts of the struct layout.
* @return a struct layout with the given member layouts.
* @throws IllegalArgumentException if the sum of the {@linkplain #bitSize() bit sizes} of the member layouts
* overflows.
*/
static GroupLayout structLayout(MemoryLayout... elements) {
Objects.requireNonNull(elements);
return new GroupLayout(GroupLayout.Kind.STRUCT,
return wrapOverflow(() ->
new GroupLayout(GroupLayout.Kind.STRUCT,
Stream.of(elements)
.map(Objects::requireNonNull)
.collect(Collectors.toList()));
.collect(Collectors.toList())));
}
/**
* Create a new <em>union</em> group layout with given member layouts.
* Creates a union layout with the given member layouts.
*
* @param elements The member layouts of the <em>union</em> layout.
* @return a new <em>union</em> group layout with given member layouts.
* @param elements The member layouts of the union layout.
* @return a union layout with the given member layouts.
*/
static GroupLayout unionLayout(MemoryLayout... elements) {
Objects.requireNonNull(elements);
@ -759,4 +699,12 @@ public sealed interface MemoryLayout extends Constable permits AbstractLayout, S
.map(Objects::requireNonNull)
.collect(Collectors.toList()));
}
private static <L extends MemoryLayout> L wrapOverflow(Supplier<L> layoutSupplier) {
try {
return layoutSupplier.get();
} catch (ArithmeticException ex) {
throw new IllegalArgumentException("Layout size exceeds Long.MAX_VALUE");
}
}
}

View file

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

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,30 +23,17 @@
* questions.
*
*/
package jdk.incubator.foreign;
package java.lang.foreign;
import java.lang.constant.ConstantDescs;
import java.lang.constant.DynamicConstantDesc;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalLong;
/**
* 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.
* <p>
* This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
* class; programmers should treat instances that are
* {@linkplain #equals(Object) equal} as interchangeable and should not
* use instances for synchronization, or unpredictable behavior may
* occur. For example, in a future release, synchronization may fail.
* The {@code equals} method should be used for comparisons.
*
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
*
* @implSpec
* This class is immutable and thread-safe.
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*/
/* package-private */ final class PaddingLayout extends AbstractLayout implements MemoryLayout {
@ -55,7 +42,7 @@ import java.util.OptionalLong;
}
PaddingLayout(long size, long alignment, Optional<String> name) {
super(OptionalLong.of(size), alignment, name);
super(size, alignment, name);
}
@Override
@ -92,12 +79,6 @@ import java.util.OptionalLong;
return true;
}
@Override
public Optional<DynamicConstantDesc<MemoryLayout>> describeConstable() {
return Optional.of(decorateLayoutConstant(DynamicConstantDesc.ofNamed(ConstantDescs.BSM_INVOKE, "padding",
CD_MEMORY_LAYOUT, MH_PADDING, bitSize())));
}
//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

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* 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
@ -23,12 +23,7 @@
* questions.
*/
package jdk.incubator.foreign;
import jdk.internal.foreign.AbstractMemorySegmentImpl;
import jdk.internal.foreign.ArenaAllocator;
import jdk.internal.foreign.ResourceScopeImpl;
import jdk.internal.foreign.Utils;
package java.lang.foreign;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Array;
@ -36,33 +31,36 @@ import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.function.Function;
import jdk.internal.foreign.AbstractMemorySegmentImpl;
import jdk.internal.foreign.ArenaAllocator;
import jdk.internal.foreign.Utils;
import jdk.internal.javac.PreviewFeature;
/**
* This interface models a memory allocator. Clients implementing this interface
* An object that may be used to allocate {@linkplain MemorySegment memory segments}. Clients implementing this interface
* must implement the {@link #allocate(long, long)} method. This interface defines several default methods
* which can be useful to create segments from several kinds of Java values such as primitives and arrays.
* This interface can be seen as a thin wrapper around the basic capabilities for
* {@linkplain MemorySegment#allocateNative(long, long, ResourceScope) creating} native segments;
* since {@link SegmentAllocator} is a <em>functional interface</em>,
* clients can easily obtain a native allocator by using either a lambda expression or a method reference.
* This interface is a {@linkplain FunctionalInterface functional interface}: clients can easily obtain a new segment allocator
* by using either a lambda expression or a method reference.
* <p>
* This interface also defines factories for commonly used allocators:
* <ul>
* <li>{@link #nativeAllocator(ResourceScope)} creates an allocator which
* {@linkplain MemorySegment#allocateNative(long, long, ResourceScope) allocates} native segments, backed by a given scope;</li>
* <li>{@link #newNativeArena(ResourceScope)} creates a more efficient arena-style native allocator, where memory
* <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 #prefixAllocator(MemorySegment)} creates an allocator which wraps a segment (either on-heap or off-heap)
* <li>{@link #implicitAllocator()} obtains an allocator which allocates native memory segment in independent,
* {@linkplain MemorySession#openImplicit() implicit memory sessions}; and</li>
* <li>{@link #prefixAllocator(MemorySegment)} obtains an allocator which wraps a segment (either on-heap or off-heap)
* and recycles its content upon each new allocation request.</li>
* </ul>
* <p>
* Passing a segment allocator to an API can be especially useful in circumstances where a client wants to communicate <em>where</em>
* the results of a certain operation (performed by the API) should be stored, as a memory segment. For instance,
* {@linkplain CLinker#downcallHandle(FunctionDescriptor) downcall method handles} can accept an additional
* {@link SegmentAllocator} parameter if the underlying native 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 native function.
* {@linkplain Linker#downcallHandle(FunctionDescriptor) downcall method handles} can accept an additional
* {@link SegmentAllocator} parameter if the underlying foreign function is known to return a struct by-value. Effectively,
* the allocator parameter tells the linker runtime where to store the return value of the foreign function.
*/
@FunctionalInterface
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public interface SegmentAllocator {
/**
@ -85,7 +83,7 @@ public interface SegmentAllocator {
}
/**
* Allocate a memory segment with given layout and initialize it with given byte value.
* Allocates a memory segment with the given layout and initializes it with the given byte value.
* @implSpec the default implementation for this method calls {@code this.allocate(layout)}.
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set on the newly allocated memory block.
@ -100,7 +98,7 @@ public interface SegmentAllocator {
}
/**
* Allocate a memory segment with given layout and initialize it with given char value.
* Allocates a memory segment with the given layout and initializes it with the given char value.
* @implSpec the default implementation for this method calls {@code this.allocate(layout)}.
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set on the newly allocated memory block.
@ -115,7 +113,7 @@ public interface SegmentAllocator {
}
/**
* Allocate a memory segment with given layout and initialize it with given short value.
* Allocates a memory segment with the given layout and initializes it with the given short value.
* @implSpec the default implementation for this method calls {@code this.allocate(layout)}.
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set on the newly allocated memory block.
@ -130,7 +128,7 @@ public interface SegmentAllocator {
}
/**
* Allocate a memory segment with given layout and initialize it with given int value.
* Allocates a memory segment with the given layout and initializes it with the given int value.
* @implSpec the default implementation for this method calls {@code this.allocate(layout)}.
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set on the newly allocated memory block.
@ -145,7 +143,7 @@ public interface SegmentAllocator {
}
/**
* Allocate a memory segment with given layout and initialize it with given float value.
* Allocates a memory segment with the given layout and initializes it with the given float value.
* @implSpec the default implementation for this method calls {@code this.allocate(layout)}.
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set on the newly allocated memory block.
@ -160,7 +158,7 @@ public interface SegmentAllocator {
}
/**
* Allocate a memory segment with given layout and initialize it with given long value.
* Allocates a memory segment with the given layout and initializes it with the given long value.
* @implSpec the default implementation for this method calls {@code this.allocate(layout)}.
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set on the newly allocated memory block.
@ -175,7 +173,7 @@ public interface SegmentAllocator {
}
/**
* Allocate a memory segment with given layout and initialize it with given double value.
* Allocates a memory segment with the given layout and initializes it with the given double value.
* @implSpec the default implementation for this method calls {@code this.allocate(layout)}.
* @param layout the layout of the block of memory to be allocated.
* @param value the value to be set on the newly allocated memory block.
@ -190,8 +188,7 @@ public interface SegmentAllocator {
}
/**
* Allocate a memory segment with given layout and initialize it with given address value
* (expressed as an {@link Addressable} instance).
* Allocates a memory segment with the given layout and initializes it with the given address value.
* The address value might be narrowed according to the platform address size (see {@link ValueLayout#ADDRESS}).
* @implSpec the default implementation for this method calls {@code this.allocate(layout)}.
* @param layout the layout of the block of memory to be allocated.
@ -207,80 +204,80 @@ public interface SegmentAllocator {
}
/**
* Allocate a memory segment with given layout and initialize it with given byte array.
* Allocates a memory segment with the given layout and initializes it with the given byte elements.
* @implSpec the default implementation for this method calls {@code this.allocateArray(layout, array.length)}.
* @param elementLayout the element layout of the array to be allocated.
* @param array the array to be copied on the newly allocated memory block.
* @param elements the byte elements to be copied to the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocateArray(ValueLayout.OfByte elementLayout, byte[] array) {
return copyArrayWithSwapIfNeeded(array, elementLayout, MemorySegment::ofArray);
default MemorySegment allocateArray(ValueLayout.OfByte elementLayout, byte... elements) {
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
}
/**
* Allocate a memory segment with given layout and initialize it with given short array.
* Allocates a memory segment with the given layout and initializes it with the given short elements.
* @implSpec the default implementation for this method calls {@code this.allocateArray(layout, array.length)}.
* @param elementLayout the element layout of the array to be allocated.
* @param array the array to be copied on the newly allocated memory block.
* @param elements the short elements to be copied to the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocateArray(ValueLayout.OfShort elementLayout, short[] array) {
return copyArrayWithSwapIfNeeded(array, elementLayout, MemorySegment::ofArray);
default MemorySegment allocateArray(ValueLayout.OfShort elementLayout, short... elements) {
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
}
/**
* Allocate a memory segment with given layout and initialize it with given char array.
* Allocates a memory segment with the given layout and initializes it with the given char elements.
* @implSpec the default implementation for this method calls {@code this.allocateArray(layout, array.length)}.
* @param elementLayout the element layout of the array to be allocated.
* @param array the array to be copied on the newly allocated memory block.
* @param elements the char elements to be copied to the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocateArray(ValueLayout.OfChar elementLayout, char[] array) {
return copyArrayWithSwapIfNeeded(array, elementLayout, MemorySegment::ofArray);
default MemorySegment allocateArray(ValueLayout.OfChar elementLayout, char... elements) {
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
}
/**
* Allocate a memory segment with given layout and initialize it with given int array.
* Allocates a memory segment with the given layout and initializes it with the given int elements.
* @implSpec the default implementation for this method calls {@code this.allocateArray(layout, array.length)}.
* @param elementLayout the element layout of the array to be allocated.
* @param array the array to be copied on the newly allocated memory block.
* @param elements the int elements to be copied to the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocateArray(ValueLayout.OfInt elementLayout, int[] array) {
return copyArrayWithSwapIfNeeded(array, elementLayout, MemorySegment::ofArray);
default MemorySegment allocateArray(ValueLayout.OfInt elementLayout, int... elements) {
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
}
/**
* Allocate a memory segment with given layout and initialize it with given float array.
* Allocates a memory segment with the given layout and initializes it with the given float elements.
* @implSpec the default implementation for this method calls {@code this.allocateArray(layout, array.length)}.
* @param elementLayout the element layout of the array to be allocated.
* @param array the array to be copied on the newly allocated memory block.
* @param elements the float elements to be copied to the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocateArray(ValueLayout.OfFloat elementLayout, float[] array) {
return copyArrayWithSwapIfNeeded(array, elementLayout, MemorySegment::ofArray);
default MemorySegment allocateArray(ValueLayout.OfFloat elementLayout, float... elements) {
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
}
/**
* Allocate a memory segment with given layout and initialize it with given long array.
* Allocates a memory segment with the given layout and initializes it with the given long elements.
* @implSpec the default implementation for this method calls {@code this.allocateArray(layout, array.length)}.
* @param elementLayout the element layout of the array to be allocated.
* @param array the array to be copied on the newly allocated memory block.
* @param elements the long elements to be copied to the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocateArray(ValueLayout.OfLong elementLayout, long[] array) {
return copyArrayWithSwapIfNeeded(array, elementLayout, MemorySegment::ofArray);
default MemorySegment allocateArray(ValueLayout.OfLong elementLayout, long... elements) {
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
}
/**
* Allocate a memory segment with given layout and initialize it with given double array.
* Allocates a memory segment with the given layout and initializes it with the given double elements.
* @implSpec the default implementation for this method calls {@code this.allocateArray(layout, array.length)}.
* @param elementLayout the element layout of the array to be allocated.
* @param array the array to be copied on the newly allocated memory block.
* @param elements the double elements to be copied to the newly allocated memory block.
* @return a segment for the newly allocated memory block.
*/
default MemorySegment allocateArray(ValueLayout.OfDouble elementLayout, double[] array) {
return copyArrayWithSwapIfNeeded(array, elementLayout, MemorySegment::ofArray);
default MemorySegment allocateArray(ValueLayout.OfDouble elementLayout, double... elements) {
return copyArrayWithSwapIfNeeded(elements, elementLayout, MemorySegment::ofArray);
}
private <Z> MemorySegment copyArrayWithSwapIfNeeded(Z array, ValueLayout elementLayout,
@ -295,7 +292,7 @@ public interface SegmentAllocator {
}
/**
* Allocate a memory segment with given layout.
* Allocates a memory segment with the given layout.
* @implSpec the default implementation for this method calls {@code this.allocate(layout.byteSize(), layout.byteAlignment())}.
* @param layout the layout of the block of memory to be allocated.
* @return a segment for the newly allocated memory block.
@ -306,11 +303,12 @@ public interface SegmentAllocator {
}
/**
* Allocate a memory segment with given element layout and size.
* Allocates a memory segment with the given element layout and size.
* @implSpec the default implementation for this method calls {@code this.allocate(MemoryLayout.sequenceLayout(count, elementLayout))}.
* @param elementLayout the array element layout.
* @param count the array element count.
* @return a segment for the newly allocated memory block.
* @throws IllegalArgumentException if {@code count < 0}.
*/
default MemorySegment allocateArray(MemoryLayout elementLayout, long count) {
Objects.requireNonNull(elementLayout);
@ -318,68 +316,74 @@ public interface SegmentAllocator {
}
/**
* Allocate a memory segment with given size
* and default alignment constraints (1-byte aligned).
* Allocates a memory segment with the given size.
* @implSpec the default implementation for this method calls {@code this.allocate(bytesSize, 1)}.
* @param bytesSize the size (in bytes) of the block of memory to be allocated.
* @return a segment for the newly allocated memory block.
* @throws IllegalArgumentException if {@code bytesSize < 0}
*/
default MemorySegment allocate(long bytesSize) {
return allocate(bytesSize, 1);
}
/**
* Allocate a memory segment with given size and alignment constraints.
* Allocates a memory segment with the given size and alignment constraints.
* @param bytesSize the size (in bytes) of the block of memory to be allocated.
* @param bytesAlignment the alignment (in bytes) of the block of memory to be allocated.
* @return a segment for the newly allocated memory block.
* @throws IllegalArgumentException if {@code bytesSize < 0}, {@code alignmentBytes <= 0},
* or if {@code alignmentBytes} is not a power of 2.
*/
MemorySegment allocate(long bytesSize, long bytesAlignment);
/**
* Returns a native unbounded arena-based allocator, with predefined block size and maximum arena size,
* associated with the provided scope. Equivalent to the following code:
* 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, scope);
* SegmentAllocator.newNativeArena(Long.MAX_VALUE, predefinedBlockSize, session);
* }
*
* @param scope the scope associated with the segments returned by the arena-based allocator.
* @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 scope} has been already closed, or if access occurs from a thread other
* than the thread owning {@code scope}.
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}.
*/
static SegmentAllocator newNativeArena(ResourceScope scope) {
return newNativeArena(Long.MAX_VALUE, ArenaAllocator.DEFAULT_BLOCK_SIZE, scope);
static SegmentAllocator newNativeArena(MemorySession session) {
return newNativeArena(Long.MAX_VALUE, ArenaAllocator.DEFAULT_BLOCK_SIZE, session);
}
/**
* Returns a native unbounded arena-based allocator, with block size set to the specified arena size, associated with
* the provided scope, with given arena size. Equivalent to the following code:
* 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, scope);
* SegmentAllocator.newNativeArena(arenaSize, arenaSize, session);
* }
*
* @param arenaSize the size (in bytes) of the allocation arena.
* @param scope the scope associated with the segments returned by the arena-based allocator.
* @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 scope} has been already closed, or if access occurs from a thread other
* than the thread owning {@code scope}.
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}.
*/
static SegmentAllocator newNativeArena(long arenaSize, ResourceScope scope) {
return newNativeArena(arenaSize, arenaSize, scope);
static SegmentAllocator newNativeArena(long arenaSize, MemorySession session) {
return newNativeArena(arenaSize, arenaSize, session);
}
/**
* Returns a native arena-based allocator, associated with the provided scope, with given arena size and block size.
* Creates an arena-based allocator used to allocate native memory segments. The returned allocator features
* the given block size {@code B} and the given arena size {@code A}, and the native segments
* it allocates are associated with the provided memory session.
* <p>
* The returned allocator {@linkplain MemorySegment#allocateNative(long, ResourceScope) allocates} a memory segment
* {@code S} of the specified block size and then responds to allocation requests in one of the following ways:
* 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'}, which has same size as {@code S}
* 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'}.
@ -389,31 +393,31 @@ public interface SegmentAllocator {
* 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, or the system capacity. Furthermore, the returned allocator is not thread safe.
* exceeds the arena size {@code A}, or the system capacity. Furthermore, the returned allocator is not thread safe.
* Concurrent allocation needs to be guarded with synchronization primitives.
*
* @param arenaSize the size (in bytes) of the allocation arena.
* @param blockSize the block size associated with the arena-based allocator.
* @param scope the scope associated with the segments returned by 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 scope} has been already closed, or if access occurs from a thread other
* than the thread owning {@code scope}.
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}.
*/
static SegmentAllocator newNativeArena(long arenaSize, long blockSize, ResourceScope scope) {
Objects.requireNonNull(scope);
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, scope);
return new ArenaAllocator(blockSize, arenaSize, session);
}
/**
* Returns a segment allocator which responds to allocation requests by recycling a single segment; that is,
* each new allocation request will return a new slice starting at the segment offset {@code 0} (alignment
* Returns a segment allocator which responds to allocation requests by recycling a single segment. Each
* new allocation request will return a new slice starting at the segment offset {@code 0} (alignment
* constraints are ignored by this allocator), hence the name <em>prefix allocator</em>.
* Equivalent to (but likely more efficient than) the following code:
* {@snippet lang=java :
@ -437,34 +441,18 @@ public interface SegmentAllocator {
}
/**
* Returns a native allocator, associated with the provided scope. Equivalent to (but likely more efficient than)
* the following code:
* {@snippet lang=java :
* ResourceScope scope = ...
* SegmentAllocator nativeAllocator = (size, align) -> MemorySegment.allocateNative(size, align, scope);
* }
*
* @param scope the scope associated with the returned allocator.
* @return a native allocator, associated with the provided scope.
*/
static SegmentAllocator nativeAllocator(ResourceScope scope) {
Objects.requireNonNull(scope);
return (ResourceScopeImpl)scope;
}
/**
* Returns a native allocator which allocates segments in independent {@linkplain ResourceScope#newImplicitScope() implicit scopes}.
* 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, ResourceScope.newImplicitScope());
* SegmentAllocator implicitAllocator = (size, align) -> MemorySegment.allocateNative(size, align, MemorySession.openImplicit());
* }
*
* @return a native allocator which allocates segments in independent {@linkplain ResourceScope#newImplicitScope() implicit scopes}.
* @return an allocator which allocates native segments in independent {@linkplain MemorySession#openImplicit() implicit memory sessions}.
*/
static SegmentAllocator implicitAllocator() {
class Holder {
static final SegmentAllocator IMPLICIT_ALLOCATOR = (size, align) ->
MemorySegment.allocateNative(size, align, ResourceScope.newImplicitScope());
MemorySegment.allocateNative(size, align, MemorySession.openImplicit());
}
return Holder.IMPLICIT_ALLOCATOR;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,19 +23,18 @@
* questions.
*
*/
package jdk.incubator.foreign;
package java.lang.foreign;
import java.lang.constant.ConstantDescs;
import java.lang.constant.DynamicConstantDesc;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalLong;
import jdk.internal.javac.PreviewFeature;
/**
* A sequence layout. A sequence layout is used to denote a repetition of a given layout, also called the sequence layout's <em>element layout</em>.
* The repetition count, where it exists (e.g. for <em>finite</em> sequence layouts) is said to be the sequence layout's <em>element count</em>.
* A finite sequence layout can be thought of as a group layout where the sequence layout's element layout is repeated a number of times
* that is equal to the sequence layout's element count. In other words this layout:
* A compound layout that denotes a repetition of a given <em>element layout</em>.
* The repetition count is said to be the sequence layout's <em>element count</em>. A finite sequence can be thought of as a
* group layout where the sequence layout's element layout is repeated a number of times that is equal to the sequence
* layout's element count. In other words this layout:
*
* {@snippet lang=java :
* MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN));
@ -50,33 +49,23 @@ import java.util.OptionalLong;
* ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN));
* }
*
* <p>
* This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
* class; programmers should treat instances that are
* {@linkplain #equals(Object) equal} as interchangeable and should not
* use instances for synchronization, or unpredictable behavior may
* occur. For example, in a future release, synchronization may fail.
* The {@code equals} method should be used for comparisons.
*
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
*
* @implSpec
* This class is immutable and thread-safe.
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public final class SequenceLayout extends AbstractLayout implements MemoryLayout {
private final OptionalLong elemCount;
private final long elemCount;
private final MemoryLayout elementLayout;
SequenceLayout(OptionalLong elemCount, MemoryLayout elementLayout) {
SequenceLayout(long elemCount, MemoryLayout elementLayout) {
this(elemCount, elementLayout, elementLayout.bitAlignment(), Optional.empty());
}
SequenceLayout(OptionalLong elemCount, MemoryLayout elementLayout, long alignment, Optional<String> name) {
super(elemCount.isPresent() && AbstractLayout.optSize(elementLayout).isPresent() ?
OptionalLong.of(elemCount.getAsLong() * elementLayout.bitSize()) :
OptionalLong.empty(), alignment, name);
SequenceLayout(long elemCount, MemoryLayout elementLayout, long alignment, Optional<String> name) {
super(Math.multiplyExact(elemCount, elementLayout.bitSize()), alignment, name);
this.elemCount = elemCount;
this.elementLayout = elementLayout;
}
@ -89,26 +78,27 @@ public final class SequenceLayout extends AbstractLayout implements MemoryLayout
}
/**
* {@return the element count of this sequence layout (if any)}
* {@return the element count of this sequence layout}
*/
public OptionalLong elementCount() {
public long elementCount() {
return elemCount;
}
/**
* Obtains a new sequence layout with same element layout, alignment constraints and name as this sequence layout
* but with the new specified element count.
* Returns a sequence layout with the same element layout, alignment constraints and name as this sequence layout,
* but with the specified element count.
* @param elementCount the new element count.
* @return a new sequence with given 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(OptionalLong.of(elementCount), elementLayout, alignment, name());
return new SequenceLayout(elementCount, elementLayout, alignment, name());
}
/**
* Returns a new sequence layout where element layouts in the flattened projection of this
* Re-arrange the elements in this sequence layout into a multi-dimensional sequence layout.
* The resulting layout is a sequence layout where element layouts in the flattened projection of this
* sequence layout (see {@link #flatten()}) are re-arranged into one or more nested sequence layouts
* according to the provided element counts. This transformation preserves the layout size;
* that is, multiplying the provided element counts must yield the same element count
@ -132,7 +122,7 @@ public final class SequenceLayout extends AbstractLayout implements MemoryLayout
* var reshapeSeqImplicit2 = seq.reshape(2, -1);
* }
* @param elementCounts an array of element counts, of which at most one can be {@code -1}.
* @return a new sequence layout where element layouts in the flattened projection of this
* @return a sequence layout where element layouts in the flattened projection of this
* sequence layout (see {@link #flatten()}) are re-arranged into one or more nested sequence layouts.
* @throws UnsupportedOperationException if this sequence layout does not have an element count.
* @throws IllegalArgumentException if two or more element counts are set to {@code -1}, or if one
@ -145,11 +135,8 @@ public final class SequenceLayout extends AbstractLayout implements MemoryLayout
if (elementCounts.length == 0) {
throw new IllegalArgumentException();
}
if (elementCount().isEmpty()) {
throw new UnsupportedOperationException("Cannot reshape a sequence layout whose element count is unspecified");
}
SequenceLayout flat = flatten();
long expectedCount = flat.elementCount().getAsLong();
long expectedCount = flat.elementCount();
long actualCount = 1;
int inferPosition = -1;
@ -186,8 +173,8 @@ public final class SequenceLayout extends AbstractLayout implements MemoryLayout
}
/**
* Returns a new, flattened sequence layout whose element layout is the first non-sequence
* element layout found by recursively traversing the element layouts of this sequence layout.
* Returns a flattened sequence layout. The element layout of the returned sequence layout
* is the first non-sequence element layout found by recursively traversing the element layouts of this sequence layout.
* This transformation preserves the layout size; nested sequence layout in this sequence layout will
* be dropped and their element counts will be incorporated into that of the returned sequence layout.
* For instance, given a sequence layout of the kind:
@ -198,32 +185,25 @@ public final class SequenceLayout extends AbstractLayout implements MemoryLayout
* {@snippet lang=java :
* var flattenedSeq = MemoryLayout.sequenceLayout(12, ValueLayout.JAVA_INT);
* }
* @return a new sequence layout with the same size as this layout (but, possibly, with different
* @return a sequence layout with the same size as this layout (but, possibly, with different
* element count), whose element layout is not a sequence layout.
* @throws UnsupportedOperationException if this sequence layout, or one of the nested sequence layouts being
* flattened, does not have an element count.
*/
public SequenceLayout flatten() {
if (elementCount().isEmpty()) {
throw badUnboundSequenceLayout();
}
long count = elementCount().getAsLong();
long count = elementCount();
MemoryLayout elemLayout = elementLayout();
while (elemLayout instanceof SequenceLayout elemSeq) {
count = count * elemSeq.elementCount().orElseThrow(this::badUnboundSequenceLayout);
count = count * elemSeq.elementCount();
elemLayout = elemSeq.elementLayout();
}
return MemoryLayout.sequenceLayout(count, elemLayout);
}
private UnsupportedOperationException badUnboundSequenceLayout() {
return new UnsupportedOperationException("Cannot flatten a sequence layout whose element count is unspecified");
}
@Override
public String toString() {
return decorateLayoutString(String.format("[%s:%s]",
elemCount.isPresent() ? elemCount.getAsLong() : "", elementLayout));
elemCount, elementLayout));
}
@Override
@ -237,7 +217,7 @@ public final class SequenceLayout extends AbstractLayout implements MemoryLayout
if (!(other instanceof SequenceLayout s)) {
return false;
}
return elemCount.equals(s.elemCount) && elementLayout.equals(s.elementLayout);
return elemCount == s.elemCount && elementLayout.equals(s.elementLayout);
}
@Override
@ -255,15 +235,6 @@ public final class SequenceLayout extends AbstractLayout implements MemoryLayout
return alignment == elementLayout.bitAlignment();
}
@Override
public Optional<DynamicConstantDesc<SequenceLayout>> describeConstable() {
return Optional.of(decorateLayoutConstant(elemCount.isPresent() ?
DynamicConstantDesc.ofNamed(ConstantDescs.BSM_INVOKE, "value",
CD_SEQUENCE_LAYOUT, MH_SIZED_SEQUENCE, elemCount.getAsLong(), elementLayout.describeConstable().get()) :
DynamicConstantDesc.ofNamed(ConstantDescs.BSM_INVOKE, "value",
CD_SEQUENCE_LAYOUT, MH_UNSIZED_SEQUENCE, elementLayout.describeConstable().get())));
}
//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

View file

@ -0,0 +1,252 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang.foreign;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.foreign.MemorySessionImpl;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.loader.BuiltinClassLoader;
import jdk.internal.loader.NativeLibrary;
import jdk.internal.loader.RawNativeLibraries;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import java.lang.invoke.MethodHandles;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
/**
* A <em>symbol lookup</em> is an object that may be used to retrieve the address of a symbol in one or more libraries.
* A symbol is a named entity, such as a function or a global variable.
* <p>
* A symbol lookup is created with respect to a particular library (or libraries). Subsequently, the {@link SymbolLookup#lookup(String)}
* method takes the name of a symbol and returns the address of the symbol in that library.
* <p>
* The address of a symbol is modelled as a zero-length {@linkplain MemorySegment memory segment}. The segment can be used in different ways:
* <ul>
* <li>It can be passed to a {@link Linker} to create a downcall method handle, which can then be used to call the foreign function at the segment's base address.</li>
* <li>It can be passed to an existing {@linkplain Linker#downcallHandle(FunctionDescriptor) downcall method handle}, as an argument to the underlying foreign function.</li>
* <li>It can be {@linkplain MemorySegment#set(ValueLayout.OfAddress, long, Addressable) stored} inside another memory segment.</li>
* <li>It can be used to dereference memory associated with a global variable (this might require
* {@link MemorySegment#ofAddress(MemoryAddress, long, MemorySession) resizing} the segment first).</li>
* </ul>
*
* <h2>Obtaining a symbol lookup</h2>
*
* The factory methods {@link #libraryLookup(String, MemorySession)} and {@link #libraryLookup(Path, MemorySession)}
* create a symbol lookup for a library known to the operating system. The library is specified by either its name or a path.
* The library is loaded if not already loaded. The symbol lookup, which is known as a <em>library lookup</em>, is associated
* with a {@linkplain MemorySession memory session}; when the session is {@linkplain MemorySession#close() closed}, the library is unloaded:
*
* {@snippet lang=java :
* try (MemorySession session = MemorySession.openConfined()) {
* SymbolLookup libGL = SymbolLookup.libraryLookup("libGL.so"); // libGL.so loaded here
* MemorySegment glGetString = libGL.lookup("glGetString").orElseThrow();
* ...
* } // libGL.so unloaded here
* }
* <p>
* If a library was previously loaded through JNI, i.e., by {@link System#load(String)}
* or {@link System#loadLibrary(String)}, then the library was also associated with a particular class loader. The factory
* method {@link #loaderLookup()} creates a symbol lookup for all the libraries associated with the caller's class loader:
*
* {@snippet lang=java :
* System.loadLibrary("GL"); // libGL.so loaded here
* ...
* SymbolLookup libGL = SymbolLookup.loaderLookup();
* MemorySegment glGetString = libGL.lookup("glGetString").orElseThrow();
* }
*
* This symbol lookup, which is known as a <em>loader lookup</em>, is dynamic with respect to the libraries associated
* with the class loader. If other libraries are subsequently loaded through JNI and associated with the class loader,
* then the loader lookup will expose their symbols automatically.
* <p>
* Note that a loader lookup only exposes symbols in libraries that were previously loaded through JNI, i.e.,
* by {@link System#load(String)} or {@link System#loadLibrary(String)}. A loader lookup does not expose symbols in libraries
* that were loaded in the course of creating a library lookup:
*
* {@snippet lang=java :
* libraryLookup("libGL.so", session).lookup("glGetString").isPresent(); // true
* loaderLookup().lookup("glGetString").isPresent(); // false
* }
*
* Note also that a library lookup for library {@code L} exposes symbols in {@code L} even if {@code L} was previously loaded
* through JNI (the association with a class loader is immaterial to the library lookup):
*
* {@snippet lang=java :
* System.loadLibrary("GL"); // libGL.so loaded here
* libraryLookup("libGL.so", session).lookup("glGetString").isPresent(); // true
* }
*
* <p>
* Finally, each {@link Linker} provides a symbol lookup for libraries that are commonly used on the OS and processor
* combination supported by that {@link Linker}. This symbol lookup, which is known as a <em>default lookup</em>,
* helps clients to quickly find addresses of well-known symbols. For example, a {@link Linker} for Linux/x64 might choose to
* expose symbols in {@code libc} through the default lookup:
*
* {@snippet lang=java :
* Linker nativeLinker = Linker.nativeLinker();
* SymbolLookup stdlib = nativeLinker.defaultLookup();
* MemorySegment malloc = stdlib.lookup("malloc").orElseThrow();
* }
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
@FunctionalInterface
public interface SymbolLookup {
/**
* Returns the address of the symbol with the given name.
* @param name the symbol name.
* @return a zero-length memory segment whose base address indicates the address of the symbol, if found.
*/
Optional<MemorySegment> lookup(String name);
/**
* Returns a symbol lookup for symbols in the libraries associated with the caller's class loader.
* <p>
* A library is associated with a class loader {@code CL} when the library is loaded via an invocation of
* {@link System#load(String)} or {@link System#loadLibrary(String)} from code in a class defined by {@code CL}.
* If that code makes further invocations of {@link System#load(String)} or {@link System#loadLibrary(String)},
* then more libraries are loaded and associated with {@code CL}. The symbol lookup returned by this method is always
* current: it reflects all the libraries associated with the relevant class loader, even if they were loaded after
* this method returned.
* <p>
* Libraries associated with a class loader are unloaded when the class loader becomes
* <a href="../../../java/lang/ref/package.html#reachability">unreachable</a>. The symbol lookup
* returned by this method is backed by a {@linkplain MemorySession#asNonCloseable() non-closeable}, shared memory
* session which keeps the caller's class loader reachable. Therefore, libraries associated with the caller's class
* loader are kept loaded (and their symbols available) as long as a loader lookup for that class loader is reachable.
* <p>
* In cases where this method is called from a context where there is no caller frame on the stack
* (e.g. when called directly from a JNI attached thread), the caller's class loader defaults to the
* {@linkplain ClassLoader#getSystemClassLoader system class loader}.
*
* @return a symbol lookup for symbols in the libraries associated with the caller's class loader.
* @see System#load(String)
* @see System#loadLibrary(String)
*/
@CallerSensitive
static SymbolLookup loaderLookup() {
Class<?> caller = Reflection.getCallerClass();
// If there's no caller class, fallback to system loader
ClassLoader loader = caller != null ?
caller.getClassLoader() :
ClassLoader.getSystemClassLoader();
MemorySession loaderSession = (loader == null || loader instanceof BuiltinClassLoader) ?
MemorySession.global() : // builtin loaders never go away
MemorySessionImpl.heapSession(loader);
return name -> {
Objects.requireNonNull(name);
JavaLangAccess javaLangAccess = SharedSecrets.getJavaLangAccess();
// note: ClassLoader::findNative supports a null loader
MemoryAddress addr = MemoryAddress.ofLong(javaLangAccess.findNative(loader, name));
return addr == MemoryAddress.NULL ?
Optional.empty() :
Optional.of(MemorySegment.ofAddress(addr, 0L, loaderSession));
};
}
/**
* Loads a library with the given name (if not already loaded) and creates a symbol lookup for symbols in that library.
* The library will be unloaded when the provided memory session is {@linkplain MemorySession#close() closed},
* if no other library lookup is still using it.
* @implNote The process of resolving a library name is OS-specific. For instance, in a POSIX-compliant OS,
* the library name is resolved according to the specification of the {@code dlopen} function for that OS.
* In Windows, the library name is resolved according to the specification of the {@code LoadLibrary} function.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
* restricted methods, and use safe and supported functionalities, where possible.
*
* @param name the name of the library in which symbols should be looked up.
* @param session the memory session which controls the library lifecycle.
* @return a new symbol lookup suitable to find symbols in a library with the given name.
* @throws IllegalArgumentException if {@code name} does not identify a valid library.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
static SymbolLookup libraryLookup(String name, MemorySession session) {
Reflection.ensureNativeAccess(Reflection.getCallerClass(), SymbolLookup.class, "libraryLookup");
return libraryLookup(name, RawNativeLibraries::load, session);
}
/**
* Loads a library from the given path (if not already loaded) and creates a symbol lookup for symbols
* in that library. The library will be unloaded when the provided memory session is {@linkplain MemorySession#close() closed},
* if no other library lookup is still using it.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
* restricted methods, and use safe and supported functionalities, where possible.
*
* @implNote On Linux, the functionalities provided by this factory method and the returned symbol lookup are
* implemented using the {@code dlopen}, {@code dlsym} and {@code dlclose} functions.
* @param path the path of the library in which symbols should be looked up.
* @param session the memory session which controls the library lifecycle.
* @return a new symbol lookup suitable to find symbols in a library with the given path.
* @throws IllegalArgumentException if {@code path} does not point to a valid library.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/
@CallerSensitive
static SymbolLookup libraryLookup(Path path, MemorySession session) {
Reflection.ensureNativeAccess(Reflection.getCallerClass(), SymbolLookup.class, "libraryLookup");
return libraryLookup(path, RawNativeLibraries::load, session);
}
private static <Z> SymbolLookup libraryLookup(Z libDesc, BiFunction<RawNativeLibraries, Z, NativeLibrary> loadLibraryFunc, MemorySession session) {
Objects.requireNonNull(libDesc);
Objects.requireNonNull(session);
// attempt to load native library from path or name
RawNativeLibraries nativeLibraries = RawNativeLibraries.newInstance(MethodHandles.lookup());
NativeLibrary library = loadLibraryFunc.apply(nativeLibraries, libDesc);
if (library == null) {
throw new IllegalArgumentException("Cannot open library: " + libDesc);
}
// register hook to unload library when session is closed
MemorySessionImpl.toSessionImpl(session).addOrCleanupIfFail(new MemorySessionImpl.ResourceList.ResourceCleanup() {
@Override
public void cleanup() {
nativeLibraries.unload(library);
}
});
return name -> {
Objects.requireNonNull(name);
MemoryAddress addr = MemoryAddress.ofLong(library.find(name));
return addr == MemoryAddress.NULL
? Optional.empty() :
Optional.of(MemorySegment.ofAddress(addr, 0L, session));
};
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* 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
@ -23,49 +23,55 @@
* questions.
*
*/
package jdk.incubator.foreign;
package java.lang.foreign;
import java.util.Objects;
import java.util.function.Consumer;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64VaList;
import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64VaList;
import jdk.internal.foreign.abi.x64.sysv.SysVVaList;
import jdk.internal.foreign.abi.x64.windows.WinVaList;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import java.util.Objects;
import java.util.function.Consumer;
/**
* An interface that models a variable argument list, similar in functionality to a C {@code va_list}.
* A variable argument list, similar in functionality to a C {@code va_list}.
* <p>
* A variable argument list is a stateful cursor used to iterate over a set of arguments. A variable argument list
* can be passed by reference e.g. to a {@linkplain CLinker#downcallHandle(FunctionDescriptor) downcall method handle}.
* can be passed by reference e.g. to a {@linkplain Linker#downcallHandle(FunctionDescriptor) downcall method handle}.
* <p>
* Per the C specification (see C standard 6.5.2.2 Function calls - item 6),
* Per the C specification (see C99 standard 6.5.2.2 Function calls - item 6),
* arguments to variadic calls are erased by way of 'default argument promotions',
* which erases integral types by way of integer promotion (see C standard 6.3.1.1 - item 2),
* which erases integral types by way of integer promotion (see C99 standard 6.3.1.1 - item 2),
* and which erases all {@code float} arguments to {@code double}.
* <p>
* As such, this interface only supports reading {@code int}, {@code double},
* and any other type that fits into a {@code long}.
*
* This class is not thread safe, and all accesses should occur within a single thread
* (regardless of the scope associated with the variable arity list).
* (regardless of the memory session associated with the variable arity list).
*
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
sealed public interface VaList extends Addressable permits WinVaList, SysVVaList, LinuxAArch64VaList, MacOsAArch64VaList, SharedUtils.EmptyVaList {
/**
* {@return the memory session associated with this variable argument list}
*/
MemorySession session();
/**
* Reads the next value as an {@code int} and advances this variable argument list's position. The behavior of this
* method is equivalent to the C {@code va_arg} function.
*
* @param layout the layout of the value to be read.
* @return the {@code int} value read from this variable argument list.
* @throws IllegalStateException if the scope associated with this variable argument list has been closed, or if access occurs from
* a thread other than the thread owning that scope.
* @throws IllegalStateException if the {@linkplain #session() session} associated with this variable argument list is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
int nextVarg(ValueLayout.OfInt layout);
@ -75,8 +81,8 @@ 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 scope associated with this variable argument list has been closed, or if access occurs from
* a thread other than the thread owning that scope.
* @throws IllegalStateException if the {@linkplain #session() session} associated with this variable argument list is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
long nextVarg(ValueLayout.OfLong layout);
@ -86,8 +92,8 @@ 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 scope associated with this variable argument list has been closed, or if access occurs from
* a thread other than the thread owning that scope.
* @throws IllegalStateException if the {@linkplain #session() session} associated with this variable argument list is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
double nextVarg(ValueLayout.OfDouble layout);
@ -97,8 +103,8 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
*
* @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 scope associated with this variable argument list has been closed, or if access occurs from
* a thread other than the thread owning that scope.
* @throws IllegalStateException if the {@linkplain #session() session} associated with this variable argument list is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
MemoryAddress nextVarg(ValueLayout.OfAddress layout);
@ -117,8 +123,8 @@ 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 scope associated with this variable argument list has been closed, or if access occurs from
* a thread other than the thread owning that scope.
* @throws IllegalStateException if the {@linkplain #session() session} associated with this variable argument list is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
MemorySegment nextVarg(GroupLayout layout, SegmentAllocator allocator);
@ -126,19 +132,14 @@ 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 scope associated with this variable argument list has been closed, or if access occurs from
* a thread other than the thread owning that scope.
* @throws IllegalStateException if the {@linkplain #session() session} associated with this variable argument list is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
void skip(MemoryLayout... layouts);
/**
* {@return the resource scope associated with this variable argument list}
*/
ResourceScope scope();
/**
* Copies this variable argument list at its current position into a new variable argument list associated
* with the same scope as this variable argument list. The behavior of this method is equivalent to the C
* with the same memory session as this variable argument list. The behavior of this method is equivalent to the C
* {@code va_copy} function.
* <p>
* Copying is useful to traverse the variable argument list elements, starting from the current position,
@ -146,22 +147,22 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
* traversed multiple times.
*
* @return a copy of this variable argument list.
* @throws IllegalStateException if the scope associated with this variable argument list has been closed, or if access occurs from
* a thread other than the thread owning that scope.
* @throws IllegalStateException if the {@linkplain #session() session} associated with this variable argument list is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
VaList copy();
/**
* {@return the {@linkplain MemoryAddress memory address} associated with this variable argument list}
* @throws IllegalStateException if the scope associated with this variable argument list has been closed, or if access occurs from
* a thread other than the thread owning that scope.
* @throws IllegalStateException if the {@linkplain #session() session} associated with this variable argument list is not
* {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
@Override
MemoryAddress address();
/**
* Constructs a new variable argument list from a memory address pointing to an existing variable argument list,
* with given resource scope.
* Creates a variable argument list from a memory address pointing to an existing variable argument list,
* with the given memory session.
* <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
@ -169,60 +170,64 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
* restricted methods, and use safe and supported functionalities, where possible.
*
* @param address a memory address pointing to an existing variable argument list.
* @param scope the resource scope to be associated with the returned 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 scope} has been already closed, or if access occurs from a thread other
* than the thread owning {@code scope}.
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}.
* @throws UnsupportedOperationException if the underlying native platform is not supported.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
* {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
* {@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, ResourceScope scope) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
static VaList ofAddress(MemoryAddress address, MemorySession session) {
Reflection.ensureNativeAccess(Reflection.getCallerClass(), VaList.class, "ofAddress");
Objects.requireNonNull(address);
Objects.requireNonNull(scope);
return SharedUtils.newVaListOfAddress(address, scope);
Objects.requireNonNull(session);
return SharedUtils.newVaListOfAddress(address, session);
}
/**
* Constructs a new variable argument list using a builder (see {@link Builder}), with a given resource scope.
* Creates a variable argument list using a builder (see {@link Builder}), with the given
* memory session.
* <p>
* If this method needs to allocate native memory, such memory will be managed by the given
* {@linkplain ResourceScope resource scope}, and will be released when the resource scope is {@linkplain ResourceScope#close closed}.
* If this method needs to allocate memory, such memory will be managed by the given
* memory session, and will be released when the memory session is {@linkplain MemorySession#close closed}.
* <p>
* Note that when there are no elements added to the created va list,
* this method will return the same as {@link #empty()}.
*
* @param actions a consumer for a builder (see {@link Builder}) which can be used to specify the elements
* of the underlying variable argument list.
* @param scope scope the scope to be associated with the new variable arity list.
* @param session the memory session to be associated with the new variable arity list.
* @return a new variable argument list.
* @throws IllegalStateException if {@code scope} has been already closed, or if access occurs from a thread other
* than the thread owning {@code scope}.
* @throws UnsupportedOperationException if the underlying native platform is not supported.
* @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from
* a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}.
*/
static VaList make(Consumer<Builder> actions, ResourceScope scope) {
static VaList make(Consumer<Builder> actions, MemorySession session) {
Objects.requireNonNull(actions);
Objects.requireNonNull(scope);
return SharedUtils.newVaList(actions, scope);
Objects.requireNonNull(session);
return SharedUtils.newVaList(actions, session);
}
/**
* Returns an empty variable argument list, associated with the {@linkplain ResourceScope#globalScope() global}
* scope. The resulting variable argument list does not contain any argument, and throws {@link UnsupportedOperationException}
* on all operations, except for {@link #scope()}, {@link #copy()} and {@link #address()}.
* Returns an empty variable argument list, associated with the {@linkplain MemorySession#global() global}
* memory session. The resulting variable argument list does not contain any argument, and throws {@link UnsupportedOperationException}
* on all operations, except for {@link VaList#address()}, {@link VaList#copy()} and {@link VaList#session()}.
* @return an empty variable argument list.
* @throws UnsupportedOperationException if the underlying native platform is not supported.
*/
static VaList empty() {
return SharedUtils.emptyVaList();
}
/**
* A builder interface used to construct a variable argument list.
* A builder used to construct a {@linkplain VaList variable argument list}.
*
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
sealed interface Builder permits WinVaList.Builder, SysVVaList.Builder, LinuxAArch64VaList.Builder, MacOsAArch64VaList.Builder {
/**
@ -262,7 +267,7 @@ sealed public interface VaList extends Addressable permits WinVaList, SysVVaList
Builder addVarg(ValueLayout.OfAddress layout, Addressable value);
/**
* Writes a {@code MemorySegment} value, with given layout, to the variable argument list being constructed.
* Writes a {@code MemorySegment} value, with the given layout, to the variable argument list being constructed.
*
* @param layout the layout of the value to be written.
* @param value the {@code MemorySegment} whose contents will be copied.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,22 +23,23 @@
* questions.
*
*/
package jdk.incubator.foreign;
package java.lang.foreign;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import jdk.internal.foreign.Utils;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.misc.Unsafe;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Stable;
import sun.invoke.util.Wrapper;
import java.lang.constant.ConstantDescs;
import java.lang.constant.DynamicConstantDesc;
import java.lang.invoke.VarHandle;
import java.nio.ByteOrder;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalLong;
/**
* 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),
@ -49,20 +50,13 @@ import java.util.OptionalLong;
* 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}.
* <p>
* This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>
* class; programmers should treat instances that are
* {@linkplain #equals(Object) equal} as interchangeable and should not
* use instances for synchronization, or unpredictable behavior may
* occur. For example, in a future release, synchronization may fail.
* The {@code equals} method should be used for comparisons.
*
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
*
* @implSpec
* This class is immutable and thread-safe.
* This class and its subclasses are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
private final Class<?> carrier;
@ -75,7 +69,7 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
}
ValueLayout(Class<?> carrier, ByteOrder order, long size, long alignment, Optional<String> name) {
super(OptionalLong.of(size), alignment, name);
super(size, alignment, name);
this.carrier = carrier;
this.order = order;
checkCarrierSize(carrier, size);
@ -89,10 +83,11 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
}
/**
* Returns a new value layout with given byte order.
* Returns a value layout with the same carrier, alignment constraints and name as this value layout,
* but with the specified byte order.
*
* @param order the desired byte order.
* @return a new value layout with given 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());
@ -100,9 +95,11 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
@Override
public String toString() {
return decorateLayoutString(String.format("%s%d",
order == ByteOrder.BIG_ENDIAN ? "B" : "b",
bitSize()));
char descriptor = carrier == MemoryAddress.class ? 'A' : carrier.descriptorString().charAt(0);
if (order == ByteOrder.LITTLE_ENDIAN) {
descriptor = Character.toLowerCase(descriptor);
}
return decorateLayoutString(String.format("%s%d", descriptor, bitSize()));
}
@Override
@ -122,6 +119,62 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
alignment == v.alignment;
}
/**
* Creates a <em>strided</em> access var handle that can be used to dereference a multi-dimensional array. The
* layout of this array is a sequence layout with {@code shape.length} nested sequence layouts. The element
* layout of the sequence layout at depth {@code shape.length} is this value layout.
* As a result, if {@code shape.length == 0}, the array layout will feature only one dimension.
* <p>
* The resulting var handle will feature {@code sizes.length + 1} coordinates of type {@code long}, which are
* used as indices into a multi-dimensional array.
* <p>
* For instance, the following method call:
*
* {@snippet lang=java :
* VarHandle arrayHandle = ValueLayout.JAVA_INT.arrayElementVarHandle(10, 20);
* }
*
* Can be used to access a multi-dimensional array whose layout is as follows:
*
* {@snippet lang=java :
* MemoryLayout arrayLayout = MemoryLayout.sequenceLayout(-1,
* MemoryLayout.sequenceLayout(10,
* MemoryLayout.sequenceLayout(20, ValueLayout.JAVA_INT)));
* }
*
* The resulting var handle {@code arrayHandle} will feature 3 coordinates of type {@code long}; each coordinate
* is interpreted as an index into the corresponding sequence layout. If we refer to the var handle coordinates, from left
* to right, as {@code x}, {@code y} and {@code z} respectively, the final offset dereferenced by the var handle can be
* computed with the following formula:
*
* <blockquote><pre>{@code
* offset = (10 * 20 * 4 * x) + (20 * 4 * y) + (4 * z)
* }</pre></blockquote>
*
* @param shape the size of each nested array dimension.
* @return a var handle which can be used to dereference a multi-dimensional array, featuring {@code shape.length + 1}
* {@code long} coordinates.
* @throws IllegalArgumentException if {@code shape[i] < 0}, for at least one index {@code i}.
* @throws UnsupportedOperationException if the layout path has one or more elements with incompatible alignment constraints.
* @see MethodHandles#memorySegmentViewVarHandle
* @see MemoryLayout#varHandle(PathElement...)
* @see SequenceLayout
*/
public VarHandle arrayElementVarHandle(int... shape) {
Objects.requireNonNull(shape);
MemoryLayout layout = this;
List<PathElement> path = new ArrayList<>();
for (int i = shape.length ; i > 0 ; i--) {
int size = shape[i - 1];
if (size < 0) throw new IllegalArgumentException("Invalid shape size: " + size);
layout = MemoryLayout.sequenceLayout(size, layout);
path.add(PathElement.sequenceElement());
}
layout = MemoryLayout.sequenceLayout(-1, layout);
path.add(PathElement.sequenceElement());
return layout.varHandle(path.toArray(new PathElement[0]));
}
/**
* {@return the carrier associated with this value layout}
*/
@ -139,12 +192,6 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
return new ValueLayout(carrier, order, bitSize(), alignment, name());
}
@Override
public Optional<DynamicConstantDesc<ValueLayout>> describeConstable() {
return Optional.of(decorateLayoutConstant(DynamicConstantDesc.ofNamed(ConstantDescs.BSM_INVOKE, "value",
CD_VALUE_LAYOUT, MH_VALUE, carrier().describeConstable().get(), order == ByteOrder.BIG_ENDIAN ? BIG_ENDIAN : LITTLE_ENDIAN)));
}
//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
@ -198,14 +245,17 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
VarHandle accessHandle() {
if (handle == null) {
// this store to stable field is safe, because return value of 'makeMemoryAccessVarHandle' has stable identity
handle = Utils.makeMemoryAccessVarHandle(this, false);
handle = Utils.makeSegmentViewVarHandle(this);
}
return handle;
}
/**
* A value layout whose carrier is {@code boolean.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfBoolean extends ValueLayout {
OfBoolean(ByteOrder order) {
super(boolean.class, order, 8);
@ -239,7 +289,10 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
/**
* A value layout whose carrier is {@code byte.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfByte extends ValueLayout {
OfByte(ByteOrder order) {
super(byte.class, order, 8);
@ -273,7 +326,10 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
/**
* A value layout whose carrier is {@code char.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfChar extends ValueLayout {
OfChar(ByteOrder order) {
super(char.class, order, 16);
@ -307,7 +363,10 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
/**
* A value layout whose carrier is {@code short.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfShort extends ValueLayout {
OfShort(ByteOrder order) {
super(short.class, order, 16);
@ -341,7 +400,10 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
/**
* A value layout whose carrier is {@code int.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfInt extends ValueLayout {
OfInt(ByteOrder order) {
super(int.class, order, 32);
@ -375,7 +437,10 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
/**
* A value layout whose carrier is {@code float.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfFloat extends ValueLayout {
OfFloat(ByteOrder order) {
super(float.class, order, 32);
@ -409,7 +474,10 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
/**
* A value layout whose carrier is {@code long.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfLong extends ValueLayout {
OfLong(ByteOrder order) {
super(long.class, order, 64);
@ -443,7 +511,10 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
/**
* A value layout whose carrier is {@code double.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfDouble extends ValueLayout {
OfDouble(ByteOrder order) {
super(double.class, order, 64);
@ -477,7 +548,10 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
/**
* A value layout whose carrier is {@code MemoryAddress.class}.
*
* @since 19
*/
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public static final class OfAddress extends ValueLayout {
OfAddress(ByteOrder order) {
super(MemoryAddress.class, order, ADDRESS_SIZE_BITS);
@ -511,13 +585,15 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
/**
* A value layout constant whose size is the same as that of a machine address ({@code size_t}),
* bit alignment set to 8, and byte order set to {@link ByteOrder#nativeOrder()}.
* bit alignment set to {@code sizeof(size_t) * 8}, and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* MemoryLayout.valueLayout(MemoryAddress.class, ByteOrder.nativeOrder()).withBitAlignment(8);
* MemoryLayout.valueLayout(MemoryAddress.class, ByteOrder.nativeOrder())
* .withBitAlignment(<address size>);
* }
*/
public static final OfAddress ADDRESS = new OfAddress(ByteOrder.nativeOrder()).withBitAlignment(8);
public static final OfAddress ADDRESS = new OfAddress(ByteOrder.nativeOrder())
.withBitAlignment(ValueLayout.ADDRESS_SIZE_BITS);
/**
* A value layout constant whose size is the same as that of a Java {@code byte},
@ -541,62 +617,62 @@ public sealed class ValueLayout extends AbstractLayout implements MemoryLayout {
/**
* A value layout constant whose size is the same as that of a Java {@code char},
* bit alignment set to 8, and byte order set to {@link ByteOrder#nativeOrder()}.
* 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(8);
* MemoryLayout.valueLayout(char.class, ByteOrder.nativeOrder()).withBitAlignment(16);
* }
*/
public static final OfChar JAVA_CHAR = new OfChar(ByteOrder.nativeOrder()).withBitAlignment(8);
public static final OfChar JAVA_CHAR = new OfChar(ByteOrder.nativeOrder()).withBitAlignment(16);
/**
* A value layout constant whose size is the same as that of a Java {@code short},
* bit alignment set to 8, and byte order set to {@link ByteOrder#nativeOrder()}.
* 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(8);
* MemoryLayout.valueLayout(short.class, ByteOrder.nativeOrder()).withBitAlignment(16);
* }
*/
public static final OfShort JAVA_SHORT = new OfShort(ByteOrder.nativeOrder()).withBitAlignment(8);
public static final OfShort JAVA_SHORT = new OfShort(ByteOrder.nativeOrder()).withBitAlignment(16);
/**
* A value layout constant whose size is the same as that of a Java {@code int},
* bit alignment set to 8, and byte order set to {@link ByteOrder#nativeOrder()}.
* 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(8);
* MemoryLayout.valueLayout(int.class, ByteOrder.nativeOrder()).withBitAlignment(32);
* }
*/
public static final OfInt JAVA_INT = new OfInt(ByteOrder.nativeOrder()).withBitAlignment(8);
public static final OfInt JAVA_INT = new OfInt(ByteOrder.nativeOrder()).withBitAlignment(32);
/**
* A value layout constant whose size is the same as that of a Java {@code long},
* bit alignment set to 8, and byte order set to {@link ByteOrder#nativeOrder()}.
* 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(8);
* MemoryLayout.valueLayout(long.class, ByteOrder.nativeOrder()).withBitAlignment(64);
* }
*/
public static final OfLong JAVA_LONG = new OfLong(ByteOrder.nativeOrder())
.withBitAlignment(8);
.withBitAlignment(64);
/**
* A value layout constant whose size is the same as that of a Java {@code float},
* bit alignment set to 8, and byte order set to {@link ByteOrder#nativeOrder()}.
* bit alignment set to 32, and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* MemoryLayout.valueLayout(float.class, ByteOrder.nativeOrder()).withBitAlignment(8);
* MemoryLayout.valueLayout(float.class, ByteOrder.nativeOrder()).withBitAlignment(32);
* }
*/
public static final OfFloat JAVA_FLOAT = new OfFloat(ByteOrder.nativeOrder()).withBitAlignment(8);
public static final OfFloat JAVA_FLOAT = new OfFloat(ByteOrder.nativeOrder()).withBitAlignment(32);
/**
* A value layout constant whose size is the same as that of a Java {@code double},
* bit alignment set to 8, and byte order set to {@link ByteOrder#nativeOrder()}.
* 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(8);
* MemoryLayout.valueLayout(double.class, ByteOrder.nativeOrder()).withBitAlignment(64);
* }
*/
public static final OfDouble JAVA_DOUBLE = new OfDouble(ByteOrder.nativeOrder()).withBitAlignment(8);
public static final OfDouble JAVA_DOUBLE = new OfDouble(ByteOrder.nativeOrder()).withBitAlignment(64);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,26 +25,24 @@
*/
/**
* <p> Classes to support low-level and efficient foreign memory/function access, directly from Java.
* <p>Provides low-level access to memory and functions outside the Java runtime.
*
* <h2>Foreign memory access</h2>
*
* <p>
* The main abstraction introduced to support foreign memory access is {@link jdk.incubator.foreign.MemorySegment}, which
* models a contiguous memory region, which can reside either inside or outside the Java heap.
* A memory segment represents the main access coordinate of a memory access var handle, which can be obtained
* using the combinator methods defined in the {@link jdk.incubator.foreign.MemoryHandles} class; a set of
* common dereference and copy operations is provided also by the {@link jdk.incubator.foreign.MemorySegment} class, which can
* be useful for simple, non-structured access. Finally, the {@link jdk.incubator.foreign.MemoryLayout} class
* hierarchy enables description of <em>memory layouts</em> and basic operations such as computing the size in bytes of a given
* layout, obtain its alignment requirements, and so on. Memory layouts also provide an alternate, more abstract way, to produce
* memory access var handles, e.g. using <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>.
* The main abstraction introduced to support foreign memory access is {@link java.lang.foreign.MemorySegment}, which
* models a contiguous memory region, residing either inside or outside the Java heap. The contents of a memory
* segment can be described using a {@link java.lang.foreign.MemoryLayout memory layout}, which provides
* basic operations to query sizes, offsets and alignment constraints. Memory layouts also provide
* an alternate, more abstract way, to <a href=MemorySegment.html#segment-deref>dereference memory segments</a>
* using {@linkplain java.lang.foreign.MemoryLayout#varHandle(java.lang.foreign.MemoryLayout.PathElement...) access var handles},
* which can be computed using <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>.
*
* For example, to allocate an off-heap memory region big enough to hold 10 values of the primitive type {@code int}, and fill it with values
* ranging from {@code 0} to {@code 9}, we can use the following code:
*
* {@snippet lang=java :
* MemorySegment segment = MemorySegment.allocateNative(10 * 4, ResourceScope.newImplicitScope());
* MemorySegment segment = MemorySegment.allocateNative(10 * 4, MemorySession.openImplicit());
* for (int i = 0 ; i < 10 ; i++) {
* segment.setAtIndex(ValueLayout.JAVA_INT, i, i);
* }
@ -53,8 +51,8 @@
* This code creates a <em>native</em> memory segment, that is, a memory segment backed by
* off-heap memory; the size of the segment is 40 bytes, enough to store 10 values of the primitive type {@code int}.
* Inside a loop, we then initialize the contents of the memory segment; note how the
* {@linkplain jdk.incubator.foreign.MemorySegment#setAtIndex(ValueLayout.OfInt, long, int) dereference method}
* accepts a {@linkplain jdk.incubator.foreign.ValueLayout value layout}, which specifies the size, alignment constraints,
* {@linkplain java.lang.foreign.MemorySegment#setAtIndex(ValueLayout.OfInt, long, int) dereference method}
* accepts a {@linkplain java.lang.foreign.ValueLayout value layout}, which specifies the size, alignment constraints,
* byte order as well as the Java type ({@code int}, in this case) associated with the dereference operation. More specifically,
* if we view the memory segment as a set of 10 adjacent slots, {@code s[i]}, where {@code 0 <= i < 10},
* where the size of each slot is exactly 4 bytes, the initialization logic above will set each slot
@ -67,18 +65,18 @@
* 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 jdk.incubator.foreign.ResourceScope} abstraction, as shown below:
* with a memory segment. This can be done, using the {@link java.lang.foreign.MemorySession} abstraction, as shown below:
*
* {@snippet lang=java :
* try (ResourceScope scope = ResourceScope.newConfinedScope()) {
* MemorySegment segment = MemorySegment.allocateNative(10 * 4, scope);
* try (MemorySession session = MemorySession.openConfined()) {
* MemorySegment segment = MemorySegment.allocateNative(10 * 4, session);
* for (int i = 0 ; i < 10 ; i++) {
* segment.setAtIndex(ValueLayout.JAVA_INT, i, i);
* }
* }
* }
*
* This example is almost identical to the prior one; this time we first create a so called <em>resource scope</em>,
* 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>.
@ -92,82 +90,82 @@
* 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 resource scope associated with the segment being accessed has not been closed prematurely.
* the memory session associated with the segment being accessed has not been closed prematurely.
* We call this guarantee <em>temporal safety</em>. Together, spatial and temporal safety ensure that each memory access
* operation either succeeds - and accesses a valid memory location - or fails.
*
* <h2>Foreign function access</h2>
* The key abstractions introduced to support foreign function access are {@link jdk.incubator.foreign.SymbolLookup},
* {@link jdk.incubator.foreign.MemoryAddress} and {@link jdk.incubator.foreign.CLinker}.
* The first is used to look up symbols inside native libraries; the second is used to model native addresses (more on that later),
* while the third provides linking capabilities which allows modelling foreign functions as {@link java.lang.invoke.MethodHandle} instances,
* so that clients can perform foreign function calls directly in Java, without the need for intermediate layers of native
* The key abstractions introduced to support foreign function access are {@link java.lang.foreign.SymbolLookup},
* {@link java.lang.foreign.FunctionDescriptor} and {@link java.lang.foreign.Linker}. The first is used to look up symbols
* inside libraries; the second is used to model the signature of foreign functions, while the third provides
* linking capabilities which allows modelling foreign functions as {@link java.lang.invoke.MethodHandle} instances,
* so that clients can perform foreign function calls directly in Java, without the need for intermediate layers of C/C++
* code (as is the case with the <a href="{@docRoot}/../specs/jni/index.html">Java Native Interface (JNI)</a>).
* <p>
* For example, to compute the length of a string using the C standard library function {@code strlen} on a Linux x64 platform,
* we can use the following code:
*
* {@snippet lang=java :
* var linker = CLinker.systemCLinker();
* var linker = Linker.nativeLinker();
* MethodHandle strlen = linker.downcallHandle(
* linker.lookup("strlen").get(),
* FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)
* );
*
* try (var scope = ResourceScope.newConfinedScope()) {
* var cString = MemorySegment.allocateNative(5 + 1, scope);
* try (var session = MemorySession.openConfined()) {
* var cString = MemorySegment.allocateNative(5 + 1, session);
* cString.setUtf8String("Hello");
* long len = (long)strlen.invoke(cString); // 5
* }
* }
*
* Here, we obtain a {@linkplain jdk.incubator.foreign.CLinker#systemCLinker() linker instance} and we use it
* to {@linkplain jdk.incubator.foreign.CLinker#lookup(java.lang.String) look up} the {@code strlen} symbol in the
* Here, we obtain a {@linkplain java.lang.foreign.Linker#nativeLinker() native linker} and we use it
* to {@linkplain java.lang.foreign.SymbolLookup#lookup(java.lang.String) look up} the {@code strlen} symbol in the
* standard C library; a <em>downcall method handle</em> targeting said symbol is subsequently
* {@linkplain jdk.incubator.foreign.CLinker#downcallHandle(jdk.incubator.foreign.FunctionDescriptor) obtained}.
* To complete the linking successfully, we must provide a {@link jdk.incubator.foreign.FunctionDescriptor} instance,
* {@linkplain java.lang.foreign.Linker#downcallHandle(java.lang.foreign.FunctionDescriptor) obtained}.
* To complete the linking successfully, we must provide a {@link java.lang.foreign.FunctionDescriptor} instance,
* describing the signature of the {@code strlen} function.
* From this information, the linker will uniquely determine the sequence of steps which will turn
* the method handle invocation (here performed using {@link java.lang.invoke.MethodHandle#invoke(java.lang.Object...)})
* into a foreign function call, according to the rules specified by the platform C ABI.
* The {@link jdk.incubator.foreign.MemorySegment} class also provides many useful methods for
* interacting with native code, such as converting Java strings
* {@linkplain jdk.incubator.foreign.MemorySegment#setUtf8String(long, java.lang.String) into} native strings and
* {@linkplain jdk.incubator.foreign.MemorySegment#getUtf8String(long) back}, as demonstrated in the above example.
* into a foreign function call, according to the rules specified by the ABI of the underlying platform.
* The {@link java.lang.foreign.MemorySegment} class also provides many useful methods for
* interacting with foreign code, such as converting Java strings
* {@linkplain java.lang.foreign.MemorySegment#setUtf8String(long, java.lang.String) into} zero-terminated, UTF-8 strings and
* {@linkplain java.lang.foreign.MemorySegment#getUtf8String(long) back}, as demonstrated in the above example.
*
* <h3>Foreign addresses</h3>
*
* When a memory segment is created from Java code, the segment properties (spatial bounds, temporal bounds and confinement)
* are fully known at segment creation. But when interacting with native libraries, clients will often receive <em>raw</em> pointers.
* 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 jdk.incubator.foreign.MemoryAddress} class. When clients receive a
* 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 jdk.incubator.foreign.MemoryAddress#get(jdk.incubator.foreign.ValueLayout.OfInt, long) dereference methods}
* {@linkplain java.lang.foreign.MemoryAddress#get(java.lang.foreign.ValueLayout.OfInt, long) dereference methods}
* provided:
*
* {@snippet lang=java :
* MemoryAddress addr = ... //obtain address from native code
* MemoryAddress addr = ... // obtain address from foreign function call
* int x = addr.get(ValueLayout.JAVA_INT, 0);
* }
*
* Alternatively, the client can
* {@linkplain jdk.incubator.foreign.MemorySegment#ofAddress(jdk.incubator.foreign.MemoryAddress, long, jdk.incubator.foreign.ResourceScope) create}
* {@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 native address:
* Here is how an unsafe segment can be created from a memory address:
*
* {@snippet lang=java :
* ResourceScope scope = ... // initialize a resource scope object
* MemoryAddress addr = ... //obtain address from native code
* MemorySegment segment = MemorySegment.ofAddress(addr, 4, scope); // segment is 4 bytes long
* MemorySession session = ... // initialize a memory session object
* MemoryAddress addr = ... // obtain address from foreign function call
* MemorySegment segment = MemorySegment.ofAddress(addr, 4, session); // segment is 4 bytes long
* int x = segment.get(ValueLayout.JAVA_INT, 0);
* }
*
* <h3>Upcalls</h3>
* The {@link jdk.incubator.foreign.CLinker} interface also allows clients to turn an existing method handle (which might point
* The {@link java.lang.foreign.Linker} interface also allows clients to turn an existing method handle (which might point
* to a Java method) into a memory address, so that Java code can effectively be passed to other foreign functions.
* For instance, we can write a method that compares two integer values, as follows:
*
@ -190,43 +188,51 @@
* CLinker.upcallType(comparFunction));
* }
*
* As before, we need to create a {@link jdk.incubator.foreign.FunctionDescriptor} instance, this time describing the signature
* 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 jdk.incubator.foreign.CLinker#upcallType(jdk.incubator.foreign.FunctionDescriptor) derive} a method type
* {@linkplain java.lang.foreign.Linker#upcallType(java.lang.foreign.FunctionDescriptor) derive} a method type
* that can be used to look up the method handle for {@code IntComparator.intCompare}.
* <p>
* Now that we have a method handle instance, we can turn it into a fresh function pointer,
* using the {@link jdk.incubator.foreign.CLinker} interface, as follows:
* using the {@link java.lang.foreign.Linker} interface, as follows:
*
* {@snippet lang=java :
* ResourceScope scope = ...
* Addressable comparFunc = CLinker.systemCLinker().upcallStub(
* intCompareHandle, intCompareDescriptor, scope);
* MemorySession session = ...
* Addressable comparFunc = CLinker.nativeLinker().upcallStub(
* intCompareHandle, intCompareDescriptor, session);
* );
* }
*
* The {@link jdk.incubator.foreign.FunctionDescriptor} instance created in the previous step is then used to
* {@linkplain jdk.incubator.foreign.CLinker#upcallStub(java.lang.invoke.MethodHandle, jdk.incubator.foreign.FunctionDescriptor, jdk.incubator.foreign.ResourceScope) create}
* The {@link java.lang.foreign.FunctionDescriptor} instance created in the previous step is then used to
* {@linkplain java.lang.foreign.Linker#upcallStub(java.lang.invoke.MethodHandle, java.lang.foreign.FunctionDescriptor, java.lang.foreign.MemorySession) create}
* a new upcall stub; the layouts in the function descriptors allow the linker to determine the sequence of steps which
* allow foreign code to call the stub for {@code intCompareHandle} according to the rules specified by the platform C ABI.
* The lifecycle of the upcall stub returned by is tied to the {@linkplain jdk.incubator.foreign.ResourceScope resource scope}
* provided when the upcall stub is created. This same scope is made available by the {@link jdk.incubator.foreign.NativeSymbol}
* allow foreign code to call the stub for {@code intCompareHandle} according to the rules specified by the ABI of the
* underlying platform.
* The lifecycle of the upcall stub is tied to the {@linkplain java.lang.foreign.MemorySession memory session}
* provided when the upcall stub is created. This same session is made available by the {@link java.lang.foreign.MemorySegment}
* instance returned by that method.
*
* <a id="restricted"></a>
* <h2>Restricted methods</h2>
* Some methods in this package are considered <em>restricted</em>. Restricted methods are typically used to bind native
* foreign data and/or functions to first-class Java API elements which can then be used directly by clients. For instance
* the restricted method {@link MemorySegment#ofAddress(MemoryAddress, long, ResourceScope)}
* can be used to create a fresh segment with given spatial bounds out of a native address.
* the restricted method {@link java.lang.foreign.MemorySegment#ofAddress(MemoryAddress, long, MemorySession)}
* can be used to create a fresh segment with the given spatial bounds out of a native address.
* <p>
* Binding foreign data and/or functions is generally unsafe and, if done incorrectly, can result in VM crashes, or memory corruption when the bound Java API element is accessed.
* For instance, in the case of {@link MemorySegment#ofAddress(MemoryAddress, long, ResourceScope)},
* For instance, in the case of {@link java.lang.foreign.MemorySegment#ofAddress(MemoryAddress, long, MemorySession)},
* if the provided spatial bounds are incorrect, a client of the segment returned by that method might crash the VM, or corrupt
* memory when attempting to dereference said segment. For these reasons, it is crucial for code that calls a restricted method
* to never pass arguments that might cause incorrect binding of foreign data and/or functions to a Java API.
* <p>
* Access to restricted methods is <em>disabled</em> by default; to enable restricted methods, the command line option
* {@code --enable-native-access} must mention the name of the caller's module.
* Access to restricted methods can be controlled using the command line option {@code --enable-native-access=M1,M2, ... Mn},
* where {@code M1}, {@code M2}, {@code ... Mn} are module names (for the unnamed module, the special value {@code ALL-UNNAMED}
* can be used). If this option is specified, access to restricted methods is only granted to the modules listed by that
* option. If this option is not specified, access to restricted methods is enabled for all modules, but
* access to restricted methods will result in runtime warnings.
* <p>
* For every class in this package, unless specified otherwise, any method arguments of reference
* type must not be null, and any null argument will elicit a {@code NullPointerException}. This fact is not individually
* documented for methods of this API.
*/
package jdk.incubator.foreign;
package java.lang.foreign;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 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
@ -82,46 +82,45 @@ public interface JavaLangInvokeAccess {
Map<String, byte[]> generateHolderClasses(Stream<String> traces);
/**
* Returns a var handle view of a given memory address.
* Returns a var handle view of a given memory segment.
* Used by {@code jdk.internal.foreign.LayoutPath} and
* {@code jdk.incubator.foreign.MemoryHandles}.
* {@code java.lang.invoke.MethodHandles}.
*/
VarHandle memoryAccessVarHandle(Class<?> carrier, boolean skipAlignmentMaskCheck, long alignmentMask,
ByteOrder order);
VarHandle memorySegmentViewHandle(Class<?> carrier, long alignmentMask, ByteOrder order);
/**
* Var handle carrier combinator.
* Used by {@code jdk.incubator.foreign.MemoryHandles}.
* Used by {@code java.lang.invoke.MethodHandles}.
*/
VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget);
/**
* Var handle filter coordinates combinator.
* Used by {@code jdk.incubator.foreign.MemoryHandles}.
* Used by {@code java.lang.invoke.MethodHandles}.
*/
VarHandle filterCoordinates(VarHandle target, int pos, MethodHandle... filters);
/**
* Var handle drop coordinates combinator.
* Used by {@code jdk.incubator.foreign.MemoryHandles}.
* Used by {@code java.lang.invoke.MethodHandles}.
*/
VarHandle dropCoordinates(VarHandle target, int pos, Class<?>... valueTypes);
/**
* Var handle permute coordinates combinator.
* Used by {@code jdk.incubator.foreign.MemoryHandles}.
* Used by {@code java.lang.invoke.MethodHandles}.
*/
VarHandle permuteCoordinates(VarHandle target, List<Class<?>> newCoordinates, int... reorder);
/**
* Var handle collect coordinates combinator.
* Used by {@code jdk.incubator.foreign.MemoryHandles}.
* Used by {@code java.lang.invoke.MethodHandles}.
*/
VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle filter);
/**
* Var handle insert coordinates combinator.
* Used by {@code jdk.incubator.foreign.MemoryHandles}.
* Used by {@code java.lang.invoke.MethodHandles}.
*/
VarHandle insertCoordinates(VarHandle target, int pos, Object... values);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 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
@ -25,11 +25,10 @@
package jdk.internal.access;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.access.foreign.UnmapperProxy;
import jdk.internal.misc.ScopedMemoryAccess.Scope;
import jdk.internal.misc.VM.BufferPool;
import java.lang.foreign.MemorySegment;
import java.io.FileDescriptor;
import java.nio.Buffer;
import java.nio.ByteBuffer;
@ -48,7 +47,7 @@ public interface JavaNioAccess {
* to the resulting buffer.
* Used by {@code jdk.internal.foreignMemorySegmentImpl}.
*/
ByteBuffer newDirectByteBuffer(long addr, int cap, Object obj, MemorySegmentProxy segment);
ByteBuffer newDirectByteBuffer(long addr, int cap, Object obj, MemorySegment segment);
/**
* Constructs a mapped ByteBuffer referring to the block of memory starting
@ -58,13 +57,13 @@ public interface JavaNioAccess {
* buffer are derived from the {@code UnmapperProxy}.
* Used by {@code jdk.internal.foreignMemorySegmentImpl}.
*/
ByteBuffer newMappedByteBuffer(UnmapperProxy unmapperProxy, long addr, int cap, Object obj, MemorySegmentProxy segment);
ByteBuffer newMappedByteBuffer(UnmapperProxy unmapperProxy, long addr, int cap, Object obj, MemorySegment segment);
/**
* Constructs an heap ByteBuffer with given backing array, offset, capacity and segment.
* Used by {@code jdk.internal.foreignMemorySegmentImpl}.
*/
ByteBuffer newHeapByteBuffer(byte[] hb, int offset, int capacity, MemorySegmentProxy segment);
ByteBuffer newHeapByteBuffer(byte[] hb, int offset, int capacity, MemorySegment segment);
/**
* Used by {@code jdk.internal.foreign.Utils}.
@ -84,15 +83,15 @@ public interface JavaNioAccess {
/**
* Used by {@code jdk.internal.foreign.AbstractMemorySegmentImpl} and byte buffer var handle views.
*/
MemorySegmentProxy bufferSegment(Buffer buffer);
MemorySegment bufferSegment(Buffer buffer);
/**
* Used by I/O operations to make a buffer's resource scope non-closeable
* (for the duration of the I/O operation) by acquiring a new resource
* scope handle. Null is returned if the buffer has no scope, or
* acquiring is not required to guarantee safety.
* Used by I/O operations to make a buffer's session non-closeable
* (for the duration of the I/O operation) by acquiring the session.
* Null is returned if the buffer has no scope, or acquiring is not
* required to guarantee safety.
*/
Runnable acquireScope(Buffer buffer, boolean async);
Runnable acquireSession(Buffer buffer, boolean async);
/**
* Used by {@code jdk.internal.foreign.MappedMemorySegmentImpl} and byte buffer var handle views.

View file

@ -1,99 +0,0 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package jdk.internal.access.foreign;
/**
* This proxy interface is required to allow instances of the {@code MemoryAddress} interface (which is defined inside
* an incubating module) to be accessed from the memory access var handles.
*/
public interface MemoryAddressProxy {
/**
* Check that memory access is within spatial and temporal bounds.
* @throws IllegalStateException if underlying segment has been closed already.
* @throws IndexOutOfBoundsException if access is out-of-bounds.
*/
void checkAccess(long offset, long length, boolean readOnly);
long unsafeGetOffset();
Object unsafeGetBase();
boolean isSmall();
/* Helper functions for offset computations. These are required so that we can avoid issuing long opcodes
* (e.g. LMUL, LADD) when we're operating on 'small' segments (segments whose length can be expressed with an int).
* C2 BCE code is very sensitive to the kind of opcode being emitted, and this workaround allows us to rescue
* BCE when working with small segments. This workaround should be dropped when JDK-8223051 is resolved.
*/
public static long addOffsets(long op1, long op2, MemoryAddressProxy addr) {
if (addr.isSmall()) {
// force ints for BCE
if (op1 > Integer.MAX_VALUE || op2 > Integer.MAX_VALUE
|| op1 < Integer.MIN_VALUE || op2 < Integer.MIN_VALUE) {
throw overflowException(Integer.MIN_VALUE, Integer.MAX_VALUE);
}
int i1 = (int)op1;
int i2 = (int)op2;
try {
return Math.addExact(i1, i2);
} catch (ArithmeticException ex) {
throw overflowException(Integer.MIN_VALUE, Integer.MAX_VALUE);
}
} else {
try {
return Math.addExact(op1, op2);
} catch (ArithmeticException ex) {
throw overflowException(Long.MIN_VALUE, Long.MAX_VALUE);
}
}
}
public static long multiplyOffsets(long op1, long op2, MemoryAddressProxy addr) {
if (addr.isSmall()) {
if (op1 > Integer.MAX_VALUE || op2 > Integer.MAX_VALUE
|| op1 < Integer.MIN_VALUE || op2 < Integer.MIN_VALUE) {
throw overflowException(Integer.MIN_VALUE, Integer.MAX_VALUE);
}
// force ints for BCE
int i1 = (int)op1;
int i2 = (int)op2;
try {
return Math.multiplyExact(i1, i2);
} catch (ArithmeticException ex) {
throw overflowException(Integer.MIN_VALUE, Integer.MAX_VALUE);
}
} else {
try {
return Math.multiplyExact(op1, op2);
} catch (ArithmeticException ex) {
throw overflowException(Long.MIN_VALUE, Long.MAX_VALUE);
}
}
}
private static IndexOutOfBoundsException overflowException(long min, long max) {
return new IndexOutOfBoundsException(String.format("Overflow occurred during offset computation ; offset exceeded range { %d .. %d }", min, max));
}
}

View file

@ -1,104 +0,0 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
package jdk.internal.access.foreign;
import jdk.internal.misc.ScopedMemoryAccess;
/**
* This abstract class is required to allow implementations of the {@code MemorySegment} interface (which is defined inside
* an incubating module) to be accessed from the memory access var handles.
*/
public abstract class MemorySegmentProxy {
/**
* Check that memory access is within spatial bounds and that access is compatible with segment access modes.
* @throws UnsupportedOperationException if underlying segment has incompatible access modes (e.g. attempting to write
* a read-only segment).
* @throws IndexOutOfBoundsException if access is out-of-bounds.
*/
public abstract void checkAccess(long offset, long length, boolean readOnly);
public abstract long unsafeGetOffset();
public abstract Object unsafeGetBase();
public abstract boolean isSmall();
public abstract ScopedMemoryAccess.Scope scope();
public abstract long maxAlignMask();
/* Helper functions for offset computations. These are required so that we can avoid issuing long opcodes
* (e.g. LMUL, LADD) when we're operating on 'small' segments (segments whose length can be expressed with an int).
* C2 BCE code is very sensitive to the kind of opcode being emitted, and this workaround allows us to rescue
* BCE when working with small segments. This workaround should be dropped when JDK-8223051 is resolved.
*/
public static long addOffsets(long op1, long op2, MemorySegmentProxy segmentProxy) {
if (segmentProxy.isSmall()) {
// force ints for BCE
if (op1 > Integer.MAX_VALUE || op2 > Integer.MAX_VALUE
|| op1 < Integer.MIN_VALUE || op2 < Integer.MIN_VALUE) {
throw overflowException(Integer.MIN_VALUE, Integer.MAX_VALUE);
}
int i1 = (int)op1;
int i2 = (int)op2;
try {
return Math.addExact(i1, i2);
} catch (ArithmeticException ex) {
throw overflowException(Integer.MIN_VALUE, Integer.MAX_VALUE);
}
} else {
try {
return Math.addExact(op1, op2);
} catch (ArithmeticException ex) {
throw overflowException(Long.MIN_VALUE, Long.MAX_VALUE);
}
}
}
public static long multiplyOffsets(long op1, long op2, MemorySegmentProxy segmentProxy) {
if (segmentProxy.isSmall()) {
if (op1 > Integer.MAX_VALUE || op2 > Integer.MAX_VALUE
|| op1 < Integer.MIN_VALUE || op2 < Integer.MIN_VALUE) {
throw overflowException(Integer.MIN_VALUE, Integer.MAX_VALUE);
}
// force ints for BCE
int i1 = (int)op1;
int i2 = (int)op2;
try {
return Math.multiplyExact(i1, i2);
} catch (ArithmeticException ex) {
throw overflowException(Integer.MIN_VALUE, Integer.MAX_VALUE);
}
} else {
try {
return Math.multiplyExact(op1, op2);
} catch (ArithmeticException ex) {
throw overflowException(Long.MIN_VALUE, Long.MAX_VALUE);
}
}
}
private static IndexOutOfBoundsException overflowException(long min, long max) {
return new IndexOutOfBoundsException(String.format("Overflow occurred during offset computation ; offset exceeded range { %d .. %d }", min, max));
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* 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
@ -25,16 +25,12 @@
package jdk.internal.foreign;
import jdk.incubator.foreign.*;
import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.access.foreign.UnmapperProxy;
import jdk.internal.misc.ScopedMemoryAccess;
import jdk.internal.util.ArraysSupport;
import jdk.internal.vm.annotation.ForceInline;
import sun.security.action.GetPropertyAction;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.SegmentAllocator;
import java.lang.foreign.ValueLayout;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.*;
@ -43,58 +39,57 @@ import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.access.foreign.UnmapperProxy;
import jdk.internal.misc.ScopedMemoryAccess;
import jdk.internal.util.ArraysSupport;
import jdk.internal.vm.annotation.ForceInline;
import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE;
import static java.lang.foreign.ValueLayout.JAVA_BYTE;
/**
* This abstract class provides an immutable implementation for the {@code MemorySegment} interface. This class contains information
* about the segment's spatial and temporal bounds; each memory segment implementation is associated with an owner thread which is set at creation time.
* Access to certain sensitive operations on the memory segment will fail with {@code IllegalStateException} if the
* segment is either in an invalid state (e.g. it has already been closed) or if access occurs from a thread other
* than the owner thread. See {@link ResourceScopeImpl} for more details on management of temporal bounds. Subclasses
* than the owner thread. See {@link MemorySessionImpl} for more details on management of temporal bounds. Subclasses
* are defined for each memory segment kind, see {@link NativeMemorySegmentImpl}, {@link HeapMemorySegmentImpl} and
* {@link MappedMemorySegmentImpl}.
*/
public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegmentProxy implements MemorySegment, SegmentAllocator, Scoped {
public abstract non-sealed class AbstractMemorySegmentImpl implements MemorySegment, SegmentAllocator, Scoped {
private static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
private static final boolean enableSmallSegments =
Boolean.parseBoolean(GetPropertyAction.privilegedGetProperty("jdk.incubator.foreign.SmallSegments", "true"));
static final int READ_ONLY = 1;
static final int SMALL = READ_ONLY << 1;
static final long NONCE = new Random().nextLong();
static final int DEFAULT_MODES = 0;
static final JavaNioAccess nioAccess = SharedSecrets.getJavaNioAccess();
final long length;
final int mask;
final ResourceScopeImpl scope;
final MemorySession session;
@ForceInline
AbstractMemorySegmentImpl(long length, int mask, ResourceScopeImpl scope) {
AbstractMemorySegmentImpl(long length, int mask, MemorySession session) {
this.length = length;
this.mask = mask;
this.scope = scope;
this.session = session;
}
abstract long min();
abstract Object base();
abstract AbstractMemorySegmentImpl dup(long offset, long size, int mask, ResourceScopeImpl scope);
abstract AbstractMemorySegmentImpl dup(long offset, long size, int mask, MemorySession session);
abstract ByteBuffer makeByteBuffer();
static int defaultAccessModes(long size) {
return (enableSmallSegments && size < Integer.MAX_VALUE) ?
SMALL : 0;
}
@Override
public AbstractMemorySegmentImpl asReadOnly() {
return dup(0, length, mask | READ_ONLY, scope);
return dup(0, length, mask | READ_ONLY, session);
}
@Override
@ -115,7 +110,7 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
}
private AbstractMemorySegmentImpl asSliceNoCheck(long offset, long newSize) {
return dup(offset, newSize, mask, scope);
return dup(offset, newSize, mask, session);
}
@Override
@ -143,12 +138,16 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
@Override
public final MemorySegment fill(byte value){
checkAccess(0, length, false);
SCOPED_MEMORY_ACCESS.setMemory(scope, base(), min(), length, value);
SCOPED_MEMORY_ACCESS.setMemory(sessionImpl(), base(), min(), length, value);
return this;
}
@Override
public MemorySegment allocate(long bytesSize, long bytesAlignment) {
if (bytesAlignment <= 0 ||
((bytesAlignment & (bytesAlignment - 1)) != 0L)) {
throw new IllegalArgumentException("Invalid alignment constraint : " + bytesAlignment);
}
return asSlice(0, bytesSize);
}
@ -170,7 +169,7 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
if (get(JAVA_BYTE, 0) != that.get(JAVA_BYTE, 0)) {
return 0;
}
i = vectorizedMismatchLargeForBytes(scope, that.scope,
i = vectorizedMismatchLargeForBytes(sessionImpl(), that.sessionImpl(),
this.base(), this.min(),
that.base(), that.min(),
length);
@ -192,7 +191,7 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
/**
* Mismatch over long lengths.
*/
private static long vectorizedMismatchLargeForBytes(ResourceScopeImpl aScope, ResourceScopeImpl bScope,
private static long vectorizedMismatchLargeForBytes(MemorySessionImpl aSession, MemorySessionImpl bSession,
Object a, long aOffset,
Object b, long bOffset,
long length) {
@ -207,7 +206,7 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
size = (int) remaining;
lastSubRange = true;
}
i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(aScope, bScope,
i = SCOPED_MEMORY_ACCESS.vectorizedMismatch(aSession, bSession,
a, aOffset + off,
b, bOffset + off,
size, ArraysSupport.LOG2_ARRAY_BYTE_INDEX_SCALE);
@ -231,7 +230,7 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
checkArraySize("ByteBuffer", 1);
ByteBuffer _bb = makeByteBuffer();
if (isSet(READ_ONLY)) {
//scope is IMMUTABLE - obtain a RO byte buffer
//session is IMMUTABLE - obtain a RO byte buffer
_bb = _bb.asReadOnlyBuffer();
}
return _bb;
@ -242,14 +241,6 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
return length;
}
public final boolean isAlive() {
return scope.isAlive();
}
public Thread ownerThread() {
return scope.ownerThread();
}
@Override
public boolean isMapped() {
return false;
@ -261,7 +252,7 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
}
@Override
public final MemorySegment asOverlappingSlice(MemorySegment other) {
public final Optional<MemorySegment> asOverlappingSlice(MemorySegment other) {
AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl)Objects.requireNonNull(other);
if (base() == that.base()) { // both either native or heap
final long thisStart = this.min();
@ -272,10 +263,10 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
if (thisStart < thatEnd && thisEnd > thatStart) { //overlap occurs
long offsetToThat = this.segmentOffset(that);
long newOffset = offsetToThat >= 0 ? offsetToThat : 0;
return asSlice(newOffset, Math.min(this.byteSize() - newOffset, that.byteSize() + offsetToThat));
return Optional.of(asSlice(newOffset, Math.min(this.byteSize() - newOffset, that.byteSize() + offsetToThat)));
}
}
return null;
return Optional.empty();
}
@Override
@ -350,12 +341,6 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
return arr;
}
@Override
public boolean isSmall() {
return isSet(SMALL);
}
@Override
public void checkAccess(long offset, long length, boolean readOnly) {
if (!readOnly && isSet(READ_ONLY)) {
throw new UnsupportedOperationException("Attempt to write a read-only segment");
@ -363,16 +348,14 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
checkBounds(offset, length);
}
void checkValidState() {
scope.checkValidStateSlow();
public void checkValidState() {
sessionImpl().checkValidStateSlow();
}
@Override
public long unsafeGetOffset() {
return min();
}
@Override
public Object unsafeGetBase() {
return base();
}
@ -383,6 +366,8 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
return (this.mask & mask) != 0;
}
public abstract long maxAlignMask();
@ForceInline
public final boolean isAlignedForElement(long offset, MemoryLayout layout) {
return (((unsafeGetOffset() + offset) | maxAlignMask()) & (layout.byteAlignment() - 1)) == 0;
@ -399,32 +384,25 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
return (int)arraySize;
}
private void checkBounds(long offset, long length) {
if (isSmall() &&
offset <= Integer.MAX_VALUE && length <= Integer.MAX_VALUE &&
offset >= Integer.MIN_VALUE && length >= Integer.MIN_VALUE) {
checkBoundsSmall((int)offset, (int)length);
} else if (this != NativeMemorySegmentImpl.EVERYTHING) { // oob not possible for everything segment
if (
length < 0 ||
offset < 0 ||
offset > this.length - length) { // careful of overflow
@ForceInline
void checkBounds(long offset, long length) {
if (length > 0) {
Objects.checkIndex(offset, this.length - length + 1);
} else if (length < 0 || offset < 0 ||
offset > this.length - length) {
throw outOfBoundException(offset, length);
}
}
}
@Override
public ResourceScopeImpl scope() {
return scope;
@ForceInline
public MemorySessionImpl sessionImpl() {
return MemorySessionImpl.toSessionImpl(session);
}
private void checkBoundsSmall(int offset, int length) {
if (length < 0 ||
offset < 0 ||
offset > (int)this.length - length) { // careful of overflow
throw outOfBoundException(offset, length);
}
@Override
public MemorySession session() {
return session;
}
private IndexOutOfBoundsException outOfBoundException(long offset, long length) {
@ -490,18 +468,9 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
if (currentIndex < elemCount) {
AbstractMemorySegmentImpl acquired = segment;
try {
if (acquired.isSmall()) {
int index = (int) currentIndex;
int limit = (int) elemCount;
int elemSize = (int) elementSize;
for (; index < limit; index++) {
action.accept(acquired.asSliceNoCheck(index * elemSize, elemSize));
}
} else {
for (long i = currentIndex ; i < elemCount ; i++) {
action.accept(acquired.asSliceNoCheck(i * elementSize, elementSize));
}
}
} finally {
currentIndex = elemCount;
segment = null;
@ -527,6 +496,27 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
return "MemorySegment{ id=0x" + Long.toHexString(id()) + " limit: " + length + " }";
}
@Override
public boolean equals(Object o) {
return o instanceof AbstractMemorySegmentImpl that &&
isNative() == that.isNative() &&
unsafeGetOffset() == that.unsafeGetOffset() &&
unsafeGetBase() == that.unsafeGetBase() &&
length == that.length &&
session.equals(that.session);
}
@Override
public int hashCode() {
return Objects.hash(
isNative(),
unsafeGetOffset(),
unsafeGetBase(),
length,
session
);
}
public static AbstractMemorySegmentImpl ofBuffer(ByteBuffer bb) {
Objects.requireNonNull(bb);
long bbAddress = nioAccess.getBufferAddress(bb);
@ -538,14 +528,14 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
int size = limit - pos;
AbstractMemorySegmentImpl bufferSegment = (AbstractMemorySegmentImpl)nioAccess.bufferSegment(bb);
final ResourceScopeImpl bufferScope;
final MemorySessionImpl bufferSession;
int modes;
if (bufferSegment != null) {
bufferScope = bufferSegment.scope;
bufferSession = bufferSegment.sessionImpl();
modes = bufferSegment.mask;
} else {
bufferScope = ResourceScopeImpl.GLOBAL;
modes = defaultAccessModes(size);
bufferSession = MemorySessionImpl.heapSession(bb);
modes = DEFAULT_MODES;
}
if (bb.isReadOnly()) {
modes |= READ_ONLY;
@ -553,9 +543,9 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
if (base != null) {
return new HeapMemorySegmentImpl.OfByte(bbAddress + pos, (byte[])base, size, modes);
} else if (unmapper == null) {
return new NativeMemorySegmentImpl(bbAddress + pos, size, modes, bufferScope);
return new NativeMemorySegmentImpl(bbAddress + pos, size, modes, bufferSession);
} else {
return new MappedMemorySegmentImpl(bbAddress + pos, unmapper, size, modes, bufferScope);
return new MappedMemorySegmentImpl(bbAddress + pos, unmapper, size, modes, bufferSession);
}
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* 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
@ -25,9 +25,9 @@
package jdk.internal.foreign;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.SegmentAllocator;
import jdk.incubator.foreign.ResourceScope;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.SegmentAllocator;
public final class ArenaAllocator implements SegmentAllocator {
@ -39,12 +39,12 @@ public final class ArenaAllocator implements SegmentAllocator {
private long size = 0;
private final long blockSize;
private final long arenaSize;
private final ResourceScope scope;
private final MemorySession session;
public ArenaAllocator(long blockSize, long arenaSize, ResourceScope scope) {
public ArenaAllocator(long blockSize, long arenaSize, MemorySession session) {
this.blockSize = blockSize;
this.arenaSize = arenaSize;
this.scope = scope;
this.session = session;
this.segment = newSegment(blockSize, 1);
}
@ -60,17 +60,13 @@ public final class ArenaAllocator implements SegmentAllocator {
}
}
public ResourceScope scope() {
return scope;
}
private MemorySegment newSegment(long bytesSize, long bytesAlignment) {
long allocatedSize = Utils.alignUp(bytesSize, bytesAlignment);
if (size + allocatedSize > arenaSize) {
throw new OutOfMemoryError();
}
size += allocatedSize;
return MemorySegment.allocateNative(bytesSize, bytesAlignment, scope);
return MemorySegment.allocateNative(bytesSize, bytesAlignment, session);
}
@Override

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* 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
@ -25,7 +25,7 @@
*/
package jdk.internal.foreign;
import static jdk.incubator.foreign.ValueLayout.ADDRESS;
import static java.lang.foreign.ValueLayout.ADDRESS;
import static sun.security.action.GetPropertyAction.privilegedGetProperty;
public enum CABI {
@ -56,7 +56,7 @@ public enum CABI {
current = LinuxAArch64;
}
} else {
throw new ExceptionInInitializerError(
throw new UnsupportedOperationException(
"Unsupported os, arch, or address size: " + os + ", " + arch + ", " + addressSize);
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* 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
@ -25,19 +25,19 @@
package jdk.internal.foreign;
import jdk.internal.vm.annotation.ForceInline;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.ref.Cleaner;
import jdk.internal.vm.annotation.ForceInline;
/**
* A confined scope, which features an owner thread. The liveness check features an additional
* confinement check - that is, calling any operation on this scope from a thread other than the
* A confined session, which features an owner thread. The liveness check features an additional
* confinement check - that is, calling any operation on this session from a thread other than the
* owner thread will result in an exception. Because of this restriction, checking the liveness bit
* can be performed in plain mode.
*/
final class ConfinedScope extends ResourceScopeImpl {
final class ConfinedSession extends MemorySessionImpl {
private int asyncReleaseCount = 0;
@ -45,13 +45,13 @@ final class ConfinedScope extends ResourceScopeImpl {
static {
try {
ASYNC_RELEASE_COUNT = MethodHandles.lookup().findVarHandle(ConfinedScope.class, "asyncReleaseCount", int.class);
ASYNC_RELEASE_COUNT = MethodHandles.lookup().findVarHandle(ConfinedSession.class, "asyncReleaseCount", int.class);
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public ConfinedScope(Thread owner, Cleaner cleaner) {
public ConfinedSession(Thread owner, Cleaner cleaner) {
super(owner, new ConfinedResourceList(), cleaner);
}
@ -65,7 +65,7 @@ final class ConfinedScope extends ResourceScopeImpl {
public void acquire0() {
checkValidStateSlow();
if (state == MAX_FORKS) {
throw new IllegalStateException("Scope keep alive limit exceeded");
throw new IllegalStateException("Session keep alive limit exceeded");
}
state++;
}
@ -76,9 +76,9 @@ final class ConfinedScope extends ResourceScopeImpl {
if (Thread.currentThread() == owner) {
state--;
} else {
// It is possible to end up here in two cases: this scope was kept alive by some other confined scope
// It is possible to end up here in two cases: this session was kept alive by some other confined session
// which is implicitly released (in which case the release call comes from the cleaner thread). Or,
// this scope might be kept alive by a shared scope, which means the release call can come from any
// this session might be kept alive by a shared session, which means the release call can come from any
// thread.
ASYNC_RELEASE_COUNT.getAndAdd(this, 1);
}
@ -89,7 +89,7 @@ final class ConfinedScope extends ResourceScopeImpl {
if (state == 0 || state - ((int)ASYNC_RELEASE_COUNT.getVolatile(this)) == 0) {
state = CLOSED;
} else {
throw new IllegalStateException("Scope is kept alive by " + state + " scopes");
throw new IllegalStateException("Session is acquired by " + state + " clients");
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* 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
@ -26,15 +26,15 @@
package jdk.internal.foreign;
import jdk.incubator.foreign.MemorySegment;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.nio.ByteBuffer;
import java.util.Objects;
import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.Unsafe;
import jdk.internal.vm.annotation.ForceInline;
import java.nio.ByteBuffer;
import java.util.Objects;
/**
* Implementation for heap memory segments. A heap memory segment is composed by an offset and
* a base object (typically an array). To enhance performances, the access to the base object needs to feature
@ -44,7 +44,7 @@ import java.util.Objects;
* the field type storing the 'base' coordinate is just Object; similarly, all the constructor in the subclasses
* accept an Object 'base' parameter instead of a sharper type (e.g. {@code byte[]}). This is deliberate, as
* using sharper types would require use of type-conversions, which in turn would inhibit some C2 optimizations,
* such as the elimination of store barriers in methods like {@link HeapMemorySegmentImpl#dup(long, long, int, ResourceScopeImpl)}.
* such as the elimination of store barriers in methods like {@link HeapMemorySegmentImpl#dup(long, long, int, MemorySession)}.
*/
public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
@ -61,7 +61,7 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
@ForceInline
HeapMemorySegmentImpl(long offset, Object base, long length, int mask) {
super(length, mask, ResourceScopeImpl.GLOBAL);
super(length, mask, MemorySessionImpl.GLOBAL);
this.offset = offset;
this.base = base;
}
@ -75,7 +75,7 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
}
@Override
abstract HeapMemorySegmentImpl dup(long offset, long size, int mask, ResourceScopeImpl scope);
abstract HeapMemorySegmentImpl dup(long offset, long size, int mask, MemorySession session);
@Override
ByteBuffer makeByteBuffer() {
@ -95,7 +95,7 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
}
@Override
OfByte dup(long offset, long size, int mask, ResourceScopeImpl scope) {
OfByte dup(long offset, long size, int mask, MemorySession session) {
return new OfByte(this.offset + offset, base, size, mask);
}
@ -107,7 +107,7 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
public static MemorySegment fromArray(byte[] arr) {
Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_BYTE_INDEX_SCALE;
return new OfByte(Unsafe.ARRAY_BYTE_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize));
return new OfByte(Unsafe.ARRAY_BYTE_BASE_OFFSET, arr, byteSize, DEFAULT_MODES);
}
@Override
@ -123,7 +123,7 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
}
@Override
OfChar dup(long offset, long size, int mask, ResourceScopeImpl scope) {
OfChar dup(long offset, long size, int mask, MemorySession session) {
return new OfChar(this.offset + offset, base, size, mask);
}
@ -135,7 +135,7 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
public static MemorySegment fromArray(char[] arr) {
Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_CHAR_INDEX_SCALE;
return new OfChar(Unsafe.ARRAY_CHAR_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize));
return new OfChar(Unsafe.ARRAY_CHAR_BASE_OFFSET, arr, byteSize, DEFAULT_MODES);
}
@Override
@ -151,7 +151,7 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
}
@Override
OfShort dup(long offset, long size, int mask, ResourceScopeImpl scope) {
OfShort dup(long offset, long size, int mask, MemorySession session) {
return new OfShort(this.offset + offset, base, size, mask);
}
@ -163,7 +163,7 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
public static MemorySegment fromArray(short[] arr) {
Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_SHORT_INDEX_SCALE;
return new OfShort(Unsafe.ARRAY_SHORT_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize));
return new OfShort(Unsafe.ARRAY_SHORT_BASE_OFFSET, arr, byteSize, DEFAULT_MODES);
}
@Override
@ -179,7 +179,7 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
}
@Override
OfInt dup(long offset, long size, int mask, ResourceScopeImpl scope) {
OfInt dup(long offset, long size, int mask, MemorySession session) {
return new OfInt(this.offset + offset, base, size, mask);
}
@ -191,7 +191,7 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
public static MemorySegment fromArray(int[] arr) {
Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_INT_INDEX_SCALE;
return new OfInt(Unsafe.ARRAY_INT_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize));
return new OfInt(Unsafe.ARRAY_INT_BASE_OFFSET, arr, byteSize, DEFAULT_MODES);
}
@Override
@ -207,7 +207,7 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
}
@Override
OfLong dup(long offset, long size, int mask, ResourceScopeImpl scope) {
OfLong dup(long offset, long size, int mask, MemorySession session) {
return new OfLong(this.offset + offset, base, size, mask);
}
@ -219,7 +219,7 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
public static MemorySegment fromArray(long[] arr) {
Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_LONG_INDEX_SCALE;
return new OfLong(Unsafe.ARRAY_LONG_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize));
return new OfLong(Unsafe.ARRAY_LONG_BASE_OFFSET, arr, byteSize, DEFAULT_MODES);
}
@Override
@ -235,7 +235,7 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
}
@Override
OfFloat dup(long offset, long size, int mask, ResourceScopeImpl scope) {
OfFloat dup(long offset, long size, int mask, MemorySession session) {
return new OfFloat(this.offset + offset, base, size, mask);
}
@ -247,7 +247,7 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
public static MemorySegment fromArray(float[] arr) {
Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_FLOAT_INDEX_SCALE;
return new OfFloat(Unsafe.ARRAY_FLOAT_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize));
return new OfFloat(Unsafe.ARRAY_FLOAT_BASE_OFFSET, arr, byteSize, DEFAULT_MODES);
}
@Override
@ -263,7 +263,7 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
}
@Override
OfDouble dup(long offset, long size, int mask, ResourceScopeImpl scope) {
OfDouble dup(long offset, long size, int mask, MemorySession session) {
return new OfDouble(this.offset + offset, base, size, mask);
}
@ -275,7 +275,7 @@ public abstract class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
public static MemorySegment fromArray(double[] arr) {
Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_DOUBLE_INDEX_SCALE;
return new OfDouble(Unsafe.ARRAY_DOUBLE_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize));
return new OfDouble(Unsafe.ARRAY_DOUBLE_BASE_OFFSET, arr, byteSize, DEFAULT_MODES);
}
@Override

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,47 +25,33 @@
*/
package jdk.internal.foreign;
import jdk.incubator.foreign.MemoryHandles;
import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.MemorySegment;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.incubator.foreign.GroupLayout;
import jdk.incubator.foreign.SequenceLayout;
import jdk.incubator.foreign.ValueLayout;
import java.lang.foreign.GroupLayout;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.SequenceLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.function.ToLongFunction;
import java.util.function.UnaryOperator;
/**
* This class provide support for constructing layout paths; that is, starting from a root path (see {@link #rootPath(MemoryLayout, ToLongFunction)},
* This class provide support for constructing layout paths; that is, starting from a root path (see {@link #rootPath(MemoryLayout)},
* a path can be constructed by selecting layout elements using the selector methods provided by this class
* (see {@link #sequenceElement()}, {@link #sequenceElement(long)}, {@link #sequenceElement(long, long)}, {@link #groupElement(String)}).
* Once a path has been fully constructed, clients can ask for the offset associated with the layout element selected
* by the path (see {@link #offset}), or obtain a memory access var handle to access the selected layout element
* by the path (see {@link #offset}), or obtain var handle to access the selected layout element
* given an address pointing to a segment associated with the root layout (see {@link #dereferenceHandle()}).
*/
public class LayoutPath {
private static final MethodHandle ADD_STRIDE;
private static final MethodHandle MH_ADD_SCALED_OFFSET;
private static final MethodHandle MH_SLICE;
private static final int UNSPECIFIED_ELEM_INDEX = -1;
static {
try {
MethodHandles.Lookup lookup = MethodHandles.lookup();
ADD_STRIDE = lookup.findStatic(LayoutPath.class, "addStride",
MethodType.methodType(long.class, MemorySegment.class, long.class, long.class, long.class));
MH_ADD_SCALED_OFFSET = lookup.findStatic(LayoutPath.class, "addScaledOffset",
MethodType.methodType(long.class, long.class, long.class, long.class));
MH_SLICE = lookup.findVirtual(MemorySegment.class, "asSlice",
@ -79,16 +65,12 @@ public class LayoutPath {
private final long offset;
private final LayoutPath enclosing;
private final long[] strides;
private final long elementIndex;
private final ToLongFunction<MemoryLayout> sizeFunc;
private LayoutPath(MemoryLayout layout, long offset, long[] strides, long elementIndex, LayoutPath enclosing, ToLongFunction<MemoryLayout> sizeFunc) {
private LayoutPath(MemoryLayout layout, long offset, long[] strides, LayoutPath enclosing) {
this.layout = layout;
this.offset = offset;
this.strides = strides;
this.enclosing = enclosing;
this.elementIndex = elementIndex;
this.sizeFunc = sizeFunc;
}
// Layout path selector methods
@ -97,7 +79,7 @@ public class LayoutPath {
check(SequenceLayout.class, "attempting to select a sequence element from a non-sequence layout");
SequenceLayout seq = (SequenceLayout)layout;
MemoryLayout elem = seq.elementLayout();
return LayoutPath.nestedPath(elem, offset, addStride(sizeFunc.applyAsLong(elem)), UNSPECIFIED_ELEM_INDEX, this);
return LayoutPath.nestedPath(elem, offset, addStride(elem.bitSize()), this);
}
public LayoutPath sequenceElement(long start, long step) {
@ -105,9 +87,8 @@ public class LayoutPath {
SequenceLayout seq = (SequenceLayout)layout;
checkSequenceBounds(seq, start);
MemoryLayout elem = seq.elementLayout();
long elemSize = sizeFunc.applyAsLong(elem);
return LayoutPath.nestedPath(elem, offset + (start * elemSize), addStride(elemSize * step),
UNSPECIFIED_ELEM_INDEX, this);
long elemSize = elem.bitSize();
return LayoutPath.nestedPath(elem, offset + (start * elemSize), addStride(elemSize * step), this);
}
public LayoutPath sequenceElement(long index) {
@ -117,10 +98,10 @@ public class LayoutPath {
long elemOffset = 0;
if (index > 0) {
//if index == 0, we do not depend on sequence element size, so skip
long elemSize = sizeFunc.applyAsLong(seq.elementLayout());
long elemSize = seq.elementLayout().bitSize();
elemOffset = elemSize * index;
}
return LayoutPath.nestedPath(seq.elementLayout(), offset + elemOffset, strides, index, this);
return LayoutPath.nestedPath(seq.elementLayout(), offset + elemOffset, strides, this);
}
public LayoutPath groupElement(String name) {
@ -128,22 +109,20 @@ public class LayoutPath {
GroupLayout g = (GroupLayout)layout;
long offset = 0;
MemoryLayout elem = null;
int index = -1;
for (int i = 0; i < g.memberLayouts().size(); i++) {
MemoryLayout l = g.memberLayouts().get(i);
if (l.name().isPresent() &&
l.name().get().equals(name)) {
elem = l;
index = i;
break;
} else if (g.isStruct()) {
offset += sizeFunc.applyAsLong(l);
offset += l.bitSize();
}
}
if (elem == null) {
throw badLayoutPath("cannot resolve '" + name + "' in layout " + layout);
}
return LayoutPath.nestedPath(elem, this.offset + offset, strides, index, this);
return LayoutPath.nestedPath(elem, this.offset + offset, strides, this);
}
// Layout path projections
@ -158,28 +137,16 @@ public class LayoutPath {
}
checkAlignment(this);
List<Class<?>> expectedCoordinates = new ArrayList<>();
Deque<Integer> perms = new ArrayDeque<>();
perms.addFirst(0);
expectedCoordinates.add(MemorySegment.class);
VarHandle handle = Utils.makeMemoryAccessVarHandle(valueLayout, true);
for (int i = 0 ; i < strides.length ; i++) {
expectedCoordinates.add(long.class);
perms.addFirst(0);
perms.addLast(i + 1);
//add stride
handle = MemoryHandles.collectCoordinates(handle, 1 + i,
MethodHandles.insertArguments(ADD_STRIDE, 1, Utils.bitsToBytesOrThrow(strides[strides.length - 1 - i], IllegalStateException::new))); // MS, long, MS_n, long_n, long
}
//add offset
handle = MemoryHandles.insertCoordinates(handle, 1 + strides.length, Utils.bitsToBytesOrThrow(offset, IllegalStateException::new));
if (strides.length > 0) {
// remove duplicate MS args
handle = MemoryHandles.permuteCoordinates(handle, expectedCoordinates, perms.stream().mapToInt(i -> i).toArray());
VarHandle handle = Utils.makeSegmentViewVarHandle(valueLayout);
for (int i = strides.length - 1; i >= 0; i--) {
MethodHandle collector = MethodHandles.insertArguments(MH_ADD_SCALED_OFFSET, 2,
Utils.bitsToBytesOrThrow(strides[i], IllegalArgumentException::new));
// (J, ...) -> J to (J, J, ...) -> J
// i.e. new coord is prefixed. Last coord will correspond to innermost layout
handle = MethodHandles.collectCoordinates(handle, 1, collector);
}
handle = MethodHandles.insertCoordinates(handle, 1,
Utils.bitsToBytesOrThrow(offset, IllegalArgumentException::new));
return handle;
}
@ -219,46 +186,14 @@ public class LayoutPath {
return layout;
}
public MemoryLayout map(UnaryOperator<MemoryLayout> op) {
MemoryLayout newLayout = op.apply(layout);
if (enclosing == null) {
return newLayout;
} else if (enclosing.layout instanceof SequenceLayout seq) {
if (seq.elementCount().isPresent()) {
return enclosing.map(l -> dup(l, MemoryLayout.sequenceLayout(seq.elementCount().getAsLong(), newLayout)));
} else {
return enclosing.map(l -> dup(l, MemoryLayout.sequenceLayout(newLayout)));
}
} else if (enclosing.layout instanceof GroupLayout g) {
List<MemoryLayout> newElements = new ArrayList<>(g.memberLayouts());
//if we selected a layout in a group we must have a valid index
newElements.set((int)elementIndex, newLayout);
if (g.isUnion()) {
return enclosing.map(l -> dup(l, MemoryLayout.unionLayout(newElements.toArray(new MemoryLayout[0]))));
} else {
return enclosing.map(l -> dup(l, MemoryLayout.structLayout(newElements.toArray(new MemoryLayout[0]))));
}
} else {
return newLayout;
}
}
private MemoryLayout dup(MemoryLayout oldLayout, MemoryLayout newLayout) {
newLayout = newLayout.withBitAlignment(oldLayout.bitAlignment());
if (oldLayout.name().isPresent()) {
newLayout.withName(oldLayout.name().get());
}
return newLayout;
}
// Layout path construction
public static LayoutPath rootPath(MemoryLayout layout, ToLongFunction<MemoryLayout> sizeFunc) {
return new LayoutPath(layout, 0L, EMPTY_STRIDES, -1, null, sizeFunc);
public static LayoutPath rootPath(MemoryLayout layout) {
return new LayoutPath(layout, 0L, EMPTY_STRIDES, null);
}
private static LayoutPath nestedPath(MemoryLayout layout, long offset, long[] strides, long elementIndex, LayoutPath encl) {
return new LayoutPath(layout, offset, strides, elementIndex, encl, encl.sizeFunc);
private static LayoutPath nestedPath(MemoryLayout layout, long offset, long[] strides, LayoutPath encl) {
return new LayoutPath(layout, offset, strides, encl);
}
// Helper methods
@ -270,8 +205,8 @@ public class LayoutPath {
}
private void checkSequenceBounds(SequenceLayout seq, long index) {
if (seq.elementCount().isPresent() && index >= seq.elementCount().getAsLong()) {
throw badLayoutPath(String.format("Sequence index out of bound; found: %d, size: %d", index, seq.elementCount().getAsLong()));
if (index >= seq.elementCount()) {
throw badLayoutPath(String.format("Sequence index out of bound; found: %d, size: %d", index, seq.elementCount()));
}
}
@ -348,9 +283,4 @@ public class LayoutPath {
return kind;
}
}
private static long addStride(MemorySegment segment, long stride, long base, long index) {
return MemorySegmentProxy.addOffsets(base,
MemorySegmentProxy.multiplyOffsets(stride, index, ((MemorySegmentProxy)segment)), (MemorySegmentProxy)segment);
}
}

View file

@ -0,0 +1,122 @@
/*
* 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 jdk.internal.foreign;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.nio.ByteBuffer;
import jdk.internal.access.foreign.UnmapperProxy;
import jdk.internal.misc.ScopedMemoryAccess;
/**
* Implementation for a mapped memory segments. A mapped memory segment is a native memory segment, which
* additionally features an {@link UnmapperProxy} object. This object provides detailed information about the
* memory mapped segment, such as the file descriptor associated with the mapping. This information is crucial
* in order to correctly reconstruct a byte buffer object from the segment (see {@link #makeByteBuffer()}).
*/
public class MappedMemorySegmentImpl extends NativeMemorySegmentImpl {
private final UnmapperProxy unmapper;
static ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
public MappedMemorySegmentImpl(long min, UnmapperProxy unmapper, long length, int mask, MemorySession session) {
super(min, length, mask, session);
this.unmapper = unmapper;
}
@Override
ByteBuffer makeByteBuffer() {
return nioAccess.newMappedByteBuffer(unmapper, min, (int)length, null,
session == MemorySessionImpl.GLOBAL ? null : this);
}
@Override
MappedMemorySegmentImpl dup(long offset, long size, int mask, MemorySession session) {
return new MappedMemorySegmentImpl(min + offset, unmapper, size, mask, session);
}
// mapped segment methods
@Override
public MappedMemorySegmentImpl asSlice(long offset, long newSize) {
return (MappedMemorySegmentImpl)super.asSlice(offset, newSize);
}
@Override
public boolean isMapped() {
return true;
}
// support for mapped segments
public MemorySegment segment() {
return MappedMemorySegmentImpl.this;
}
public void load() {
SCOPED_MEMORY_ACCESS.load(sessionImpl(), min, unmapper.isSync(), length);
}
public void unload() {
SCOPED_MEMORY_ACCESS.unload(sessionImpl(), min, unmapper.isSync(), length);
}
public boolean isLoaded() {
return SCOPED_MEMORY_ACCESS.isLoaded(sessionImpl(), min, unmapper.isSync(), length);
}
public void force() {
SCOPED_MEMORY_ACCESS.force(sessionImpl(), unmapper.fileDescriptor(), min, unmapper.isSync(), 0, length);
}
public static class EmptyMappedMemorySegmentImpl extends MappedMemorySegmentImpl {
public EmptyMappedMemorySegmentImpl(int modes, MemorySession session) {
super(0, null, 0, modes, session);
}
@Override
public void load() {
// do nothing
}
@Override
public void unload() {
// do nothing
}
@Override
public boolean isLoaded() {
return true;
}
@Override
public void force() {
// do nothing
}
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,15 +25,14 @@
*/
package jdk.internal.foreign;
import jdk.incubator.foreign.Addressable;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.ResourceScope;
import jdk.incubator.foreign.ValueLayout;
import java.lang.foreign.Addressable;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.ValueLayout;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.vm.annotation.ForceInline;
/**
@ -87,24 +86,24 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
return ofLongUnchecked(value, Long.MAX_VALUE);
}
public static MemorySegment ofLongUnchecked(long value, long byteSize, ResourceScopeImpl resourceScope) {
return NativeMemorySegmentImpl.makeNativeSegmentUnchecked(MemoryAddress.ofLong(value), byteSize, resourceScope);
public static MemorySegment ofLongUnchecked(long value, long byteSize, MemorySession session) {
return NativeMemorySegmentImpl.makeNativeSegmentUnchecked(MemoryAddress.ofLong(value), byteSize, session);
}
public static MemorySegment ofLongUnchecked(long value, long byteSize) {
return NativeMemorySegmentImpl.makeNativeSegmentUnchecked(MemoryAddress.ofLong(value), byteSize, ResourceScopeImpl.GLOBAL);
return NativeMemorySegmentImpl.makeNativeSegmentUnchecked(MemoryAddress.ofLong(value), byteSize, MemorySessionImpl.GLOBAL);
}
@Override
public ResourceScope scope() {
return ResourceScopeImpl.GLOBAL;
public MemorySessionImpl sessionImpl() {
return MemorySessionImpl.GLOBAL;
}
@Override
@CallerSensitive
@ForceInline
public String getUtf8String(long offset) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "getUtf8String");
SharedUtils.checkAddress(this);
return NativeMemorySegmentImpl.EVERYTHING.getUtf8String(toRawLongValue() + offset);
}
@ -113,7 +112,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@CallerSensitive
@ForceInline
public void setUtf8String(long offset, String str) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "setUtf8String");
SharedUtils.checkAddress(this);
NativeMemorySegmentImpl.EVERYTHING.setUtf8String(toRawLongValue() + offset, str);
}
@ -122,7 +121,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public byte get(ValueLayout.OfByte layout, long offset) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "get");
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + offset);
}
@ -130,7 +129,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public void set(ValueLayout.OfByte layout, long offset, byte value) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "set");
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + offset, value);
}
@ -138,7 +137,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public boolean get(ValueLayout.OfBoolean layout, long offset) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "get");
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + offset);
}
@ -146,7 +145,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public void set(ValueLayout.OfBoolean layout, long offset, boolean value) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "set");
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + offset, value);
}
@ -154,7 +153,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public char get(ValueLayout.OfChar layout, long offset) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "get");
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + offset);
}
@ -162,7 +161,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public void set(ValueLayout.OfChar layout, long offset, char value) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "set");
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + offset, value);
}
@ -170,7 +169,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public short get(ValueLayout.OfShort layout, long offset) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "get");
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + offset);
}
@ -178,7 +177,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public void set(ValueLayout.OfShort layout, long offset, short value) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "set");
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + offset, value);
}
@ -186,7 +185,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public int get(ValueLayout.OfInt layout, long offset) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "get");
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + offset);
}
@ -194,7 +193,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public void set(ValueLayout.OfInt layout, long offset, int value) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "set");
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + offset, value);
}
@ -202,7 +201,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public float get(ValueLayout.OfFloat layout, long offset) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "get");
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + offset);
}
@ -210,7 +209,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public void set(ValueLayout.OfFloat layout, long offset, float value) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "set");
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + offset, value);
}
@ -218,7 +217,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public long get(ValueLayout.OfLong layout, long offset) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "get");
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + offset);
}
@ -226,7 +225,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public void set(ValueLayout.OfLong layout, long offset, long value) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "set");
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + offset, value);
}
@ -234,7 +233,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public double get(ValueLayout.OfDouble layout, long offset) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "get");
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + offset);
}
@ -242,7 +241,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public void set(ValueLayout.OfDouble layout, long offset, double value) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "set");
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + offset, value);
}
@ -250,7 +249,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public MemoryAddress get(ValueLayout.OfAddress layout, long offset) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "get");
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + offset);
}
@ -258,7 +257,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public void set(ValueLayout.OfAddress layout, long offset, Addressable value) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "set");
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + offset, value.address());
}
@ -266,7 +265,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public char getAtIndex(ValueLayout.OfChar layout, long index) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "getAtIndex");
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + (index * layout.byteSize()));
}
@ -275,7 +274,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public void setAtIndex(ValueLayout.OfChar layout, long index, char value) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "setAtIndex");
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + (index * layout.byteSize()), value);
}
@ -284,7 +283,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public short getAtIndex(ValueLayout.OfShort layout, long index) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "getAtIndex");
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + (index * layout.byteSize()));
}
@ -293,7 +292,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public void setAtIndex(ValueLayout.OfShort layout, long index, short value) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "setAtIndex");
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + (index * layout.byteSize()), value);
}
@ -302,7 +301,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public int getAtIndex(ValueLayout.OfInt layout, long index) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "getAtIndex");
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + (index * layout.byteSize()));
}
@ -311,7 +310,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public void setAtIndex(ValueLayout.OfInt layout, long index, int value) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "setAtIndex");
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + (index * layout.byteSize()), value);
}
@ -320,7 +319,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public float getAtIndex(ValueLayout.OfFloat layout, long index) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "getAtIndex");
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + (index * layout.byteSize()));
}
@ -329,7 +328,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public void setAtIndex(ValueLayout.OfFloat layout, long index, float value) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "setAtIndex");
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + (index * layout.byteSize()), value);
}
@ -338,7 +337,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public long getAtIndex(ValueLayout.OfLong layout, long index) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "getAtIndex");
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + (index * layout.byteSize()));
}
@ -347,7 +346,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public void setAtIndex(ValueLayout.OfLong layout, long index, long value) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "setAtIndex");
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + (index * layout.byteSize()), value);
}
@ -356,7 +355,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public double getAtIndex(ValueLayout.OfDouble layout, long index) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "getAtIndex");
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + (index * layout.byteSize()));
}
@ -365,7 +364,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public void setAtIndex(ValueLayout.OfDouble layout, long index, double value) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "setAtIndex");
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + (index * layout.byteSize()), value);
}
@ -374,7 +373,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public MemoryAddress getAtIndex(ValueLayout.OfAddress layout, long index) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "getAtIndex");
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
return NativeMemorySegmentImpl.EVERYTHING.get(layout, toRawLongValue() + (index * layout.byteSize()));
}
@ -383,7 +382,7 @@ public final class MemoryAddressImpl implements MemoryAddress, Scoped {
@ForceInline
@CallerSensitive
public void setAtIndex(ValueLayout.OfAddress layout, long index, Addressable value) {
Reflection.ensureNativeAccess(Reflection.getCallerClass());
Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemoryAddress.class, "setAtIndex");
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
NativeMemorySegmentImpl.EVERYTHING.set(layout, toRawLongValue() + (index * layout.byteSize()), value.address());
}

View file

@ -0,0 +1,463 @@
/*
* 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 jdk.internal.foreign;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.SegmentAllocator;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.ref.Cleaner;
import java.lang.ref.Reference;
import java.util.Objects;
import jdk.internal.misc.ScopedMemoryAccess;
import jdk.internal.ref.CleanerFactory;
import jdk.internal.vm.annotation.ForceInline;
import sun.nio.ch.DirectBuffer;
/**
* This class manages the temporal bounds associated with a memory segment as well
* as thread confinement. A session has a liveness bit, which is updated when the session is closed
* (this operation is triggered by {@link MemorySession#close()}). This bit is consulted prior
* to memory access (see {@link #checkValidState()}).
* There are two kinds of memory session: confined memory session and shared memory session.
* A confined memory session has an associated owner thread that confines some operations to
* associated owner thread such as {@link #close()} or {@link #checkValidState()}.
* Shared sessions do not feature an owner thread - meaning their operations can be called, in a racy
* manner, by multiple threads. To guarantee temporal safety in the presence of concurrent thread,
* shared sessions use a more sophisticated synchronization mechanism, which guarantees that no concurrent
* access is possible when a session is being closed (see {@link jdk.internal.misc.ScopedMemoryAccess}).
*/
public abstract non-sealed class MemorySessionImpl implements Scoped, MemorySession, SegmentAllocator {
final ResourceList resourceList;
final Cleaner.Cleanable cleanable;
final Thread owner;
static final int OPEN = 0;
static final int CLOSING = -1;
static final int CLOSED = -2;
int state = OPEN;
static final VarHandle STATE;
static {
try {
STATE = MethodHandles.lookup().findVarHandle(MemorySessionImpl.class, "state", int.class);
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
static final int MAX_FORKS = Integer.MAX_VALUE;
@Override
public void addCloseAction(Runnable runnable) {
Objects.requireNonNull(runnable);
addInternal(runnable instanceof ResourceList.ResourceCleanup cleanup ?
cleanup : ResourceList.ResourceCleanup.ofRunnable(runnable));
}
/**
* Add a cleanup action. If a failure occurred (because of a add vs. close race), call the cleanup action.
* This semantics is useful when allocating new memory segments, since we first do a malloc/mmap and _then_
* we register the cleanup (free/munmap) against the session; so, if registration fails, we still have to
* cleanup memory. From the perspective of the client, such a failure would manifest as a factory
* returning a segment that is already "closed" - which is always possible anyway (e.g. if the session
* is closed _after_ the cleanup for the segment is registered but _before_ the factory returns the
* new segment to the client). For this reason, it's not worth adding extra complexity to the segment
* initialization logic here - and using an optimistic logic works well in practice.
*/
public void addOrCleanupIfFail(ResourceList.ResourceCleanup resource) {
try {
addInternal(resource);
} catch (Throwable ex) {
resource.cleanup();
}
}
void addInternal(ResourceList.ResourceCleanup resource) {
try {
checkValidStateSlow();
resourceList.add(resource);
} catch (ScopedMemoryAccess.ScopedAccessError err) {
throw new IllegalStateException("Already closed");
}
}
protected MemorySessionImpl(Thread owner, ResourceList resourceList, Cleaner cleaner) {
this.owner = owner;
this.resourceList = resourceList;
cleanable = (cleaner != null) ?
cleaner.register(this, resourceList) : null;
}
public static MemorySession createConfined(Thread thread, Cleaner cleaner) {
return new ConfinedSession(thread, cleaner);
}
public static MemorySession createShared(Cleaner cleaner) {
return new SharedSession(cleaner);
}
public static MemorySessionImpl createImplicit() {
return new ImplicitSession();
}
@Override
public MemorySegment allocate(long bytesSize, long bytesAlignment) {
return MemorySegment.allocateNative(bytesSize, bytesAlignment, this);
}
public abstract void release0();
public abstract void acquire0();
@Override
public boolean equals(Object o) {
return (o instanceof MemorySession other) &&
toSessionImpl(other) == this;
}
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public void whileAlive(Runnable action) {
Objects.requireNonNull(action);
acquire0();
try {
action.run();
} finally {
release0();
}
}
/**
* Returns "owner" thread of this session.
* @return owner thread (or null for a shared session)
*/
public final Thread ownerThread() {
return owner;
}
/**
* Returns true, if this session is still open. This method may be called in any thread.
* @return {@code true} if this session is not closed yet.
*/
public abstract boolean isAlive();
@Override
public MemorySession asNonCloseable() {
return isCloseable() ?
new NonCloseableView(this) : this;
}
public static MemorySessionImpl toSessionImpl(MemorySession session) {
return ((Scoped)session).sessionImpl();
}
@Override
public MemorySessionImpl sessionImpl() {
return this;
}
/**
* This is a faster version of {@link #checkValidStateSlow()}, which is called upon memory access, and which
* relies on invariants associated with the memory session implementations (volatile access
* to the closed state bit is replaced with plain access). This method should be monomorphic,
* to avoid virtual calls in the memory access hot path. This method is not intended as general purpose method
* and should only be used in the memory access handle hot path; for liveness checks triggered by other API methods,
* please use {@link #checkValidStateSlow()}.
*/
@ForceInline
public final void checkValidState() {
if (owner != null && owner != Thread.currentThread()) {
throw new IllegalStateException("Attempted access outside owning thread");
}
if (state < OPEN) {
throw ScopedMemoryAccess.ScopedAccessError.INSTANCE;
}
}
/**
* Checks that this session is still alive (see {@link #isAlive()}).
* @throws IllegalStateException if this session is already closed or if this is
* a confined session and this method is called outside of the owner thread.
*/
public final void checkValidStateSlow() {
if (owner != null && Thread.currentThread() != owner) {
throw new IllegalStateException("Attempted access outside owning thread");
} else if (!isAlive()) {
throw new IllegalStateException("Already closed");
}
}
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
@Override
public boolean isCloseable() {
return true;
}
/**
* Closes this session, executing any cleanup action (where provided).
* @throws IllegalStateException if this session is already closed or if this is
* a confined session and this method is called outside of the owner thread.
*/
@Override
public void close() {
try {
justClose();
if (cleanable != null) {
cleanable.clean();
} else {
resourceList.cleanup();
}
} finally {
Reference.reachabilityFence(this);
}
}
abstract void justClose();
/**
* The global, non-closeable, shared session. Similar to a shared session, but its {@link #close()} method throws unconditionally.
* Adding new resources to the global session, does nothing: as the session can never become not-alive, there is nothing to track.
* Acquiring and or releasing a memory session similarly does nothing.
*/
static class GlobalSessionImpl extends MemorySessionImpl {
final Object ref;
public GlobalSessionImpl(Object ref) {
super(null, null ,null);
this.ref = ref;
}
@Override
@ForceInline
public void release0() {
// do nothing
}
@Override
public boolean isCloseable() {
return false;
}
@Override
@ForceInline
public void acquire0() {
// do nothing
}
@Override
void addInternal(ResourceList.ResourceCleanup resource) {
// do nothing
}
@Override
public boolean isAlive() {
return true;
}
@Override
public void justClose() {
throw new UnsupportedOperationException();
}
}
public static final MemorySessionImpl GLOBAL = new GlobalSessionImpl(null);
public static MemorySessionImpl heapSession(Object ref) {
return new GlobalSessionImpl(ref);
}
/**
* This is an implicit, GC-backed memory session. Implicit sessions cannot be closed explicitly.
* While it would be possible to model an implicit session as a non-closeable view of a shared
* session, it is better to capture the fact that an implicit session is not just a non-closeable
* view of some session which might be closeable. This is useful e.g. in the implementations of
* {@link DirectBuffer#address()}, where obtaining an address of a buffer instance associated
* with a potentially closeable session is forbidden.
*/
static class ImplicitSession extends SharedSession {
public ImplicitSession() {
super(CleanerFactory.cleaner());
}
@Override
public void release0() {
Reference.reachabilityFence(this);
}
@Override
public void acquire0() {
// do nothing
}
@Override
public boolean isCloseable() {
return false;
}
@Override
public boolean isAlive() {
return true;
}
@Override
public MemorySession asNonCloseable() {
return this;
}
@Override
public void justClose() {
throw new UnsupportedOperationException();
}
}
/**
* This is a non-closeable view of another memory session. Instances of this class are used in resource session
* accessors (see {@link MemorySegment#session()}). This class forwards all session methods to the underlying
* "root" session implementation, and throws {@link UnsupportedOperationException} on close. This class contains
* a strong reference to the original session, so even if the original session is dropped by the client
* it would still be reachable by the GC, which is important if the session is implicitly closed.
*/
public final static class NonCloseableView implements MemorySession, Scoped {
final MemorySessionImpl session;
public NonCloseableView(MemorySessionImpl session) {
this.session = session;
}
public MemorySessionImpl sessionImpl() {
return session;
}
@Override
public boolean isAlive() {
return session.isAlive();
}
@Override
public boolean isCloseable() {
return false;
}
@Override
public Thread ownerThread() {
return session.ownerThread();
}
@Override
public boolean equals(Object o) {
return session.equals(o);
}
@Override
public int hashCode() {
return session.hashCode();
}
@Override
public void whileAlive(Runnable action) {
session.whileAlive(action);
}
@Override
public MemorySession asNonCloseable() {
return this;
}
@Override
public void addCloseAction(Runnable runnable) {
session.addCloseAction(runnable);
}
@Override
public void close() {
throw new UnsupportedOperationException();
}
}
/**
* A list of all cleanup actions associated with a memory session. Cleanup actions are modelled as instances
* of the {@link ResourceCleanup} class, and, together, form a linked list. Depending on whether a session
* is shared or confined, different implementations of this class will be used, see {@link ConfinedSession.ConfinedResourceList}
* and {@link SharedSession.SharedResourceList}.
*/
public abstract static class ResourceList implements Runnable {
ResourceCleanup fst;
abstract void add(ResourceCleanup cleanup);
abstract void cleanup();
public final void run() {
cleanup(); // cleaner interop
}
static void cleanup(ResourceCleanup first) {
ResourceCleanup current = first;
while (current != null) {
current.cleanup();
current = current.next;
}
}
public abstract static class ResourceCleanup {
ResourceCleanup next;
public abstract void cleanup();
static final ResourceCleanup CLOSED_LIST = new ResourceCleanup() {
@Override
public void cleanup() {
throw new IllegalStateException("This resource list has already been closed!");
}
};
static ResourceCleanup ofRunnable(Runnable cleanupAction) {
return new ResourceCleanup() {
@Override
public void cleanup() {
cleanupAction.run();
}
};
}
}
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* 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
@ -26,22 +26,32 @@
package jdk.internal.foreign;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemorySegment;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.nio.ByteBuffer;
import jdk.internal.misc.Unsafe;
import jdk.internal.misc.VM;
import jdk.internal.vm.annotation.ForceInline;
import sun.security.action.GetBooleanAction;
import java.nio.ByteBuffer;
/**
* Implementation for native memory segments. A native memory segment is essentially a wrapper around
* a native long address.
*/
public class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl {
public static final MemorySegment EVERYTHING = makeNativeSegmentUnchecked(MemoryAddress.NULL, Long.MAX_VALUE, ResourceScopeImpl.GLOBAL);
public static final MemorySegment EVERYTHING = new NativeMemorySegmentImpl(0, Long.MAX_VALUE, 0, MemorySessionImpl.GLOBAL) {
@Override
void checkBounds(long offset, long length) {
// do nothing
}
@Override
NativeMemorySegmentImpl dup(long offset, long size, int mask, MemorySession scope) {
throw new IllegalStateException();
}
};
private static final Unsafe unsafe = Unsafe.getUnsafe();
@ -54,8 +64,8 @@ public class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl {
final long min;
@ForceInline
NativeMemorySegmentImpl(long min, long length, int mask, ResourceScopeImpl scope) {
super(length, mask, scope);
NativeMemorySegmentImpl(long min, long length, int mask, MemorySession session) {
super(length, mask, session);
this.min = min;
}
@ -67,14 +77,14 @@ public class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl {
}
@Override
NativeMemorySegmentImpl dup(long offset, long size, int mask, ResourceScopeImpl scope) {
return new NativeMemorySegmentImpl(min + offset, size, mask, scope);
NativeMemorySegmentImpl dup(long offset, long size, int mask, MemorySession session) {
return new NativeMemorySegmentImpl(min + offset, size, mask, session);
}
@Override
ByteBuffer makeByteBuffer() {
return nioAccess.newDirectByteBuffer(min(), (int) this.length, null,
scope == ResourceScopeImpl.GLOBAL ? null : this);
session == MemorySessionImpl.GLOBAL ? null : this);
}
@Override
@ -99,14 +109,15 @@ public class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl {
// factories
public static MemorySegment makeNativeSegment(long bytesSize, long alignmentBytes, ResourceScopeImpl scope) {
scope.checkValidStateSlow();
public static MemorySegment makeNativeSegment(long bytesSize, long alignmentBytes, MemorySession session) {
MemorySessionImpl sessionImpl = MemorySessionImpl.toSessionImpl(session);
sessionImpl.checkValidStateSlow();
if (VM.isDirectMemoryPageAligned()) {
alignmentBytes = Math.max(alignmentBytes, nioAccess.pageSize());
}
long alignedSize = alignmentBytes > MAX_MALLOC_ALIGN ?
long alignedSize = Math.max(1L, alignmentBytes > MAX_MALLOC_ALIGN ?
bytesSize + (alignmentBytes - 1) :
bytesSize;
bytesSize);
nioAccess.reserveMemory(alignedSize, bytesSize);
@ -116,8 +127,8 @@ public class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl {
}
long alignedBuf = Utils.alignUp(buf, alignmentBytes);
AbstractMemorySegmentImpl segment = new NativeMemorySegmentImpl(buf, alignedSize,
defaultAccessModes(alignedSize), scope);
scope.addOrCleanupIfFail(new ResourceScopeImpl.ResourceList.ResourceCleanup() {
DEFAULT_MODES, session);
sessionImpl.addOrCleanupIfFail(new MemorySessionImpl.ResourceList.ResourceCleanup() {
@Override
public void cleanup() {
unsafe.freeMemory(buf);
@ -131,9 +142,10 @@ public class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl {
return segment;
}
public static MemorySegment makeNativeSegmentUnchecked(MemoryAddress min, long bytesSize, ResourceScopeImpl scope) {
scope.checkValidStateSlow();
AbstractMemorySegmentImpl segment = new NativeMemorySegmentImpl(min.toRawLongValue(), bytesSize, defaultAccessModes(bytesSize), scope);
public static MemorySegment makeNativeSegmentUnchecked(MemoryAddress min, long bytesSize, MemorySession session) {
MemorySessionImpl sessionImpl = MemorySessionImpl.toSessionImpl(session);
sessionImpl.checkValidStateSlow();
AbstractMemorySegmentImpl segment = new NativeMemorySegmentImpl(min.toRawLongValue(), bytesSize, DEFAULT_MODES, session);
return segment;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* 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
@ -25,8 +25,8 @@
*/
package jdk.internal.foreign;
import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.ValueLayout;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.ValueLayout;
public class PlatformLayouts {
public static <Z extends MemoryLayout> Z pick(Z sysv, Z win64, Z aarch64) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* 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
@ -25,8 +25,6 @@
package jdk.internal.foreign;
import jdk.incubator.foreign.ResourceScope;
public interface Scoped {
ResourceScope scope();
MemorySessionImpl sessionImpl();
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* 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
@ -25,27 +25,26 @@
package jdk.internal.foreign;
import jdk.internal.misc.ScopedMemoryAccess;
import jdk.internal.vm.annotation.ForceInline;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.ref.Cleaner;
import jdk.internal.misc.ScopedMemoryAccess;
import jdk.internal.vm.annotation.ForceInline;
/**
* A shared scope, which can be shared across multiple threads. Closing a shared scope has to ensure that
* (i) only one thread can successfully close a scope (e.g. in a close vs. close race) and that
* (ii) no other thread is accessing the memory associated with this scope while the segment is being
* A shared session, which can be shared across multiple threads. Closing a shared session has to ensure that
* (i) only one thread can successfully close a session (e.g. in a close vs. close race) and that
* (ii) no other thread is accessing the memory associated with this session while the segment is being
* closed. To ensure the former condition, a CAS is performed on the liveness bit. Ensuring the latter
* is trickier, and require a complex synchronization protocol (see {@link jdk.internal.misc.ScopedMemoryAccess}).
* Since it is the responsibility of the closing thread to make sure that no concurrent access is possible,
* checking the liveness bit upon access can be performed in plain mode, as in the confined case.
*/
class SharedScope extends ResourceScopeImpl {
class SharedSession extends MemorySessionImpl {
private static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
SharedScope(Cleaner cleaner) {
SharedSession(Cleaner cleaner) {
super(null, new SharedResourceList(), cleaner);
}
@ -55,12 +54,12 @@ class SharedScope extends ResourceScopeImpl {
int value;
do {
value = (int) STATE.getVolatile(this);
if (value < ALIVE) {
//segment is not alive!
if (value < OPEN) {
//segment is not open!
throw new IllegalStateException("Already closed");
} else if (value == MAX_FORKS) {
//overflow
throw new IllegalStateException("Scope keep alive limit exceeded");
throw new IllegalStateException("Session acquire limit exceeded");
}
} while (!STATE.compareAndSet(this, value, value + 1));
}
@ -71,7 +70,7 @@ class SharedScope extends ResourceScopeImpl {
int value;
do {
value = (int) STATE.getVolatile(this);
if (value <= ALIVE) {
if (value <= OPEN) {
//cannot get here - we can't close segment twice
throw new IllegalStateException("Already closed");
}
@ -79,16 +78,16 @@ class SharedScope extends ResourceScopeImpl {
}
void justClose() {
int prevState = (int) STATE.compareAndExchange(this, ALIVE, CLOSING);
int prevState = (int) STATE.compareAndExchange(this, OPEN, CLOSING);
if (prevState < 0) {
throw new IllegalStateException("Already closed");
} else if (prevState != ALIVE) {
throw new IllegalStateException("Scope is kept alive by " + prevState + " scopes");
} else if (prevState != OPEN) {
throw new IllegalStateException("Session is acquired by " + prevState + " clients");
}
boolean success = SCOPED_MEMORY_ACCESS.closeScope(this);
STATE.setVolatile(this, success ? CLOSED : ALIVE);
STATE.setVolatile(this, success ? CLOSED : OPEN);
if (!success) {
throw new IllegalStateException("Cannot close while another thread is accessing the segment");
throw new IllegalStateException("Session is acquired by 1 client");
}
}
@ -130,7 +129,7 @@ class SharedScope extends ResourceScopeImpl {
void cleanup() {
// At this point we are only interested about add vs. close races - not close vs. close
// (because MemoryScope::justClose ensured that this thread won the race to close the scope).
// (because MemorySessionImpl::justClose ensured that this thread won the race to close the session).
// So, the only "bad" thing that could happen is that some other thread adds to this list
// while we're closing it.
if (FST.getAcquire(this) != ResourceCleanup.CLOSED_LIST) {

View file

@ -25,24 +25,21 @@
package jdk.internal.foreign;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.NativeSymbol;
import jdk.incubator.foreign.ResourceScope;
import jdk.incubator.foreign.SymbolLookup;
import jdk.incubator.foreign.MemoryAddress;
import jdk.internal.loader.NativeLibrary;
import jdk.internal.loader.RawNativeLibraries;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.SymbolLookup;
import java.lang.invoke.MethodHandles;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import jdk.internal.loader.NativeLibrary;
import jdk.internal.loader.RawNativeLibraries;
import sun.security.action.GetPropertyAction;
import static jdk.incubator.foreign.ValueLayout.ADDRESS;
import static java.lang.foreign.ValueLayout.ADDRESS;
public class SystemLookup implements SymbolLookup {
@ -50,14 +47,28 @@ public class SystemLookup implements SymbolLookup {
static final SystemLookup INSTANCE = new SystemLookup();
/* A fallback lookup, used when creation of system lookup fails. */
private static final SymbolLookup fallbackLookup = name -> Optional.empty();
/*
* On POSIX systems, dlsym will allow us to lookup symbol in library dependencies; the same trick doesn't work
* on Windows. For this reason, on Windows we do not generate any side-library, and load msvcrt.dll directly instead.
*/
private static final SymbolLookup syslookup = switch (CABI.current()) {
private static final SymbolLookup syslookup = makeSystemLookup();
private static final SymbolLookup makeSystemLookup() {
try {
return switch (CABI.current()) {
case SysV, LinuxAArch64, MacOsAArch64 -> libLookup(libs -> libs.load(jdkLibraryPath("syslookup")));
case Win64 -> makeWindowsLookup(); // out of line to workaround javac crash
};
} catch (Throwable ex) {
// This can happen in the event of a library loading failure - e.g. if one of the libraries the
// system lookup depends on cannot be loaded for some reason. In such extreme cases, rather than
// fail, return a dummy lookup.
return fallbackLookup;
}
}
private static SymbolLookup makeWindowsLookup() {
Path system32 = Path.of(System.getenv("SystemRoot"), "System32");
@ -70,17 +81,19 @@ public class SystemLookup implements SymbolLookup {
if (useUCRT) {
// use a fallback lookup to look up inline functions from fallback lib
SymbolLookup fallbackLibLookup = libLookup(libs -> libs.load(jdkLibraryPath("WinFallbackLookup")));
SymbolLookup fallbackLibLookup =
libLookup(libs -> libs.load(jdkLibraryPath("syslookup")));
int numSymbols = WindowsFallbackSymbols.values().length;
MemorySegment funcs = MemorySegment.ofAddress(fallbackLibLookup.lookup("funcs").orElseThrow().address(),
ADDRESS.byteSize() * numSymbols, ResourceScope.globalScope());
ADDRESS.byteSize() * numSymbols, MemorySession.global());
SymbolLookup fallbackLookup = name -> Optional.ofNullable(WindowsFallbackSymbols.valueOfOrNull(name))
.map(symbol -> NativeSymbol.ofAddress(symbol.name(), funcs.getAtIndex(ADDRESS, symbol.ordinal()), ResourceScope.globalScope()));
Function<String, Optional<MemorySegment>> fallbackLookup = name -> Optional.ofNullable(WindowsFallbackSymbols.valueOfOrNull(name))
.map(symbol -> MemorySegment.ofAddress(funcs.getAtIndex(ADDRESS, symbol.ordinal()), 0L, MemorySession.global()));
final SymbolLookup finalLookup = lookup;
lookup = name -> finalLookup.lookup(name).or(() -> fallbackLookup.lookup(name));
lookup = name -> finalLookup.lookup(name).or(() -> fallbackLookup.apply(name));
}
return lookup;
@ -94,7 +107,7 @@ public class SystemLookup implements SymbolLookup {
long addr = lib.lookup(name);
return addr == 0 ?
Optional.empty() :
Optional.of(NativeSymbol.ofAddress(name, MemoryAddress.ofLong(addr), ResourceScope.globalScope()));
Optional.of(MemorySegment.ofAddress(MemoryAddress.ofLong(addr), 0, MemorySession.global()));
} catch (NoSuchMethodException e) {
return Optional.empty();
}
@ -114,15 +127,16 @@ public class SystemLookup implements SymbolLookup {
return javahome.resolve(lib).resolve(libname);
}
@Override
public Optional<NativeSymbol> lookup(String name) {
return syslookup.lookup(name);
}
public static SystemLookup getInstance() {
return INSTANCE;
}
@Override
public Optional<MemorySegment> lookup(String name) {
return syslookup.lookup(name);
}
// fallback symbols missing from ucrtbase.dll
// this list has to be kept in sync with the table in the companion native library
private enum WindowsFallbackSymbols {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,11 +26,11 @@
package jdk.internal.foreign;
import jdk.incubator.foreign.*;
import jdk.internal.access.SharedSecrets;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.vm.annotation.ForceInline;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.SegmentAllocator;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@ -38,19 +38,14 @@ import java.lang.invoke.VarHandle;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE;
import static sun.security.action.GetPropertyAction.*;
import jdk.internal.access.SharedSecrets;
import jdk.internal.vm.annotation.ForceInline;
import static java.lang.foreign.ValueLayout.JAVA_BYTE;
/**
* This class contains misc helper functions to support creation of memory segments.
*/
public final class Utils {
// used when testing invoke exact behavior of memory access handles
private static final boolean SHOULD_ADAPT_HANDLES
= Boolean.parseBoolean(privilegedGetProperty("jdk.internal.foreign.SHOULD_ADAPT_HANDLES", "true"));
private static final MethodHandle SEGMENT_FILTER;
private static final MethodHandle BYTE_TO_BOOL;
private static final MethodHandle BOOL_TO_BYTE;
private static final MethodHandle ADDRESS_TO_LONG;
@ -63,8 +58,6 @@ public final class Utils {
static {
try {
MethodHandles.Lookup lookup = MethodHandles.lookup();
SEGMENT_FILTER = lookup.findStatic(Utils.class, "filterSegment",
MethodType.methodType(MemorySegmentProxy.class, MemorySegment.class));
BYTE_TO_BOOL = lookup.findStatic(Utils.class, "byteToBoolean",
MethodType.methodType(boolean.class, byte.class));
BOOL_TO_BYTE = lookup.findStatic(Utils.class, "booleanToByte",
@ -105,13 +98,12 @@ public final class Utils {
}
}
public static VarHandle makeMemoryAccessVarHandle(ValueLayout layout, boolean skipAlignmentCheck) {
public static VarHandle makeSegmentViewVarHandle(ValueLayout layout) {
class VarHandleCache {
private static final Map<ValueLayout, VarHandle> handleMap = new ConcurrentHashMap<>();
private static final Map<ValueLayout, VarHandle> handleMapNoAlignCheck = new ConcurrentHashMap<>();
static VarHandle put(ValueLayout layout, VarHandle handle, boolean skipAlignmentCheck) {
VarHandle prev = (skipAlignmentCheck ? handleMapNoAlignCheck : handleMap).putIfAbsent(layout, handle);
static VarHandle put(ValueLayout layout, VarHandle handle) {
VarHandle prev = handleMap.putIfAbsent(layout, handle);
return prev != null ? prev : handle;
}
}
@ -126,26 +118,17 @@ public final class Utils {
baseCarrier = byte.class;
}
VarHandle handle = SharedSecrets.getJavaLangInvokeAccess().memoryAccessVarHandle(baseCarrier, skipAlignmentCheck,
VarHandle handle = SharedSecrets.getJavaLangInvokeAccess().memorySegmentViewHandle(baseCarrier,
layout.byteAlignment() - 1, layout.order());
// This adaptation is required, otherwise the memory access var handle will have type MemorySegmentProxy,
// and not MemorySegment (which the user expects), which causes performance issues with asType() adaptations.
handle = SHOULD_ADAPT_HANDLES
? MemoryHandles.filterCoordinates(handle, 0, SEGMENT_FILTER)
: handle;
if (layout.carrier() == boolean.class) {
handle = MemoryHandles.filterValue(handle, BOOL_TO_BYTE, BYTE_TO_BOOL);
handle = MethodHandles.filterValue(handle, BOOL_TO_BYTE, BYTE_TO_BOOL);
} else if (layout.carrier() == MemoryAddress.class) {
handle = MemoryHandles.filterValue(handle,
handle = MethodHandles.filterValue(handle,
MethodHandles.explicitCastArguments(ADDRESS_TO_LONG, MethodType.methodType(baseCarrier, MemoryAddress.class)),
MethodHandles.explicitCastArguments(LONG_TO_ADDRESS, MethodType.methodType(MemoryAddress.class, baseCarrier)));
}
return VarHandleCache.put(layout, handle, skipAlignmentCheck);
}
private static MemorySegmentProxy filterSegment(MemorySegment segment) {
return (AbstractMemorySegmentImpl)segment;
return VarHandleCache.put(layout, handle);
}
private static boolean byteToBoolean(byte b) {
@ -168,12 +151,6 @@ public final class Utils {
return addr;
}
@ForceInline
public static long scaleOffset(MemorySegment segment, long index, long size) {
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
return MemorySegmentProxy.multiplyOffsets(index, (int)size, (AbstractMemorySegmentImpl)segment);
}
@ForceInline
public static boolean isAligned(long offset, long align) {
return (offset & (align - 1)) == 0;
@ -181,7 +158,7 @@ public final class Utils {
@ForceInline
public static void checkElementAlignment(MemoryLayout layout, String msg) {
if (layout.byteAlignment() > layout.byteSize()) {
if (layout.bitAlignment() > layout.bitSize()) {
throw new IllegalArgumentException(msg);
}
}

View file

@ -24,16 +24,14 @@
*/
package jdk.internal.foreign.abi;
import jdk.incubator.foreign.Addressable;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemoryHandles;
import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.ResourceScope;
import jdk.incubator.foreign.SegmentAllocator;
import jdk.incubator.foreign.ValueLayout;
import java.lang.foreign.Addressable;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.SegmentAllocator;
import java.lang.foreign.ValueLayout;
import jdk.internal.foreign.MemoryAddressImpl;
import jdk.internal.foreign.ResourceScopeImpl;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@ -232,36 +230,36 @@ public abstract class Binding {
/**
* A binding context is used as an helper to carry out evaluation of certain bindings; for instance,
* it helps {@link Allocate} bindings, by providing the {@link SegmentAllocator} that should be used for
* the allocation operation, or {@link ToSegment} bindings, by providing the {@link ResourceScope} that
* the allocation operation, or {@link ToSegment} bindings, by providing the {@link MemorySession} that
* should be used to create an unsafe struct from a memory address.
*/
public static class Context implements AutoCloseable {
private final SegmentAllocator allocator;
private final ResourceScope scope;
private final MemorySession session;
private Context(SegmentAllocator allocator, ResourceScope scope) {
private Context(SegmentAllocator allocator, MemorySession session) {
this.allocator = allocator;
this.scope = scope;
this.session = session;
}
public SegmentAllocator allocator() {
return allocator;
}
public ResourceScope scope() {
return scope;
public MemorySession session() {
return session;
}
@Override
public void close() {
scope().close();
session().close();
}
/**
* Create a binding context from given native scope.
*/
public static Context ofBoundedAllocator(long size) {
ResourceScope scope = ResourceScope.newConfinedScope();
MemorySession scope = MemorySession.openConfined();
return new Context(SegmentAllocator.newNativeArena(size, scope), scope);
}
@ -272,7 +270,7 @@ public abstract class Binding {
public static Context ofAllocator(SegmentAllocator allocator) {
return new Context(allocator, null) {
@Override
public ResourceScope scope() {
public MemorySession session() {
throw new UnsupportedOperationException();
}
};
@ -283,7 +281,7 @@ public abstract class Binding {
* the context's allocator is accessed.
*/
public static Context ofScope() {
ResourceScope scope = ResourceScope.newConfinedScope();
MemorySession scope = MemorySession.openConfined();
return new Context(null, scope) {
@Override
public SegmentAllocator allocator() { throw new UnsupportedOperationException(); }
@ -301,7 +299,7 @@ public abstract class Binding {
}
@Override
public ResourceScope scope() {
public MemorySession session() {
throw new UnsupportedOperationException();
}
@ -630,7 +628,7 @@ public abstract class Binding {
// copies of e.g. 2 int fields of a struct as a single long, while the struct is only
// 4-byte-aligned (since it only contains ints)
ValueLayout layout = MemoryLayout.valueLayout(type(), ByteOrder.nativeOrder()).withBitAlignment(8);
return MemoryHandles.insertCoordinates(MemoryHandles.varHandle(layout), 1, offset);
return MethodHandles.insertCoordinates(MethodHandles.memorySegmentViewVarHandle(layout), 1, offset);
}
}
@ -970,7 +968,7 @@ public abstract class Binding {
}
private static MemorySegment toSegment(MemoryAddress operand, long size, Context context) {
return MemoryAddressImpl.ofLongUnchecked(operand.toRawLongValue(), size, (ResourceScopeImpl) context.scope);
return MemoryAddressImpl.ofLongUnchecked(operand.toRawLongValue(), size, context.session);
}
@Override

View file

@ -24,8 +24,8 @@
*/
package jdk.internal.foreign.abi;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.ValueLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout;
import jdk.internal.foreign.MemoryAddressImpl;
import java.io.PrintStream;
@ -45,12 +45,12 @@ class BufferLayout {
final long[] input_type_offsets;
final long[] output_type_offsets;
private final Map<jdk.internal.foreign.abi.VMStorage, Long> argOffsets;
private final Map<jdk.internal.foreign.abi.VMStorage, Long> retOffsets;
private final Map<VMStorage, Long> argOffsets;
private final Map<VMStorage, Long> retOffsets;
private BufferLayout(long size, long arguments_next_pc, long stack_args_bytes, long stack_args,
long[] input_type_offsets, long[] output_type_offsets,
Map<jdk.internal.foreign.abi.VMStorage, Long> argOffsets, Map<jdk.internal.foreign.abi.VMStorage, Long> retOffsets) {
Map<VMStorage, Long> argOffsets, Map<VMStorage, Long> retOffsets) {
this.size = size;
this.arguments_next_pc = arguments_next_pc;
this.stack_args_bytes = stack_args_bytes;
@ -76,25 +76,25 @@ class BufferLayout {
long stack_args = offset;
offset += 8;
Map<jdk.internal.foreign.abi.VMStorage, Long> argOffsets = new HashMap<>();
Map<VMStorage, Long> argOffsets = new HashMap<>();
long[] input_type_offsets = new long[abi.inputStorage.length];
for (int i = 0; i < abi.inputStorage.length; i++) {
long size = abi.arch.typeSize(i);
offset = SharedUtils.alignUp(offset, size);
input_type_offsets[i] = offset;
for (jdk.internal.foreign.abi.VMStorage store : abi.inputStorage[i]) {
for (VMStorage store : abi.inputStorage[i]) {
argOffsets.put(store, offset);
offset += size;
}
}
Map<jdk.internal.foreign.abi.VMStorage, Long> retOffsets = new HashMap<>();
Map<VMStorage, Long> retOffsets = new HashMap<>();
long[] output_type_offsets = new long[abi.outputStorage.length];
for (int i = 0; i < abi.outputStorage.length; i++) {
long size = abi.arch.typeSize(i);
offset = SharedUtils.alignUp(offset, size);
output_type_offsets[i] = offset;
for (jdk.internal.foreign.abi.VMStorage store : abi.outputStorage[i]) {
for (VMStorage store : abi.outputStorage[i]) {
retOffsets.put(store, offset);
offset += size;
}
@ -104,11 +104,11 @@ class BufferLayout {
input_type_offsets, output_type_offsets, argOffsets, retOffsets);
}
long argOffset(jdk.internal.foreign.abi.VMStorage storage) {
long argOffset(VMStorage storage) {
return argOffsets.get(storage);
}
long retOffset(jdk.internal.foreign.abi.VMStorage storage) {
long retOffset(VMStorage storage) {
return retOffsets.get(storage);
}
@ -116,8 +116,8 @@ class BufferLayout {
return Long.toHexString((long) VH_LONG.get(buffer.asSlice(offset)));
}
private void dumpValues(jdk.internal.foreign.abi.Architecture arch, MemorySegment buff, PrintStream stream,
Map<jdk.internal.foreign.abi.VMStorage, Long> offsets) {
private void dumpValues(Architecture arch, MemorySegment buff, PrintStream stream,
Map<VMStorage, Long> offsets) {
for (var entry : offsets.entrySet()) {
VMStorage storage = entry.getKey();
stream.print(storage.name());

View file

@ -24,7 +24,7 @@
*/
package jdk.internal.foreign.abi;
import jdk.incubator.foreign.FunctionDescriptor;
import java.lang.foreign.FunctionDescriptor;
import java.lang.invoke.MethodType;
import java.util.List;

View file

@ -24,8 +24,8 @@
*/
package jdk.internal.foreign.abi;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.MemoryLayout;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemoryLayout;
import sun.security.action.GetPropertyAction;
import java.lang.invoke.MethodType;
@ -40,7 +40,7 @@ import static jdk.internal.foreign.abi.Binding.Tag.*;
public class CallingSequenceBuilder {
private static final boolean VERIFY_BINDINGS = Boolean.parseBoolean(
GetPropertyAction.privilegedGetProperty("jdk.incubator.foreign.VERIFY_BINDINGS", "true"));
GetPropertyAction.privilegedGetProperty("java.lang.foreign.VERIFY_BINDINGS", "true"));
private boolean isTrivial;
private final boolean forUpcall;

View file

@ -24,12 +24,11 @@
*/
package jdk.internal.foreign.abi;
import jdk.incubator.foreign.Addressable;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.NativeSymbol;
import jdk.incubator.foreign.ResourceScope;
import jdk.incubator.foreign.SegmentAllocator;
import jdk.incubator.foreign.ValueLayout;
import java.lang.foreign.Addressable;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.SegmentAllocator;
import java.lang.foreign.ValueLayout;
import jdk.internal.access.JavaLangInvokeAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.invoke.NativeEntryPoint;
@ -86,10 +85,10 @@ public class ProgrammableInvoker {
MH_INVOKE_MOVES = lookup.findVirtual(ProgrammableInvoker.class, "invokeMoves",
methodType(Object.class, long.class, Object[].class, Binding.VMStore[].class, Binding.VMLoad[].class));
MH_INVOKE_INTERP_BINDINGS = lookup.findVirtual(ProgrammableInvoker.class, "invokeInterpBindings",
methodType(Object.class, NativeSymbol.class, SegmentAllocator.class, Object[].class, MethodHandle.class, Map.class, Map.class));
methodType(Object.class, Addressable.class, SegmentAllocator.class, Object[].class, MethodHandle.class, Map.class, Map.class));
MH_WRAP_ALLOCATOR = lookup.findStatic(Binding.Context.class, "ofAllocator",
methodType(Binding.Context.class, SegmentAllocator.class));
MH_ADDR_TO_LONG = lookup.findStatic(ProgrammableInvoker.class, "unboxTargetAddress", methodType(long.class, NativeSymbol.class));
MH_ADDR_TO_LONG = lookup.findStatic(ProgrammableInvoker.class, "unboxTargetAddress", methodType(long.class, Addressable.class));
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
@ -171,7 +170,7 @@ public class ProgrammableInvoker {
return handle;
}
private static long unboxTargetAddress(NativeSymbol addr) {
private static long unboxTargetAddress(Addressable addr) {
SharedUtils.checkSymbol(addr);
return addr.address().toRawLongValue();
}
@ -262,10 +261,10 @@ public class ProgrammableInvoker {
*/
Object invokeMoves(long addr, Object[] args, Binding.VMStore[] argBindings, Binding.VMLoad[] returnBindings) {
MemorySegment stackArgsSeg = null;
try (ResourceScope scope = ResourceScope.newConfinedScope()) {
MemorySegment argBuffer = MemorySegment.allocateNative(layout.size, 64, scope);
try (MemorySession session = MemorySession.openConfined()) {
MemorySegment argBuffer = MemorySegment.allocateNative(layout.size, 64, session);
if (stackArgsBytes > 0) {
stackArgsSeg = MemorySegment.allocateNative(stackArgsBytes, 8, scope);
stackArgsSeg = MemorySegment.allocateNative(stackArgsBytes, 8, session);
}
VH_LONG.set(argBuffer.asSlice(layout.arguments_next_pc), addr);
@ -311,7 +310,7 @@ public class ProgrammableInvoker {
}
}
Object invokeInterpBindings(NativeSymbol symbol, SegmentAllocator allocator, Object[] args, MethodHandle leaf,
Object invokeInterpBindings(Addressable symbol, SegmentAllocator allocator, Object[] args, MethodHandle leaf,
Map<VMStorage, Integer> argIndexMap,
Map<VMStorage, Integer> retIndexMap) throws Throwable {
Binding.Context unboxContext = bufferCopySize != 0

View file

@ -25,11 +25,10 @@
package jdk.internal.foreign.abi;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.NativeSymbol;
import jdk.incubator.foreign.ResourceScope;
import jdk.incubator.foreign.ValueLayout;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.ValueLayout;
import jdk.internal.access.JavaLangInvokeAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.foreign.MemoryAddressImpl;
@ -46,7 +45,6 @@ import java.util.Objects;
import java.util.stream.Stream;
import static java.lang.invoke.MethodHandles.dropArguments;
import static java.lang.invoke.MethodHandles.exactInvoker;
import static java.lang.invoke.MethodHandles.filterReturnValue;
import static java.lang.invoke.MethodHandles.identity;
import static java.lang.invoke.MethodHandles.insertArguments;
@ -89,7 +87,7 @@ public class ProgrammableUpcallHandler {
}
}
public static NativeSymbol make(ABIDescriptor abi, MethodHandle target, CallingSequence callingSequence, ResourceScope scope) {
public static MemorySegment make(ABIDescriptor abi, MethodHandle target, CallingSequence callingSequence, MemorySession session) {
Binding.VMLoad[] argMoves = argMoveBindings(callingSequence);
Binding.VMStore[] retMoves = retMoveBindings(callingSequence);
@ -135,7 +133,7 @@ public class ProgrammableUpcallHandler {
MethodHandle invokeMoves = insertArguments(MH_invokeMoves, 1, doBindingsErased, argMoves, retMoves, abi, layout);
entryPoint = allocateUpcallStub(invokeMoves, abi, layout);
}
return UpcallStubs.makeUpcall(entryPoint, scope);
return UpcallStubs.makeUpcall(entryPoint, session);
}
private static void checkPrimitive(MethodType type) {

View file

@ -24,31 +24,30 @@
*/
package jdk.internal.foreign.abi;
import jdk.incubator.foreign.Addressable;
import jdk.incubator.foreign.CLinker;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.GroupLayout;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.NativeSymbol;
import jdk.incubator.foreign.ResourceScope;
import jdk.incubator.foreign.SegmentAllocator;
import jdk.incubator.foreign.SequenceLayout;
import jdk.incubator.foreign.VaList;
import jdk.incubator.foreign.ValueLayout;
import java.lang.foreign.Addressable;
import java.lang.foreign.Linker;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.GroupLayout;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.SegmentAllocator;
import java.lang.foreign.SequenceLayout;
import java.lang.foreign.VaList;
import java.lang.foreign.ValueLayout;
import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker;
import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker;
import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.JavaLangInvokeAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.foreign.MemorySessionImpl;
import jdk.internal.foreign.Scoped;
import jdk.internal.foreign.CABI;
import jdk.internal.foreign.MemoryAddressImpl;
import jdk.internal.foreign.ResourceScopeImpl;
import jdk.internal.foreign.Utils;
import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker;
import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64Linker;
import jdk.internal.foreign.abi.x64.sysv.SysVx64Linker;
import jdk.internal.foreign.abi.x64.windows.Windowsx64Linker;
import jdk.internal.vm.annotation.ForceInline;
import java.lang.invoke.MethodHandle;
@ -78,15 +77,14 @@ import static java.lang.invoke.MethodHandles.insertArguments;
import static java.lang.invoke.MethodHandles.permuteArguments;
import static java.lang.invoke.MethodHandles.tryFinally;
import static java.lang.invoke.MethodType.methodType;
import static jdk.incubator.foreign.ValueLayout.ADDRESS;
import static jdk.incubator.foreign.ValueLayout.JAVA_BOOLEAN;
import static jdk.incubator.foreign.ValueLayout.JAVA_BYTE;
import static jdk.incubator.foreign.ValueLayout.JAVA_CHAR;
import static jdk.incubator.foreign.ValueLayout.JAVA_DOUBLE;
import static jdk.incubator.foreign.ValueLayout.JAVA_FLOAT;
import static jdk.incubator.foreign.ValueLayout.JAVA_INT;
import static jdk.incubator.foreign.ValueLayout.JAVA_LONG;
import static jdk.incubator.foreign.ValueLayout.JAVA_SHORT;
import static java.lang.foreign.ValueLayout.JAVA_BOOLEAN;
import static java.lang.foreign.ValueLayout.JAVA_BYTE;
import static java.lang.foreign.ValueLayout.JAVA_CHAR;
import static java.lang.foreign.ValueLayout.JAVA_DOUBLE;
import static java.lang.foreign.ValueLayout.JAVA_FLOAT;
import static java.lang.foreign.ValueLayout.JAVA_INT;
import static java.lang.foreign.ValueLayout.JAVA_LONG;
import static java.lang.foreign.ValueLayout.JAVA_SHORT;
public class SharedUtils {
@ -174,7 +172,7 @@ public class SharedUtils {
}
private static long alignmentOfArray(SequenceLayout ar, boolean isVar) {
if (ar.elementCount().orElseThrow() == 0) {
if (ar.elementCount() == 0) {
// VLA or incomplete
return 16;
} else if ((ar.byteSize()) >= 16 && isVar) {
@ -269,7 +267,7 @@ public class SharedUtils {
throw new IllegalArgumentException("No type for size: " + size + " isFloat=" + useFloat);
}
public static CLinker getSystemLinker() {
public static Linker getSystemLinker() {
return switch (CABI.current()) {
case Win64 -> Windowsx64Linker.getInstance();
case SysV -> SysVx64Linker.getInstance();
@ -395,7 +393,7 @@ public class SharedUtils {
// downcalls get the leading NativeSymbol/SegmentAllocator param as well
if (!upcall) {
closer = collectArguments(closer, insertPos++, reachabilityFenceHandle(NativeSymbol.class));
closer = collectArguments(closer, insertPos++, reachabilityFenceHandle(Addressable.class));
closer = dropArguments(closer, insertPos++, SegmentAllocator.class); // (Throwable, V?, NativeSymbol, SegmentAllocator) -> V/void
}
@ -420,35 +418,35 @@ public class SharedUtils {
@ForceInline
@SuppressWarnings("fallthrough")
public static void acquire(Scoped[] args) {
ResourceScope scope4 = null;
ResourceScope scope3 = null;
ResourceScope scope2 = null;
ResourceScope scope1 = null;
ResourceScope scope0 = null;
MemorySessionImpl scope4 = null;
MemorySessionImpl scope3 = null;
MemorySessionImpl scope2 = null;
MemorySessionImpl scope1 = null;
MemorySessionImpl scope0 = null;
switch (args.length) {
default:
// slow path, acquire all remaining addressable parameters in isolation
for (int i = 5 ; i < args.length ; i++) {
acquire(args[i].scope());
acquire(args[i].sessionImpl());
}
// fast path, acquire only scopes not seen in other parameters
case 5:
scope4 = args[4].scope();
scope4 = args[4].sessionImpl();
acquire(scope4);
case 4:
scope3 = args[3].scope();
scope3 = args[3].sessionImpl();
if (scope3 != scope4)
acquire(scope3);
case 3:
scope2 = args[2].scope();
scope2 = args[2].sessionImpl();
if (scope2 != scope3 && scope2 != scope4)
acquire(scope2);
case 2:
scope1 = args[1].scope();
scope1 = args[1].sessionImpl();
if (scope1 != scope2 && scope1 != scope3 && scope1 != scope4)
acquire(scope1);
case 1:
scope0 = args[0].scope();
scope0 = args[0].sessionImpl();
if (scope0 != scope1 && scope0 != scope2 && scope0 != scope3 && scope0 != scope4)
acquire(scope0);
case 0: break;
@ -458,35 +456,35 @@ public class SharedUtils {
@ForceInline
@SuppressWarnings("fallthrough")
public static void release(Scoped[] args) {
ResourceScope scope4 = null;
ResourceScope scope3 = null;
ResourceScope scope2 = null;
ResourceScope scope1 = null;
ResourceScope scope0 = null;
MemorySessionImpl scope4 = null;
MemorySessionImpl scope3 = null;
MemorySessionImpl scope2 = null;
MemorySessionImpl scope1 = null;
MemorySessionImpl scope0 = null;
switch (args.length) {
default:
// slow path, release all remaining addressable parameters in isolation
for (int i = 5 ; i < args.length ; i++) {
release(args[i].scope());
release(args[i].sessionImpl());
}
// fast path, release only scopes not seen in other parameters
case 5:
scope4 = args[4].scope();
scope4 = args[4].sessionImpl();
release(scope4);
case 4:
scope3 = args[3].scope();
scope3 = args[3].sessionImpl();
if (scope3 != scope4)
release(scope3);
case 3:
scope2 = args[2].scope();
scope2 = args[2].sessionImpl();
if (scope2 != scope3 && scope2 != scope4)
release(scope2);
case 2:
scope1 = args[1].scope();
scope1 = args[1].sessionImpl();
if (scope1 != scope2 && scope1 != scope3 && scope1 != scope4)
release(scope1);
case 1:
scope0 = args[0].scope();
scope0 = args[0].sessionImpl();
if (scope0 != scope1 && scope0 != scope2 && scope0 != scope3 && scope0 != scope4)
release(scope0);
case 0: break;
@ -494,13 +492,13 @@ public class SharedUtils {
}
@ForceInline
private static void acquire(ResourceScope scope) {
((ResourceScopeImpl)scope).acquire0();
private static void acquire(MemorySessionImpl session) {
session.acquire0();
}
@ForceInline
private static void release(ResourceScope scope) {
((ResourceScopeImpl)scope).release0();
private static void release(MemorySessionImpl session) {
session.release0();
}
/*
@ -518,7 +516,7 @@ public class SharedUtils {
List<UnaryOperator<MethodHandle>> adapters = new ArrayList<>();
for (int i = 0 ; i < downcallHandle.type().parameterCount() ; i++) {
Class<?> ptype = downcallHandle.type().parameterType(i);
if (ptype == Addressable.class || ptype == NativeSymbol.class) {
if (ptype == Addressable.class) {
addressableCount++;
} else {
int pos = i;
@ -531,7 +529,7 @@ public class SharedUtils {
MethodType adapterType = MethodType.methodType(void.class);
for (int i = 0 ; i < addressableCount ; i++) {
adapterType = adapterType.appendParameterTypes(i == 0 ? NativeSymbol.class : Addressable.class);
adapterType = adapterType.appendParameterTypes(Addressable.class);
}
MethodHandle acquireHandle = ACQUIRE_MH.asCollector(Scoped[].class, addressableCount).asType(adapterType);
@ -558,19 +556,7 @@ public class SharedUtils {
}
}
// lazy init MH_ALLOC and MH_FREE handles
private static class AllocHolder {
private static final CLinker SYS_LINKER = getSystemLinker();
static final MethodHandle MH_MALLOC = SYS_LINKER.downcallHandle(CLinker.systemCLinker().lookup("malloc").get(),
FunctionDescriptor.of(ADDRESS, JAVA_LONG));
static final MethodHandle MH_FREE = SYS_LINKER.downcallHandle(CLinker.systemCLinker().lookup("free").get(),
FunctionDescriptor.ofVoid(ADDRESS));
}
public static void checkSymbol(NativeSymbol symbol) {
public static void checkSymbol(Addressable symbol) {
checkAddressable(symbol, "Symbol is NULL");
}
@ -584,37 +570,21 @@ public class SharedUtils {
throw new IllegalArgumentException("Symbol is NULL: " + symbol);
}
public static MemoryAddress allocateMemoryInternal(long size) {
try {
return (MemoryAddress) AllocHolder.MH_MALLOC.invokeExact(size);
} catch (Throwable th) {
throw new RuntimeException(th);
}
}
public static void freeMemoryInternal(MemoryAddress addr) {
try {
AllocHolder.MH_FREE.invokeExact((Addressable)addr);
} catch (Throwable th) {
throw new RuntimeException(th);
}
}
public static VaList newVaList(Consumer<VaList.Builder> actions, ResourceScope scope) {
public static VaList newVaList(Consumer<VaList.Builder> actions, MemorySession session) {
return switch (CABI.current()) {
case Win64 -> Windowsx64Linker.newVaList(actions, scope);
case SysV -> SysVx64Linker.newVaList(actions, scope);
case LinuxAArch64 -> LinuxAArch64Linker.newVaList(actions, scope);
case MacOsAArch64 -> MacOsAArch64Linker.newVaList(actions, scope);
case Win64 -> Windowsx64Linker.newVaList(actions, session);
case SysV -> SysVx64Linker.newVaList(actions, session);
case LinuxAArch64 -> LinuxAArch64Linker.newVaList(actions, session);
case MacOsAArch64 -> MacOsAArch64Linker.newVaList(actions, session);
};
}
public static VaList newVaListOfAddress(MemoryAddress ma, ResourceScope scope) {
public static VaList newVaListOfAddress(MemoryAddress ma, MemorySession session) {
return switch (CABI.current()) {
case Win64 -> Windowsx64Linker.newVaListOfAddress(ma, scope);
case SysV -> SysVx64Linker.newVaListOfAddress(ma, scope);
case LinuxAArch64 -> LinuxAArch64Linker.newVaListOfAddress(ma, scope);
case MacOsAArch64 -> MacOsAArch64Linker.newVaListOfAddress(ma, scope);
case Win64 -> Windowsx64Linker.newVaListOfAddress(ma, session);
case SysV -> SysVx64Linker.newVaListOfAddress(ma, session);
case LinuxAArch64 -> LinuxAArch64Linker.newVaListOfAddress(ma, session);
case MacOsAArch64 -> MacOsAArch64Linker.newVaListOfAddress(ma, session);
};
}
@ -702,8 +672,13 @@ public class SharedUtils {
}
@Override
public ResourceScope scope() {
return ResourceScope.globalScope();
public MemorySession session() {
return MemorySessionImpl.GLOBAL;
}
@Override
public MemorySessionImpl sessionImpl() {
return MemorySessionImpl.GLOBAL;
}
@Override
@ -720,21 +695,22 @@ public class SharedUtils {
static void writeOverSized(MemorySegment ptr, Class<?> type, Object o) {
// use VH_LONG for integers to zero out the whole register in the process
if (type == long.class) {
ptr.set(JAVA_LONG, 0, (long) o);
ptr.set(JAVA_LONG_UNALIGNED, 0, (long) o);
} else if (type == int.class) {
ptr.set(JAVA_LONG, 0, (int) o);
ptr.set(JAVA_LONG_UNALIGNED, 0, (int) o);
} else if (type == short.class) {
ptr.set(JAVA_LONG, 0, (short) o);
ptr.set(JAVA_LONG_UNALIGNED, 0, (short) o);
} else if (type == char.class) {
ptr.set(JAVA_LONG, 0, (char) o);
ptr.set(JAVA_LONG_UNALIGNED, 0, (char) o);
} else if (type == byte.class) {
ptr.set(JAVA_LONG, 0, (byte) o);
ptr.set(JAVA_LONG_UNALIGNED, 0, (byte) o);
} else if (type == float.class) {
ptr.set(JAVA_FLOAT, 0, (float) o);
ptr.set(JAVA_FLOAT_UNALIGNED, 0, (float) o);
} else if (type == double.class) {
ptr.set(JAVA_DOUBLE, 0, (double) o);
ptr.set(JAVA_DOUBLE_UNALIGNED, 0, (double) o);
} else if (type == boolean.class) {
ptr.set(JAVA_BOOLEAN, 0, (boolean) o);
boolean b = (boolean)o;
ptr.set(JAVA_LONG_UNALIGNED, 0, b ? (long)1 : (long)0);
} else {
throw new IllegalArgumentException("Unsupported carrier: " + type);
}
@ -742,19 +718,19 @@ public class SharedUtils {
static void write(MemorySegment ptr, Class<?> type, Object o) {
if (type == long.class) {
ptr.set(JAVA_LONG, 0, (long) o);
ptr.set(JAVA_LONG_UNALIGNED, 0, (long) o);
} else if (type == int.class) {
ptr.set(JAVA_INT, 0, (int) o);
ptr.set(JAVA_INT_UNALIGNED, 0, (int) o);
} else if (type == short.class) {
ptr.set(JAVA_SHORT, 0, (short) o);
ptr.set(JAVA_SHORT_UNALIGNED, 0, (short) o);
} else if (type == char.class) {
ptr.set(JAVA_CHAR, 0, (char) o);
ptr.set(JAVA_CHAR_UNALIGNED, 0, (char) o);
} else if (type == byte.class) {
ptr.set(JAVA_BYTE, 0, (byte) o);
} else if (type == float.class) {
ptr.set(JAVA_FLOAT, 0, (float) o);
ptr.set(JAVA_FLOAT_UNALIGNED, 0, (float) o);
} else if (type == double.class) {
ptr.set(JAVA_DOUBLE, 0, (double) o);
ptr.set(JAVA_DOUBLE_UNALIGNED, 0, (double) o);
} else if (type == boolean.class) {
ptr.set(JAVA_BOOLEAN, 0, (boolean) o);
} else {
@ -764,19 +740,19 @@ public class SharedUtils {
static Object read(MemorySegment ptr, Class<?> type) {
if (type == long.class) {
return ptr.get(JAVA_LONG, 0);
return ptr.get(JAVA_LONG_UNALIGNED, 0);
} else if (type == int.class) {
return ptr.get(JAVA_INT, 0);
return ptr.get(JAVA_INT_UNALIGNED, 0);
} else if (type == short.class) {
return ptr.get(JAVA_SHORT, 0);
return ptr.get(JAVA_SHORT_UNALIGNED, 0);
} else if (type == char.class) {
return ptr.get(JAVA_CHAR, 0);
return ptr.get(JAVA_CHAR_UNALIGNED, 0);
} else if (type == byte.class) {
return ptr.get(JAVA_BYTE, 0);
} else if (type == float.class) {
return ptr.get(JAVA_FLOAT, 0);
return ptr.get(JAVA_FLOAT_UNALIGNED, 0);
} else if (type == double.class) {
return ptr.get(JAVA_DOUBLE, 0);
return ptr.get(JAVA_DOUBLE_UNALIGNED, 0);
} else if (type == boolean.class) {
return ptr.get(JAVA_BOOLEAN, 0);
} else {
@ -784,6 +760,14 @@ public class SharedUtils {
}
}
// unaligned constants
public final static ValueLayout.OfShort JAVA_SHORT_UNALIGNED = JAVA_SHORT.withBitAlignment(8);
public final static ValueLayout.OfChar JAVA_CHAR_UNALIGNED = JAVA_CHAR.withBitAlignment(8);
public final static ValueLayout.OfInt JAVA_INT_UNALIGNED = JAVA_INT.withBitAlignment(8);
public final static ValueLayout.OfLong JAVA_LONG_UNALIGNED = JAVA_LONG.withBitAlignment(8);
public final static ValueLayout.OfFloat JAVA_FLOAT_UNALIGNED = JAVA_FLOAT.withBitAlignment(8);
public final static ValueLayout.OfDouble JAVA_DOUBLE_UNALIGNED = JAVA_DOUBLE.withBitAlignment(8);
public static MethodType inferMethodType(FunctionDescriptor descriptor, boolean upcall) {
MethodType type = MethodType.methodType(descriptor.returnLayout().isPresent() ?
carrierFor(descriptor.returnLayout().get(), upcall) : void.class);

View file

@ -24,11 +24,11 @@
*/
package jdk.internal.foreign.abi;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.NativeSymbol;
import jdk.incubator.foreign.ResourceScope;
import jdk.internal.foreign.NativeSymbolImpl;
import jdk.internal.foreign.ResourceScopeImpl;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import jdk.internal.foreign.MemorySessionImpl;
public class UpcallStubs {
@ -48,13 +48,13 @@ public class UpcallStubs {
registerNatives();
}
static NativeSymbol makeUpcall(long entry, ResourceScope scope) {
((ResourceScopeImpl)scope).addOrCleanupIfFail(new ResourceScopeImpl.ResourceList.ResourceCleanup() {
static MemorySegment makeUpcall(long entry, MemorySession session) {
MemorySessionImpl.toSessionImpl(session).addOrCleanupIfFail(new MemorySessionImpl.ResourceList.ResourceCleanup() {
@Override
public void cleanup() {
freeUpcallStub(entry);
}
});
return new NativeSymbolImpl("upcall:" + Long.toHexString(entry), MemoryAddress.ofLong(entry), scope);
return MemorySegment.ofAddress(MemoryAddress.ofLong(entry), 0, session);
}
}

View file

@ -25,25 +25,24 @@
*/
package jdk.internal.foreign.abi.aarch64;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.GroupLayout;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.NativeSymbol;
import jdk.incubator.foreign.ResourceScope;
import jdk.internal.foreign.Utils;
import jdk.internal.foreign.abi.CallingSequenceBuilder;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.GroupLayout;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import jdk.internal.foreign.abi.ABIDescriptor;
import jdk.internal.foreign.abi.Binding;
import jdk.internal.foreign.abi.CallingSequence;
import jdk.internal.foreign.abi.ProgrammableInvoker;
import jdk.internal.foreign.abi.CallingSequenceBuilder;
import jdk.internal.foreign.abi.ProgrammableUpcallHandler;
import jdk.internal.foreign.abi.VMStorage;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.VMStorage;
import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64CallArranger;
import jdk.internal.foreign.abi.aarch64.macos.MacOsAArch64CallArranger;
import jdk.internal.foreign.Utils;
import jdk.internal.foreign.abi.ProgrammableInvoker;
import java.lang.foreign.MemorySession;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.util.List;
@ -79,7 +78,7 @@ public abstract class CallArranger {
// Although the AAPCS64 says r0-7 and v0-7 are all valid return
// registers, it's not possible to generate a C function that uses
// r2-7 and v4-7 so they are omitted here.
private static final ABIDescriptor C = AArch64Architecture.abiFor(
private static final ABIDescriptor C = abiFor(
new VMStorage[] { r0, r1, r2, r3, r4, r5, r6, r7, INDIRECT_RESULT},
new VMStorage[] { v0, v1, v2, v3, v4, v5, v6, v7 },
new VMStorage[] { r0, r1 },
@ -157,14 +156,14 @@ public abstract class CallArranger {
return handle;
}
public NativeSymbol arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc, ResourceScope scope) {
public MemorySegment arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc, MemorySession session) {
Bindings bindings = getBindings(mt, cDesc, true);
if (bindings.isInMemoryReturn) {
target = SharedUtils.adaptUpcallForIMR(target, true /* drop return, since we don't have bindings for it */);
}
return ProgrammableUpcallHandler.make(C, target, bindings.callingSequence,scope);
return ProgrammableUpcallHandler.make(C, target, bindings.callingSequence, session);
}
private static boolean isInMemoryReturn(Optional<MemoryLayout> returnLayout) {
@ -190,7 +189,7 @@ public abstract class CallArranger {
stackOffset = Utils.alignUp(stackOffset, alignment);
VMStorage storage =
AArch64Architecture.stackStorage((int)(stackOffset / STACK_SLOT_SIZE));
stackStorage((int)(stackOffset / STACK_SLOT_SIZE));
stackOffset += size;
return storage;
}

View file

@ -25,11 +25,11 @@
*/
package jdk.internal.foreign.abi.aarch64;
import jdk.incubator.foreign.GroupLayout;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.SequenceLayout;
import jdk.incubator.foreign.ValueLayout;
import java.lang.foreign.GroupLayout;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.SequenceLayout;
import java.lang.foreign.ValueLayout;
public enum TypeClass {
STRUCT_REGISTER,

View file

@ -25,7 +25,7 @@
*/
package jdk.internal.foreign.abi.aarch64.linux;
import jdk.internal.foreign.abi.aarch64.*;
import jdk.internal.foreign.abi.aarch64.CallArranger;
/**
* AArch64 CallArranger specialized for Linux ABI.

View file

@ -25,13 +25,14 @@
*/
package jdk.internal.foreign.abi.aarch64.linux;
import jdk.incubator.foreign.CLinker;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.NativeSymbol;
import jdk.incubator.foreign.ResourceScope;
import jdk.incubator.foreign.VaList;
import java.lang.foreign.Linker;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.VaList;
import jdk.internal.foreign.SystemLookup;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.aarch64.CallArranger;
@ -39,13 +40,14 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
/**
* ABI implementation based on ARM document "Procedure Call Standard for
* the ARM 64-bit Architecture".
*/
public final class LinuxAArch64Linker implements CLinker {
public final class LinuxAArch64Linker implements Linker {
private static LinuxAArch64Linker instance;
static final long ADDRESS_SIZE = 64; // bits
@ -70,8 +72,8 @@ public final class LinuxAArch64Linker implements CLinker {
}
@Override
public final NativeSymbol upcallStub(MethodHandle target, FunctionDescriptor function, ResourceScope scope) {
Objects.requireNonNull(scope);
public final MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, MemorySession session) {
Objects.requireNonNull(session);
Objects.requireNonNull(target);
Objects.requireNonNull(function);
SharedUtils.checkExceptions(target);
@ -79,21 +81,25 @@ public final class LinuxAArch64Linker implements CLinker {
if (!type.equals(target.type())) {
throw new IllegalArgumentException("Wrong method handle type: " + target.type());
}
return CallArranger.LINUX.arrangeUpcall(target, target.type(), function, scope);
return CallArranger.LINUX.arrangeUpcall(target, target.type(), function, session);
}
public static VaList newVaList(Consumer<VaList.Builder> actions, ResourceScope scope) {
LinuxAArch64VaList.Builder builder = LinuxAArch64VaList.builder(scope);
public static VaList newVaList(Consumer<VaList.Builder> actions, MemorySession session) {
LinuxAArch64VaList.Builder builder = LinuxAArch64VaList.builder(session);
actions.accept(builder);
return builder.build();
}
public static VaList newVaListOfAddress(MemoryAddress ma, ResourceScope scope) {
return LinuxAArch64VaList.ofAddress(ma, scope);
public static VaList newVaListOfAddress(MemoryAddress ma, MemorySession session) {
return LinuxAArch64VaList.ofAddress(ma, session);
}
public static VaList emptyVaList() {
return LinuxAArch64VaList.empty();
}
@Override
public SystemLookup defaultLookup() {
return SystemLookup.getInstance();
}
}

View file

@ -25,12 +25,12 @@
*/
package jdk.internal.foreign.abi.aarch64.linux;
import jdk.incubator.foreign.*;
import jdk.internal.foreign.ResourceScopeImpl;
import java.lang.foreign.*;
import jdk.internal.foreign.abi.aarch64.TypeClass;
import jdk.internal.foreign.MemorySessionImpl;
import jdk.internal.foreign.Scoped;
import jdk.internal.foreign.Utils;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.aarch64.*;
import jdk.internal.misc.Unsafe;
import java.lang.invoke.VarHandle;
@ -40,7 +40,7 @@ import java.util.Objects;
import static jdk.internal.foreign.PlatformLayouts.AArch64;
import static jdk.incubator.foreign.MemoryLayout.PathElement.groupElement;
import static java.lang.foreign.MemoryLayout.PathElement.groupElement;
import static jdk.internal.foreign.abi.SharedUtils.SimpleVaArg;
import static jdk.internal.foreign.abi.SharedUtils.THROWING_ALLOCATOR;
import static jdk.internal.foreign.abi.aarch64.CallArranger.MAX_REGISTER_ARGUMENTS;
@ -112,19 +112,19 @@ public non-sealed class LinuxAArch64VaList implements VaList, Scoped {
private static LinuxAArch64VaList readFromSegment(MemorySegment segment) {
MemorySegment gpRegsArea = MemorySegment.ofAddress(grTop(segment).addOffset(-MAX_GP_OFFSET),
MAX_GP_OFFSET, segment.scope());
MAX_GP_OFFSET, segment.session());
MemorySegment fpRegsArea = MemorySegment.ofAddress(vrTop(segment).addOffset(-MAX_FP_OFFSET),
MAX_FP_OFFSET, segment.scope());
MAX_FP_OFFSET, segment.session());
return new LinuxAArch64VaList(segment, gpRegsArea, fpRegsArea);
}
private static MemoryAddress emptyListAddress() {
long ptr = U.allocateMemory(LAYOUT.byteSize());
ResourceScope scope = ResourceScope.newImplicitScope();
scope.addCloseAction(() -> U.freeMemory(ptr));
MemorySession session = MemorySession.openImplicit();
session.addCloseAction(() -> U.freeMemory(ptr));
MemorySegment ms = MemorySegment.ofAddress(MemoryAddress.ofLong(ptr),
LAYOUT.byteSize(), scope);
LAYOUT.byteSize(), session);
VH_stack.set(ms, MemoryAddress.NULL);
VH_gr_top.set(ms, MemoryAddress.NULL);
VH_vr_top.set(ms, MemoryAddress.NULL);
@ -246,7 +246,7 @@ public non-sealed class LinuxAArch64VaList implements VaList, Scoped {
preAlignStack(layout);
return switch (typeClass) {
case STRUCT_REGISTER, STRUCT_HFA, STRUCT_REFERENCE -> {
MemorySegment slice = MemorySegment.ofAddress(stackPtr(), layout.byteSize(), scope());
MemorySegment slice = MemorySegment.ofAddress(stackPtr(), layout.byteSize(), session());
MemorySegment seg = allocator.allocate(layout);
seg.copyFrom(slice);
postAlignStack(layout);
@ -254,7 +254,7 @@ public non-sealed class LinuxAArch64VaList implements VaList, Scoped {
}
case POINTER, INTEGER, FLOAT -> {
VarHandle reader = layout.varHandle();
MemorySegment slice = MemorySegment.ofAddress(stackPtr(), layout.byteSize(), scope());
MemorySegment slice = MemorySegment.ofAddress(stackPtr(), layout.byteSize(), session());
Object res = reader.get(slice);
postAlignStack(layout);
yield res;
@ -296,7 +296,7 @@ public non-sealed class LinuxAArch64VaList implements VaList, Scoped {
gpRegsArea.asSlice(currentGPOffset()));
consumeGPSlots(1);
MemorySegment slice = MemorySegment.ofAddress(ptr, layout.byteSize(), scope());
MemorySegment slice = MemorySegment.ofAddress(ptr, layout.byteSize(), session());
MemorySegment seg = allocator.allocate(layout);
seg.copyFrom(slice);
yield seg;
@ -320,7 +320,7 @@ public non-sealed class LinuxAArch64VaList implements VaList, Scoped {
@Override
public void skip(MemoryLayout... layouts) {
Objects.requireNonNull(layouts);
((ResourceScopeImpl)segment.scope()).checkValidStateSlow();
MemorySessionImpl.toSessionImpl(session()).checkValidStateSlow();
for (MemoryLayout layout : layouts) {
Objects.requireNonNull(layout);
TypeClass typeClass = TypeClass.classifyLayout(layout);
@ -337,22 +337,27 @@ public non-sealed class LinuxAArch64VaList implements VaList, Scoped {
}
}
static LinuxAArch64VaList.Builder builder(ResourceScope scope) {
return new LinuxAArch64VaList.Builder(scope);
static LinuxAArch64VaList.Builder builder(MemorySession session) {
return new LinuxAArch64VaList.Builder(session);
}
public static VaList ofAddress(MemoryAddress ma, ResourceScope scope) {
return readFromSegment(MemorySegment.ofAddress(ma, LAYOUT.byteSize(), scope));
public static VaList ofAddress(MemoryAddress ma, MemorySession session) {
return readFromSegment(MemorySegment.ofAddress(ma, LAYOUT.byteSize(), session));
}
@Override
public ResourceScope scope() {
return segment.scope();
public MemorySession session() {
return segment.session();
}
@Override
public MemorySessionImpl sessionImpl() {
return MemorySessionImpl.toSessionImpl(session());
}
@Override
public VaList copy() {
MemorySegment copy = MemorySegment.allocateNative(LAYOUT, segment.scope());
MemorySegment copy = MemorySegment.allocateNative(LAYOUT, segment.session());
copy.copyFrom(segment);
return new LinuxAArch64VaList(copy, gpRegsArea, fpRegsArea);
}
@ -389,7 +394,7 @@ public non-sealed class LinuxAArch64VaList implements VaList, Scoped {
}
public static non-sealed class Builder implements VaList.Builder {
private final ResourceScope scope;
private final MemorySession session;
private final MemorySegment gpRegs;
private final MemorySegment fpRegs;
@ -397,10 +402,10 @@ public non-sealed class LinuxAArch64VaList implements VaList, Scoped {
private long currentFPOffset = 0;
private final List<SimpleVaArg> stackArgs = new ArrayList<>();
Builder(ResourceScope scope) {
this.scope = scope;
this.gpRegs = MemorySegment.allocateNative(LAYOUT_GP_REGS, scope);
this.fpRegs = MemorySegment.allocateNative(LAYOUT_FP_REGS, scope);
Builder(MemorySession session) {
this.session = session;
this.gpRegs = MemorySegment.allocateNative(LAYOUT_GP_REGS, session);
this.fpRegs = MemorySegment.allocateNative(LAYOUT_FP_REGS, session);
}
@Override
@ -493,7 +498,7 @@ public non-sealed class LinuxAArch64VaList implements VaList, Scoped {
return EMPTY;
}
SegmentAllocator allocator = SegmentAllocator.newNativeArena(scope);
SegmentAllocator allocator = SegmentAllocator.newNativeArena(session);
MemorySegment vaListSegment = allocator.allocate(LAYOUT);
MemoryAddress stackArgsPtr = MemoryAddress.NULL;
if (!stackArgs.isEmpty()) {
@ -516,8 +521,8 @@ public non-sealed class LinuxAArch64VaList implements VaList, Scoped {
VH_gr_offs.set(vaListSegment, -MAX_GP_OFFSET);
VH_vr_offs.set(vaListSegment, -MAX_FP_OFFSET);
assert gpRegs.scope().ownerThread() == vaListSegment.scope().ownerThread();
assert fpRegs.scope().ownerThread() == vaListSegment.scope().ownerThread();
assert gpRegs.session().ownerThread() == vaListSegment.session().ownerThread();
assert fpRegs.session().ownerThread() == vaListSegment.session().ownerThread();
return new LinuxAArch64VaList(vaListSegment, gpRegs, fpRegs);
}
}

View file

@ -25,7 +25,7 @@
*/
package jdk.internal.foreign.abi.aarch64.macos;
import jdk.internal.foreign.abi.aarch64.*;
import jdk.internal.foreign.abi.aarch64.CallArranger;
/**
* AArch64 CallArranger specialized for macOS ABI.

View file

@ -25,13 +25,14 @@
*/
package jdk.internal.foreign.abi.aarch64.macos;
import jdk.incubator.foreign.CLinker;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.NativeSymbol;
import jdk.incubator.foreign.ResourceScope;
import jdk.incubator.foreign.VaList;
import java.lang.foreign.Linker;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.VaList;
import jdk.internal.foreign.SystemLookup;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.aarch64.CallArranger;
@ -39,13 +40,14 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
/**
* ABI implementation for macOS on Apple silicon. Based on AAPCS with
* changes to va_list and passing arguments on the stack.
*/
public final class MacOsAArch64Linker implements CLinker {
public final class MacOsAArch64Linker implements Linker {
private static MacOsAArch64Linker instance;
static final long ADDRESS_SIZE = 64; // bits
@ -70,29 +72,33 @@ public final class MacOsAArch64Linker implements CLinker {
}
@Override
public final NativeSymbol upcallStub(MethodHandle target, FunctionDescriptor function, ResourceScope scope) {
Objects.requireNonNull(scope);
public final MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, MemorySession session) {
Objects.requireNonNull(session);
Objects.requireNonNull(target);
Objects.requireNonNull(function);
MethodType type = SharedUtils.inferMethodType(function, true);
if (!type.equals(target.type())) {
throw new IllegalArgumentException("Wrong method handle type: " + target.type());
}
return CallArranger.MACOS.arrangeUpcall(target, target.type(), function, scope);
return CallArranger.MACOS.arrangeUpcall(target, target.type(), function, session);
}
public static VaList newVaList(Consumer<VaList.Builder> actions, ResourceScope scope) {
MacOsAArch64VaList.Builder builder = MacOsAArch64VaList.builder(scope);
public static VaList newVaList(Consumer<VaList.Builder> actions, MemorySession session) {
MacOsAArch64VaList.Builder builder = MacOsAArch64VaList.builder(session);
actions.accept(builder);
return builder.build();
}
public static VaList newVaListOfAddress(MemoryAddress ma, ResourceScope scope) {
return MacOsAArch64VaList.ofAddress(ma, scope);
public static VaList newVaListOfAddress(MemoryAddress ma, MemorySession session) {
return MacOsAArch64VaList.ofAddress(ma, session);
}
public static VaList emptyVaList() {
return MacOsAArch64VaList.empty();
}
@Override
public SystemLookup defaultLookup() {
return SystemLookup.getInstance();
}
}

View file

@ -25,12 +25,12 @@
*/
package jdk.internal.foreign.abi.aarch64.macos;
import jdk.incubator.foreign.*;
import java.lang.foreign.*;
import jdk.internal.foreign.abi.aarch64.TypeClass;
import jdk.internal.foreign.MemorySessionImpl;
import jdk.internal.foreign.Scoped;
import jdk.internal.foreign.ResourceScopeImpl;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.SharedUtils.SimpleVaArg;
import jdk.internal.foreign.abi.aarch64.*;
import java.lang.invoke.VarHandle;
import java.util.ArrayList;
@ -53,11 +53,11 @@ public non-sealed class MacOsAArch64VaList implements VaList, Scoped {
private static final VaList EMPTY = new SharedUtils.EmptyVaList(MemoryAddress.NULL);
private MemorySegment segment;
private final ResourceScope scope;
private final MemorySession session;
private MacOsAArch64VaList(MemorySegment segment, ResourceScope scope) {
private MacOsAArch64VaList(MemorySegment segment, MemorySession session) {
this.segment = segment;
this.scope = scope;
this.session = session;
}
public static final VaList empty() {
@ -102,7 +102,7 @@ public non-sealed class MacOsAArch64VaList implements VaList, Scoped {
res = switch (typeClass) {
case STRUCT_REFERENCE -> {
MemoryAddress structAddr = (MemoryAddress) VH_address.get(segment);
MemorySegment struct = MemorySegment.ofAddress(structAddr, layout.byteSize(), scope());
MemorySegment struct = MemorySegment.ofAddress(structAddr, layout.byteSize(), session());
MemorySegment seg = allocator.allocate(layout);
seg.copyFrom(struct);
segment = segment.asSlice(VA_SLOT_SIZE_BYTES);
@ -127,7 +127,7 @@ public non-sealed class MacOsAArch64VaList implements VaList, Scoped {
@Override
public void skip(MemoryLayout... layouts) {
Objects.requireNonNull(layouts);
((ResourceScopeImpl)scope).checkValidStateSlow();
MemorySessionImpl.toSessionImpl(session()).checkValidStateSlow();
for (MemoryLayout layout : layouts) {
Objects.requireNonNull(layout);
@ -138,24 +138,29 @@ public non-sealed class MacOsAArch64VaList implements VaList, Scoped {
}
}
static MacOsAArch64VaList ofAddress(MemoryAddress addr, ResourceScope scope) {
MemorySegment segment = MemorySegment.ofAddress(addr, Long.MAX_VALUE, scope);
return new MacOsAArch64VaList(segment, scope);
static MacOsAArch64VaList ofAddress(MemoryAddress addr, MemorySession session) {
MemorySegment segment = MemorySegment.ofAddress(addr, Long.MAX_VALUE, session);
return new MacOsAArch64VaList(segment, session);
}
static Builder builder(ResourceScope scope) {
return new Builder(scope);
static Builder builder(MemorySession session) {
return new Builder(session);
}
@Override
public ResourceScope scope() {
return scope;
public MemorySession session() {
return session;
}
@Override
public MemorySessionImpl sessionImpl() {
return MemorySessionImpl.toSessionImpl(session());
}
@Override
public VaList copy() {
((ResourceScopeImpl)scope).checkValidStateSlow();
return new MacOsAArch64VaList(segment, scope);
MemorySessionImpl.toSessionImpl(session()).checkValidStateSlow();
return new MacOsAArch64VaList(segment, session);
}
@Override
@ -165,12 +170,12 @@ public non-sealed class MacOsAArch64VaList implements VaList, Scoped {
public static non-sealed class Builder implements VaList.Builder {
private final ResourceScope scope;
private final MemorySession session;
private final List<SimpleVaArg> args = new ArrayList<>();
public Builder(ResourceScope scope) {
((ResourceScopeImpl)scope).checkValidStateSlow();
this.scope = scope;
public Builder(MemorySession session) {
MemorySessionImpl.toSessionImpl(session).checkValidStateSlow();
this.session = session;
}
private Builder arg(Class<?> carrier, MemoryLayout layout, Object value) {
@ -210,7 +215,7 @@ public non-sealed class MacOsAArch64VaList implements VaList, Scoped {
return EMPTY;
}
SegmentAllocator allocator = SegmentAllocator.newNativeArena(scope);
SegmentAllocator allocator = SegmentAllocator.newNativeArena(session);
// Each argument may occupy up to four slots
MemorySegment segment = allocator.allocate(VA_SLOT_SIZE_BYTES * args.size() * 4);
@ -243,7 +248,7 @@ public non-sealed class MacOsAArch64VaList implements VaList, Scoped {
}
}
return new MacOsAArch64VaList(segment, scope);
return new MacOsAArch64VaList(segment, session);
}
}
}

View file

@ -25,21 +25,19 @@
*/
package jdk.internal.foreign.abi.x64.sysv;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.GroupLayout;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.NativeSymbol;
import jdk.incubator.foreign.ResourceScope;
import jdk.internal.foreign.abi.CallingSequenceBuilder;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.GroupLayout;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import jdk.internal.foreign.abi.ABIDescriptor;
import jdk.internal.foreign.abi.Binding;
import jdk.internal.foreign.abi.CallingSequence;
import jdk.internal.foreign.abi.CallingSequenceBuilder;
import jdk.internal.foreign.abi.VMStorage;
import jdk.internal.foreign.abi.Binding;
import jdk.internal.foreign.abi.ProgrammableInvoker;
import jdk.internal.foreign.abi.ProgrammableUpcallHandler;
import jdk.internal.foreign.abi.VMStorage;
import jdk.internal.foreign.abi.x64.X86_64Architecture;
import jdk.internal.foreign.abi.SharedUtils;
import java.lang.invoke.MethodHandle;
@ -51,8 +49,6 @@ import java.util.Optional;
import static jdk.internal.foreign.PlatformLayouts.*;
import static jdk.internal.foreign.abi.Binding.*;
import static jdk.internal.foreign.abi.x64.X86_64Architecture.*;
import static jdk.internal.foreign.abi.x64.sysv.SysVx64Linker.MAX_INTEGER_ARGUMENT_REGISTERS;
import static jdk.internal.foreign.abi.x64.sysv.SysVx64Linker.MAX_VECTOR_ARGUMENT_REGISTERS;
/**
* For the SysV x64 C ABI specifically, this class uses the ProgrammableInvoker API, namely CallingSequenceBuilder2
@ -61,7 +57,7 @@ import static jdk.internal.foreign.abi.x64.sysv.SysVx64Linker.MAX_VECTOR_ARGUMEN
* This includes taking care of synthetic arguments like pointers to return buffers for 'in-memory' returns.
*/
public class CallArranger {
private static final ABIDescriptor CSysV = X86_64Architecture.abiFor(
private static final ABIDescriptor CSysV = abiFor(
new VMStorage[] { rdi, rsi, rdx, rcx, r8, r9, rax },
new VMStorage[] { xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 },
new VMStorage[] { rax, rdx },
@ -133,14 +129,14 @@ public class CallArranger {
return handle;
}
public static NativeSymbol arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc, ResourceScope scope) {
public static MemorySegment arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc, MemorySession session) {
Bindings bindings = getBindings(mt, cDesc, true);
if (bindings.isInMemoryReturn) {
target = SharedUtils.adaptUpcallForIMR(target, true /* drop return, since we don't have bindings for it */);
}
return ProgrammableUpcallHandler.make(CSysV, target, bindings.callingSequence, scope);
return ProgrammableUpcallHandler.make(CSysV, target, bindings.callingSequence, session);
}
private static boolean isInMemoryReturn(Optional<MemoryLayout> returnLayout) {
@ -163,13 +159,13 @@ public class CallArranger {
private int maxRegisterArguments(int type) {
return type == StorageClasses.INTEGER ?
MAX_INTEGER_ARGUMENT_REGISTERS :
SysVx64Linker.MAX_INTEGER_ARGUMENT_REGISTERS :
SysVx64Linker.MAX_VECTOR_ARGUMENT_REGISTERS;
}
VMStorage stackAlloc() {
assert forArguments : "no stack returns";
VMStorage storage = X86_64Architecture.stackStorage((int)stackOffset);
VMStorage storage = stackStorage((int)stackOffset);
stackOffset++;
return storage;
}
@ -192,14 +188,14 @@ public class CallArranger {
}
long nIntegerReg = typeClass.nIntegerRegs();
if (this.nIntegerReg + nIntegerReg > MAX_INTEGER_ARGUMENT_REGISTERS) {
if (this.nIntegerReg + nIntegerReg > SysVx64Linker.MAX_INTEGER_ARGUMENT_REGISTERS) {
//not enough registers - pass on stack
return typeClass.classes.stream().map(c -> stackAlloc()).toArray(VMStorage[]::new);
}
long nVectorReg = typeClass.nVectorRegs();
if (this.nVectorReg + nVectorReg > MAX_VECTOR_ARGUMENT_REGISTERS) {
if (this.nVectorReg + nVectorReg > SysVx64Linker.MAX_VECTOR_ARGUMENT_REGISTERS) {
//not enough registers - pass on stack
return typeClass.classes.stream().map(c -> stackAlloc()).toArray(VMStorage[]::new);
}

View file

@ -25,8 +25,9 @@
*/
package jdk.internal.foreign.abi.x64.sysv;
import jdk.incubator.foreign.*;
import jdk.internal.foreign.ResourceScopeImpl;
import java.lang.foreign.*;
import jdk.internal.foreign.MemorySessionImpl;
import jdk.internal.foreign.Scoped;
import jdk.internal.foreign.Utils;
import jdk.internal.foreign.abi.SharedUtils;
@ -39,7 +40,7 @@ import java.util.Objects;
import static jdk.internal.foreign.PlatformLayouts.SysV;
import static jdk.incubator.foreign.MemoryLayout.PathElement.groupElement;
import static java.lang.foreign.MemoryLayout.PathElement.groupElement;
import static jdk.internal.foreign.abi.SharedUtils.SimpleVaArg;
import static jdk.internal.foreign.abi.SharedUtils.THROWING_ALLOCATOR;
@ -125,10 +126,10 @@ public non-sealed class SysVVaList implements VaList, Scoped {
private static MemoryAddress emptyListAddress() {
long ptr = U.allocateMemory(LAYOUT.byteSize());
ResourceScope scope = ResourceScope.newImplicitScope();
scope.addCloseAction(() -> U.freeMemory(ptr));
MemorySession session = MemorySession.openImplicit();
session.addCloseAction(() -> U.freeMemory(ptr));
MemorySegment base = MemorySegment.ofAddress(MemoryAddress.ofLong(ptr),
LAYOUT.byteSize(), scope);
LAYOUT.byteSize(), session);
VH_gp_offset.set(base, MAX_GP_OFFSET);
VH_fp_offset.set(base, MAX_FP_OFFSET);
VH_overflow_arg_area.set(base, MemoryAddress.NULL);
@ -170,7 +171,7 @@ public non-sealed class SysVVaList implements VaList, Scoped {
private static MemorySegment getRegSaveArea(MemorySegment segment) {
return MemorySegment.ofAddress(((MemoryAddress)VH_reg_save_area.get(segment)),
LAYOUT_REG_SAVE_AREA.byteSize(), segment.scope());
LAYOUT_REG_SAVE_AREA.byteSize(), segment.session());
}
private void preAlignStack(MemoryLayout layout) {
@ -221,7 +222,7 @@ public non-sealed class SysVVaList implements VaList, Scoped {
preAlignStack(layout);
return switch (typeClass.kind()) {
case STRUCT -> {
MemorySegment slice = MemorySegment.ofAddress(stackPtr(), layout.byteSize(), scope());
MemorySegment slice = MemorySegment.ofAddress(stackPtr(), layout.byteSize(), session());
MemorySegment seg = allocator.allocate(layout);
seg.copyFrom(slice);
postAlignStack(layout);
@ -229,8 +230,8 @@ public non-sealed class SysVVaList implements VaList, Scoped {
}
case POINTER, INTEGER, FLOAT -> {
VarHandle reader = layout.varHandle();
try (ResourceScope localScope = ResourceScope.newConfinedScope()) {
MemorySegment slice = MemorySegment.ofAddress(stackPtr(), layout.byteSize(), localScope);
try (MemorySession localSession = MemorySession.openConfined()) {
MemorySegment slice = MemorySegment.ofAddress(stackPtr(), layout.byteSize(), localSession);
Object res = reader.get(slice);
postAlignStack(layout);
yield res;
@ -276,7 +277,7 @@ public non-sealed class SysVVaList implements VaList, Scoped {
@Override
public void skip(MemoryLayout... layouts) {
Objects.requireNonNull(layouts);
((ResourceScopeImpl)segment.scope()).checkValidStateSlow();
MemorySessionImpl.toSessionImpl(session()).checkValidStateSlow();
for (MemoryLayout layout : layouts) {
Objects.requireNonNull(layout);
TypeClass typeClass = TypeClass.classifyLayout(layout);
@ -290,22 +291,27 @@ public non-sealed class SysVVaList implements VaList, Scoped {
}
}
static SysVVaList.Builder builder(ResourceScope scope) {
return new SysVVaList.Builder(scope);
static SysVVaList.Builder builder(MemorySession session) {
return new SysVVaList.Builder(session);
}
public static VaList ofAddress(MemoryAddress ma, ResourceScope scope) {
return readFromSegment(MemorySegment.ofAddress(ma, LAYOUT.byteSize(), scope));
public static VaList ofAddress(MemoryAddress ma, MemorySession session) {
return readFromSegment(MemorySegment.ofAddress(ma, LAYOUT.byteSize(), session));
}
@Override
public ResourceScope scope() {
return segment.scope();
public MemorySession session() {
return segment.session();
}
@Override
public MemorySessionImpl sessionImpl() {
return MemorySessionImpl.toSessionImpl(session());
}
@Override
public VaList copy() {
MemorySegment copy = MemorySegment.allocateNative(LAYOUT, segment.scope());
MemorySegment copy = MemorySegment.allocateNative(LAYOUT, segment.session());
copy.copyFrom(segment);
return new SysVVaList(copy, regSaveArea);
}
@ -331,15 +337,15 @@ public non-sealed class SysVVaList implements VaList, Scoped {
}
public static non-sealed class Builder implements VaList.Builder {
private final ResourceScope scope;
private final MemorySession session;
private final MemorySegment reg_save_area;
private long currentGPOffset = 0;
private long currentFPOffset = FP_OFFSET;
private final List<SimpleVaArg> stackArgs = new ArrayList<>();
public Builder(ResourceScope scope) {
this.scope = scope;
this.reg_save_area = MemorySegment.allocateNative(LAYOUT_REG_SAVE_AREA, scope);
public Builder(MemorySession session) {
this.session = session;
this.reg_save_area = MemorySegment.allocateNative(LAYOUT_REG_SAVE_AREA, session);
}
@Override
@ -418,7 +424,7 @@ public non-sealed class SysVVaList implements VaList, Scoped {
return EMPTY;
}
SegmentAllocator allocator = SegmentAllocator.newNativeArena(scope);
SegmentAllocator allocator = SegmentAllocator.newNativeArena(session);
MemorySegment vaListSegment = allocator.allocate(LAYOUT);
MemoryAddress stackArgsPtr = MemoryAddress.NULL;
if (!stackArgs.isEmpty()) {
@ -443,7 +449,7 @@ public non-sealed class SysVVaList implements VaList, Scoped {
VH_fp_offset.set(vaListSegment, (int) FP_OFFSET);
VH_overflow_arg_area.set(vaListSegment, stackArgsPtr);
VH_reg_save_area.set(vaListSegment, reg_save_area.address());
assert reg_save_area.scope().ownerThread() == vaListSegment.scope().ownerThread();
assert reg_save_area.session().ownerThread() == vaListSegment.session().ownerThread();
return new SysVVaList(vaListSegment, reg_save_area);
}
}

View file

@ -25,25 +25,27 @@
package jdk.internal.foreign.abi.x64.sysv;
import jdk.incubator.foreign.CLinker;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.NativeSymbol;
import jdk.incubator.foreign.ResourceScope;
import jdk.incubator.foreign.VaList;
import java.lang.foreign.Linker;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.VaList;
import jdk.internal.foreign.SystemLookup;
import jdk.internal.foreign.abi.SharedUtils;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
/**
* ABI implementation based on System V ABI AMD64 supplement v.0.99.6
*/
public final class SysVx64Linker implements CLinker {
public final class SysVx64Linker implements Linker {
public static final int MAX_INTEGER_ARGUMENT_REGISTERS = 6;
public static final int MAX_INTEGER_RETURN_REGISTERS = 2;
public static final int MAX_VECTOR_ARGUMENT_REGISTERS = 8;
@ -61,8 +63,8 @@ public final class SysVx64Linker implements CLinker {
return instance;
}
public static VaList newVaList(Consumer<VaList.Builder> actions, ResourceScope scope) {
SysVVaList.Builder builder = SysVVaList.builder(scope);
public static VaList newVaList(Consumer<VaList.Builder> actions, MemorySession session) {
SysVVaList.Builder builder = SysVVaList.builder(session);
actions.accept(builder);
return builder.build();
}
@ -80,8 +82,8 @@ public final class SysVx64Linker implements CLinker {
}
@Override
public final NativeSymbol upcallStub(MethodHandle target, FunctionDescriptor function, ResourceScope scope) {
Objects.requireNonNull(scope);
public final MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, MemorySession session) {
Objects.requireNonNull(session);
Objects.requireNonNull(target);
Objects.requireNonNull(function);
SharedUtils.checkExceptions(target);
@ -89,14 +91,19 @@ public final class SysVx64Linker implements CLinker {
if (!type.equals(target.type())) {
throw new IllegalArgumentException("Wrong method handle type: " + target.type());
}
return CallArranger.arrangeUpcall(target, target.type(), function, scope);
return CallArranger.arrangeUpcall(target, target.type(), function, session);
}
public static VaList newVaListOfAddress(MemoryAddress ma, ResourceScope scope) {
return SysVVaList.ofAddress(ma, scope);
public static VaList newVaListOfAddress(MemoryAddress ma, MemorySession session) {
return SysVVaList.ofAddress(ma, session);
}
public static VaList emptyVaList() {
return SysVVaList.empty();
}
@Override
public SystemLookup defaultLookup() {
return SystemLookup.getInstance();
}
}

View file

@ -24,11 +24,11 @@
*/
package jdk.internal.foreign.abi.x64.sysv;
import jdk.incubator.foreign.GroupLayout;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.SequenceLayout;
import jdk.incubator.foreign.ValueLayout;
import java.lang.foreign.GroupLayout;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.SequenceLayout;
import java.lang.foreign.ValueLayout;
import jdk.internal.foreign.Utils;
import java.util.ArrayList;
@ -214,7 +214,7 @@ class TypeClass {
} else if (l instanceof SequenceLayout) {
SequenceLayout seq = (SequenceLayout)l;
MemoryLayout elem = seq.elementLayout();
for (long i = 0 ; i < seq.elementCount().getAsLong() ; i++) {
for (long i = 0 ; i < seq.elementCount() ; i++) {
groupByEightBytes(elem, offset, groups);
offset += elem.byteSize();
}

View file

@ -24,13 +24,12 @@
*/
package jdk.internal.foreign.abi.x64.windows;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.GroupLayout;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.NativeSymbol;
import jdk.incubator.foreign.ResourceScope;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.GroupLayout;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import jdk.internal.foreign.Utils;
import jdk.internal.foreign.abi.CallingSequenceBuilder;
import jdk.internal.foreign.abi.ABIDescriptor;
@ -133,14 +132,14 @@ public class CallArranger {
return handle;
}
public static NativeSymbol arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc, ResourceScope scope) {
public static MemorySegment arrangeUpcall(MethodHandle target, MethodType mt, FunctionDescriptor cDesc, MemorySession session) {
Bindings bindings = getBindings(mt, cDesc, true);
if (bindings.isInMemoryReturn) {
target = SharedUtils.adaptUpcallForIMR(target, false /* need the return value as well */);
}
return ProgrammableUpcallHandler.make(CWindows, target, bindings.callingSequence, scope);
return ProgrammableUpcallHandler.make(CWindows, target, bindings.callingSequence, session);
}
private static boolean isInMemoryReturn(Optional<MemoryLayout> returnLayout) {

View file

@ -24,10 +24,10 @@
*/
package jdk.internal.foreign.abi.x64.windows;
import jdk.incubator.foreign.GroupLayout;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.ValueLayout;
import java.lang.foreign.GroupLayout;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.ValueLayout;
enum TypeClass {
STRUCT_REGISTER,

View file

@ -25,9 +25,10 @@
*/
package jdk.internal.foreign.abi.x64.windows;
import jdk.incubator.foreign.*;
import java.lang.foreign.*;
import jdk.internal.foreign.MemorySessionImpl;
import jdk.internal.foreign.Scoped;
import jdk.internal.foreign.ResourceScopeImpl;
import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.SharedUtils.SimpleVaArg;
@ -63,11 +64,11 @@ public non-sealed class WinVaList implements VaList, Scoped {
private static final VaList EMPTY = new SharedUtils.EmptyVaList(MemoryAddress.NULL);
private MemorySegment segment;
private final ResourceScope scope;
private final MemorySession session;
private WinVaList(MemorySegment segment, ResourceScope scope) {
private WinVaList(MemorySegment segment, MemorySession session) {
this.segment = segment;
this.scope = scope;
this.session = session;
}
public static final VaList empty() {
@ -112,7 +113,7 @@ public non-sealed class WinVaList implements VaList, Scoped {
res = switch (typeClass) {
case STRUCT_REFERENCE -> {
MemoryAddress structAddr = (MemoryAddress) VH_address.get(segment);
MemorySegment struct = MemorySegment.ofAddress(structAddr, layout.byteSize(), scope());
MemorySegment struct = MemorySegment.ofAddress(structAddr, layout.byteSize(), session());
MemorySegment seg = allocator.allocate(layout);
seg.copyFrom(struct);
yield seg;
@ -132,29 +133,34 @@ public non-sealed class WinVaList implements VaList, Scoped {
@Override
public void skip(MemoryLayout... layouts) {
Objects.requireNonNull(layouts);
((ResourceScopeImpl)scope).checkValidStateSlow();
MemorySessionImpl.toSessionImpl(session()).checkValidStateSlow();
Stream.of(layouts).forEach(Objects::requireNonNull);
segment = segment.asSlice(layouts.length * VA_SLOT_SIZE_BYTES);
}
static WinVaList ofAddress(MemoryAddress addr, ResourceScope scope) {
MemorySegment segment = MemorySegment.ofAddress(addr, Long.MAX_VALUE, scope);
return new WinVaList(segment, scope);
static WinVaList ofAddress(MemoryAddress addr, MemorySession session) {
MemorySegment segment = MemorySegment.ofAddress(addr, Long.MAX_VALUE, session);
return new WinVaList(segment, session);
}
static Builder builder(ResourceScope scope) {
return new Builder(scope);
static Builder builder(MemorySession session) {
return new Builder(session);
}
@Override
public ResourceScope scope() {
return scope;
public MemorySession session() {
return session;
}
@Override
public MemorySessionImpl sessionImpl() {
return MemorySessionImpl.toSessionImpl(session());
}
@Override
public VaList copy() {
((ResourceScopeImpl)scope).checkValidStateSlow();
return new WinVaList(segment, scope);
MemorySessionImpl.toSessionImpl(session).checkValidStateSlow();
return new WinVaList(segment, session);
}
@Override
@ -164,12 +170,12 @@ public non-sealed class WinVaList implements VaList, Scoped {
public static non-sealed class Builder implements VaList.Builder {
private final ResourceScope scope;
private final MemorySession session;
private final List<SimpleVaArg> args = new ArrayList<>();
public Builder(ResourceScope scope) {
((ResourceScopeImpl)scope).checkValidStateSlow();
this.scope = scope;
public Builder(MemorySession session) {
MemorySessionImpl.toSessionImpl(session).checkValidStateSlow();
this.session = session;
}
private Builder arg(Class<?> carrier, MemoryLayout layout, Object value) {
@ -208,7 +214,7 @@ public non-sealed class WinVaList implements VaList, Scoped {
if (args.isEmpty()) {
return EMPTY;
}
SegmentAllocator allocator = SegmentAllocator.newNativeArena(scope);
SegmentAllocator allocator = SegmentAllocator.newNativeArena(session);
MemorySegment segment = allocator.allocate(VA_SLOT_SIZE_BYTES * args.size());
List<MemorySegment> attachedSegments = new ArrayList<>();
attachedSegments.add(segment);
@ -236,7 +242,7 @@ public non-sealed class WinVaList implements VaList, Scoped {
cursor = cursor.asSlice(VA_SLOT_SIZE_BYTES);
}
return new WinVaList(segment, scope);
return new WinVaList(segment, session);
}
}
}

View file

@ -24,25 +24,27 @@
*/
package jdk.internal.foreign.abi.x64.windows;
import jdk.incubator.foreign.CLinker;
import jdk.incubator.foreign.FunctionDescriptor;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.NativeSymbol;
import jdk.incubator.foreign.ResourceScope;
import jdk.incubator.foreign.VaList;
import java.lang.foreign.Linker;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.lang.foreign.VaList;
import jdk.internal.foreign.SystemLookup;
import jdk.internal.foreign.abi.SharedUtils;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
/**
* ABI implementation based on Windows ABI AMD64 supplement v.0.99.6
*/
public final class Windowsx64Linker implements CLinker {
public final class Windowsx64Linker implements Linker {
public static final int MAX_INTEGER_ARGUMENT_REGISTERS = 4;
public static final int MAX_INTEGER_RETURN_REGISTERS = 1;
@ -62,8 +64,8 @@ public final class Windowsx64Linker implements CLinker {
return instance;
}
public static VaList newVaList(Consumer<VaList.Builder> actions, ResourceScope scope) {
WinVaList.Builder builder = WinVaList.builder(scope);
public static VaList newVaList(Consumer<VaList.Builder> actions, MemorySession session) {
WinVaList.Builder builder = WinVaList.builder(session);
actions.accept(builder);
return builder.build();
}
@ -81,8 +83,8 @@ public final class Windowsx64Linker implements CLinker {
}
@Override
public final NativeSymbol upcallStub(MethodHandle target, FunctionDescriptor function, ResourceScope scope) {
Objects.requireNonNull(scope);
public final MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, MemorySession session) {
Objects.requireNonNull(session);
Objects.requireNonNull(target);
Objects.requireNonNull(function);
SharedUtils.checkExceptions(target);
@ -90,14 +92,19 @@ public final class Windowsx64Linker implements CLinker {
if (!type.equals(target.type())) {
throw new IllegalArgumentException("Wrong method handle type: " + target.type());
}
return CallArranger.arrangeUpcall(target, target.type(), function, scope);
return CallArranger.arrangeUpcall(target, target.type(), function, session);
}
public static VaList newVaListOfAddress(MemoryAddress ma, ResourceScope scope) {
return WinVaList.ofAddress(ma, scope);
public static VaList newVaListOfAddress(MemoryAddress ma, MemorySession session) {
return WinVaList.ofAddress(ma, session);
}
public static VaList emptyVaList() {
return WinVaList.empty();
}
@Override
public SystemLookup defaultLookup() {
return SystemLookup.getInstance();
}
}

View file

@ -62,6 +62,7 @@ public @interface PreviewFeature {
public enum Feature {
SWITCH_PATTERN_MATCHING,
VIRTUAL_THREADS,
FOREIGN,
/**
* A key for testing.
*/

View file

@ -1,698 +1,698 @@
@ForceInline
public $type$ get$Type$(Scope scope, Object base, long offset) {
public $type$ get$Type$(MemorySessionImpl session, Object base, long offset) {
try {
return get$Type$Internal(scope, base, offset);
} catch (Scope.ScopedAccessError ex) {
return get$Type$Internal(session, base, offset);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ get$Type$Internal(Scope scope, Object base, long offset) {
private $type$ get$Type$Internal(MemorySessionImpl session, Object base, long offset) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.get$Type$(base, offset);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public void put$Type$(Scope scope, Object base, long offset, $type$ value) {
public void put$Type$(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
put$Type$Internal(scope, base, offset, value);
} catch (Scope.ScopedAccessError ex) {
put$Type$Internal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private void put$Type$Internal(Scope scope, Object base, long offset, $type$ value) {
private void put$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
UNSAFE.put$Type$(base, offset, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
#if[Unaligned]
@ForceInline
public $type$ get$Type$Unaligned(Scope scope, Object base, long offset, boolean be) {
public $type$ get$Type$Unaligned(MemorySessionImpl session, Object base, long offset, boolean be) {
try {
return get$Type$UnalignedInternal(scope, base, offset, be);
} catch (Scope.ScopedAccessError ex) {
return get$Type$UnalignedInternal(session, base, offset, be);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ get$Type$UnalignedInternal(Scope scope, Object base, long offset, boolean be) {
private $type$ get$Type$UnalignedInternal(MemorySessionImpl session, Object base, long offset, boolean be) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.get$Type$Unaligned(base, offset, be);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public void put$Type$Unaligned(Scope scope, Object base, long offset, $type$ value, boolean be) {
public void put$Type$Unaligned(MemorySessionImpl session, Object base, long offset, $type$ value, boolean be) {
try {
put$Type$UnalignedInternal(scope, base, offset, value, be);
} catch (Scope.ScopedAccessError ex) {
put$Type$UnalignedInternal(session, base, offset, value, be);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private void put$Type$UnalignedInternal(Scope scope, Object base, long offset, $type$ value, boolean be) {
private void put$Type$UnalignedInternal(MemorySessionImpl session, Object base, long offset, $type$ value, boolean be) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
UNSAFE.put$Type$Unaligned(base, offset, value, be);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
#end[Unaligned]
@ForceInline
public $type$ get$Type$Volatile(Scope scope, Object base, long offset) {
public $type$ get$Type$Volatile(MemorySessionImpl session, Object base, long offset) {
try {
return get$Type$VolatileInternal(scope, base, offset);
} catch (Scope.ScopedAccessError ex) {
return get$Type$VolatileInternal(session, base, offset);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ get$Type$VolatileInternal(Scope scope, Object base, long offset) {
private $type$ get$Type$VolatileInternal(MemorySessionImpl session, Object base, long offset) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.get$Type$Volatile(base, offset);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public void put$Type$Volatile(Scope scope, Object base, long offset, $type$ value) {
public void put$Type$Volatile(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
put$Type$VolatileInternal(scope, base, offset, value);
} catch (Scope.ScopedAccessError ex) {
put$Type$VolatileInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private void put$Type$VolatileInternal(Scope scope, Object base, long offset, $type$ value) {
private void put$Type$VolatileInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
UNSAFE.put$Type$Volatile(base, offset, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ get$Type$Acquire(Scope scope, Object base, long offset) {
public $type$ get$Type$Acquire(MemorySessionImpl session, Object base, long offset) {
try {
return get$Type$AcquireInternal(scope, base, offset);
} catch (Scope.ScopedAccessError ex) {
return get$Type$AcquireInternal(session, base, offset);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ get$Type$AcquireInternal(Scope scope, Object base, long offset) {
private $type$ get$Type$AcquireInternal(MemorySessionImpl session, Object base, long offset) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.get$Type$Acquire(base, offset);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public void put$Type$Release(Scope scope, Object base, long offset, $type$ value) {
public void put$Type$Release(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
put$Type$ReleaseInternal(scope, base, offset, value);
} catch (Scope.ScopedAccessError ex) {
put$Type$ReleaseInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private void put$Type$ReleaseInternal(Scope scope, Object base, long offset, $type$ value) {
private void put$Type$ReleaseInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
UNSAFE.put$Type$Release(base, offset, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ get$Type$Opaque(Scope scope, Object base, long offset) {
public $type$ get$Type$Opaque(MemorySessionImpl session, Object base, long offset) {
try {
return get$Type$OpaqueInternal(scope, base, offset);
} catch (Scope.ScopedAccessError ex) {
return get$Type$OpaqueInternal(session, base, offset);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ get$Type$OpaqueInternal(Scope scope, Object base, long offset) {
private $type$ get$Type$OpaqueInternal(MemorySessionImpl session, Object base, long offset) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.get$Type$Opaque(base, offset);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public void put$Type$Opaque(Scope scope, Object base, long offset, $type$ value) {
public void put$Type$Opaque(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
put$Type$OpaqueInternal(scope, base, offset, value);
} catch (Scope.ScopedAccessError ex) {
put$Type$OpaqueInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private void put$Type$OpaqueInternal(Scope scope, Object base, long offset, $type$ value) {
private void put$Type$OpaqueInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
UNSAFE.put$Type$Opaque(base, offset, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
#if[CAS]
@ForceInline
public boolean compareAndSet$Type$(Scope scope, Object base, long offset, $type$ expected, $type$ value) {
public boolean compareAndSet$Type$(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
return compareAndSet$Type$Internal(scope, base, offset, expected, value);
} catch (Scope.ScopedAccessError ex) {
return compareAndSet$Type$Internal(session, base, offset, expected, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private boolean compareAndSet$Type$Internal(Scope scope, Object base, long offset, $type$ expected, $type$ value) {
private boolean compareAndSet$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.compareAndSet$Type$(base, offset, expected, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ compareAndExchange$Type$(Scope scope, Object base, long offset, $type$ expected, $type$ value) {
public $type$ compareAndExchange$Type$(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
return compareAndExchange$Type$Internal(scope, base, offset, expected, value);
} catch (Scope.ScopedAccessError ex) {
return compareAndExchange$Type$Internal(session, base, offset, expected, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ compareAndExchange$Type$Internal(Scope scope, Object base, long offset, $type$ expected, $type$ value) {
private $type$ compareAndExchange$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.compareAndExchange$Type$(base, offset, expected, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ compareAndExchange$Type$Acquire(Scope scope, Object base, long offset, $type$ expected, $type$ value) {
public $type$ compareAndExchange$Type$Acquire(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
return compareAndExchange$Type$AcquireInternal(scope, base, offset, expected, value);
} catch (Scope.ScopedAccessError ex) {
return compareAndExchange$Type$AcquireInternal(session, base, offset, expected, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ compareAndExchange$Type$AcquireInternal(Scope scope, Object base, long offset, $type$ expected, $type$ value) {
private $type$ compareAndExchange$Type$AcquireInternal(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.compareAndExchange$Type$Acquire(base, offset, expected, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ compareAndExchange$Type$Release(Scope scope, Object base, long offset, $type$ expected, $type$ value) {
public $type$ compareAndExchange$Type$Release(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
return compareAndExchange$Type$ReleaseInternal(scope, base, offset, expected, value);
} catch (Scope.ScopedAccessError ex) {
return compareAndExchange$Type$ReleaseInternal(session, base, offset, expected, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ compareAndExchange$Type$ReleaseInternal(Scope scope, Object base, long offset, $type$ expected, $type$ value) {
private $type$ compareAndExchange$Type$ReleaseInternal(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.compareAndExchange$Type$Release(base, offset, expected, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public boolean weakCompareAndSet$Type$Plain(Scope scope, Object base, long offset, $type$ expected, $type$ value) {
public boolean weakCompareAndSet$Type$Plain(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
return weakCompareAndSet$Type$PlainInternal(scope, base, offset, expected, value);
} catch (Scope.ScopedAccessError ex) {
return weakCompareAndSet$Type$PlainInternal(session, base, offset, expected, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private boolean weakCompareAndSet$Type$PlainInternal(Scope scope, Object base, long offset, $type$ expected, $type$ value) {
private boolean weakCompareAndSet$Type$PlainInternal(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.weakCompareAndSet$Type$Plain(base, offset, expected, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public boolean weakCompareAndSet$Type$(Scope scope, Object base, long offset, $type$ expected, $type$ value) {
public boolean weakCompareAndSet$Type$(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
return weakCompareAndSet$Type$Internal(scope, base, offset, expected, value);
} catch (Scope.ScopedAccessError ex) {
return weakCompareAndSet$Type$Internal(session, base, offset, expected, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private boolean weakCompareAndSet$Type$Internal(Scope scope, Object base, long offset, $type$ expected, $type$ value) {
private boolean weakCompareAndSet$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.weakCompareAndSet$Type$(base, offset, expected, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public boolean weakCompareAndSet$Type$Acquire(Scope scope, Object base, long offset, $type$ expected, $type$ value) {
public boolean weakCompareAndSet$Type$Acquire(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
return weakCompareAndSet$Type$AcquireInternal(scope, base, offset, expected, value);
} catch (Scope.ScopedAccessError ex) {
return weakCompareAndSet$Type$AcquireInternal(session, base, offset, expected, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private boolean weakCompareAndSet$Type$AcquireInternal(Scope scope, Object base, long offset, $type$ expected, $type$ value) {
private boolean weakCompareAndSet$Type$AcquireInternal(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.weakCompareAndSet$Type$Acquire(base, offset, expected, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public boolean weakCompareAndSet$Type$Release(Scope scope, Object base, long offset, $type$ expected, $type$ value) {
public boolean weakCompareAndSet$Type$Release(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
return weakCompareAndSet$Type$ReleaseInternal(scope, base, offset, expected, value);
} catch (Scope.ScopedAccessError ex) {
return weakCompareAndSet$Type$ReleaseInternal(session, base, offset, expected, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private boolean weakCompareAndSet$Type$ReleaseInternal(Scope scope, Object base, long offset, $type$ expected, $type$ value) {
private boolean weakCompareAndSet$Type$ReleaseInternal(MemorySessionImpl session, Object base, long offset, $type$ expected, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.weakCompareAndSet$Type$Release(base, offset, expected, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ getAndSet$Type$(Scope scope, Object base, long offset, $type$ value) {
public $type$ getAndSet$Type$(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
return getAndSet$Type$Internal(scope, base, offset, value);
} catch (Scope.ScopedAccessError ex) {
return getAndSet$Type$Internal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ getAndSet$Type$Internal(Scope scope, Object base, long offset, $type$ value) {
private $type$ getAndSet$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.getAndSet$Type$(base, offset, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ getAndSet$Type$Acquire(Scope scope, Object base, long offset, $type$ value) {
public $type$ getAndSet$Type$Acquire(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
return getAndSet$Type$AcquireInternal(scope, base, offset, value);
} catch (Scope.ScopedAccessError ex) {
return getAndSet$Type$AcquireInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ getAndSet$Type$AcquireInternal(Scope scope, Object base, long offset, $type$ value) {
private $type$ getAndSet$Type$AcquireInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.getAndSet$Type$Acquire(base, offset, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ getAndSet$Type$Release(Scope scope, Object base, long offset, $type$ value) {
public $type$ getAndSet$Type$Release(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
return getAndSet$Type$ReleaseInternal(scope, base, offset, value);
} catch (Scope.ScopedAccessError ex) {
return getAndSet$Type$ReleaseInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ getAndSet$Type$ReleaseInternal(Scope scope, Object base, long offset, $type$ value) {
private $type$ getAndSet$Type$ReleaseInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.getAndSet$Type$Release(base, offset, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
#end[CAS]
#if[AtomicAdd]
@ForceInline
public $type$ getAndAdd$Type$(Scope scope, Object base, long offset, $type$ delta) {
public $type$ getAndAdd$Type$(MemorySessionImpl session, Object base, long offset, $type$ delta) {
try {
return getAndAdd$Type$Internal(scope, base, offset, delta);
} catch (Scope.ScopedAccessError ex) {
return getAndAdd$Type$Internal(session, base, offset, delta);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ getAndAdd$Type$Internal(Scope scope, Object base, long offset, $type$ delta) {
private $type$ getAndAdd$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ delta) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.getAndAdd$Type$(base, offset, delta);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ getAndAdd$Type$Acquire(Scope scope, Object base, long offset, $type$ delta) {
public $type$ getAndAdd$Type$Acquire(MemorySessionImpl session, Object base, long offset, $type$ delta) {
try {
return getAndAdd$Type$AcquireInternal(scope, base, offset, delta);
} catch (Scope.ScopedAccessError ex) {
return getAndAdd$Type$AcquireInternal(session, base, offset, delta);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ getAndAdd$Type$AcquireInternal(Scope scope, Object base, long offset, $type$ delta) {
private $type$ getAndAdd$Type$AcquireInternal(MemorySessionImpl session, Object base, long offset, $type$ delta) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.getAndAdd$Type$Acquire(base, offset, delta);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ getAndAdd$Type$Release(Scope scope, Object base, long offset, $type$ delta) {
public $type$ getAndAdd$Type$Release(MemorySessionImpl session, Object base, long offset, $type$ delta) {
try {
return getAndAdd$Type$ReleaseInternal(scope, base, offset, delta);
} catch (Scope.ScopedAccessError ex) {
return getAndAdd$Type$ReleaseInternal(session, base, offset, delta);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ getAndAdd$Type$ReleaseInternal(Scope scope, Object base, long offset, $type$ delta) {
private $type$ getAndAdd$Type$ReleaseInternal(MemorySessionImpl session, Object base, long offset, $type$ delta) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.getAndAdd$Type$Release(base, offset, delta);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
#end[AtomicAdd]
#if[Bitwise]
@ForceInline
public $type$ getAndBitwiseOr$Type$(Scope scope, Object base, long offset, $type$ value) {
public $type$ getAndBitwiseOr$Type$(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
return getAndBitwiseOr$Type$Internal(scope, base, offset, value);
} catch (Scope.ScopedAccessError ex) {
return getAndBitwiseOr$Type$Internal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ getAndBitwiseOr$Type$Internal(Scope scope, Object base, long offset, $type$ value) {
private $type$ getAndBitwiseOr$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.getAndBitwiseOr$Type$(base, offset, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ getAndBitwiseOr$Type$Acquire(Scope scope, Object base, long offset, $type$ value) {
public $type$ getAndBitwiseOr$Type$Acquire(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
return getAndBitwiseOr$Type$AcquireInternal(scope, base, offset, value);
} catch (Scope.ScopedAccessError ex) {
return getAndBitwiseOr$Type$AcquireInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ getAndBitwiseOr$Type$AcquireInternal(Scope scope, Object base, long offset, $type$ value) {
private $type$ getAndBitwiseOr$Type$AcquireInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.getAndBitwiseOr$Type$Acquire(base, offset, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ getAndBitwiseOr$Type$Release(Scope scope, Object base, long offset, $type$ value) {
public $type$ getAndBitwiseOr$Type$Release(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
return getAndBitwiseOr$Type$ReleaseInternal(scope, base, offset, value);
} catch (Scope.ScopedAccessError ex) {
return getAndBitwiseOr$Type$ReleaseInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ getAndBitwiseOr$Type$ReleaseInternal(Scope scope, Object base, long offset, $type$ value) {
private $type$ getAndBitwiseOr$Type$ReleaseInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.getAndBitwiseOr$Type$Release(base, offset, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ getAndBitwiseAnd$Type$(Scope scope, Object base, long offset, $type$ value) {
public $type$ getAndBitwiseAnd$Type$(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
return getAndBitwiseAnd$Type$Internal(scope, base, offset, value);
} catch (Scope.ScopedAccessError ex) {
return getAndBitwiseAnd$Type$Internal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ getAndBitwiseAnd$Type$Internal(Scope scope, Object base, long offset, $type$ value) {
private $type$ getAndBitwiseAnd$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.getAndBitwiseAnd$Type$(base, offset, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ getAndBitwiseAnd$Type$Acquire(Scope scope, Object base, long offset, $type$ value) {
public $type$ getAndBitwiseAnd$Type$Acquire(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
return getAndBitwiseAnd$Type$AcquireInternal(scope, base, offset, value);
} catch (Scope.ScopedAccessError ex) {
return getAndBitwiseAnd$Type$AcquireInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ getAndBitwiseAnd$Type$AcquireInternal(Scope scope, Object base, long offset, $type$ value) {
private $type$ getAndBitwiseAnd$Type$AcquireInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.getAndBitwiseAnd$Type$Acquire(base, offset, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ getAndBitwiseAnd$Type$Release(Scope scope, Object base, long offset, $type$ value) {
public $type$ getAndBitwiseAnd$Type$Release(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
return getAndBitwiseAnd$Type$ReleaseInternal(scope, base, offset, value);
} catch (Scope.ScopedAccessError ex) {
return getAndBitwiseAnd$Type$ReleaseInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ getAndBitwiseAnd$Type$ReleaseInternal(Scope scope, Object base, long offset, $type$ value) {
private $type$ getAndBitwiseAnd$Type$ReleaseInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.getAndBitwiseAnd$Type$Release(base, offset, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ getAndBitwiseXor$Type$(Scope scope, Object base, long offset, $type$ value) {
public $type$ getAndBitwiseXor$Type$(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
return getAndBitwiseXor$Type$Internal(scope, base, offset, value);
} catch (Scope.ScopedAccessError ex) {
return getAndBitwiseXor$Type$Internal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ getAndBitwiseXor$Type$Internal(Scope scope, Object base, long offset, $type$ value) {
private $type$ getAndBitwiseXor$Type$Internal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.getAndBitwiseXor$Type$(base, offset, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ getAndBitwiseXor$Type$Acquire(Scope scope, Object base, long offset, $type$ value) {
public $type$ getAndBitwiseXor$Type$Acquire(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
return getAndBitwiseXor$Type$AcquireInternal(scope, base, offset, value);
} catch (Scope.ScopedAccessError ex) {
return getAndBitwiseXor$Type$AcquireInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ getAndBitwiseXor$Type$AcquireInternal(Scope scope, Object base, long offset, $type$ value) {
private $type$ getAndBitwiseXor$Type$AcquireInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.getAndBitwiseXor$Type$Acquire(base, offset, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public $type$ getAndBitwiseXor$Type$Release(Scope scope, Object base, long offset, $type$ value) {
public $type$ getAndBitwiseXor$Type$Release(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
return getAndBitwiseXor$Type$ReleaseInternal(scope, base, offset, value);
} catch (Scope.ScopedAccessError ex) {
return getAndBitwiseXor$Type$ReleaseInternal(session, base, offset, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private $type$ getAndBitwiseXor$Type$ReleaseInternal(Scope scope, Object base, long offset, $type$ value) {
private $type$ getAndBitwiseXor$Type$ReleaseInternal(MemorySessionImpl session, Object base, long offset, $type$ value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return UNSAFE.getAndBitwiseXor$Type$Release(base, offset, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
#end[Bitwise]

View file

@ -29,6 +29,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.foreign.MemorySegment;
import java.lang.ref.Reference;
import java.io.FileDescriptor;
import java.nio.Buffer;
@ -36,7 +37,8 @@ import java.nio.ByteBuffer;
import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.foreign.AbstractMemorySegmentImpl;
import jdk.internal.foreign.MemorySessionImpl;
import jdk.internal.util.ArraysSupport;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.vector.VectorSupport;
@ -45,7 +47,7 @@ import jdk.internal.vm.vector.VectorSupport;
/**
* This class defines low-level methods to access on-heap and off-heap memory. The methods in this class
* can be thought of as thin wrappers around methods provided in the {@link Unsafe} class. All the methods in this
* class, accept one or more {@link Scope} parameter, which is used to validate as to whether access to memory
* class accept one or more {@link MemorySessionImpl} parameter, which is used to validate as to whether access to memory
* can be performed in a safe fashion - more specifically, to ensure that the memory being accessed has not
* already been released (which would result in a hard VM crash).
* <p>
@ -56,17 +58,16 @@ import jdk.internal.vm.vector.VectorSupport;
* <p>
* This class provides tools to manage races when multiple threads are accessing and/or releasing the same memory
* region concurrently. More specifically, when a thread wants to release a memory region, it should call the
* {@link #closeScope(jdk.internal.misc.ScopedMemoryAccess.Scope)} method provided by this class. This method initiates
* thread-local handshakes with all the other VM threads, which are then stopped one by one. If any thread is found
* accessing memory that is associated to the very scope object being closed, that thread execution is asynchronously
* interrupted with a {@link Scope.ScopedAccessError}.
* {@link MemorySessionImpl#close()} method. This method initiates thread-local handshakes with all the other VM threads,
* which are then stopped one by one. If any thread is found accessing a resource associated to the very memory session
* being closed, the handshake fails, and the session cannot be closed.
* <p>
* This synchronization strategy relies on the idea that accessing memory is atomic with respect to checking the
* validity of the scope associated with that memory region - that is, a thread that wants to perform memory access will be
* suspended either <em>before</em> a scope check or <em>after</em> the memory access. To ensure this atomicity,
* validity of the session associated with that memory region - that is, a thread that wants to perform memory access will be
* suspended either <em>before</em> a liveness check or <em>after</em> the memory access. To ensure this atomicity,
* all methods in this class are marked with the special {@link Scoped} annotation, which is recognized by the VM,
* and used during the thread-local handshake to detect (and stop) threads performing potentially problematic memory access
* operations. Additionally, to make sure that the scope object(s) of the memory being accessed is always
* operations. Additionally, to make sure that the session object(s) of the memory being accessed is always
* reachable during an access operation, all the methods in this class add reachability fences around the underlying
* unsafe access.
* <p>
@ -83,11 +84,11 @@ public class ScopedMemoryAccess {
registerNatives();
}
public boolean closeScope(Scope scope) {
return closeScope0(scope, Scope.ScopedAccessError.INSTANCE);
public boolean closeScope(MemorySessionImpl session) {
return closeScope0(session);
}
native boolean closeScope0(Scope scope, Scope.ScopedAccessError exception);
native boolean closeScope0(MemorySessionImpl session);
private ScopedMemoryAccess() {}
@ -97,28 +98,7 @@ public class ScopedMemoryAccess {
return theScopedMemoryAccess;
}
/**
* Scope interface used during scoped memory access operations. A scope can be thought of as an object
* which embodies the temporal checks associated with a given memory region.
*/
public interface Scope {
void checkValidState();
Thread ownerThread();
void acquire0();
void release0();
/**
* Error thrown when memory access fails because the memory has already been released.
* Note: for performance reasons, this exception is never created by client; instead a shared instance
* is thrown (sometimes, this instance can be thrown asynchronously inside VM code). For this reason,
* it is important for clients to always catch this exception and throw a regular exception instead
* (which contains full stack information).
*/
final class ScopedAccessError extends Error {
public static final class ScopedAccessError extends Error {
private ScopedAccessError() {
super("Attempt to access an already released memory resource", null, false, false);
}
@ -126,7 +106,6 @@ public class ScopedMemoryAccess {
public static final ScopedAccessError INSTANCE = new ScopedAccessError();
}
}
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
@ -135,19 +114,19 @@ public class ScopedMemoryAccess {
// bulk ops
@ForceInline
public void copyMemory(Scope srcScope, Scope dstScope,
public void copyMemory(MemorySessionImpl srcScope, MemorySessionImpl dstScope,
Object srcBase, long srcOffset,
Object destBase, long destOffset,
long bytes) {
try {
copyMemoryInternal(srcScope, dstScope, srcBase, srcOffset, destBase, destOffset, bytes);
} catch (Scope.ScopedAccessError ex) {
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private void copyMemoryInternal(Scope srcScope, Scope dstScope,
private void copyMemoryInternal(MemorySessionImpl srcScope, MemorySessionImpl dstScope,
Object srcBase, long srcOffset,
Object destBase, long destOffset,
long bytes) {
@ -166,19 +145,19 @@ public class ScopedMemoryAccess {
}
@ForceInline
public void copySwapMemory(Scope srcScope, Scope dstScope,
public void copySwapMemory(MemorySessionImpl srcScope, MemorySessionImpl dstScope,
Object srcBase, long srcOffset,
Object destBase, long destOffset,
long bytes, long elemSize) {
try {
copySwapMemoryInternal(srcScope, dstScope, srcBase, srcOffset, destBase, destOffset, bytes, elemSize);
} catch (Scope.ScopedAccessError ex) {
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private void copySwapMemoryInternal(Scope srcScope, Scope dstScope,
private void copySwapMemoryInternal(MemorySessionImpl srcScope, MemorySessionImpl dstScope,
Object srcBase, long srcOffset,
Object destBase, long destOffset,
long bytes, long elemSize) {
@ -197,41 +176,41 @@ public class ScopedMemoryAccess {
}
@ForceInline
public void setMemory(Scope scope, Object o, long offset, long bytes, byte value) {
public void setMemory(MemorySessionImpl session, Object o, long offset, long bytes, byte value) {
try {
setMemoryInternal(scope, o, offset, bytes, value);
} catch (Scope.ScopedAccessError ex) {
setMemoryInternal(session, o, offset, bytes, value);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private void setMemoryInternal(Scope scope, Object o, long offset, long bytes, byte value) {
private void setMemoryInternal(MemorySessionImpl session, Object o, long offset, long bytes, byte value) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
UNSAFE.setMemory(o, offset, bytes, value);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public int vectorizedMismatch(Scope aScope, Scope bScope,
public int vectorizedMismatch(MemorySessionImpl aScope, MemorySessionImpl bScope,
Object a, long aOffset,
Object b, long bOffset,
int length,
int log2ArrayIndexScale) {
try {
return vectorizedMismatchInternal(aScope, bScope, a, aOffset, b, bOffset, length, log2ArrayIndexScale);
} catch (Scope.ScopedAccessError ex) {
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
private int vectorizedMismatchInternal(Scope aScope, Scope bScope,
private int vectorizedMismatchInternal(MemorySessionImpl aScope, MemorySessionImpl bScope,
Object a, long aOffset,
Object b, long bOffset,
int length,
@ -251,86 +230,86 @@ public class ScopedMemoryAccess {
}
@ForceInline
public boolean isLoaded(Scope scope, long address, boolean isSync, long size) {
public boolean isLoaded(MemorySessionImpl session, long address, boolean isSync, long size) {
try {
return isLoadedInternal(scope, address, isSync, size);
} catch (Scope.ScopedAccessError ex) {
return isLoadedInternal(session, address, isSync, size);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
public boolean isLoadedInternal(Scope scope, long address, boolean isSync, long size) {
public boolean isLoadedInternal(MemorySessionImpl session, long address, boolean isSync, long size) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return SharedSecrets.getJavaNioAccess().isLoaded(address, isSync, size);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public void load(Scope scope, long address, boolean isSync, long size) {
public void load(MemorySessionImpl session, long address, boolean isSync, long size) {
try {
loadInternal(scope, address, isSync, size);
} catch (Scope.ScopedAccessError ex) {
loadInternal(session, address, isSync, size);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
public void loadInternal(Scope scope, long address, boolean isSync, long size) {
public void loadInternal(MemorySessionImpl session, long address, boolean isSync, long size) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
SharedSecrets.getJavaNioAccess().load(address, isSync, size);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public void unload(Scope scope, long address, boolean isSync, long size) {
public void unload(MemorySessionImpl session, long address, boolean isSync, long size) {
try {
unloadInternal(scope, address, isSync, size);
} catch (Scope.ScopedAccessError ex) {
unloadInternal(session, address, isSync, size);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
public void unloadInternal(Scope scope, long address, boolean isSync, long size) {
public void unloadInternal(MemorySessionImpl session, long address, boolean isSync, long size) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
SharedSecrets.getJavaNioAccess().unload(address, isSync, size);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ForceInline
public void force(Scope scope, FileDescriptor fd, long address, boolean isSync, long index, long length) {
public void force(MemorySessionImpl session, FileDescriptor fd, long address, boolean isSync, long index, long length) {
try {
forceInternal(scope, fd, address, isSync, index, length);
} catch (Scope.ScopedAccessError ex) {
forceInternal(session, fd, address, isSync, index, length);
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ForceInline @Scoped
public void forceInternal(Scope scope, FileDescriptor fd, long address, boolean isSync, long index, long length) {
public void forceInternal(MemorySessionImpl session, FileDescriptor fd, long address, boolean isSync, long index, long length) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
SharedSecrets.getJavaNioAccess().force(fd, address, isSync, index, length);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ -363,10 +342,10 @@ public class ScopedMemoryAccess {
static final JavaNioAccess NIO_ACCESS = SharedSecrets.getJavaNioAccess();
@ForceInline
static ScopedMemoryAccess.Scope scope(ByteBuffer bb) {
MemorySegmentProxy segmentProxy = NIO_ACCESS.bufferSegment(bb);
return segmentProxy != null ?
segmentProxy.scope() : null;
static MemorySessionImpl session(ByteBuffer bb) {
MemorySegment segment = NIO_ACCESS.bufferSegment(bb);
return segment != null ?
((AbstractMemorySegmentImpl)segment).sessionImpl() : null;
}
}
@ -384,12 +363,12 @@ public class ScopedMemoryAccess {
VectorSupport.LoadOperation<ByteBuffer, V, S> defaultImpl) {
try {
return loadFromByteBufferScoped(
BufferAccess.scope(bb),
BufferAccess.session(bb),
vmClass, e, length,
bb, offset,
s,
defaultImpl);
} catch (ScopedMemoryAccess.Scope.ScopedAccessError ex) {
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ -398,14 +377,14 @@ public class ScopedMemoryAccess {
@ForceInline
private static
<V extends VectorSupport.Vector<E>, E, S extends VectorSupport.VectorSpecies<E>>
V loadFromByteBufferScoped(ScopedMemoryAccess.Scope scope,
V loadFromByteBufferScoped(MemorySessionImpl session,
Class<? extends V> vmClass, Class<E> e, int length,
ByteBuffer bb, int offset,
S s,
VectorSupport.LoadOperation<ByteBuffer, V, S> defaultImpl) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
final byte[] base = (byte[]) BufferAccess.bufferBase(bb);
@ -415,7 +394,7 @@ public class ScopedMemoryAccess {
bb, offset, s,
defaultImpl);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ -428,12 +407,12 @@ public class ScopedMemoryAccess {
VectorSupport.LoadVectorMaskedOperation<ByteBuffer, V, S, M> defaultImpl) {
try {
return loadFromByteBufferMaskedScoped(
BufferAccess.scope(bb),
BufferAccess.session(bb),
vmClass, maskClass, e, length,
bb, offset, m,
s,
defaultImpl);
} catch (ScopedMemoryAccess.Scope.ScopedAccessError ex) {
} catch (ScopedMemoryAccess.ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ -443,14 +422,14 @@ public class ScopedMemoryAccess {
private static
<V extends VectorSupport.Vector<E>, E, S extends VectorSupport.VectorSpecies<E>,
M extends VectorSupport.VectorMask<E>>
V loadFromByteBufferMaskedScoped(ScopedMemoryAccess.Scope scope, Class<? extends V> vmClass,
V loadFromByteBufferMaskedScoped(MemorySessionImpl session, Class<? extends V> vmClass,
Class<M> maskClass, Class<E> e, int length,
ByteBuffer bb, int offset, M m,
S s,
VectorSupport.LoadVectorMaskedOperation<ByteBuffer, V, S, M> defaultImpl) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
return VectorSupport.loadMasked(vmClass, maskClass, e, length,
@ -458,7 +437,7 @@ public class ScopedMemoryAccess {
bb, offset, s,
defaultImpl);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ -471,12 +450,12 @@ public class ScopedMemoryAccess {
VectorSupport.StoreVectorOperation<ByteBuffer, V> defaultImpl) {
try {
storeIntoByteBufferScoped(
BufferAccess.scope(bb),
BufferAccess.session(bb),
vmClass, e, length,
v,
bb, offset,
defaultImpl);
} catch (ScopedMemoryAccess.Scope.ScopedAccessError ex) {
} catch (ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ -485,14 +464,14 @@ public class ScopedMemoryAccess {
@ForceInline
private static
<V extends VectorSupport.Vector<E>, E>
void storeIntoByteBufferScoped(ScopedMemoryAccess.Scope scope,
void storeIntoByteBufferScoped(MemorySessionImpl session,
Class<? extends V> vmClass, Class<E> e, int length,
V v,
ByteBuffer bb, int offset,
VectorSupport.StoreVectorOperation<ByteBuffer, V> defaultImpl) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
final byte[] base = (byte[]) BufferAccess.bufferBase(bb);
@ -503,7 +482,7 @@ public class ScopedMemoryAccess {
bb, offset,
defaultImpl);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}
@ -516,12 +495,12 @@ public class ScopedMemoryAccess {
VectorSupport.StoreVectorMaskedOperation<ByteBuffer, V, M> defaultImpl) {
try {
storeIntoByteBufferMaskedScoped(
BufferAccess.scope(bb),
BufferAccess.session(bb),
vmClass, maskClass, e, length,
v, m,
bb, offset,
defaultImpl);
} catch (ScopedMemoryAccess.Scope.ScopedAccessError ex) {
} catch (ScopedMemoryAccess.ScopedAccessError ex) {
throw new IllegalStateException("This segment is already closed");
}
}
@ -530,14 +509,14 @@ public class ScopedMemoryAccess {
@ForceInline
private static
<V extends VectorSupport.Vector<E>, E, M extends VectorSupport.VectorMask<E>>
void storeIntoByteBufferMaskedScoped(ScopedMemoryAccess.Scope scope,
void storeIntoByteBufferMaskedScoped(MemorySessionImpl session,
Class<? extends V> vmClass, Class<M> maskClass,
Class<E> e, int length, V v, M m,
ByteBuffer bb, int offset,
VectorSupport.StoreVectorMaskedOperation<ByteBuffer, V, M> defaultImpl) {
try {
if (scope != null) {
scope.checkValidState();
if (session != null) {
session.checkValidState();
}
VectorSupport.storeMasked(vmClass, maskClass, e, length,
@ -546,7 +525,7 @@ public class ScopedMemoryAccess {
bb, offset,
defaultImpl);
} finally {
Reference.reachabilityFence(scope);
Reference.reachabilityFence(session);
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 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
@ -772,11 +772,23 @@ public final class ModuleBootstrap {
}
}
private static final boolean HAS_ENABLE_NATIVE_ACCESS_FLAG;
private static final Set<String> NATIVE_ACCESS_MODULES;
public static boolean hasEnableNativeAccessFlag() {
return HAS_ENABLE_NATIVE_ACCESS_FLAG;
}
static {
NATIVE_ACCESS_MODULES = decodeEnableNativeAccess();
HAS_ENABLE_NATIVE_ACCESS_FLAG = !NATIVE_ACCESS_MODULES.isEmpty();
}
/**
* Process the --enable-native-access option to grant access to restricted methods to selected modules.
*/
private static void addEnableNativeAccess(ModuleLayer layer) {
for (String name : decodeEnableNativeAccess()) {
for (String name : NATIVE_ACCESS_MODULES) {
if (name.equals("ALL-UNNAMED")) {
JLA.addEnableNativeAccessAllUnnamed();
} else {

View file

@ -30,8 +30,10 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.VM;
import jdk.internal.module.ModuleBootstrap;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.IntrinsicCandidate;
@ -108,10 +110,37 @@ public class Reflection {
}
@ForceInline
public static void ensureNativeAccess(Class<?> currentClass) {
Module module = currentClass.getModule();
if (!SharedSecrets.getJavaLangAccess().isEnableNativeAccess(module)) {
public static void ensureNativeAccess(Class<?> currentClass, Class<?> owner, String methodName) {
// if there is no caller class, act as if the call came from unnamed module of system class loader
Module module = currentClass != null ?
currentClass.getModule() :
ClassLoader.getSystemClassLoader().getUnnamedModule();
boolean isNativeAccessEnabled = SharedSecrets.getJavaLangAccess().isEnableNativeAccess(module);
if (!isNativeAccessEnabled) {
synchronized(module) {
isNativeAccessEnabled = SharedSecrets.getJavaLangAccess().isEnableNativeAccess(module);
if (isNativeAccessEnabled) {
// some other thread got to it, do nothing
} else if (ModuleBootstrap.hasEnableNativeAccessFlag()) {
throw new IllegalCallerException("Illegal native access from: " + module);
} else {
// warn and set flag, so that only one warning is reported per module
String cls = owner.getName();
String mtd = cls + "::" + methodName;
String mod = module.isNamed() ? "module " + module.getName() : "the unnamed module";
String modflag = module.isNamed() ? module.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);
if (module.isNamed()) {
SharedSecrets.getJavaLangAccess().addEnableNativeAccess(module);
} else {
SharedSecrets.getJavaLangAccess().addEnableNativeAccessAllUnnamed();
}
}
}
}
}

View file

@ -80,6 +80,7 @@ module java.base {
exports java.lang;
exports java.lang.annotation;
exports java.lang.constant;
exports java.lang.foreign;
exports java.lang.invoke;
exports java.lang.module;
exports java.lang.ref;
@ -137,8 +138,7 @@ module java.base {
exports com.sun.crypto.provider to
jdk.crypto.cryptoki;
exports sun.invoke.util to
jdk.compiler,
jdk.incubator.foreign;
jdk.compiler;
exports com.sun.security.ntlm to
java.security.sasl;
exports jdk.internal.javac to
@ -157,10 +157,7 @@ module java.base {
jdk.charsets,
jdk.jartool,
jdk.jlink,
jdk.net,
jdk.incubator.foreign;
exports jdk.internal.access.foreign to
jdk.incubator.foreign;
jdk.net;
exports jdk.internal.event to
jdk.jfr;
exports jdk.internal.jimage to
@ -170,8 +167,7 @@ module java.base {
exports jdk.internal.loader to
java.instrument,
java.logging,
java.naming,
jdk.incubator.foreign;
java.naming;
exports jdk.internal.jmod to
jdk.compiler,
jdk.jlink;
@ -209,16 +205,14 @@ module java.base {
jdk.jshell,
jdk.nio.mapmode,
jdk.unsupported,
jdk.internal.vm.ci,
jdk.incubator.foreign;
jdk.internal.vm.ci;
exports jdk.internal.module to
java.instrument,
java.management.rmi,
jdk.jartool,
jdk.jfr,
jdk.jlink,
jdk.jpackage,
jdk.incubator.foreign;
jdk.jpackage;
exports jdk.internal.perf to
java.management,
jdk.management.agent,
@ -227,16 +221,14 @@ module java.base {
jdk.management,
jdk.jfr;
exports jdk.internal.ref to
java.desktop,
jdk.incubator.foreign;
java.desktop;
exports jdk.internal.reflect to
java.logging,
java.sql,
java.sql.rowset,
jdk.dynalink,
jdk.internal.vm.ci,
jdk.unsupported,
jdk.incubator.foreign;
jdk.unsupported;
exports jdk.internal.vm to
java.management,
jdk.internal.jvmstat,
@ -246,13 +238,10 @@ module java.base {
java.instrument,
jdk.internal.vm.ci,
jdk.incubator.vector,
jdk.incubator.foreign,
jdk.jfr,
jdk.unsupported;
exports jdk.internal.vm.vector to
jdk.incubator.vector;
exports jdk.internal.util to
jdk.incubator.foreign;
exports jdk.internal.util.jar to
jdk.jartool;
exports jdk.internal.util.xml to
@ -283,8 +272,7 @@ module java.base {
java.management,
jdk.crypto.cryptoki,
jdk.net,
jdk.sctp,
jdk.incubator.foreign;
jdk.sctp;
exports sun.nio.cs to
jdk.charsets;
exports sun.nio.fs to
@ -303,8 +291,7 @@ module java.base {
exports sun.security.action to
java.desktop,
java.security.jgss,
jdk.crypto.ec,
jdk.incubator.foreign;
jdk.crypto.ec;
exports sun.security.internal.interfaces to
jdk.crypto.cryptoki;
exports sun.security.internal.spec to
@ -367,8 +354,6 @@ module java.base {
java.prefs;
exports sun.util.resources to
jdk.localedata;
exports jdk.internal.invoke to
jdk.incubator.foreign;
// the service types defined by the APIs in this module

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