diff --git a/make/conf/docs-modules.conf b/make/conf/docs-modules.conf
index 5d0c696c75b..09b26eae9a1 100644
--- a/make/conf/docs-modules.conf
+++ b/make/conf/docs-modules.conf
@@ -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 \
diff --git a/make/conf/module-loader-map.conf b/make/conf/module-loader-map.conf
index c86ebf954c0..f3e38bf9c28 100644
--- a/make/conf/module-loader-map.conf
+++ b/make/conf/module-loader-map.conf
@@ -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 \
diff --git a/make/modules/java.base/Lib.gmk b/make/modules/java.base/Lib.gmk
index eee488607f2..0d5a6c9846c 100644
--- a/make/modules/java.base/Lib.gmk
+++ b/make/modules/java.base/Lib.gmk
@@ -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)
diff --git a/make/modules/java.base/gensrc/GensrcVarHandles.gmk b/make/modules/java.base/gensrc/GensrcVarHandles.gmk
index e1686834bf5..fe4c4e97648 100644
--- a/make/modules/java.base/gensrc/GensrcVarHandles.gmk
+++ b/make/modules/java.base/gensrc/GensrcVarHandles.gmk
@@ -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)
diff --git a/make/modules/jdk.incubator.foreign/Lib.gmk b/make/modules/jdk.incubator.foreign/Lib.gmk
deleted file mode 100644
index d30c7490792..00000000000
--- a/make/modules/jdk.incubator.foreign/Lib.gmk
+++ /dev/null
@@ -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)
-
-################################################################################
diff --git a/make/test/BuildMicrobenchmark.gmk b/make/test/BuildMicrobenchmark.gmk
index 0a0bd39cb69..1c89328a388 100644
--- a/make/test/BuildMicrobenchmark.gmk
+++ b/make/test/BuildMicrobenchmark.gmk
@@ -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 \
diff --git a/make/test/JtregNativeJdk.gmk b/make/test/JtregNativeJdk.gmk
index 2ec0be639f9..892d33927a8 100644
--- a/make/test/JtregNativeJdk.gmk
+++ b/make/test/JtregNativeJdk.gmk
@@ -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
diff --git a/src/hotspot/share/ci/ciField.cpp b/src/hotspot/share/ci/ciField.cpp
index 36055a70c38..485db1b2748 100644
--- a/src/hotspot/share/ci/ciField.cpp
+++ b/src/hotspot/share/ci/ciField.cpp
@@ -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;
diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp
index 3f744fae633..cef0a9e8109 100644
--- a/src/hotspot/share/code/codeBlob.hpp
+++ b/src/hotspot/share/code/codeBlob.hpp
@@ -764,7 +764,6 @@ class OptimizedEntryBlob: public BufferBlob {
JavaThread* thread;
JNIHandleBlock* old_handles;
JNIHandleBlock* new_handles;
- bool should_detach;
};
// defined in frame_ARCH.cpp
diff --git a/src/hotspot/share/prims/scopedMemoryAccess.cpp b/src/hotspot/share/prims/scopedMemoryAccess.cpp
index 6f3c2964fd2..6e6c572ecb0 100644
--- a/src/hotspot/share/prims/scopedMemoryAccess.cpp
+++ b/src/hotspot/share/prims/scopedMemoryAccess.cpp
@@ -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.
diff --git a/src/hotspot/share/prims/universalUpcallHandler.cpp b/src/hotspot/share/prims/universalUpcallHandler.cpp
index 6257036ef9f..0fd0d70d744 100644
--- a/src/hotspot/share/prims/universalUpcallHandler.cpp
+++ b/src/hotspot/share/prims/universalUpcallHandler.cpp
@@ -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() {
diff --git a/src/hotspot/share/prims/universalUpcallHandler.hpp b/src/hotspot/share/prims/universalUpcallHandler.hpp
index 3005762a593..e296c11556e 100644
--- a/src/hotspot/share/prims/universalUpcallHandler.hpp
+++ b/src/hotspot/share/prims/universalUpcallHandler.hpp
@@ -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);
diff --git a/src/java.base/share/classes/java/lang/foreign/AbstractLayout.java b/src/java.base/share/classes/java/lang/foreign/AbstractLayout.java
new file mode 100644
index 00000000000..f931f832e5b
--- /dev/null
+++ b/src/java.base/share/classes/java/lang/foreign/AbstractLayout.java
@@ -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
- * 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 by reference
- * (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 by reference
+ * (e.g. memory addresses, variable argument lists and upcall stubs).
*
- * @implSpec
- * Implementations of this interface are value-based.
+ * @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}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/FunctionDescriptor.java b/src/java.base/share/classes/java/lang/foreign/FunctionDescriptor.java
similarity index 71%
rename from src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/FunctionDescriptor.java
rename to src/java.base/share/classes/java/lang/foreign/FunctionDescriptor.java
index 6bedfc4c16a..3d0a22239c6 100644
--- a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/FunctionDescriptor.java
+++ b/src/java.base/share/classes/java/lang/foreign/FunctionDescriptor.java
@@ -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}.
*
- * 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.
- * This is a value-based
- * 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.
- *
- * 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.
+ * 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.
+ *
+ * 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:
+ *
+ * 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.
+ *
+ *
+ * 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:
+ *
+ * The downcall method handle type, derived as above, might be decorated by additional leading parameters,
+ * in the given order if both are present:
+ *
+ * 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:
+ *
+ * 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 value-based.
+ *
+ * @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.
+ *
+ * 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:
+ *
+ * Any layout not listed above is unsupported; 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}.
+ *
+ * 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...) variadic}
+ * 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}).
+ *
+ * This method is restricted.
+ * 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.
+ *
+ * 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.
+ *
+ * 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 inferred
+ * @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.
+ *
+ * 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.
+ *
+ * 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 inferred
+ * 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.
+ *
+ * The returned memory segment's base address points to the newly allocated upcall stub, and is associated with
+ * the provided memory session. When such session is closed, the corresponding upcall stub will be deallocated.
+ *
+ * The 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 inferred type.
+ * @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.
+ *
+ * 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.
+ * 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);
+ }
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryAddress.java b/src/java.base/share/classes/java/lang/foreign/MemoryAddress.java
similarity index 74%
rename from src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryAddress.java
rename to src/java.base/share/classes/java/lang/foreign/MemoryAddress.java
index 007464d1691..e60ebb3628e 100644
--- a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryAddress.java
+++ b/src/java.base/share/classes/java/lang/foreign/MemoryAddress.java
@@ -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:
*
- * All implementations of this interface must be value-based;
- * 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.
- *
- * 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.
* 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.
*
* 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}.
+ *
+ * This method is restricted.
+ * 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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.
*
* This method is restricted.
* 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
* incompatible with the alignment constraints 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
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryLayout.java b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
similarity index 74%
rename from src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryLayout.java
rename to src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
index 991897c367d..fe542d3afd8 100644
--- a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
@@ -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 group layout denotes an aggregation of (typically) heterogeneous
* member layouts (see {@link GroupLayout}).
*
- * For instance, consider the following struct declaration in C:
+ * Layouts can be optionally associated with a name. A layout name can be referred to when
+ * constructing layout paths.
+ *
+ * Consider the following struct declaration in C:
*
* {@snippet lang=c :
* typedef struct {
@@ -76,14 +76,6 @@ import java.util.stream.Stream;
* )
* ).withName("TaggedValues");
* }
- *
- * All implementations of this interface must be value-based;
- * 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.
- *
- * 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.
* 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.
*
* Such layout paths 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 free dimensions. 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
* which 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 additional {@code long}
+ * it follows that the var handle {@code valueHandle} will feature an additional {@code long}
* access coordinate.
*
* 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
* }
*
- * 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.
*
* 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.
*
- * 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:
*
* 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 dynamic values provided as {@code long}
* arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are static offset constants
- * and {@code s_0}, {@code s_1}, ... {@code s_n} are static stride constants which are derived from
+ * and {@code s_1}, {@code s_2}, ... {@code s_n} are static stride constants which are derived from
* the layout path.
*
* 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 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.
- * All implementations of this interface must be value-based;
- * programmers should treat instances that are {@linkplain Object#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.
- *
- * Non-platform classes should not implement {@linkplain MemorySegment} directly.
+ * Heap and buffer segments are always associated with a global, shared memory session. This session cannot be closed,
+ * and segments associated with it can be considered as always alive.
*
- * 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.
- * It is also possible to obtain a memory segment backed by an existing heap-allocated Java array,
- * using one of the provided factory methods (e.g. {@link MemorySegment#ofArray(int[])}). Memory segments obtained
- * in this way are called array memory segments.
- *
- * It is possible to obtain a memory segment backed by an existing Java byte buffer (see {@link ByteBuffer}),
- * using the factory method {@link MemorySegment#ofByteBuffer(ByteBuffer)}.
- * Memory segments obtained in this way are called buffer memory segments. Note that buffer memory segments might
- * be backed by native memory (as in the case of native memory segments) or heap memory (as in the case of array memory segments),
- * depending on the characteristics of the byte buffer instance the segment is associated with. For instance, a buffer memory
- * segment obtained from a byte buffer created with the {@link ByteBuffer#allocateDirect(int)} method will be backed
- * by native memory.
- *
- *
- * Contents of mapped memory segments can be {@linkplain #force() persisted} and {@linkplain #load() loaded} to and from the underlying file;
- * these capabilities are suitable replacements for some capabilities in the {@link java.nio.MappedByteBuffer} class.
- * Note that, while it is possible to map a segment into a byte buffer (see {@link MemorySegment#asByteBuffer()}),
- * and then call e.g. {@link java.nio.MappedByteBuffer#force()} that way, this can only be done when the source segment
- * is small enough, due to the size limitation inherent to the ByteBuffer API.
- *
- * Clients requiring sophisticated, low-level control over mapped memory segments, should consider writing
- * custom mapped memory segment factories; using {@link CLinker}, e.g. on Linux, it is possible to call {@code mmap}
- * with the desired parameters; the returned address can be easily wrapped into a memory segment, using
- * {@link MemoryAddress#ofLong(long)} and {@link MemorySegment#ofAddress(MemoryAddress, long, ResourceScope)}.
- *
- *
+ * A client might obtain a {@link Stream} from a segment, which can then be used to slice the segment (according to a given
+ * element layout) and even allow multiple threads to work in parallel on disjoint segment slices
+ * (to do this, the segment has to be associated with a shared memory session). The following code can be used to sum all int
+ * values in a memory segment in parallel:
+ *
+ * {@snippet lang=java :
+ * try (MemorySession session = MemorySession.openShared()) {
+ * SequenceLayout SEQUENCE_LAYOUT = MemoryLayout.sequenceLayout(1024, ValueLayout.JAVA_INT);
+ * MemorySegment segment = MemorySegment.allocateNative(SEQUENCE_LAYOUT, session);
+ * int sum = segment.elements(ValueLayout.JAVA_INT).parallel()
+ * .mapToInt(s -> s.get(ValueLayout.JAVA_INT, 0))
+ * .sum();
+ * }
+ * }
*
*
- * Heap and buffer segments are always associated with a global, shared scope. This scope cannot be closed,
- * and segments associated with it can be considered as always alive.
- *
- *
- * Temporal bounds of the original segment are inherited by the views; that is, when the scope associated with a segment
- * is closed, all the views associated with that segment will also be rendered inaccessible.
- *
- * To allow for interoperability with existing code, a byte buffer view can be obtained from a memory segment
- * (see {@link #asByteBuffer()}). This can be useful, for instance, for those clients that want to keep using the
- * {@link ByteBuffer} API, but need to operate on large memory segments. Byte buffers obtained in such a way support
- * the same spatial and temporal access restrictions associated with the memory segment from which they originated.
- *
- *
* The returned spliterator effectively allows to slice this segment into disjoint {@linkplain #asSlice(long, long) slices},
* which can then be processed in parallel by multiple threads.
@@ -298,9 +286,9 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory
Stream
* Equivalent to the following code:
* {@snippet lang=java :
@@ -332,7 +320,7 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory
* @see #asSlice(long, long)
*
* @param offset The new segment base offset (relative to the current segment base address), specified in bytes.
- * @return a new memory segment view with updated base/limit addresses.
+ * @return a slice of this memory segment.
* @throws IndexOutOfBoundsException if {@code offset < 0}, or {@code offset > byteSize()}.
*/
default MemorySegment asSlice(long offset) {
@@ -346,7 +334,7 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory
boolean isReadOnly();
/**
- * Obtains a read-only view of this segment. The resulting segment will be identical to this one, but
+ * Returns a read-only view of this segment. The resulting segment will be identical to this one, but
* attempts to overwrite the contents of the returned segment will cause runtime exceptions.
* @return a read-only view of this segment
* @see #isReadOnly()
@@ -355,8 +343,8 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory
/**
* Returns {@code true} if this segment is a native segment. A native memory segment is
- * created using the {@link #allocateNative(long, ResourceScope)} (and related) factory, or a buffer segment
- * derived from a direct {@link java.nio.ByteBuffer} using the {@link #ofByteBuffer(ByteBuffer)} factory,
+ * created using the {@link #allocateNative(long, MemorySession)} (and related) factory, or a buffer segment
+ * derived from a {@linkplain ByteBuffer#allocateDirect(int) direct byte buffer} using the {@link #ofByteBuffer(ByteBuffer)} factory,
* or if this is a {@linkplain #isMapped() mapped} segment.
* @return {@code true} if this segment is native segment.
*/
@@ -364,7 +352,7 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory
/**
* Returns {@code true} if this segment is a mapped segment. A mapped memory segment is
- * created using the {@link #mapFile(Path, long, long, FileChannel.MapMode, ResourceScope)} factory, or a buffer segment
+ * created using the {@link FileChannel#map(FileChannel.MapMode, long, long, MemorySession)} factory, or a buffer segment
* derived from a {@link java.nio.MappedByteBuffer} using the {@link #ofByteBuffer(ByteBuffer)} factory.
* @return {@code true} if this segment is a mapped segment.
*/
@@ -377,13 +365,13 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory
* Two segments {@code S1} and {@code S2} are said to overlap if it is possible to find
* at least two slices {@code L1} (from {@code S1}) and {@code L2} (from {@code S2}) that are backed by the
* same memory region. As such, it is not possible for a
- * {@link #isNative() native} segment to overlap with a heap segment; in
+ * {@linkplain #isNative() native} segment to overlap with a heap segment; in
* this case, or when no overlap occurs, {@code null} is returned.
*
* @param other the segment to test for an overlap with this segment.
- * @return a slice of this segment, or {@code null} if no overlap occurs.
+ * @return a slice of this segment (where overlapping occurs).
*/
- MemorySegment asOverlappingSlice(MemorySegment other);
+ Optional
+ *
+ *
+ * @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();
+}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/Addressable.java b/src/java.base/share/classes/java/lang/foreign/Addressable.java
similarity index 63%
rename from src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/Addressable.java
rename to src/java.base/share/classes/java/lang/foreign/Addressable.java
index 17d417bee51..c1b8f5fc29d 100644
--- a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/Addressable.java
+++ b/src/java.base/share/classes/java/lang/foreign/Addressable.java
@@ -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 addressable. 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}.
*
- *
*
* @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
+ *
+ * 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}.
+ * Downcall method handles
+ *
+ * {@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.
+ *
+ *
+ *
+ *
+ *
+ *
+ * Upcall stubs
+ *
+ * {@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.
+ *
+ *
+ * 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}.
+ *
+ *
+ *
Safety considerations
+ *
+ * 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}):
+ *
+ *
+ *
+ *
+ *
*
* A memory address is backed by a raw machine pointer, expressed as a {@linkplain #toRawLongValue() long value}.
*
- * Dereference
+ * Dereferencing memory addresses
*
* 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 restricted: 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.
- * Size, alignment and byte order
*
@@ -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:
*
- *
* @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.
+ * Layout attributes
- *
- * Layouts can be optionally associated with a name. A layout name can be referred to when
- * constructing layout paths.
- *
* @implSpec
* Implementations of this interface are immutable, thread-safe and value-based.
+ *
+ * @since 19
*/
-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)})
- * always have a specified size, therefore this method always returns {@code true} in these cases.
- *
- * @return {@code true}, if this layout has a specified size.
- */
- 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 name (if any) associated with this layout}
+ * {@return the name (if any) associated with this layout}
* @see MemoryLayout#withName(String)
*/
Optional{@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 dynamic values provided as {@code long}
* arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are static offset constants
- * and {@code s_0}, {@code s_1}, ... {@code s_n} are static stride constants which are derived from
+ * and {@code s_1}, {@code s_2}, ... {@code s_n} are static 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 access mode restrictions, which are common to all memory access var handles.
+ * features certain access mode restrictions, 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.
*
*
+ *
* 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
* {@code
* E * (S + I * F)
* }
+ *
+ * @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) {
- AbstractLayout.checkSize(elementCount, true);
- OptionalLong size = OptionalLong.of(elementCount);
- return new SequenceLayout(size, Objects.requireNonNull(elementLayout));
+ if (elementCount == -1) {
+ // inferred element count
+ long inferredElementCount = Long.MAX_VALUE / elementLayout.bitSize();
+ return new SequenceLayout(inferredElementCount, elementLayout);
+ } else {
+ // explicit element count
+ AbstractLayout.checkSize(elementCount, true);
+ return wrapOverflow(() ->
+ new SequenceLayout(elementCount, Objects.requireNonNull(elementLayout)));
+ }
}
/**
- * 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 struct group layout with given member layouts.
- *
- * @param elements The member layouts of the struct group layout.
- * @return a new struct 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,
- Stream.of(elements)
- .map(Objects::requireNonNull)
- .collect(Collectors.toList()));
+ return wrapOverflow(() ->
+ new GroupLayout(GroupLayout.Kind.STRUCT,
+ Stream.of(elements)
+ .map(Objects::requireNonNull)
+ .collect(Collectors.toList())));
}
/**
- * Create a new union group layout with given member layouts.
+ * Creates a union layout with the given member layouts.
*
- * @param elements The member layouts of the union layout.
- * @return a new union 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 {@code
+ * inferredElementCount = Long.MAX_VALUE / elementLayout.bitSize();
+ * }
+ *
+ *
+ * Lifecycle and confinement
+ *
+ * Memory segments are associated with a {@linkplain MemorySegment#session() memory session}. As for all resources associated
+ * with a memory session, a segment cannot be accessed after its underlying session has been closed. For instance,
+ * the following code will result in an exception:
+ * {@snippet lang=java :
+ * MemorySegment segment = null;
+ * try (MemorySession session = MemorySession.openConfined()) {
+ * segment = MemorySegment.allocateNative(8, session);
+ * }
+ * segment.get(ValueLayout.JAVA_LONG, 0); // already closed!
+ * }
+ * Additionally, access to a memory segment is subject to the thread-confinement checks enforced by the owning memory
+ * session; that is, if the segment is associated with a shared session, it can be accessed by multiple threads;
+ * if it is associated with a confined session, it can only be accessed by the thread which owns the memory session.
* Constructing memory segments
- *
- * There are multiple ways to obtain a memory segment. First, memory segments backed by off-heap memory can
- * be allocated using one of the many factory methods provided (see {@link MemorySegment#allocateNative(MemoryLayout, ResourceScope)},
- * {@link MemorySegment#allocateNative(long, ResourceScope)} and {@link MemorySegment#allocateNative(long, long, ResourceScope)}). Memory segments obtained
- * in this way are called native memory segments.
- * Mapping memory segments from files
- *
- * It is also possible to obtain a native memory segment backed by a memory-mapped file using the factory method
- * {@link MemorySegment#mapFile(Path, long, long, FileChannel.MapMode, ResourceScope)}. Such native memory segments are
- * called mapped memory segments; mapped memory segments are associated with an underlying file descriptor.
- * Restricted native segments
- *
- * Sometimes it is necessary to turn a memory address obtained from native code into a memory segment with
- * full spatial, temporal and confinement bounds. To do this, clients can {@link #ofAddress(MemoryAddress, long, ResourceScope) obtain}
- * a native segment unsafely from a give memory address, by providing the segment size, as well as the segment {@linkplain ResourceScope scope}.
- * This is a restricted operation and should be used with
- * caution: for instance, an incorrect segment size could result in a VM crash when attempting to dereference
- * the memory segment.
- *
- * Dereference
+ * Dereferencing memory segments
*
* A memory segment 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 :
* MemorySegment segment = ...
* int value = segment.get(ValueLayout.JAVA_INT, 0);
* }
*
- * If the value to be read is stored in memory using {@link ByteOrder#BIG_ENDIAN big-endian} encoding, the dereference operation
+ * If the value to be read is stored in memory using {@linkplain ByteOrder#BIG_ENDIAN big-endian} encoding, the dereference operation
* can be expressed as follows:
* {@snippet lang=java :
* MemorySegment segment = ...
* int value = segment.get(ValueLayout.JAVA_INT.withOrder(BIG_ENDIAN), 0);
* }
*
- * For more complex dereference operations (e.g. structured memory access), clients can obtain a memory access var handle,
- * that is, a var handle that accepts a segment and, optionally, one or more additional {@code long} coordinates. Memory
- * access var handles can be obtained from {@linkplain MemoryLayout#varHandle(MemoryLayout.PathElement...) memory layouts}
- * by providing a so called layout path.
- * Alternatively, clients can obtain raw memory access var handles from a given
- * {@linkplain MemoryHandles#varHandle(ValueLayout) value layout}, and then adapt it using the var handle combinator
- * functions defined in the {@link MemoryHandles} class.
+ * For more complex dereference operations (e.g. structured memory access), clients can obtain a
+ * {@linkplain MethodHandles#memorySegmentViewVarHandle(ValueLayout) memory segment view var handle},
+ * that is, a var handle that accepts a segment and a {@code long} offset. More complex access var handles
+ * can be obtained by adapting a segment var handle view using the var handle combinator functions defined in the
+ * {@link java.lang.invoke.MethodHandles} class:
+ *
+ * {@snippet lang=java :
+ * MemorySegment segment = ...
+ * VarHandle intHandle = MethodHandles.memorySegmentViewVarHandle(ValueLayout.JAVA_INT);
+ * MethodHandle multiplyExact = MethodHandles.lookup()
+ * .findStatic(Math.class, "multiplyExact",
+ * MethodType.methodType(long.class, long.class, long.class));
+ * intHandle = MethodHandles.filterCoordinates(intHandle, 1,
+ * MethodHandles.insertArguments(multiplyExact, 0, 4L));
+ * intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
+ * }
+ *
+ * Alternatively, complex access var handles can can be obtained
+ * from {@linkplain MemoryLayout#varHandle(MemoryLayout.PathElement...) memory layouts}
+ * by providing a so called layout path:
+ *
+ * {@snippet lang=java :
+ * MemorySegment segment = ...
+ * VarHandle intHandle = ValueLayout.JAVA_INT.arrayElementVarHandle();
+ * intHandle.get(segment, 3L); // get int element at offset 3 * 4 = 12
+ * }
+ *
+ * Slicing memory segments
+ *
+ * Memory segments support slicing. A memory segment can be used to {@linkplain MemorySegment#asSlice(long, long) obtain}
+ * other segments backed by the same underlying memory region, but with stricter spatial bounds than the ones
+ * of the original segment:
+ * {@snippet lang=java :
+ * MemorySession session = ...
+ * MemorySegment segment = MemorySegment.allocateNative(100, session);
+ * MemorySegment slice = segment.asSlice(50, 10);
+ * slice.get(ValueLayout.JAVA_INT, 20); // Out of bounds!
+ * session.close();
+ * slice.get(ValueLayout.JAVA_INT, 0); // Already closed!
+ * }
+ * The above code creates a native segment that is 100 bytes long; then, it creates a slice that starts at offset 50
+ * of {@code segment}, and is 10 bytes long. As a result, attempting to read an int value at offset 20 of the
+ * {@code slice} segment will result in an exception. The {@linkplain MemorySession temporal bounds} of the original segment
+ * are inherited by its slices; that is, when the memory session associated with {@code segment} is closed, {@code slice}
+ * will also be become inaccessible.
+ * Alignment
*
@@ -146,11 +173,11 @@ import java.util.stream.Stream;
* dereferenced is a native segment, then it has a concrete {@linkplain #address() base address}, which can
* be used to perform the alignment check. The pseudo-function below demonstrates this:
*
- *
+ * {@snippet lang=java :
+ * boolean isAligned(MemorySegment segment, long offset, MemoryLayout layout) {
+ * return ((segment.address().toRawLongValue() + offset) % layout.byteAlignment()) == 0
+ * }
+ * }
*
* If, however, the segment being dereferenced is a heap segment, the above function will not work: a heap
* segment's base address is virtualized and, as such, cannot be used to construct an alignment check. Instead,
@@ -189,71 +216,32 @@ boolean isAligned(MemorySegment segment, long offset, MemoryLayout layout) {
* constructed from a {@code byte[]} might have a subset of addresses {@code S} which happen to be 8-byte aligned. But determining
* which segment addresses belong to {@code S} requires reasoning about details which are ultimately implementation-dependent.
*
- * {@code
-boolean isAligned(MemorySegment segment, long offset, MemoryLayout layout) {
- return ((segment.address().toRawLongValue() + offset) % layout.byteAlignment()) == 0
-}
- * }Lifecycle and confinement
- *
- * Memory segments are associated with a resource scope (see {@link ResourceScope}), which can be accessed using
- * the {@link #scope()} method. As for all resources associated with a resource scope, a segment cannot be
- * accessed after its corresponding scope has been closed. For instance, the following code will result in an
- * exception:
- * {@snippet lang=java :
- * MemorySegment segment = null;
- * try (ResourceScope scope = ResourceScope.newConfinedScope()) {
- * segment = MemorySegment.allocateNative(8, scope);
- * }
- * segment.get(ValueLayout.JAVA_LONG, 0); // already closed!
- * }
- * Additionally, access to a memory segment is subject to the thread-confinement checks enforced by the owning scope; that is,
- * if the segment is associated with a shared scope, it can be accessed by multiple threads; if it is associated with a confined
- * scope, it can only be accessed by the thread which owns the scope.
+ * Restricted memory segments
+ * Sometimes it is necessary to turn a memory address obtained from native code into a memory segment with
+ * full spatial, temporal and confinement bounds. To do this, clients can {@linkplain #ofAddress(MemoryAddress, long, MemorySession) obtain}
+ * a native segment unsafely from a give memory address, by providing the segment size, as well as the segment {@linkplain MemorySession session}.
+ * This is a restricted operation and should be used with
+ * caution: for instance, an incorrect segment size could result in a VM crash when attempting to dereference
+ * the memory segment.
* Memory segment views
- *
- * Memory segments support views. For instance, it is possible to create an immutable view of a memory segment, as follows:
- * {@snippet lang=java :
- * MemorySegment segment = ...
- * MemorySegment roSegment = segment.asReadOnly();
- * }
- * It is also possible to create views whose spatial bounds are stricter than the ones of the original segment
- * (see {@link MemorySegment#asSlice(long, long)}).
- * Stream support
- *
- * A client might obtain a {@link Stream} from a segment, which can then be used to slice the segment (according to a given
- * element layout) and even allow multiple threads to work in parallel on disjoint segment slices
- * (to do this, the segment has to be associated with a shared scope). The following code can be used to sum all int
- * values in a memory segment in parallel:
- *
- * {@snippet lang=java :
- * try (ResourceScope scope = ResourceScope.newSharedScope()) {
- * SequenceLayout SEQUENCE_LAYOUT = MemoryLayout.sequenceLayout(1024, ValueLayout.JAVA_INT);
- * MemorySegment segment = MemorySegment.allocateNative(SEQUENCE_LAYOUT, scope);
- * int sum = segment.elements(ValueLayout.JAVA_INT).parallel()
- * .mapToInt(s -> s.get(ValueLayout.JAVA_INT, 0))
- * .sum();
- * }
- * }
+ * Clients requiring sophisticated, low-level control over mapped memory segments, might consider writing
+ * custom mapped memory segment factories; using {@link Linker}, e.g. on Linux, it is possible to call {@code mmap}
+ * with the desired parameters; the returned address can be easily wrapped into a memory segment, using
+ * {@link MemoryAddress#ofLong(long)} and {@link MemorySegment#ofAddress(MemoryAddress, long, MemorySession)}.
*
* @implSpec
* Implementations of this interface are immutable, thread-safe and value-based.
+ *
+ * @since 19
*/
+@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public sealed interface MemorySegment extends Addressable permits AbstractMemorySegmentImpl {
/**
* {@return the base memory address associated with this native memory segment}
* @throws UnsupportedOperationException if this segment is not a {@linkplain #isNative() native} segment.
- * @throws IllegalStateException if the scope associated with this segment 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 segment is not
+ * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session.
*/
@Override
MemoryAddress address();
@@ -267,7 +255,7 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory
* if the supplied layout has size N, then calling {@link Spliterator#trySplit()} will result in a spliterator serving
* approximately {@code S/N} elements (depending on whether N is even or not), where {@code S} is the size of
* this segment. As such, splitting is possible as long as {@code S/N >= 2}. The spliterator returns segments that
- * are associated with the same scope as this segment.
+ * are associated with the same memory session as this segment.
*
* The life-cycle of the returned buffer will be tied to that of this segment. That is, accessing the returned buffer - * after the scope associated with this segment has been closed (see {@link ResourceScope#close()}), will throw an {@link IllegalStateException}. + * after the memory session associated with this segment has been closed (see {@link MemorySession#close()}), will throw an {@link IllegalStateException}. *
- * If this segment is associated with a confined scope, calling read/write I/O operations on the resulting buffer + * If this segment is associated with a confined memory session, calling read/write I/O operations on the resulting buffer * might result in an unspecified exception being thrown. Examples of such problematic operations are * {@link java.nio.channels.AsynchronousSocketChannel#read(ByteBuffer)} and * {@link java.nio.channels.AsynchronousSocketChannel#write(ByteBuffer)}. @@ -593,84 +583,91 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory ByteBuffer asByteBuffer(); /** - * Copy the contents of this memory segment into a fresh byte array. + * Copy the contents of this memory segment into a new byte array. * @param elementLayout the source element layout. If the byte order associated with the layout is - * different from the native order, a byte swap operation will be performed on each array element. - * @return a fresh byte array copy of this memory segment. - * @throws IllegalStateException if the scope associated with this segment has been closed, or if access occurs from - * a thread other than the thread owning that scope, or if this segment's contents cannot be copied into a {@link byte[]} instance, + * different from the {@linkplain ByteOrder#nativeOrder native order}, a byte swap operation will be performed on each array element. + * @return a new byte array whose contents are copied from this memory segment. + * @throws IllegalStateException if the {@linkplain #session() session} associated with this segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. + * @throws IllegalStateException if this segment's contents cannot be copied into a {@code byte[]} instance, * e.g. its size is greater than {@link Integer#MAX_VALUE}. */ byte[] toArray(ValueLayout.OfByte elementLayout); /** - * Copy the contents of this memory segment into a fresh short array. + * Copy the contents of this memory segment into a new short array. * @param elementLayout the source element layout. If the byte order associated with the layout is - * different from the native order, a byte swap operation will be performed on each array element. - * @return a fresh short array copy of this memory segment. - * @throws IllegalStateException if the scope associated with this segment has been closed, or if access occurs from - * a thread other than the thread owning that scope, or if this segment's contents cannot be copied into a {@link short[]} instance, + * different from the {@linkplain ByteOrder#nativeOrder native order}, a byte swap operation will be performed on each array element. + * @return a new short array whose contents are copied from this memory segment. + * @throws IllegalStateException if the {@linkplain #session() session} associated with this segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. + * @throws IllegalStateException if this segment's contents cannot be copied into a {@code short[]} instance, * e.g. because {@code byteSize() % 2 != 0}, or {@code byteSize() / 2 > Integer#MAX_VALUE} */ short[] toArray(ValueLayout.OfShort elementLayout); /** - * Copy the contents of this memory segment into a fresh char array. + * Copy the contents of this memory segment into a new char array. * @param elementLayout the source element layout. If the byte order associated with the layout is - * different from the native order, a byte swap operation will be performed on each array element. - * @return a fresh char array copy of this memory segment. - * @throws IllegalStateException if the scope associated with this segment has been closed, or if access occurs from - * a thread other than the thread owning that scope, or if this segment's contents cannot be copied into a {@link char[]} instance, + * different from the {@linkplain ByteOrder#nativeOrder native order}, a byte swap operation will be performed on each array element. + * @return a new char array whose contents are copied from this memory segment. + * @throws IllegalStateException if the {@linkplain #session() session} associated with this segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. + * @throws IllegalStateException if this segment's contents cannot be copied into a {@code char[]} instance, * e.g. because {@code byteSize() % 2 != 0}, or {@code byteSize() / 2 > Integer#MAX_VALUE}. */ char[] toArray(ValueLayout.OfChar elementLayout); /** - * Copy the contents of this memory segment into a fresh int array. + * Copy the contents of this memory segment into a new int array. * @param elementLayout the source element layout. If the byte order associated with the layout is - * different from the native order, a byte swap operation will be performed on each array element. - * @return a fresh int array copy of this memory segment. - * @throws IllegalStateException if the scope associated with this segment has been closed, or if access occurs from - * a thread other than the thread owning that scope, or if this segment's contents cannot be copied into a {@link int[]} instance, + * different from the {@linkplain ByteOrder#nativeOrder native order}, a byte swap operation will be performed on each array element. + * @return a new int array whose contents are copied from this memory segment. + * @throws IllegalStateException if the {@linkplain #session() session} associated with this segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. + * @throws IllegalStateException if this segment's contents cannot be copied into a {@code int[]} instance, * e.g. because {@code byteSize() % 4 != 0}, or {@code byteSize() / 4 > Integer#MAX_VALUE}. */ int[] toArray(ValueLayout.OfInt elementLayout); /** - * Copy the contents of this memory segment into a fresh float array. + * Copy the contents of this memory segment into a new float array. * @param elementLayout the source element layout. If the byte order associated with the layout is - * different from the native order, a byte swap operation will be performed on each array element. - * @return a fresh float array copy of this memory segment. - * @throws IllegalStateException if the scope associated with this segment has been closed, or if access occurs from - * a thread other than the thread owning that scope, or if this segment's contents cannot be copied into a {@link float[]} instance, + * different from the {@linkplain ByteOrder#nativeOrder native order}, a byte swap operation will be performed on each array element. + * @return a new float array whose contents are copied from this memory segment. + * @throws IllegalStateException if the {@linkplain #session() session} associated with this segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. + * @throws IllegalStateException if this segment's contents cannot be copied into a {@code float[]} instance, * e.g. because {@code byteSize() % 4 != 0}, or {@code byteSize() / 4 > Integer#MAX_VALUE}. */ float[] toArray(ValueLayout.OfFloat elementLayout); /** - * Copy the contents of this memory segment into a fresh long array. + * Copy the contents of this memory segment into a new long array. * @param elementLayout the source element layout. If the byte order associated with the layout is - * different from the native order, a byte swap operation will be performed on each array element. - * @return a fresh long array copy of this memory segment. - * @throws IllegalStateException if the scope associated with this segment has been closed, or if access occurs from - * a thread other than the thread owning that scope, or if this segment's contents cannot be copied into a {@link long[]} instance, + * different from the {@linkplain ByteOrder#nativeOrder native order}, a byte swap operation will be performed on each array element. + * @return a new long array whose contents are copied from this memory segment. + * @throws IllegalStateException if the {@linkplain #session() session} associated with this segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. + * @throws IllegalStateException if this segment's contents cannot be copied into a {@code long[]} instance, * e.g. because {@code byteSize() % 8 != 0}, or {@code byteSize() / 8 > Integer#MAX_VALUE}. */ long[] toArray(ValueLayout.OfLong elementLayout); /** - * Copy the contents of this memory segment into a fresh double array. + * Copy the contents of this memory segment into a new double array. * @param elementLayout the source element layout. If the byte order associated with the layout is - * different from the native order, a byte swap operation will be performed on each array element. - * @return a fresh double array copy of this memory segment. - * @throws IllegalStateException if the scope associated with this segment has been closed, or if access occurs from - * a thread other than the thread owning that scope, or if this segment's contents cannot be copied into a {@link double[]} instance, + * different from the {@linkplain ByteOrder#nativeOrder native order}, a byte swap operation will be performed on each array element. + * @return a new double array whose contents are copied from this memory segment. + * @throws IllegalStateException if the {@linkplain #session() session} associated with this segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. + * @throws IllegalStateException if this segment's contents cannot be copied into a {@code double[]} instance, * e.g. because {@code byteSize() % 8 != 0}, or {@code byteSize() / 8 > Integer#MAX_VALUE}. */ double[] toArray(ValueLayout.OfDouble elementLayout); /** - * Reads a UTF-8 encoded, null-terminated string from this segment at given offset. + * Reads a UTF-8 encoded, null-terminated string from this segment at the given offset. *
* This method always replaces malformed-input and unmappable-character * sequences with this charset's default replacement string. The {@link @@ -680,16 +677,18 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory * the final address of this read operation can be expressed as {@code address().toRowLongValue() + offset}. * @return a Java string constructed from the bytes read from the given starting address up to (but not including) * the first {@code '\0'} terminator character (assuming one is found). - * @throws IllegalArgumentException if the size of the native string is greater than the largest string supported by the platform. - * @throws IllegalStateException if the size of the native string is greater than the size of this segment, - * or if the scope associated with this segment has been closed, or if access occurs from a thread other than the thread owning that scope. + * @throws IllegalArgumentException if the size of the UTF-8 string is greater than the largest string supported by the platform. + * @throws IndexOutOfBoundsException if {@code S + offset > byteSize()}, where {@code S} is the size of the UTF-8 + * string (including the terminator character). + * @throws IllegalStateException if the {@linkplain #session() session} associated with this segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. */ default String getUtf8String(long offset) { return SharedUtils.toJavaStringInternal(this, offset); } /** - * Writes the given string into this segment at given offset, converting it to a null-terminated byte sequence using UTF-8 encoding. + * Writes the given string into this segment at the given offset, converting it to a null-terminated byte sequence using UTF-8 encoding. *
* This method always replaces malformed-input and unmappable-character * sequences with this charset's default replacement string. The {@link @@ -698,10 +697,9 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + offset}. * @param str the Java string to be written into this segment. - * @throws IllegalArgumentException if the size of the native string is greater than the largest string supported by the platform. - * @throws IllegalStateException if the size of the native string is greater than the size of this segment, - * or if the scope associated with this segment has been closed, or if access occurs from a thread other than the thread owning that scope. - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. + * @throws IndexOutOfBoundsException if {@code str.getBytes().length() + offset >= byteSize()}. + * @throws IllegalStateException if the {@linkplain #session() session} associated with this segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. */ default void setUtf8String(long offset, String str) { Utils.toCString(str.getBytes(StandardCharsets.UTF_8), SegmentAllocator.prefixAllocator(asSlice(offset))); @@ -709,96 +707,96 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory /** - * Creates a new buffer memory segment that models the memory associated with the given byte + * Creates a buffer memory segment that models the memory associated with the given byte * buffer. The segment starts relative to the buffer's position (inclusive) * and ends relative to the buffer's limit (exclusive). *
- * If the buffer is {@link ByteBuffer#isReadOnly() read-only}, the resulting segment will also be - * {@link ByteBuffer#isReadOnly() read-only}. The scope associated with this segment can either be the - * {@linkplain ResourceScope#globalScope() global} resource scope, in case the buffer has been created independently, - * or some other resource scope, in case the buffer has been obtained using {@link #asByteBuffer()}. + * If the buffer is {@linkplain ByteBuffer#isReadOnly() read-only}, the resulting segment will also be + * {@linkplain ByteBuffer#isReadOnly() read-only}. The memory session associated with this segment can either be the + * {@linkplain MemorySession#global() global} memory session, in case the buffer has been created independently, + * or some other memory session, in case the buffer has been obtained using {@link #asByteBuffer()}. *
* The resulting memory segment keeps a reference to the backing buffer, keeping it reachable. * * @param bb the byte buffer backing the buffer memory segment. - * @return a new buffer memory segment. + * @return a buffer memory segment. */ static MemorySegment ofByteBuffer(ByteBuffer bb) { return AbstractMemorySegmentImpl.ofBuffer(bb); } /** - * Creates a new array memory segment that models the memory associated with a given heap-allocated byte array. - * The returned segment is associated with the {@linkplain ResourceScope#globalScope() global} resource scope. + * Creates an array memory segment that models the memory associated with the given heap-allocated byte array. + * The returned segment is associated with the {@linkplain MemorySession#global() global} memory session. * * @param arr the primitive array backing the array memory segment. - * @return a new array memory segment. + * @return an array memory segment. */ static MemorySegment ofArray(byte[] arr) { return HeapMemorySegmentImpl.OfByte.fromArray(arr); } /** - * Creates a new array memory segment that models the memory associated with a given heap-allocated char array. - * The returned segment is associated with the {@linkplain ResourceScope#globalScope() global} resource scope. + * Creates an array memory segment that models the memory associated with the given heap-allocated char array. + * The returned segment is associated with the {@linkplain MemorySession#global() global} memory session. * * @param arr the primitive array backing the array memory segment. - * @return a new array memory segment. + * @return an array memory segment. */ static MemorySegment ofArray(char[] arr) { return HeapMemorySegmentImpl.OfChar.fromArray(arr); } /** - * Creates a new array memory segment that models the memory associated with a given heap-allocated short array. - * The returned segment is associated with the {@linkplain ResourceScope#globalScope() global} resource scope. + * Creates an array memory segment that models the memory associated with the given heap-allocated short array. + * The returned segment is associated with the {@linkplain MemorySession#global() global} memory session. * * @param arr the primitive array backing the array memory segment. - * @return a new array memory segment. + * @return an array memory segment. */ static MemorySegment ofArray(short[] arr) { return HeapMemorySegmentImpl.OfShort.fromArray(arr); } /** - * Creates a new array memory segment that models the memory associated with a given heap-allocated int array. - * The returned segment is associated with the {@linkplain ResourceScope#globalScope() global} resource scope. + * Creates an array memory segment that models the memory associated with the given heap-allocated int array. + * The returned segment is associated with the {@linkplain MemorySession#global() global} memory session. * * @param arr the primitive array backing the array memory segment. - * @return a new array memory segment. + * @return an array memory segment. */ static MemorySegment ofArray(int[] arr) { return HeapMemorySegmentImpl.OfInt.fromArray(arr); } /** - * Creates a new array memory segment that models the memory associated with a given heap-allocated float array. - * The returned segment is associated with the {@linkplain ResourceScope#globalScope() global} resource scope. + * Creates an array memory segment that models the memory associated with the given heap-allocated float array. + * The returned segment is associated with the {@linkplain MemorySession#global() global} memory session. * * @param arr the primitive array backing the array memory segment. - * @return a new array memory segment. + * @return an array memory segment. */ static MemorySegment ofArray(float[] arr) { return HeapMemorySegmentImpl.OfFloat.fromArray(arr); } /** - * Creates a new array memory segment that models the memory associated with a given heap-allocated long array. - * The returned segment is associated with the {@linkplain ResourceScope#globalScope() global} resource scope. + * Creates an array memory segment that models the memory associated with the given heap-allocated long array. + * The returned segment is associated with the {@linkplain MemorySession#global() global} memory session. * * @param arr the primitive array backing the array memory segment. - * @return a new array memory segment. + * @return an array memory segment. */ static MemorySegment ofArray(long[] arr) { return HeapMemorySegmentImpl.OfLong.fromArray(arr); } /** - * Creates a new array memory segment that models the memory associated with a given heap-allocated double array. - * The returned segment is associated with the {@linkplain ResourceScope#globalScope() global} resource scope. + * Creates an array memory segment that models the memory associated with the given heap-allocated double array. + * The returned segment is associated with the {@linkplain MemorySession#global() global} memory session. * * @param arr the primitive array backing the array memory segment. - * @return a new array memory segment. + * @return an array memory segment. */ static MemorySegment ofArray(double[] arr) { return HeapMemorySegmentImpl.OfDouble.fromArray(arr); @@ -806,12 +804,13 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory /** - * Creates a new native memory segment with given size and resource scope, and whose base address is the given address. - * This method can be useful when interacting with custom - * native memory sources (e.g. custom allocators), where an address to some - * underlying memory region is typically obtained from native code (often as a plain {@code long} value). + * Creates a native memory segment with the given size, base address, and memory session. + * This method can be useful when interacting with custom memory sources (e.g. custom allocators), + * where an address to some underlying memory region is typically obtained from foreign code + * (often as a plain {@code long} value). + *
* The returned segment is not read-only (see {@link MemorySegment#isReadOnly()}), and is associated with the - * provided resource scope. + * provided memory session. *
* Clients should ensure that the address and bounds refer to a valid region of memory that is accessible for reading and, * if appropriate, writing; an attempt to access an invalid memory location from Java code will either return an arbitrary value, @@ -825,94 +824,92 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory * * @param address the returned segment's base address. * @param bytesSize the desired size. - * @param scope the native segment scope. - * @return a new native memory segment with given base address, size and scope. - * @throws IllegalArgumentException if {@code bytesSize <= 0}. - * @throws IllegalStateException if the provided scope has been already closed, - * or if access occurs from a thread other than the thread owning the scope. + * @param session the native segment memory session. + * @return a native memory segment with the given base address, size and memory session. + * @throws IllegalArgumentException if {@code bytesSize < 0}. + * @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from + * a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}. * @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 MemorySegment ofAddress(MemoryAddress address, long bytesSize, ResourceScope scope) { - Reflection.ensureNativeAccess(Reflection.getCallerClass()); + static MemorySegment ofAddress(MemoryAddress address, long bytesSize, MemorySession session) { + Reflection.ensureNativeAccess(Reflection.getCallerClass(), MemorySegment.class, "ofAddress"); Objects.requireNonNull(address); - Objects.requireNonNull(scope); - if (bytesSize <= 0) { + Objects.requireNonNull(session); + if (bytesSize < 0) { throw new IllegalArgumentException("Invalid size : " + bytesSize); } - return NativeMemorySegmentImpl.makeNativeSegmentUnchecked(address, bytesSize, (ResourceScopeImpl)scope); + return NativeMemorySegmentImpl.makeNativeSegmentUnchecked(address, bytesSize, session); } /** - * Creates a new native memory segment that models a newly allocated block of off-heap memory with given layout - * and resource scope. A client is responsible make sure that the resource scope associated with the returned segment is closed + * Creates a native memory segment with the given layout and memory session. + * A client is responsible for ensuring that the memory session associated with the returned segment is closed * when the segment is no longer in use. Failure to do so will result in off-heap memory leaks. *
* This is equivalent to the following code: * {@snippet lang=java : - * allocateNative(layout.bytesSize(), layout.bytesAlignment(), scope); + * allocateNative(layout.bytesSize(), layout.bytesAlignment(), session); * } *
* The block of off-heap memory associated with the returned native memory segment is initialized to zero. * * @param layout the layout of the off-heap memory block backing the native memory segment. - * @param scope the segment scope. + * @param session the segment memory session. * @return a new native memory segment. - * @throws IllegalArgumentException if the specified layout has illegal size or alignment constraint. - * @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 MemorySegment allocateNative(MemoryLayout layout, ResourceScope scope) { - Objects.requireNonNull(scope); + static MemorySegment allocateNative(MemoryLayout layout, MemorySession session) { + Objects.requireNonNull(session); Objects.requireNonNull(layout); - return allocateNative(layout.byteSize(), layout.byteAlignment(), scope); + return allocateNative(layout.byteSize(), layout.byteAlignment(), session); } /** - * Creates a new native memory segment that models a newly allocated block of off-heap memory with given size (in bytes) - * and resource scope. A client is responsible make sure that the resource scope associated with the returned segment is closed + * Creates a native memory segment with the given size (in bytes) and memory session. + * A client is responsible for ensuring that the memory session associated with the returned segment is closed * when the segment is no longer in use. Failure to do so will result in off-heap memory leaks. *
* This is equivalent to the following code: * {@snippet lang=java : - * allocateNative(bytesSize, 1, scope); + * allocateNative(bytesSize, 1, session); * } *
* The block of off-heap memory associated with the returned native memory segment is initialized to zero. * * @param bytesSize the size (in bytes) of the off-heap memory block backing the native memory segment. - * @param scope the segment scope. + * @param session the segment temporal bounds. * @return a new native memory segment. - * @throws IllegalArgumentException if {@code bytesSize <= 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 IllegalArgumentException if {@code bytesSize < 0}. + * @throws IllegalStateException if {@code session} is not {@linkplain MemorySession#isAlive() alive}, or if access occurs from + * a thread other than the thread {@linkplain MemorySession#ownerThread() owning} {@code session}. */ - static MemorySegment allocateNative(long bytesSize, ResourceScope scope) { - return allocateNative(bytesSize, 1, scope); + static MemorySegment allocateNative(long bytesSize, MemorySession session) { + return allocateNative(bytesSize, 1, session); } /** - * Creates a new native memory segment that models a newly allocated block of off-heap memory with given size - * (in bytes), alignment constraint (in bytes) and resource scope. A client is responsible make sure that the resource - * scope associated with the returned segment is closed when the segment is no longer in use. - * Failure to do so will result in off-heap memory leaks. + * Creates a native memory segment with the given size (in bytes), alignment constraint (in bytes) and memory session. + * A client is responsible for ensuring that the memory session associated with the returned segment is closed when the + * segment is no longer in use. Failure to do so will result in off-heap memory leaks. *
* The block of off-heap memory associated with the returned native memory segment is initialized to zero. * * @param bytesSize the size (in bytes) of the off-heap memory block backing the native memory segment. * @param alignmentBytes the alignment constraint (in bytes) of the off-heap memory block backing the native memory segment. - * @param scope the segment scope. + * @param session the segment memory session. * @return a new native memory segment. - * @throws IllegalArgumentException if {@code bytesSize <= 0}, {@code alignmentBytes <= 0}, or if {@code alignmentBytes} + * @throws IllegalArgumentException if {@code bytesSize < 0}, {@code alignmentBytes <= 0}, or if {@code alignmentBytes} * is not a power of 2. - * @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 MemorySegment allocateNative(long bytesSize, long alignmentBytes, ResourceScope scope) { - Objects.requireNonNull(scope); - if (bytesSize <= 0) { + static MemorySegment allocateNative(long bytesSize, long alignmentBytes, MemorySession session) { + Objects.requireNonNull(session); + if (bytesSize < 0) { throw new IllegalArgumentException("Invalid allocation size : " + bytesSize); } @@ -921,53 +918,7 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory throw new IllegalArgumentException("Invalid alignment constraint : " + alignmentBytes); } - return NativeMemorySegmentImpl.makeNativeSegment(bytesSize, alignmentBytes, (ResourceScopeImpl) scope); - } - - /** - * Creates a new mapped memory segment that models a memory-mapped region of a file from a given path. - *
- * If the specified mapping mode is {@linkplain FileChannel.MapMode#READ_ONLY READ_ONLY}, the resulting segment - * will be read-only (see {@link #isReadOnly()}). - *
- * 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. - *
- * 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, 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 path the path to the file to memory map. - * @param bytesOffset the offset (expressed in bytes) within the file at which the mapped segment is to start. - * @param bytesSize the size (in bytes) of the mapped memory backing the memory segment. - * @param mapMode a 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 #force()}). - * @param scope the segment scope. - * @return a new mapped memory segment. - * @throws IllegalArgumentException if {@code bytesOffset < 0}, {@code bytesSize < 0}, or if {@code path} is not associated - * with the default file system. - * @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 an unsupported map mode is specified. - * @throws IOException if the specified path does not point to an existing file, or if some other I/O error occurs. - * @throws SecurityException If a security manager is installed, and it denies an unspecified permission required by the implementation. - * In the case of the default provider, the {@link SecurityManager#checkRead(String)} method is invoked to check - * read access if the file is opened for reading. The {@link SecurityManager#checkWrite(String)} method is invoked to check - * write access if the file is opened for writing. - */ - static MemorySegment mapFile(Path path, long bytesOffset, long bytesSize, FileChannel.MapMode mapMode, ResourceScope scope) throws IOException { - Objects.requireNonNull(scope); - return MappedMemorySegmentImpl.makeMappedSegment(path, bytesOffset, bytesSize, mapMode, (ResourceScopeImpl) scope); + return NativeMemorySegmentImpl.makeNativeSegment(bytesSize, alignmentBytes, session); } /** @@ -982,7 +933,7 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory *
* The result of a bulk copy is unspecified if, in the uncommon case, the source segment and the destination segment * do not overlap, but refer to overlapping regions of the same backing storage using different addresses. - * For example, this may occur if the same file is {@linkplain MemorySegment#mapFile mapped} to two segments. + * For example, this may occur if the same file is {@linkplain FileChannel#map mapped} to two segments. *
* Calling this method is equivalent to the following code: * {@snippet lang=java : @@ -993,9 +944,10 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory * @param dstSegment the destination segment. * @param dstOffset the starting offset, in bytes, of the destination segment. * @param bytes the number of bytes to be copied. - * @throws IllegalStateException if either the scope associated with the source segment or the scope associated - * with the destination segment have been already closed, or if access occurs from a thread other than the thread - * owning either scopes. + * @throws IllegalStateException if the {@linkplain #session() session} associated with {@code srcSegment} is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. + * @throws IllegalStateException if the {@linkplain #session() session} associated with {@code dstSegment} is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IndexOutOfBoundsException if {@code srcOffset + bytes > srcSegment.byteSize()} or if * {@code dstOffset + bytes > dstSegment.byteSize()}, or if either {@code srcOffset}, {@code dstOffset} * or {@code bytes} are {@code < 0}. @@ -1024,7 +976,7 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory *
* The result of a bulk copy is unspecified if, in the uncommon case, the source segment and the destination segment * do not overlap, but refer to overlapping regions of the same backing storage using different addresses. - * For example, this may occur if the same file is {@linkplain MemorySegment#mapFile mapped} to two segments. + * For example, this may occur if the same file is {@linkplain FileChannel#map mapped} to two segments. * @param srcSegment the source segment. * @param srcElementLayout the element layout associated with the source segment. * @param srcOffset the starting offset, in bytes, of the source segment. @@ -1035,9 +987,10 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory * @throws IllegalArgumentException if the element layouts have different sizes, if the source (resp. destination) segment/offset are * incompatible with the alignment constraints in the source * (resp. destination) element layout, or if the source (resp. destination) element layout alignment is greater than its size. - * @throws IllegalStateException if either the scope associated with the source segment or the scope associated - * with the destination segment have been already closed, or if access occurs from a thread other than the thread - * owning either scopes. + * @throws IllegalStateException if the {@linkplain #session() session} associated with {@code srcSegment} is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. + * @throws IllegalStateException if the {@linkplain #session() session} associated with {@code dstSegment} is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IndexOutOfBoundsException if {@code srcOffset + (elementCount * S) > srcSegment.byteSize()} or if * {@code dstOffset + (elementCount * S) > dstSegment.byteSize()}, where {@code S} is the byte size * of the element layouts, or if either {@code srcOffset}, {@code dstOffset} or {@code elementCount} are {@code < 0}. @@ -1067,25 +1020,25 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory srcImpl.checkAccess(srcOffset, size, true); dstImpl.checkAccess(dstOffset, size, false); if (srcElementLayout.byteSize() == 1 || srcElementLayout.order() == dstElementLayout.order()) { - ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(srcImpl.scope(), dstImpl.scope(), + ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(srcImpl.sessionImpl(), dstImpl.sessionImpl(), srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset, dstImpl.unsafeGetBase(), dstImpl.unsafeGetOffset() + dstOffset, size); } else { - ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(srcImpl.scope(), dstImpl.scope(), + ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(srcImpl.sessionImpl(), dstImpl.sessionImpl(), srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset, dstImpl.unsafeGetBase(), dstImpl.unsafeGetOffset() + dstOffset, size, srcElementLayout.byteSize()); } } /** - * Reads a byte from this segment and offset with given layout. + * Reads a byte at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be read. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this read operation can be expressed as {@code address().toRowLongValue() + offset}. * @return a byte value read from this address. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1097,14 +1050,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Writes a byte to this segment and offset with given layout. + * Writes a byte at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be written. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + offset}. * @param value the byte value to be written. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1117,14 +1070,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Reads a boolean from this segment and offset with given layout. + * Reads a boolean at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be read. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this read operation can be expressed as {@code address().toRowLongValue() + offset}. * @return a boolean value read from this address. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1136,14 +1089,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Writes a boolean to this segment and offset with given layout. + * Writes a boolean at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be written. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + offset}. * @param value the boolean value to be written. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1156,14 +1109,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Reads a char from this segment and offset with given layout. + * Reads a char at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be read. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this read operation can be expressed as {@code address().toRowLongValue() + offset}. * @return a char value read from this address. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1175,14 +1128,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Writes a char to this segment and offset with given layout. + * Writes a char at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be written. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + offset}. * @param value the char value to be written. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1195,14 +1148,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Reads a short from this segment and offset with given layout. + * Reads a short at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be read. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this read operation can be expressed as {@code address().toRowLongValue() + offset}. * @return a short value read from this address. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1214,14 +1167,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Writes a short to this segment and offset with given layout. + * Writes a short at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be written. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + offset}. * @param value the short value to be written. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1234,14 +1187,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Reads an int from this segment and offset with given layout. + * Reads an int at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be read. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this read operation can be expressed as {@code address().toRowLongValue() + offset}. * @return an int value read from this address. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1253,14 +1206,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Writes an int to this segment and offset with given layout. + * Writes an int at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be written. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + offset}. * @param value the int value to be written. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1273,14 +1226,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Reads a float from this segment and offset with given layout. + * Reads a float at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be read. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this read operation can be expressed as {@code address().toRowLongValue() + offset}. * @return a float value read from this address. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1292,14 +1245,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Writes a float to this segment and offset with given layout. + * Writes a float at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be written. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + offset}. * @param value the float value to be written. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1312,14 +1265,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Reads a long from this segment and offset with given layout. + * Reads a long at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be read. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this read operation can be expressed as {@code address().toRowLongValue() + offset}. * @return a long value read from this address. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1331,14 +1284,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Writes a long to this segment and offset with given layout. + * Writes a long at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be written. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + offset}. * @param value the long value to be written. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1351,14 +1304,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Reads a double from this segment and offset with given layout. + * Reads a double at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be read. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this read operation can be expressed as {@code address().toRowLongValue() + offset}. * @return a double value read from this address. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1370,14 +1323,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Writes a double to this segment and offset with given layout. + * Writes a double at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be written. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + offset}. * @param value the double value to be written. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1390,14 +1343,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Reads an address from this segment and offset with given layout. + * Reads an address at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be read. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this read operation can be expressed as {@code address().toRowLongValue() + offset}. * @return an address value read from this address. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1409,14 +1362,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Writes an address to this segment and offset with given layout. + * Writes an address at the given offset from this segment, with the given layout. * * @param layout the layout of the memory region to be written. * @param offset offset in bytes (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + offset}. * @param value the address value to be written. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout. * @throws IndexOutOfBoundsException when the dereference operation falls outside the spatial bounds of the @@ -1429,14 +1382,14 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory } /** - * Reads a char from this segment and index, scaled by given layout size. + * Reads a char from this segment at the given index, scaled by the given layout size. * * @param layout the layout of the memory region to be read. * @param index index (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this read operation can be expressed as {@code address().toRowLongValue() + (index * layout.byteSize())}. * @return a char value read from this address. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout, * or if the layout alignment is greater than its size. @@ -1446,18 +1399,19 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory @ForceInline default char getAtIndex(ValueLayout.OfChar layout, long index) { Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - return (char)layout.accessHandle().get(this, Utils.scaleOffset(this, index, layout.byteSize())); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + return (char)layout.accessHandle().get(this, index * layout.byteSize()); } /** - * Writes a char to this segment and index, scaled by given layout size. + * Writes a char to this segment at the given index, scaled by the given layout size. * * @param layout the layout of the memory region to be written. * @param index index (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + (index * layout.byteSize())}. * @param value the char value to be written. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout, * or if the layout alignment is greater than its size. @@ -1468,18 +1422,19 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory @ForceInline default void setAtIndex(ValueLayout.OfChar layout, long index, char value) { Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - layout.accessHandle().set(this, Utils.scaleOffset(this, index, layout.byteSize()), value); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + layout.accessHandle().set(this, index * layout.byteSize(), value); } /** - * Reads a short from this segment and index, scaled by given layout size. + * Reads a short from this segment at the given index, scaled by the given layout size. * * @param layout the layout of the memory region to be read. * @param index index (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this read operation can be expressed as {@code address().toRowLongValue() + (index * layout.byteSize())}. * @return a short value read from this address. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout, * or if the layout alignment is greater than its size. @@ -1489,18 +1444,19 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory @ForceInline default short getAtIndex(ValueLayout.OfShort layout, long index) { Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - return (short)layout.accessHandle().get(this, Utils.scaleOffset(this, index, layout.byteSize())); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + return (short)layout.accessHandle().get(this, index * layout.byteSize()); } /** - * Writes a short to this segment and index, scaled by given layout size. + * Writes a short to this segment at the given index, scaled by the given layout size. * * @param layout the layout of the memory region to be written. * @param index index (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + (index * layout.byteSize())}. * @param value the short value to be written. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout, * or if the layout alignment is greater than its size. @@ -1511,18 +1467,19 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory @ForceInline default void setAtIndex(ValueLayout.OfShort layout, long index, short value) { Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - layout.accessHandle().set(this, Utils.scaleOffset(this, index, layout.byteSize()), value); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + layout.accessHandle().set(this, index * layout.byteSize(), value); } /** - * Reads an int from this segment and index, scaled by given layout size. + * Reads an int from this segment at the given index, scaled by the given layout size. * * @param layout the layout of the memory region to be read. * @param index index (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this read operation can be expressed as {@code address().toRowLongValue() + (index * layout.byteSize())}. * @return an int value read from this address. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout, * or if the layout alignment is greater than its size. @@ -1532,18 +1489,19 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory @ForceInline default int getAtIndex(ValueLayout.OfInt layout, long index) { Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - return (int)layout.accessHandle().get(this, Utils.scaleOffset(this, index, layout.byteSize())); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + return (int)layout.accessHandle().get(this, index * layout.byteSize()); } /** - * Writes an int to this segment and index, scaled by given layout size. + * Writes an int to this segment at the given index, scaled by the given layout size. * * @param layout the layout of the memory region to be written. * @param index index (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + (index * layout.byteSize())}. * @param value the int value to be written. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout, * or if the layout alignment is greater than its size. @@ -1554,18 +1512,19 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory @ForceInline default void setAtIndex(ValueLayout.OfInt layout, long index, int value) { Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - layout.accessHandle().set(this, Utils.scaleOffset(this, index, layout.byteSize()), value); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + layout.accessHandle().set(this, index * layout.byteSize(), value); } /** - * Reads a float from this segment and index, scaled by given layout size. + * Reads a float from this segment at the given index, scaled by the given layout size. * * @param layout the layout of the memory region to be read. * @param index index (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this read operation can be expressed as {@code address().toRowLongValue() + (index * layout.byteSize())}. * @return a float value read from this address. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout, * or if the layout alignment is greater than its size. @@ -1575,18 +1534,19 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory @ForceInline default float getAtIndex(ValueLayout.OfFloat layout, long index) { Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - return (float)layout.accessHandle().get(this, Utils.scaleOffset(this, index, layout.byteSize())); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + return (float)layout.accessHandle().get(this, index * layout.byteSize()); } /** - * Writes a float to this segment and index, scaled by given layout size. + * Writes a float to this segment at the given index, scaled by the given layout size. * * @param layout the layout of the memory region to be written. * @param index index (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + (index * layout.byteSize())}. * @param value the float value to be written. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout, * or if the layout alignment is greater than its size. @@ -1597,18 +1557,19 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory @ForceInline default void setAtIndex(ValueLayout.OfFloat layout, long index, float value) { Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - layout.accessHandle().set(this, Utils.scaleOffset(this, index, layout.byteSize()), value); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + layout.accessHandle().set(this, index * layout.byteSize(), value); } /** - * Reads a long from this segment and index, scaled by given layout size. + * Reads a long from this segment at the given index, scaled by the given layout size. * * @param layout the layout of the memory region to be read. * @param index index (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this read operation can be expressed as {@code address().toRowLongValue() + (index * layout.byteSize())}. * @return a long value read from this address. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout, * or if the layout alignment is greater than its size. @@ -1618,18 +1579,19 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory @ForceInline default long getAtIndex(ValueLayout.OfLong layout, long index) { Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - return (long)layout.accessHandle().get(this, Utils.scaleOffset(this, index, layout.byteSize())); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + return (long)layout.accessHandle().get(this, index * layout.byteSize()); } /** - * Writes a long to this segment and index, scaled by given layout size. + * Writes a long to this segment at the given index, scaled by the given layout size. * * @param layout the layout of the memory region to be written. * @param index index (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + (index * layout.byteSize())}. * @param value the long value to be written. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout, * or if the layout alignment is greater than its size. @@ -1640,18 +1602,19 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory @ForceInline default void setAtIndex(ValueLayout.OfLong layout, long index, long value) { Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - layout.accessHandle().set(this, Utils.scaleOffset(this, index, layout.byteSize()), value); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + layout.accessHandle().set(this, index * layout.byteSize(), value); } /** - * Reads a double from this segment and index, scaled by given layout size. + * Reads a double from this segment at the given index, scaled by the given layout size. * * @param layout the layout of the memory region to be read. * @param index index (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this read operation can be expressed as {@code address().toRowLongValue() + (index * layout.byteSize())}. * @return a double value read from this address. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout, * or if the layout alignment is greater than its size. @@ -1661,18 +1624,19 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory @ForceInline default double getAtIndex(ValueLayout.OfDouble layout, long index) { Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - return (double)layout.accessHandle().get(this, Utils.scaleOffset(this, index, layout.byteSize())); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + return (double)layout.accessHandle().get(this, index * layout.byteSize()); } /** - * Writes a double to this segment and index, scaled by given layout size. + * Writes a double to this segment at the given index, scaled by the given layout size. * * @param layout the layout of the memory region to be written. * @param index index (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + (index * layout.byteSize())}. * @param value the double value to be written. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout, * or if the layout alignment is greater than its size. @@ -1683,18 +1647,19 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory @ForceInline default void setAtIndex(ValueLayout.OfDouble layout, long index, double value) { Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - layout.accessHandle().set(this, Utils.scaleOffset(this, index, layout.byteSize()), value); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + layout.accessHandle().set(this, index * layout.byteSize(), value); } /** - * Reads an address from this segment and index, scaled by given layout size. + * Reads an address from this segment at the given index, scaled by the given layout size. * * @param layout the layout of the memory region to be read. * @param index index (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this read operation can be expressed as {@code address().toRowLongValue() + (index * layout.byteSize())}. * @return an address value read from this address. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout, * or if the layout alignment is greater than its size. @@ -1704,18 +1669,19 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory @ForceInline default MemoryAddress getAtIndex(ValueLayout.OfAddress layout, long index) { Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - return (MemoryAddress)layout.accessHandle().get(this, Utils.scaleOffset(this, index, layout.byteSize())); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + return (MemoryAddress)layout.accessHandle().get(this, index * layout.byteSize()); } /** - * Writes an address to this segment and index, scaled by given layout size. + * Writes an address to this segment at the given index, scaled by the given layout size. * * @param layout the layout of the memory region to be written. * @param index index (relative to this segment). For instance, if this segment is a {@linkplain #isNative() native} segment, * the final address of this write operation can be expressed as {@code address().toRowLongValue() + (index * layout.byteSize())}. * @param value the address value to be written. - * @throws IllegalStateException if the scope associated with this segment 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 segment is not + * {@linkplain MemorySession#isAlive() alive}, or if access occurs from a thread other than the thread owning that session. * @throws IllegalArgumentException if the dereference operation is * incompatible with the alignment constraints in the provided layout, * or if the layout alignment is greater than its size. @@ -1726,21 +1692,55 @@ public sealed interface MemorySegment extends Addressable permits AbstractMemory @ForceInline default void setAtIndex(ValueLayout.OfAddress layout, long index, Addressable value) { Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - layout.accessHandle().set(this, Utils.scaleOffset(this, index, layout.byteSize()), value.address()); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + layout.accessHandle().set(this, index * layout.byteSize(), value.address()); } + /** + * Compares the specified object with this memory segment for equality. Returns {@code true} if and only if the specified + * object is also a memory segment, and if that segment refers to the same memory region as this segment. More specifically, + * for two segments to be considered equals, all the following must be true: + *
+ * 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}. + *
+ * 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. + *
+ * 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}. + * + *
+ * 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}. + *
+ * 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). + * + *
+ * 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 try-with-resources construct). 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 unreachable. + * 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 exactly once. + * + *
- * This is a value-based - * 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. - * - *
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.
* * @implSpec - * This class is immutable and thread-safe. + * This class is immutable, thread-safe and value-based. */ /* package-private */ final class PaddingLayout extends AbstractLayout implements MemoryLayout { @@ -55,7 +42,7 @@ import java.util.OptionalLong; } PaddingLayout(long size, long alignment, Optional* This interface also defines factories for commonly used allocators: *
* Passing a segment allocator to an API can be especially useful in circumstances where a client wants to communicate where
* 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
- * 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:
*
* 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 prefix allocator.
* 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;
}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/SequenceLayout.java b/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java
similarity index 66%
rename from src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/SequenceLayout.java
rename to src/java.base/share/classes/java/lang/foreign/SequenceLayout.java
index 8143d2929ce..8ea0e1a9fdc 100644
--- a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/SequenceLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java
@@ -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 element layout.
- * The repetition count, where it exists (e.g. for finite sequence layouts) is said to be the sequence layout's element count.
- * 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 element layout.
+ * The repetition count is said to be the sequence layout's element count. 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));
* }
*
- *
- * This is a value-based
- * 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.
- *
- * 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.
+ * 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.
+ *
+ * The address of a symbol is modelled as a zero-length {@linkplain MemorySegment memory segment}. The segment can be used in different ways:
+ *
+ * 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 loader lookup, 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.
+ *
+ * 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
+ * }
+ *
+ *
+ * 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 default lookup,
+ * 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
+ * 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.
+ *
+ * Libraries associated with a class loader are unloaded when the class loader becomes
+ * unreachable. 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.
+ *
+ * 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.
+ *
+ * This method is restricted.
+ * 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.
+ *
+ * This method is restricted.
+ * 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
* 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}.
*
- * 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}.
*
* 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).
*
- * 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.
* 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.
*
* This method is restricted.
* 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.
*
- * 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}.
*
* 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 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.
- * This is a value-based
- * 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.
- *
- * 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.
+ * 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.
+ *
+ * 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:
+ *
+ * Classes to support low-level and efficient foreign memory/function access, directly from Java.
+ * Provides low-level access to memory and functions outside the Java runtime.
*
*
- * 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 memory layouts 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 layout paths.
+ * 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 dereference memory segments
+ * using {@linkplain java.lang.foreign.MemoryLayout#varHandle(java.lang.foreign.MemoryLayout.PathElement...) access var handles},
+ * which can be computed using layout paths.
*
* 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 native 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 unreachable 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 resource scope,
+ * This example is almost identical to the prior one; this time we first create a so called memory session,
* which is used to bind the life-cycle of the segment created immediately afterwards. Note the use of the
* try-with-resources 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 The Java Language Specification.
@@ -92,82 +90,82 @@
* Section {@jls 15.10.4} of The Java Language Specification.
*
* 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 temporal safety. Together, spatial and temporal safety ensure that each memory access
* operation either succeeds - and accesses a valid memory location - or fails.
*
*
* 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 downcall method handle 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.
*
*
- * 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 unsafe
- * {@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 unsafely. 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);
* }
*
*
* 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.
*
*
*
* 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.
*
- * Access to restricted methods is disabled 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.
+ *
+ * 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;
diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
index 7b2c49f37e6..fcdc9662d0a 100644
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
@@ -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
diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
index bec07d50b69..7b460b6de7f 100644
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
@@ -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.
+ *
+ * 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.
+ *
+ * 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}.
+ *
+ * As an example, consider the memory layout expressed by a {@link GroupLayout} instance constructed as follows:
+ *
+ * Alternatively, a memory access operation is partially aligned 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}.
+ *
+ * Finally, in all other cases, we say that a memory access operation is misaligned; 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.
+ *
+ * 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 last 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 last 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.
+ *
+ * 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).
+ *
+ * If the boxing and unboxing filters throw any checked exceptions when invoked, the resulting var handle will
+ * throw an {@link IllegalStateException}.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * If any of the filters throws a checked exception when invoked, the resulting var handle will
+ * throw an {@link IllegalStateException}.
+ *
+ * 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 bound coordinates
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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]}.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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
+ * 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.
+ *
+ * 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.
+ *
+ * If any of the filters throws a checked exception when invoked, the resulting var handle will
+ * throw an {@link IllegalStateException}.
+ *
+ * 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 too many coordinates,
+ * 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.
+ *
+ * The {@code pos} argument may range between zero and N, where N 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 N they will come after.
+ *
+ * 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);
+ }
}
diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandle.java b/src/java.base/share/classes/java/lang/invoke/VarHandle.java
index f7765b96136..3ba9de4ac29 100644
--- a/src/java.base/share/classes/java/lang/invoke/VarHandle.java
+++ b/src/java.base/share/classes/java/lang/invoke/VarHandle.java
@@ -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,
diff --git a/src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleBase.java b/src/java.base/share/classes/java/lang/invoke/VarHandleSegmentViewBase.java
similarity index 70%
rename from src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleBase.java
rename to src/java.base/share/classes/java/lang/invoke/VarHandleSegmentViewBase.java
index 6fbb7108eb7..199eb7d6c11 100644
--- a/src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleBase.java
+++ b/src/java.base/share/classes/java/lang/invoke/VarHandleSegmentViewBase.java
@@ -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;
diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandles.java b/src/java.base/share/classes/java/lang/invoke/VarHandles.java
index 2708e04688d..7d1c150c12a 100644
--- a/src/java.base/share/classes/java/lang/invoke/VarHandles.java
+++ b/src/java.base/share/classes/java/lang/invoke/VarHandles.java
@@ -300,23 +300,18 @@ final class VarHandles {
}
/**
- * Creates a memory access VarHandle.
+ * Creates a memory segment view var handle.
*
- * Resulting VarHandle will take a memory address as first argument,
- * and a certain number of coordinate {@code long} parameters, depending on the length
- * of the {@code strides} argument array.
- *
- * Coordinates are multiplied with corresponding scale factors ({@code strides}) and added
- * to a single fixed offset to compute an effective offset from the given MemoryAddress for the access.
+ * The resulting var handle will take a memory segment as first argument (the segment to be dereferenced),
+ * and a {@code long} as second argument (the offset into the segment).
*
* @param carrier the Java carrier type.
- * @param skipAlignmentMaskCheck if true, only the base part of the address will be checked for alignment.
* @param alignmentMask alignment requirement to be checked upon access. In bytes. Expressed as a mask.
* @param byteOrder the byte order.
* @return the created VarHandle.
*/
- static VarHandle makeMemoryAddressViewHandle(Class> carrier, boolean skipAlignmentMaskCheck, long alignmentMask,
- ByteOrder byteOrder) {
+ static VarHandle memorySegmentViewHandle(Class> carrier, long alignmentMask,
+ ByteOrder byteOrder) {
if (!carrier.isPrimitive() || carrier == void.class || carrier == boolean.class) {
throw new IllegalArgumentException("Invalid carrier: " + carrier.getName());
}
@@ -325,19 +320,19 @@ final class VarHandles {
boolean exact = false;
if (carrier == byte.class) {
- return maybeAdapt(new MemoryAccessVarHandleByteHelper(skipAlignmentMaskCheck, be, size, alignmentMask, exact));
+ return maybeAdapt(new VarHandleSegmentAsBytes(be, size, alignmentMask, exact));
} else if (carrier == char.class) {
- return maybeAdapt(new MemoryAccessVarHandleCharHelper(skipAlignmentMaskCheck, be, size, alignmentMask, exact));
+ return maybeAdapt(new VarHandleSegmentAsChars(be, size, alignmentMask, exact));
} else if (carrier == short.class) {
- return maybeAdapt(new MemoryAccessVarHandleShortHelper(skipAlignmentMaskCheck, be, size, alignmentMask, exact));
+ return maybeAdapt(new VarHandleSegmentAsShorts(be, size, alignmentMask, exact));
} else if (carrier == int.class) {
- return maybeAdapt(new MemoryAccessVarHandleIntHelper(skipAlignmentMaskCheck, be, size, alignmentMask, exact));
+ return maybeAdapt(new VarHandleSegmentAsInts(be, size, alignmentMask, exact));
} else if (carrier == float.class) {
- return maybeAdapt(new MemoryAccessVarHandleFloatHelper(skipAlignmentMaskCheck, be, size, alignmentMask, exact));
+ return maybeAdapt(new VarHandleSegmentAsFloats(be, size, alignmentMask, exact));
} else if (carrier == long.class) {
- return maybeAdapt(new MemoryAccessVarHandleLongHelper(skipAlignmentMaskCheck, be, size, alignmentMask, exact));
+ return maybeAdapt(new VarHandleSegmentAsLongs(be, size, alignmentMask, exact));
} else if (carrier == double.class) {
- return maybeAdapt(new MemoryAccessVarHandleDoubleHelper(skipAlignmentMaskCheck, be, size, alignmentMask, exact));
+ return maybeAdapt(new VarHandleSegmentAsDoubles(be, size, alignmentMask, exact));
} else {
throw new IllegalStateException("Cannot get here");
}
diff --git a/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template b/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template
index f4c8ee3de80..05923554f19 100644
--- a/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template
+++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template
@@ -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)));
diff --git a/src/java.base/share/classes/java/lang/invoke/X-VarHandleMemoryAccess.java.template b/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template
similarity index 52%
rename from src/java.base/share/classes/java/lang/invoke/X-VarHandleMemoryAccess.java.template
rename to src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template
index bdb4904d994..303acbdaeae 100644
--- a/src/java.base/share/classes/java/lang/invoke/X-VarHandleMemoryAccess.java.template
+++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandleSegmentView.java.template
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,10 +24,11 @@
*/
package java.lang.invoke;
-import jdk.internal.access.foreign.MemorySegmentProxy;
+import jdk.internal.foreign.AbstractMemorySegmentImpl;
import jdk.internal.misc.ScopedMemoryAccess;
import jdk.internal.vm.annotation.ForceInline;
+import java.lang.foreign.MemorySegment;
import java.lang.ref.Reference;
import java.util.Objects;
@@ -36,7 +37,7 @@ import static java.lang.invoke.MethodHandleStatics.UNSAFE;
#warn
-final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase {
+final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
static final boolean BE = UNSAFE.isBigEndian();
@@ -44,29 +45,29 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
static final int VM_ALIGN = $BoxType$.BYTES - 1;
- static final VarForm FORM = new VarForm(MemoryAccessVarHandle$Type$Helper.class, MemorySegmentProxy.class, $type$.class, long.class);
+ static final VarForm FORM = new VarForm(VarHandleSegmentAs$Type$s.class, MemorySegment.class, $type$.class, long.class);
- MemoryAccessVarHandle$Type$Helper(boolean skipAlignmentMaskCheck, boolean be, long length, long alignmentMask, boolean exact) {
- super(FORM, skipAlignmentMaskCheck, be, length, alignmentMask, exact);
+ VarHandleSegmentAs$Type$s(boolean be, long length, long alignmentMask, boolean exact) {
+ super(FORM, be, length, alignmentMask, exact);
}
@Override
final MethodType accessModeTypeUncached(VarHandle.AccessType accessType) {
- return accessType.accessModeType(MemorySegmentProxy.class, $type$.class, long.class);
+ return accessType.accessModeType(MemorySegment.class, $type$.class, long.class);
}
@Override
- public MemoryAccessVarHandle$Type$Helper withInvokeExactBehavior() {
+ public VarHandleSegmentAs$Type$s withInvokeExactBehavior() {
return hasInvokeExactBehavior() ?
this :
- new MemoryAccessVarHandle$Type$Helper(skipAlignmentMaskCheck, be, length, alignmentMask, true);
+ new VarHandleSegmentAs$Type$s(be, length, alignmentMask, true);
}
@Override
- public MemoryAccessVarHandle$Type$Helper withInvokeBehavior() {
+ public VarHandleSegmentAs$Type$s withInvokeBehavior() {
return !hasInvokeExactBehavior() ?
this :
- new MemoryAccessVarHandle$Type$Helper(skipAlignmentMaskCheck, be, length, alignmentMask, false);
+ new VarHandleSegmentAs$Type$s(be, length, alignmentMask, false);
}
#if[floatingPoint]
@@ -96,58 +97,51 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
#end[floatingPoint]
@ForceInline
- static MemorySegmentProxy checkAddress(Object obb, long offset, long length, boolean ro) {
- MemorySegmentProxy oo = (MemorySegmentProxy)Objects.requireNonNull(obb);
+ static AbstractMemorySegmentImpl checkAddress(Object obb, long offset, long length, boolean ro) {
+ AbstractMemorySegmentImpl oo = (AbstractMemorySegmentImpl)Objects.requireNonNull(obb);
oo.checkAccess(offset, length, ro);
return oo;
}
@ForceInline
- static long offset(boolean skipAlignmentMaskCheck, MemorySegmentProxy bb, long offset, long alignmentMask) {
- long address = offsetNoVMAlignCheck(skipAlignmentMaskCheck, bb, offset, alignmentMask);
+ static long offset(AbstractMemorySegmentImpl bb, long offset, long alignmentMask) {
+ long address = offsetNoVMAlignCheck(bb, offset, alignmentMask);
if ((address & VM_ALIGN) != 0) {
- throw MemoryAccessVarHandleBase.newIllegalArgumentExceptionForMisalignedAccess(address);
+ throw VarHandleSegmentViewBase.newIllegalArgumentExceptionForMisalignedAccess(address);
}
return address;
}
@ForceInline
- static long offsetNoVMAlignCheck(boolean skipAlignmentMaskCheck, MemorySegmentProxy bb, long offset, long alignmentMask) {
+ static long offsetNoVMAlignCheck(AbstractMemorySegmentImpl bb, long offset, long alignmentMask) {
long base = bb.unsafeGetOffset();
long address = base + offset;
long maxAlignMask = bb.maxAlignMask();
- if (skipAlignmentMaskCheck) {
- //note: the offset portion has already been aligned-checked, by construction
- if (((base | maxAlignMask) & alignmentMask) != 0) {
- throw MemoryAccessVarHandleBase.newIllegalArgumentExceptionForMisalignedAccess(address);
- }
- } else {
- if (((address | maxAlignMask) & alignmentMask) != 0) {
- throw MemoryAccessVarHandleBase.newIllegalArgumentExceptionForMisalignedAccess(address);
- }
+ if (((address | maxAlignMask) & alignmentMask) != 0) {
+ throw VarHandleSegmentViewBase.newIllegalArgumentExceptionForMisalignedAccess(address);
}
return address;
}
@ForceInline
static $type$ get(VarHandle ob, Object obb, long base) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, true);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, true);
#if[floatingPoint]
- $rawType$ rawValue = SCOPED_MEMORY_ACCESS.get$RawType$Unaligned(bb.scope(),
+ $rawType$ rawValue = SCOPED_MEMORY_ACCESS.get$RawType$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
- offsetNoVMAlignCheck(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
handle.be);
return $Type$.$rawType$BitsTo$Type$(rawValue);
#else[floatingPoint]
#if[byte]
- return SCOPED_MEMORY_ACCESS.get$Type$(bb.scope(),
+ return SCOPED_MEMORY_ACCESS.get$Type$(bb.sessionImpl(),
bb.unsafeGetBase(),
- offsetNoVMAlignCheck(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask));
+ offsetNoVMAlignCheck(bb, base, handle.alignmentMask));
#else[byte]
- return SCOPED_MEMORY_ACCESS.get$Type$Unaligned(bb.scope(),
+ return SCOPED_MEMORY_ACCESS.get$Type$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
- offsetNoVMAlignCheck(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
handle.be);
#end[byte]
#end[floatingPoint]
@@ -155,24 +149,24 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
@ForceInline
static void set(VarHandle ob, Object obb, long base, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
#if[floatingPoint]
- SCOPED_MEMORY_ACCESS.put$RawType$Unaligned(bb.scope(),
+ SCOPED_MEMORY_ACCESS.put$RawType$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
- offsetNoVMAlignCheck(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
$Type$.$type$ToRaw$RawType$Bits(value),
handle.be);
#else[floatingPoint]
#if[byte]
- SCOPED_MEMORY_ACCESS.put$Type$(bb.scope(),
+ SCOPED_MEMORY_ACCESS.put$Type$(bb.sessionImpl(),
bb.unsafeGetBase(),
- offsetNoVMAlignCheck(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
value);
#else[byte]
- SCOPED_MEMORY_ACCESS.put$Type$Unaligned(bb.scope(),
+ SCOPED_MEMORY_ACCESS.put$Type$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
- offsetNoVMAlignCheck(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
value,
handle.be);
#end[byte]
@@ -181,178 +175,178 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
@ForceInline
static $type$ getVolatile(VarHandle ob, Object obb, long base) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, true);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, true);
return convEndian(handle.be,
- SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.scope(),
+ SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask)));
+ offset(bb, base, handle.alignmentMask)));
}
@ForceInline
static void setVolatile(VarHandle ob, Object obb, long base, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
- SCOPED_MEMORY_ACCESS.put$RawType$Volatile(bb.scope(),
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
+ SCOPED_MEMORY_ACCESS.put$RawType$Volatile(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value));
}
@ForceInline
static $type$ getAcquire(VarHandle ob, Object obb, long base) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, true);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, true);
return convEndian(handle.be,
- SCOPED_MEMORY_ACCESS.get$RawType$Acquire(bb.scope(),
+ SCOPED_MEMORY_ACCESS.get$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask)));
+ offset(bb, base, handle.alignmentMask)));
}
@ForceInline
static void setRelease(VarHandle ob, Object obb, long base, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
- SCOPED_MEMORY_ACCESS.put$RawType$Release(bb.scope(),
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
+ SCOPED_MEMORY_ACCESS.put$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value));
}
@ForceInline
static $type$ getOpaque(VarHandle ob, Object obb, long base) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, true);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, true);
return convEndian(handle.be,
- SCOPED_MEMORY_ACCESS.get$RawType$Opaque(bb.scope(),
+ SCOPED_MEMORY_ACCESS.get$RawType$Opaque(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask)));
+ offset(bb, base, handle.alignmentMask)));
}
@ForceInline
static void setOpaque(VarHandle ob, Object obb, long base, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
- SCOPED_MEMORY_ACCESS.put$RawType$Opaque(bb.scope(),
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
+ SCOPED_MEMORY_ACCESS.put$RawType$Opaque(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value));
}
#if[CAS]
@ForceInline
static boolean compareAndSet(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
- return SCOPED_MEMORY_ACCESS.compareAndSet$RawType$(bb.scope(),
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
+ return SCOPED_MEMORY_ACCESS.compareAndSet$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ForceInline
static $type$ compareAndExchange(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
- SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$(bb.scope(),
+ SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value)));
}
@ForceInline
static $type$ compareAndExchangeAcquire(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
- SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Acquire(bb.scope(),
+ SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value)));
}
@ForceInline
static $type$ compareAndExchangeRelease(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
- SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Release(bb.scope(),
+ SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value)));
}
@ForceInline
static boolean weakCompareAndSetPlain(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
- return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Plain(bb.scope(),
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
+ return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Plain(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ForceInline
static boolean weakCompareAndSet(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
- return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.scope(),
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
+ return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ForceInline
static boolean weakCompareAndSetAcquire(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
- return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Acquire(bb.scope(),
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
+ return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ForceInline
static boolean weakCompareAndSetRelease(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
- return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Release(bb.scope(),
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
+ return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ForceInline
static $type$ getAndSet(VarHandle ob, Object obb, long base, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
- SCOPED_MEMORY_ACCESS.getAndSet$RawType$(bb.scope(),
+ SCOPED_MEMORY_ACCESS.getAndSet$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value)));
}
@ForceInline
static $type$ getAndSetAcquire(VarHandle ob, Object obb, long base, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
- SCOPED_MEMORY_ACCESS.getAndSet$RawType$Acquire(bb.scope(),
+ SCOPED_MEMORY_ACCESS.getAndSet$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value)));
}
@ForceInline
static $type$ getAndSetRelease(VarHandle ob, Object obb, long base, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
- SCOPED_MEMORY_ACCESS.getAndSet$RawType$Release(bb.scope(),
+ SCOPED_MEMORY_ACCESS.getAndSet$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value)));
}
#end[CAS]
@@ -360,54 +354,54 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
@ForceInline
static $type$ getAndAdd(VarHandle ob, Object obb, long base, $type$ delta) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
- return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$(bb.scope(),
+ return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
delta);
} else {
- return getAndAddConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), delta);
+ return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta);
}
}
@ForceInline
static $type$ getAndAddAcquire(VarHandle ob, Object obb, long base, $type$ delta) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
- return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Acquire(bb.scope(),
+ return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
delta);
} else {
- return getAndAddConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), delta);
+ return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta);
}
}
@ForceInline
static $type$ getAndAddRelease(VarHandle ob, Object obb, long base, $type$ delta) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
- return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Release(bb.scope(),
+ return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
delta);
} else {
- return getAndAddConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), delta);
+ return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta);
}
}
@ForceInline
- static $type$ getAndAddConvEndianWithCAS(MemorySegmentProxy bb, long offset, $type$ delta) {
+ static $type$ getAndAddConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ delta) {
$type$ nativeExpectedValue, expectedValue;
Object base = bb.unsafeGetBase();
do {
- nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.scope(),base, offset);
+ nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
- } while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.scope(),base, offset,
+ } while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue + delta)));
return expectedValue;
}
@@ -416,108 +410,108 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
@ForceInline
static $type$ getAndBitwiseOr(VarHandle ob, Object obb, long base, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
- return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$(bb.scope(),
+ return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
value);
} else {
- return getAndBitwiseOrConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
+ return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseOrRelease(VarHandle ob, Object obb, long base, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
- return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Release(bb.scope(),
+ return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
value);
} else {
- return getAndBitwiseOrConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
+ return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseOrAcquire(VarHandle ob, Object obb, long base, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
- return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Acquire(bb.scope(),
+ return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
value);
} else {
- return getAndBitwiseOrConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
+ return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
- static $type$ getAndBitwiseOrConvEndianWithCAS(MemorySegmentProxy bb, long offset, $type$ value) {
+ static $type$ getAndBitwiseOrConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ value) {
$type$ nativeExpectedValue, expectedValue;
Object base = bb.unsafeGetBase();
do {
- nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.scope(),base, offset);
+ nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
- } while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.scope(),base, offset,
+ } while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue | value)));
return expectedValue;
}
@ForceInline
static $type$ getAndBitwiseAnd(VarHandle ob, Object obb, long base, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
- return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$(bb.scope(),
+ return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
value);
} else {
- return getAndBitwiseAndConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
+ return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseAndRelease(VarHandle ob, Object obb, long base, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
- return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Release(bb.scope(),
+ return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
value);
} else {
- return getAndBitwiseAndConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
+ return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseAndAcquire(VarHandle ob, Object obb, long base, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
- return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Acquire(bb.scope(),
+ return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
value);
} else {
- return getAndBitwiseAndConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
+ return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
- static $type$ getAndBitwiseAndConvEndianWithCAS(MemorySegmentProxy bb, long offset, $type$ value) {
+ static $type$ getAndBitwiseAndConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ value) {
$type$ nativeExpectedValue, expectedValue;
Object base = bb.unsafeGetBase();
do {
- nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.scope(),base, offset);
+ nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
- } while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.scope(),base, offset,
+ } while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue & value)));
return expectedValue;
}
@@ -525,54 +519,54 @@ final class MemoryAccessVarHandle$Type$Helper extends MemoryAccessVarHandleBase
@ForceInline
static $type$ getAndBitwiseXor(VarHandle ob, Object obb, long base, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
- return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$(bb.scope(),
+ return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
value);
} else {
- return getAndBitwiseXorConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
+ return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseXorRelease(VarHandle ob, Object obb, long base, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
- return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Release(bb.scope(),
+ return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
value);
} else {
- return getAndBitwiseXorConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
+ return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseXorAcquire(VarHandle ob, Object obb, long base, $type$ value) {
- MemoryAccessVarHandleBase handle = (MemoryAccessVarHandleBase)ob;
- MemorySegmentProxy bb = checkAddress(obb, base, handle.length, false);
+ VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
+ AbstractMemorySegmentImpl bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
- return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Acquire(bb.scope(),
+ return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(),
- offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask),
+ offset(bb, base, handle.alignmentMask),
value);
} else {
- return getAndBitwiseXorConvEndianWithCAS(bb, offset(handle.skipAlignmentMaskCheck, bb, base, handle.alignmentMask), value);
+ return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
- static $type$ getAndBitwiseXorConvEndianWithCAS(MemorySegmentProxy bb, long offset, $type$ value) {
+ static $type$ getAndBitwiseXorConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ value) {
$type$ nativeExpectedValue, expectedValue;
Object base = bb.unsafeGetBase();
do {
- nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.scope(),base, offset);
+ nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
- } while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.scope(),base, offset,
+ } while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue ^ value)));
return expectedValue;
}
diff --git a/src/java.base/share/classes/java/nio/Buffer.java b/src/java.base/share/classes/java/nio/Buffer.java
index 4df2f620611..8bc35186b5a 100644
--- a/src/java.base/share/classes/java/nio/Buffer.java
+++ b/src/java.base/share/classes/java/nio/Buffer.java
@@ -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
diff --git a/src/java.base/share/classes/java/nio/BufferMismatch.java b/src/java.base/share/classes/java/nio/BufferMismatch.java
index a9988f77b8c..d8611253b3b 100644
--- a/src/java.base/share/classes/java/nio/BufferMismatch.java
+++ b/src/java.base/share/classes/java/nio/BufferMismatch.java
@@ -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,
diff --git a/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template b/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template
index 6040ac79411..b57c2b96635 100644
--- a/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template
+++ b/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template
@@ -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]
diff --git a/src/java.base/share/classes/java/nio/Direct-X-Buffer-bin.java.template b/src/java.base/share/classes/java/nio/Direct-X-Buffer-bin.java.template
index 4a1eb380f03..4a281453886 100644
--- a/src/java.base/share/classes/java/nio/Direct-X-Buffer-bin.java.template
+++ b/src/java.base/share/classes/java/nio/Direct-X-Buffer-bin.java.template
@@ -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);
}
diff --git a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template
index 38697b39480..9de53f68a9d 100644
--- a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template
+++ b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template
@@ -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);
diff --git a/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template b/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template
index 541dbd6c8f8..2ead79fc86b 100644
--- a/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template
+++ b/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template
@@ -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();
diff --git a/src/java.base/share/classes/java/nio/MappedByteBuffer.java b/src/java.base/share/classes/java/nio/MappedByteBuffer.java
index 8f9ca9f8fe6..231f749f870 100644
--- a/src/java.base/share/classes/java/nio/MappedByteBuffer.java
+++ b/src/java.base/share/classes/java/nio/MappedByteBuffer.java
@@ -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;
}
diff --git a/src/java.base/share/classes/java/nio/X-Buffer.java.template b/src/java.base/share/classes/java/nio/X-Buffer.java.template
index e559b46f37c..caae8936c52 100644
--- a/src/java.base/share/classes/java/nio/X-Buffer.java.template
+++ b/src/java.base/share/classes/java/nio/X-Buffer.java.template
@@ -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);
diff --git a/src/java.base/share/classes/java/nio/channels/FileChannel.java b/src/java.base/share/classes/java/nio/channels/FileChannel.java
index 524e8e67cee..ae632a2216a 100644
--- a/src/java.base/share/classes/java/nio/channels/FileChannel.java
+++ b/src/java.base/share/classes/java/nio/channels/FileChannel.java
@@ -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.
+ *
+ * If the specified mapping mode is
+ * {@linkplain FileChannel.MapMode#READ_ONLY READ_ONLY}, the resulting
+ * segment will be read-only (see {@link MemorySegment#isReadOnly()}).
+ *
+ * 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.
+ *
+ * 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 --
diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java
index 20823fcfcad..83b25f05a96 100644
--- a/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java
+++ b/src/java.base/share/classes/jdk/internal/access/JavaLangInvokeAccess.java
@@ -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
@@ -56,17 +58,16 @@ import jdk.internal.vm.vector.VectorSupport;
*
* 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.
*
* 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 before a scope check or after 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 before a liveness check or after 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.
*
@@ -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,35 +98,13 @@ 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 {
- private ScopedAccessError() {
- super("Attempt to access an already released memory resource", null, false, false);
- }
- static final long serialVersionUID = 1L;
-
- public static final ScopedAccessError INSTANCE = new ScopedAccessError();
+ public static final class ScopedAccessError extends Error {
+ private ScopedAccessError() {
+ super("Attempt to access an already released memory resource", null, false, false);
}
+ static final long serialVersionUID = 1L;
+
+ public static final ScopedAccessError INSTANCE = new ScopedAccessError();
}
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
@@ -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
- * On unsupported platforms this class will fail to initialize with an {@link ExceptionInInitializerError}.
- *
- * 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.
- * {@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 native function.
- * 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:
- *
- * The downcall method handle type, derived as above, might be decorated by additional leading parameters,
- * in the given order if both are present:
- * Variadic functions, declared in C either 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 native
- * variadic function by using a {@linkplain FunctionDescriptor#asVariadic(MemoryLayout...) variadic} function descriptor,
- * in which the specialized signature of a given variable arity callsite is described in full. Alternatively,
- * if the foreign library allows it, clients might also be able to interact with variable arity methods
- * by passing a trailing parameter of type {@link VaList}.
- *
- *
- * The type of the provided method handle has to 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:
- *
- * 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 native 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 native 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 value-based.
- */
-public sealed interface CLinker extends SymbolLookup permits Windowsx64Linker, SysVx64Linker, LinuxAArch64Linker, MacOsAArch64Linker {
-
- /**
- * Returns the C linker for the current platform.
- *
- * This method is restricted.
- * Restricted methods are unsafe, and, if used incorrectly, their use might crash
- * the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
- * restricted methods, and use safe and supported functionalities, where possible.
- *
- * @return a linker for this system.
- * @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 CLinker systemCLinker() {
- Reflection.ensureNativeAccess(Reflection.getCallerClass());
- return SharedUtils.getSystemLinker();
- }
-
- /**
- * Look up a symbol in the standard libraries associated with this linker.
- * The set of symbols available for lookup is unspecified, as it depends on the platform and on the operating system.
- * @return a symbol in the standard libraries associated with this linker.
- */
- @Override
- default Optional
- * 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.
- *
- * Calling this method is equivalent to the following code:
- * {@snippet lang=java :
- * linker.downcallHandle(function).bindTo(symbol);
- * }
- *
- * @param symbol downcall symbol.
- * @param function the function descriptor.
- * @return the downcall method handle. The method handle type is inferred
- * @throws IllegalArgumentException if the provided descriptor contains either a sequence or a padding layout,
- * or if the symbol is {@link MemoryAddress#NULL}
- *
- * @see SymbolLookup
- */
- default MethodHandle downcallHandle(NativeSymbol symbol, FunctionDescriptor function) {
- SharedUtils.checkSymbol(symbol);
- return downcallHandle(function).bindTo(symbol);
- }
-
- /**
- * Obtains a foreign method handle, with the given type and featuring the given function descriptor, which can be
- * used to call a target foreign function at the address in a dynamically provided native symbol.
- * The resulting method handle features a prefix parameter (as the first parameter) corresponding to the foreign function
- * entry point, of type {@link NativeSymbol}.
- *
- * 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.
- *
- * The returned method handle will throw an {@link IllegalArgumentException} if the native symbol passed to it is
- * associated with the {@link MemoryAddress#NULL} address, or a {@link NullPointerException} if the native symbol is {@code null}.
- *
- * @param function the function descriptor.
- * @return the downcall method handle. The method handle type is inferred
- * from the provided function descriptor.
- * @throws IllegalArgumentException if the provided descriptor contains either a sequence or a padding layout.
- *
- * @see SymbolLookup
- */
- MethodHandle downcallHandle(FunctionDescriptor function);
-
- /**
- * Allocates a native stub with given scope which can be passed to other foreign functions (as a function pointer);
- * calling such a function pointer from native code will result in the execution of the provided method handle.
- *
- *
- * The returned function pointer is associated with the provided scope. When such scope is closed,
- * the corresponding native stub will be deallocated.
- *
- * 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 function descriptor.
- * @param scope the upcall stub scope.
- * @return the native stub symbol.
- * @throws IllegalArgumentException if the provided descriptor contains either a sequence or a padding layout,
- * or 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 inferred type.
- * @throws IllegalStateException if {@code scope} has been already closed, or if access occurs from a thread other
- * than the thread owning {@code scope}.
- */
- NativeSymbol upcallStub(MethodHandle target, FunctionDescriptor function, ResourceScope scope);
-
- /**
- * Obtains the downcall method handle {@linkplain MethodType type} associated with a given function descriptor.
- * @param functionDescriptor a function descriptor.
- * @return the downcall method handle {@linkplain MethodType type} associated with a given 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);
- }
-
- /**
- * Obtains the method handle {@linkplain MethodType type} associated with an upcall stub with given function descriptor.
- * @param functionDescriptor a function descriptor.
- * @return the method handle {@linkplain MethodType type} associated with an upcall stub with given 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);
- }
-}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryHandles.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryHandles.java
deleted file mode 100644
index f24f5c7bc6e..00000000000
--- a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/MemoryHandles.java
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * Copyright (c) 2019, 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.
- *
- */
-package jdk.incubator.foreign;
-
-import jdk.internal.access.JavaLangInvokeAccess;
-import jdk.internal.access.SharedSecrets;
-import sun.invoke.util.Wrapper;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import java.lang.invoke.VarHandle;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * This class defines several factory methods for constructing and combining memory access var handles.
- * Memory access var handles can be obtained using {@link MemoryHandles#varHandle(ValueLayout)}. The provided value layout
- * determines the type, as well as the alignment constraint and the byte order associated with the memory access var handle.
- *
- * The resulting memory access var handle can then be combined in various ways
- * to emulate different addressing modes. The var handles created by this class feature a mandatory coordinate type
- * (of type {@link MemorySegment}), and one {@code long} coordinate type, which represents the offset, in bytes, relative
- * to the segment, at which dereference should occur.
- *
- * As an example, consider the memory layout expressed by a {@link GroupLayout} instance constructed as follows:
- * {@snippet lang=java :
- * GroupLayout seq = MemoryLayout.structLayout(
- * MemoryLayout.paddingLayout(32),
- * ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value")
- * );
- * }
- * To access the member layout named {@code value}, we can construct a memory access var handle as follows:
- * {@snippet lang=java :
- * VarHandle handle = MemoryHandles.varHandle(ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN)); //(MemorySegment, long) -> int
- * handle = MemoryHandles.insertCoordinates(handle, 1, 4); //(MemorySegment) -> int
- * }
- *
- * 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.
- * Alternatively, a memory access operation is partially aligned 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}.
- *
- * Finally, in all other cases, we say that a memory access operation is misaligned; in such cases an
- * {@code IllegalStateException} is thrown, irrespective of the access mode being used.
- */
-public final class MemoryHandles {
-
- private static final JavaLangInvokeAccess JLI = SharedSecrets.getJavaLangInvokeAccess();
-
- private MemoryHandles() {
- //sorry, just the one!
- }
-
- private static final MethodHandle INT_TO_BYTE;
- private static final MethodHandle BYTE_TO_UNSIGNED_INT;
- private static final MethodHandle INT_TO_SHORT;
- private static final MethodHandle SHORT_TO_UNSIGNED_INT;
- private static final MethodHandle LONG_TO_BYTE;
- private static final MethodHandle BYTE_TO_UNSIGNED_LONG;
- private static final MethodHandle LONG_TO_SHORT;
- private static final MethodHandle SHORT_TO_UNSIGNED_LONG;
- private static final MethodHandle LONG_TO_INT;
- private static final MethodHandle INT_TO_UNSIGNED_LONG;
-
- static {
- try {
- INT_TO_BYTE = MethodHandles.explicitCastArguments(MethodHandles.identity(byte.class),
- MethodType.methodType(byte.class, int.class));
- BYTE_TO_UNSIGNED_INT = MethodHandles.lookup().findStatic(Byte.class, "toUnsignedInt",
- MethodType.methodType(int.class, byte.class));
- INT_TO_SHORT = MethodHandles.explicitCastArguments(MethodHandles.identity(short.class),
- MethodType.methodType(short.class, int.class));
- SHORT_TO_UNSIGNED_INT = MethodHandles.lookup().findStatic(Short.class, "toUnsignedInt",
- MethodType.methodType(int.class, short.class));
- LONG_TO_BYTE = MethodHandles.explicitCastArguments(MethodHandles.identity(byte.class),
- MethodType.methodType(byte.class, long.class));
- BYTE_TO_UNSIGNED_LONG = MethodHandles.lookup().findStatic(Byte.class, "toUnsignedLong",
- MethodType.methodType(long.class, byte.class));
- LONG_TO_SHORT = MethodHandles.explicitCastArguments(MethodHandles.identity(short.class),
- MethodType.methodType(short.class, long.class));
- SHORT_TO_UNSIGNED_LONG = MethodHandles.lookup().findStatic(Short.class, "toUnsignedLong",
- MethodType.methodType(long.class, short.class));
- LONG_TO_INT = MethodHandles.explicitCastArguments(MethodHandles.identity(int.class),
- MethodType.methodType(int.class, long.class));
- INT_TO_UNSIGNED_LONG = MethodHandles.lookup().findStatic(Integer.class, "toUnsignedLong",
- MethodType.methodType(long.class, int.class));
- } catch (Throwable ex) {
- throw new ExceptionInInitializerError(ex);
- }
- }
-
- /**
- * Creates a memory access var handle from given value layout. The provided layout will specify the
- * {@linkplain ValueLayout#carrier() carrier type}, the {@linkplain ValueLayout#byteSize() the byte size},
- * the {@linkplain ValueLayout#byteAlignment() byte alignment} and the {@linkplain ValueLayout#order() byte order}
- * associated to the returned var handle.
- *
- * 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 memory access var handle is given by {@code alignmentBytes}.
- *
- * @apiNote the resulting var handle features certain access mode restrictions,
- * which are common to all memory access var handles.
- *
- * @param layout the value layout for which a memory access handle is to be obtained.
- * @return the new memory access var handle.
- * @throws IllegalArgumentException if an illegal carrier type is used, or if {@code alignmentBytes} is not a power of two.
- */
- public static VarHandle varHandle(ValueLayout layout) {
- Objects.requireNonNull(layout);
- return layout.accessHandle();
- }
-
- /**
- * Adapts a target var handle by narrowing incoming values and widening
- * outgoing values, to and from the given type, respectively.
- *
- * The returned var handle can be used to conveniently treat unsigned
- * primitive data types as if they were a wider signed primitive type. For
- * example, it is often convenient to model an unsigned short as a
- * Java {@code int} to avoid dealing with negative values, which would be
- * the case if modeled as a Java {@code short}. This is illustrated in the following example:
- * {@snippet lang=java :
- * MemorySegment segment = MemorySegment.allocateNative(2, ResourceScope.newImplicitScope());
- * VarHandle SHORT_VH = ValueLayout.JAVA_SHORT.varHandle();
- * VarHandle INT_VH = MemoryHandles.asUnsigned(SHORT_VH, int.class);
- * SHORT_VH.set(segment, (short)-1);
- * INT_VH.get(segment); // returns 65535
- * }
- *
- * When calling e.g. {@link VarHandle#set(Object...)} on the resulting var
- * handle, the incoming value (of type {@code adaptedType}) is converted by a
- * narrowing primitive conversion and then passed to the {@code
- * target} var handle. A narrowing primitive conversion may lose information
- * about the overall magnitude of a numeric value. Conversely, when calling
- * e.g. {@link VarHandle#get(Object...)} on the resulting var handle, the
- * returned value obtained from the {@code target} var handle is converted
- * by a unsigned widening conversion before being returned to the
- * caller. In an unsigned widening conversion the high-order bits greater
- * than that of the {@code target} carrier type are zero, and the low-order
- * bits (equal to the width of the {@code target} carrier type) are equal to
- * the bits of the value obtained from the {@code target} var handle.
- *
- * The returned var handle will feature the variable type {@code adaptedType},
- * and the same access coordinates, the same access modes (see {@link
- * java.lang.invoke.VarHandle.AccessMode}), and the same atomic access
- * guarantees, as those featured by the {@code target} var handle.
- *
- * @param target the memory access var handle to be adapted
- * @param adaptedType the adapted type
- * @return the adapted var handle.
- * @throws IllegalArgumentException if the carrier type of {@code target}
- * is not one of {@code byte}, {@code short}, or {@code int}; if {@code
- * adaptedType} is not one of {@code int}, or {@code long}; if the bit width
- * of the {@code adaptedType} is not greater than that of the {@code target}
- * carrier type.
- *
- * @jls 5.1.3 Narrowing Primitive Conversion
- */
- public static VarHandle asUnsigned(VarHandle target, final Class> adaptedType) {
- Objects.requireNonNull(target);
- Objects.requireNonNull(adaptedType);
- final Class> carrier = target.varType();
- checkWidenable(carrier);
- checkNarrowable(adaptedType);
- checkTargetWiderThanCarrier(carrier, adaptedType);
-
- if (adaptedType == int.class && carrier == byte.class) {
- return filterValue(target, INT_TO_BYTE, BYTE_TO_UNSIGNED_INT);
- } else if (adaptedType == int.class && carrier == short.class) {
- return filterValue(target, INT_TO_SHORT, SHORT_TO_UNSIGNED_INT);
- } else if (adaptedType == long.class && carrier == byte.class) {
- return filterValue(target, LONG_TO_BYTE, BYTE_TO_UNSIGNED_LONG);
- } else if (adaptedType == long.class && carrier == short.class) {
- return filterValue(target, LONG_TO_SHORT, SHORT_TO_UNSIGNED_LONG);
- } else if (adaptedType == long.class && carrier == int.class) {
- return filterValue(target, LONG_TO_INT, INT_TO_UNSIGNED_LONG);
- } else {
- throw new InternalError("should not reach here");
- }
- }
-
- /**
- * Adapts a target var handle by pre-processing incoming and outgoing values using a pair of filter functions.
- *
- * 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 last 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 last 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 java.lang.invoke.VarHandle.AccessMode#COMPARE_AND_EXCHANGE} might apply both filters at the same time.
- *
- * 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).
- *
- * If the boxing and unboxing filters throw any checked exceptions when invoked, the resulting var handle will
- * throw an {@link IllegalStateException}.
- *
- * The resulting var handle will feature the same access modes (see {@link java.lang.invoke.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.
- */
- public static VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget) {
- return JLI.filterValue(target, filterToTarget, filterFromTarget);
- }
-
- /**
- * Adapts a target var handle by pre-processing incoming coordinate values using unary filter functions.
- *
- * 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 type
- * 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.
- *
- * 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.
- *
- * If any of the filters throws a checked exception when invoked, the resulting var handle will
- * throw an {@link IllegalStateException}.
- *
- * The resulting var handle will feature the same access modes (see {@link java.lang.invoke.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.
- */
- public static VarHandle filterCoordinates(VarHandle target, int pos, MethodHandle... filters) {
- return JLI.filterCoordinates(target, pos, filters);
- }
-
- /**
- * Provides a target var handle with one or more bound coordinates
- * 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.
- *
- * 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.
- *
- * 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.
- *
- * The resulting var handle will feature the same access modes (see {@link java.lang.invoke.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 an 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.
- */
- public static VarHandle insertCoordinates(VarHandle target, int pos, Object... values) {
- return JLI.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.
- *
- * 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]}.
- *
- * 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.
- *
- * 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.
- *
- * The resulting var handle will feature the same access modes (see {@link java.lang.invoke.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.
- */
- public static VarHandle permuteCoordinates(VarHandle target, List
- * 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.
- *
- * 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.
- *
- * If any of the filters throws a checked exception when invoked, the resulting var handle will
- * throw an {@link IllegalStateException}.
- *
- * The resulting var handle will feature the same access modes (see {@link java.lang.invoke.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 too many coordinates,
- * or if it's determined that {@code filter} throws any checked exceptions.
- */
- public static VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle filter) {
- return JLI.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.
- *
- * The {@code pos} argument may range between zero and N, where N 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 N they will come after.
- *
- * The resulting var handle will feature the same access modes (see {@link java.lang.invoke.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 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.
- */
- public static VarHandle dropCoordinates(VarHandle target, int pos, Class>... valueTypes) {
- return JLI.dropCoordinates(target, pos, valueTypes);
- }
-
- private static void checkWidenable(Class> carrier) {
- if (!(carrier == byte.class || carrier == short.class || carrier == int.class)) {
- throw new IllegalArgumentException("illegal carrier:" + carrier.getSimpleName());
- }
- }
-
- private static void checkNarrowable(Class> type) {
- if (!(type == int.class || type == long.class)) {
- throw new IllegalArgumentException("illegal adapter type: " + type.getSimpleName());
- }
- }
-
- private static void checkTargetWiderThanCarrier(Class> carrier, Class> target) {
- if (Wrapper.forPrimitiveType(target).bitWidth() <= Wrapper.forPrimitiveType(carrier).bitWidth()) {
- throw new IllegalArgumentException(
- target.getSimpleName() + " is not wider than: " + carrier.getSimpleName());
- }
- }
-}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/NativeSymbol.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/NativeSymbol.java
deleted file mode 100644
index 3dc583f98fc..00000000000
--- a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/NativeSymbol.java
+++ /dev/null
@@ -1,86 +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.
- *
- */
-package jdk.incubator.foreign;
-
-import jdk.internal.foreign.NativeSymbolImpl;
-import jdk.internal.reflect.CallerSensitive;
-import jdk.internal.reflect.Reflection;
-
-import java.lang.invoke.MethodHandle;
-import java.util.Objects;
-
-/**
- * A native symbol models a reference to a location (typically the entry point of a function) in a native library.
- * A native symbol has a name, and is associated with a scope, which governs the native symbol's lifecycle.
- * This is useful, since the library a native symbol refers to can be unloaded, thus invalidating the native symbol.
- * While native symbols are typically obtained using a {@link SymbolLookup#lookup(String) symbol lookup}, it is also possible to obtain an
- * anonymous native symbol, in the form of an {@linkplain CLinker#upcallStub(MethodHandle, FunctionDescriptor, ResourceScope) upcall stub},
- * that is, a reference to a dynamically-generated native symbol which can be used to call back into Java code.
- */
-sealed public interface NativeSymbol extends Addressable permits NativeSymbolImpl {
-
- /**
- * {@return the name of this symbol}
- */
- String name();
-
- /**
- * {@return the resource scope associated with this symbol}
- */
- ResourceScope scope();
-
- /**
- * {@return the memory address associated with this symbol}
- * @throws IllegalStateException if the scope associated with this symbol has been closed, or if access occurs from
- * a thread other than the thread owning that scope.
- */
- @Override
- MemoryAddress address();
-
- /**
- * Creates a new symbol from given name, address and scope.
- *
- * This method is restricted.
- * 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 symbol name.
- * @param address the symbol address.
- * @param scope the symbol scope.
- * @return A new symbol from given name, address and scope.
- * @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 NativeSymbol ofAddress(String name, MemoryAddress address, ResourceScope scope) {
- Reflection.ensureNativeAccess(Reflection.getCallerClass());
- Objects.requireNonNull(name);
- Objects.requireNonNull(address);
- Objects.requireNonNull(scope);
- return new NativeSymbolImpl(name, address, scope);
- }
-}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/ResourceScope.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/ResourceScope.java
deleted file mode 100644
index 6c5d6b2b66f..00000000000
--- a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/ResourceScope.java
+++ /dev/null
@@ -1,257 +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.
- */
-
-package jdk.incubator.foreign;
-
-import jdk.internal.foreign.ResourceScopeImpl;
-import jdk.internal.ref.CleanerFactory;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.ref.Cleaner;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.file.Path;
-import java.util.Objects;
-import java.util.Spliterator;
-
-/**
- * A resource scope manages the lifecycle of one or more resources. Resources (e.g. {@link MemorySegment}) associated
- * with a resource scope can only be accessed while the resource scope is {@linkplain #isAlive() alive},
- * and by the {@linkplain #ownerThread() thread} associated with the resource scope (if any).
- *
- *
- * Closing a resource scope will cause all the {@linkplain #addCloseAction(Runnable) close actions} associated with that scope to be called.
- * Moreover, closing a resource scope might trigger the releasing of the underlying memory resources associated with said scope; for instance:
- *
- * {@linkplain #newConfinedScope() Confined resource scopes}, 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 resource scope, only the owner thread will be allowed to directly manipulate the resources
- * associated with this resource scope. Any attempt to perform resource access from a thread other than the
- * owner thread will result in a runtime failure.
- *
- * {@linkplain #newSharedScope() Shared resource scopes}, on the other hand, have no owner thread;
- * as such, resources associated with shared resource scopes 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).
- * For instance, a client might obtain a {@link Spliterator} from a segment backed by a shared scope, which can then be used to slice the
- * segment and allow multiple threads to work in parallel on disjoint segment slices. The following code can be used to sum
- * all int values in a memory segment in parallel:
- *
- * {@snippet lang=java :
- * try (ResourceScope scope = ResourceScope.newSharedScope()) {
- * SequenceLayout SEQUENCE_LAYOUT = MemoryLayout.sequenceLayout(1024, ValueLayout.JAVA_INT);
- * MemorySegment segment = MemorySegment.allocateNative(SEQUENCE_LAYOUT, scope);
- * int sum = segment.elements(ValueLayout.JAVA_INT).parallel()
- * .mapToInt(s -> s.get(ValueLayout.JAVA_INT, 0))
- * .sum();
- * }
- * }
- *
- *
- * Shared resource scopes, while powerful, must be used with caution: if one or more threads accesses
- * a resource associated with a shared scope while the scope is being closed from another thread, an exception might occur on both
- * the accessing and the closing threads. Clients should refrain from attempting to close a shared resource scope repeatedly
- * (e.g. keep calling {@link #close()} until no exception is thrown). Instead, clients of shared resource scopes
- * should always ensure that proper synchronization mechanisms (e.g. using temporal dependencies, see below) are put in place
- * so that threads closing shared resource scopes can never race against threads accessing resources managed by same scopes.
- *
- *
- * This can be useful when clients need to perform a critical operation on a memory segment, during which they have
- * to ensure that the scope associated with that segment will not be closed; this can be done as follows:
- *
- * {@snippet lang=java :
- * MemorySegment segment = ...
- * try (ResourceScope criticalScope = ResourceScope.newConfinedScope()) {
- * criticalScope.keepAlive(segment.scope());
- * 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.
- * This method is restricted.
- * Restricted methods are unsafe, and, if used incorrectly, their use might crash
- * the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
- * restricted methods, and use safe and supported functionalities, where possible.
- *
- * @return a symbol lookup suitable to find symbols in libraries loaded by the caller's classloader.
- * @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 loaderLookup() {
- Class> caller = Reflection.getCallerClass();
- Reflection.ensureNativeAccess(caller);
- ClassLoader loader = Objects.requireNonNull(caller.getClassLoader());
- ResourceScope loaderScope = ResourceScopeImpl.heapScope(loader);
- return name -> {
- Objects.requireNonNull(name);
- JavaLangAccess javaLangAccess = SharedSecrets.getJavaLangAccess();
- MemoryAddress addr = MemoryAddress.ofLong(javaLangAccess.findNative(loader, name));
- return addr == MemoryAddress.NULL? Optional.empty() : Optional.of(NativeSymbol.ofAddress(name, addr, loaderScope));
- };
- }
-
-}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MappedMemorySegmentImpl.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MappedMemorySegmentImpl.java
deleted file mode 100644
index 85332b66a5b..00000000000
--- a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/MappedMemorySegmentImpl.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (c) 2020, 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 jdk.incubator.foreign.MemorySegment;
-import jdk.internal.access.foreign.UnmapperProxy;
-import jdk.internal.misc.ExtendedMapMode;
-import jdk.internal.misc.ScopedMemoryAccess;
-import sun.nio.ch.FileChannelImpl;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.file.FileSystem;
-import java.nio.file.FileSystems;
-import java.nio.file.OpenOption;
-import java.nio.file.Path;
-import java.nio.file.StandardOpenOption;
-import java.util.Objects;
-
-/**
- * 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();
-
- MappedMemorySegmentImpl(long min, UnmapperProxy unmapper, long length, int mask, ResourceScopeImpl scope) {
- super(min, length, mask, scope);
- this.unmapper = unmapper;
- }
-
- @Override
- ByteBuffer makeByteBuffer() {
- return nioAccess.newMappedByteBuffer(unmapper, min, (int)length, null,
- scope == ResourceScopeImpl.GLOBAL ? null : this);
- }
-
- @Override
- MappedMemorySegmentImpl dup(long offset, long size, int mask, ResourceScopeImpl scope) {
- return new MappedMemorySegmentImpl(min + offset, unmapper, size, mask, scope);
- }
-
- // 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(scope, min, unmapper.isSync(), length);
- }
-
- public void unload() {
- SCOPED_MEMORY_ACCESS.unload(scope, min, unmapper.isSync(), length);
- }
-
- public boolean isLoaded() {
- return SCOPED_MEMORY_ACCESS.isLoaded(scope, min, unmapper.isSync(), length);
- }
-
- public void force() {
- SCOPED_MEMORY_ACCESS.force(scope, unmapper.fileDescriptor(), min, unmapper.isSync(), 0, length);
- }
-
- // factories
-
- public static MemorySegment makeMappedSegment(Path path, long bytesOffset, long bytesSize, FileChannel.MapMode mapMode, ResourceScopeImpl scope) throws IOException {
- Objects.requireNonNull(path);
- Objects.requireNonNull(mapMode);
- scope.checkValidStateSlow();
- if (bytesSize < 0) throw new IllegalArgumentException("Requested bytes size must be >= 0.");
- if (bytesOffset < 0) throw new IllegalArgumentException("Requested bytes offset must be >= 0.");
- FileSystem fs = path.getFileSystem();
- if (fs != FileSystems.getDefault() ||
- fs.getClass().getModule() != Object.class.getModule()) {
- throw new IllegalArgumentException("Unsupported file system");
- }
- try (FileChannel channelImpl = FileChannel.open(path, openOptions(mapMode))) {
- UnmapperProxy unmapperProxy = ((FileChannelImpl)channelImpl).mapInternal(mapMode, bytesOffset, bytesSize);
- int modes = defaultAccessModes(bytesSize);
- if (mapMode == FileChannel.MapMode.READ_ONLY) {
- modes |= READ_ONLY;
- }
- if (unmapperProxy != null) {
- AbstractMemorySegmentImpl segment = new MappedMemorySegmentImpl(unmapperProxy.address(), unmapperProxy, bytesSize,
- modes, scope);
- scope.addOrCleanupIfFail(new ResourceScopeImpl.ResourceList.ResourceCleanup() {
- @Override
- public void cleanup() {
- unmapperProxy.unmap();
- }
- });
- return segment;
- } else {
- return new EmptyMappedMemorySegmentImpl(modes, scope);
- }
- }
- }
-
- private static OpenOption[] openOptions(FileChannel.MapMode mapMode) {
- if (mapMode == FileChannel.MapMode.READ_ONLY ||
- mapMode == ExtendedMapMode.READ_ONLY_SYNC) {
- return new OpenOption[] { StandardOpenOption.READ };
- } else if (mapMode == FileChannel.MapMode.READ_WRITE ||
- mapMode == FileChannel.MapMode.PRIVATE ||
- mapMode == ExtendedMapMode.READ_WRITE_SYNC) {
- return new OpenOption[] { StandardOpenOption.READ, StandardOpenOption.WRITE };
- } else {
- throw new UnsupportedOperationException("Unsupported map mode: " + mapMode);
- }
- }
-
- static class EmptyMappedMemorySegmentImpl extends MappedMemorySegmentImpl {
-
- public EmptyMappedMemorySegmentImpl(int modes, ResourceScopeImpl scope) {
- super(0, null, 0, modes, scope);
- }
-
- @Override
- public void load() {
- // do nothing
- }
-
- @Override
- public void unload() {
- // do nothing
- }
-
- @Override
- public boolean isLoaded() {
- return true;
- }
-
- @Override
- public void force() {
- // do nothing
- }
- };
-}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/ResourceScopeImpl.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/ResourceScopeImpl.java
deleted file mode 100644
index 173753b1586..00000000000
--- a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/ResourceScopeImpl.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright (c) 2019, 2020, 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 jdk.incubator.foreign.MemorySegment;
-import jdk.incubator.foreign.ResourceScope;
-import jdk.incubator.foreign.SegmentAllocator;
-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 java.lang.ref.Reference;
-import java.util.Objects;
-
-/**
- * This class manages the temporal bounds associated with a memory segment as well
- * as thread confinement. A scope has a liveness bit, which is updated when the scope is closed
- * (this operation is triggered by {@link ResourceScope#close()}). This bit is consulted prior
- * to memory access (see {@link #checkValidState()}).
- * There are two kinds of memory scope: confined memory scope and shared memory scope.
- * A confined memory scope has an associated owner thread that confines some operations to
- * associated owner thread such as {@link #close()} or {@link #checkValidState()}.
- * Shared scopes 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 scopes use a more sophisticated synchronization mechanism, which guarantees that no concurrent
- * access is possible when a scope is being closed (see {@link jdk.internal.misc.ScopedMemoryAccess}).
- */
-public abstract non-sealed class ResourceScopeImpl implements ResourceScope, SegmentAllocator, ScopedMemoryAccess.Scope {
-
- final ResourceList resourceList;
- final Cleaner.Cleanable cleanable;
- final Thread owner;
-
- static final int ALIVE = 0;
- static final int CLOSING = -1;
- static final int CLOSED = -2;
-
- int state = ALIVE;
-
- static final VarHandle STATE;
-
- static {
- try {
- STATE = MethodHandles.lookup().findVarHandle(ResourceScopeImpl.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(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 scope; 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 scope
- * 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.Scope.ScopedAccessError err) {
- throw new IllegalStateException("Already closed");
- }
- }
-
- protected ResourceScopeImpl(Thread owner, ResourceList resourceList, Cleaner cleaner) {
- this.owner = owner;
- this.resourceList = resourceList;
- cleanable = (cleaner != null) ?
- cleaner.register(this, resourceList) : null;
- }
-
- public static ResourceScopeImpl createConfined(Thread thread, Cleaner cleaner) {
- return new ConfinedScope(thread, cleaner);
- }
-
- public static ResourceScopeImpl createShared(Cleaner cleaner) {
- return new SharedScope(cleaner);
- }
-
- @Override
- public MemorySegment allocate(long bytesSize, long bytesAlignment) {
- return MemorySegment.allocateNative(bytesSize, bytesAlignment, this);
- }
-
- public abstract void release0();
-
- public abstract void acquire0();
-
- @Override
- public void keepAlive(ResourceScope target) {
- Objects.requireNonNull(target);
- if (target == this) {
- throw new IllegalArgumentException("Invalid target scope.");
- }
- ResourceScopeImpl targetImpl = (ResourceScopeImpl)target;
- targetImpl.acquire0();
- addCloseAction(targetImpl::release0);
- }
-
- /**
- * Closes this scope, executing any cleanup action (where provided).
- * @throws IllegalStateException if this scope is already closed or if this is
- * a confined scope and this method is called outside of the owner thread.
- */
- public void close() {
- try {
- justClose();
- if (cleanable != null) {
- cleanable.clean();
- } else {
- resourceList.cleanup();
- }
- } finally {
- Reference.reachabilityFence(this);
- }
- }
-
- abstract void justClose();
-
- /**
- * Returns "owner" thread of this scope.
- * @return owner thread (or null for a shared scope)
- */
- public final Thread ownerThread() {
- return owner;
- }
-
- /**
- * Returns true, if this scope is still alive. This method may be called in any thread.
- * @return {@code true} if this scope is not closed yet.
- */
- public abstract boolean isAlive();
-
- /**
- * This is a faster version of {@link #checkValidStateSlow()}, which is called upon memory access, and which
- * relies on invariants associated with the memory scope 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 < ALIVE) {
- throw ScopedAccessError.INSTANCE;
- }
- }
-
- /**
- * Checks that this scope is still alive (see {@link #isAlive()}).
- * @throws IllegalStateException if this scope is already closed or if this is
- * a confined scope 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();
- }
-
- /**
- * The global, always alive, non-closeable, shared scope. Similar to a shared scope, but its {@link #close()} method throws unconditionally.
- * Adding new resources to the global scope, does nothing: as the scope can never become not-alive, there is nothing to track.
- * Acquiring and or releasing a resource scope similarly does nothing.
- */
- static class GlobalScopeImpl extends SharedScope {
-
- final Object ref;
-
- public GlobalScopeImpl(Object ref) {
- super(null);
- this.ref = ref;
- }
-
- @Override
- public void close() {
- throw new UnsupportedOperationException("Scope cannot be closed");
- }
-
- @Override
- @ForceInline
- public void release0() {
- // do nothing
- }
-
- @Override
- @ForceInline
- public void acquire0() {
- // do nothing
- }
-
- @Override
- void addInternal(ResourceList.ResourceCleanup resource) {
- // do nothing
- }
-
- @Override
- public boolean isAlive() {
- return true;
- }
- }
-
- public static final ResourceScopeImpl GLOBAL = new GlobalScopeImpl(null);
-
- public static ResourceScopeImpl heapScope(Object ref) {
- return new GlobalScopeImpl(ref);
- }
-
- /**
- * A list of all cleanup actions associated with a resource scope. Cleanup actions are modelled as instances
- * of the {@link ResourceCleanup} class, and, together, form a linked list. Depending on whether a scope
- * is shared or confined, different implementations of this class will be used, see {@link ConfinedScope.ConfinedResourceList}
- * and {@link SharedScope.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();
- }
- };
- }
- }
-
- }
-}
diff --git a/test/hotspot/jtreg/gc/shenandoah/compiler/TestLinkToNativeRBP.java b/test/hotspot/jtreg/gc/shenandoah/compiler/TestLinkToNativeRBP.java
index a5ebe6f5de8..aed3c9350de 100644
--- a/test/hotspot/jtreg/gc/shenandoah/compiler/TestLinkToNativeRBP.java
+++ b/test/hotspot/jtreg/gc/shenandoah/compiler/TestLinkToNativeRBP.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, Red Hat, Inc. All rights reserved.
+ * Copyright (c) 2021, 2022, Red Hat, Inc. 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,6 +23,7 @@
/**
* @test
+ * @enablePreview
* @bug 8259937
* @summary guarantee(loc != NULL) failed: missing saved register with native invoke
*
@@ -30,18 +31,16 @@
* @requires ((os.arch == "amd64" | os.arch == "x86_64") & sun.arch.data.model == "64") | os.arch == "aarch64"
* @requires vm.gc.Shenandoah
*
- * @modules jdk.incubator.foreign
- *
* @run main/othervm --enable-native-access=ALL-UNNAMED -XX:+UnlockDiagnosticVMOptions
* -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive TestLinkToNativeRBP
*
*/
-import jdk.incubator.foreign.CLinker;
-import jdk.incubator.foreign.FunctionDescriptor;
-import jdk.incubator.foreign.SymbolLookup;
-import jdk.incubator.foreign.ValueLayout;
+import java.lang.foreign.Linker;
+import java.lang.foreign.FunctionDescriptor;
+import java.lang.foreign.SymbolLookup;
+import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
public class TestLinkToNativeRBP {
@@ -49,7 +48,7 @@ public class TestLinkToNativeRBP {
System.loadLibrary("LinkToNativeRBP");
}
- final static CLinker abi = CLinker.systemCLinker();
+ final static Linker abi = Linker.nativeLinker();
static final SymbolLookup lookup = SymbolLookup.loaderLookup();
final static MethodHandle foo = abi.downcallHandle(lookup.lookup("foo").get(),
FunctionDescriptor.of(ValueLayout.JAVA_INT));
diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt
index a33987e40a7..b8258c6e2fd 100644
--- a/test/jdk/ProblemList.txt
+++ b/test/jdk/ProblemList.txt
@@ -486,7 +486,7 @@ java/beans/XMLEncoder/Test6570354.java 8015593 macosx-all
# jdk_foreign
-java/foreign/TestMismatch.java 8249684 macosx-all
+java/foreign/TestUpcallStack.java 8275584 macosx-aarch64
############################################################################
diff --git a/test/jdk/java/foreign/CallGeneratorHelper.java b/test/jdk/java/foreign/CallGeneratorHelper.java
index a69fe1a5d81..f075616f582 100644
--- a/test/jdk/java/foreign/CallGeneratorHelper.java
+++ b/test/jdk/java/foreign/CallGeneratorHelper.java
@@ -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
@@ -22,17 +22,16 @@
*
*/
-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.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.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.VarHandle;
@@ -42,6 +41,7 @@ import java.util.Stack;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
+import java.util.stream.Stream;
import org.testng.annotations.*;
@@ -49,6 +49,11 @@ import static org.testng.Assert.*;
public class CallGeneratorHelper extends NativeTestHelper {
+ static final List
*
+ *
+ *
+ * Obtaining a symbol lookup
+ *
+ * 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 library lookup, 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
+ * }
+ *
+ *
+ * @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{@code
+ * offset = (10 * 20 * 4 * x) + (20 * 4 * y) + (4 * z)
+ * }Foreign memory access
*
* Foreign function access
- * 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 Java Native Interface (JNI)).
* Foreign addresses
*
* 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 raw pointers.
+ * are fully known at segment creation. But when interacting with foreign functions, clients will often receive raw 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.
* Upcalls
- * 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}.
* Restricted methods
* Some methods in this package are considered restricted. 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.
*
+ * To access the member layout named {@code value}, we can construct a memory segment view var handle as follows:
+ * {@code
+ * GroupLayout seq = java.lang.foreign.MemoryLayout.structLayout(
+ * MemoryLayout.paddingLayout(32),
+ * ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value")
+ * );
+ * }
+ *
+ * @apiNote The resulting var handle features certain access mode restrictions,
+ * 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 fully aligned 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:
+ * {@code
+ * VarHandle handle = MethodHandles.memorySegmentViewVarHandle(ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN)); //(MemorySegment, long) -> int
+ * handle = MethodHandles.insertCoordinates(handle, 1, 4); //(MemorySegment) -> int
+ * }
+ *
+ *
+ * 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).
+ * Downcall method handles
- *
- *
- *
- *
- *
- * Upcall stubs
- *
- * {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, ResourceScope) 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.
- *
- *
- * Upcall stubs are modelled by instances of type {@link NativeSymbol}; upcall stubs can be passed by reference to other
- * downcall method handles (as {@link NativeSymbol} implements the {@link Addressable} interface) and,
- * when no longer required, they can be {@link ResourceScope#close() released}, via their {@linkplain NativeSymbol#scope() scope}.
- *
- *
- *
System lookup
- *
- * This class implements the {@link SymbolLookup} interface; as such clients can {@linkplain #lookup(String) look up} symbols
- * in the standard libraries associated with this linker. The set of symbols available for lookup is unspecified,
- * as it depends on the platform and on the operating system.
- *
- * Safety considerations
- *
- * Obtaining downcall method handle is intrinsically unsafe. A symbol in a native library does not, in general,
- * contain enough signature information (e.g. arity and types of native 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},
- * {@link NativeSymbol} or {@link VaList}):
- *
- *
- * Alignment and access modes
- *
- * A memory access 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 fully aligned 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:
- *
- *
- *
- * 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).
- * Deterministic deallocation
- *
- * Resource scopes support deterministic deallocation; that is, they can be {@linkplain ResourceScope#close() closed}
- * explicitly. When a resource scope is closed, it is no longer {@link #isAlive() alive}, and subsequent
- * operations on resources associated with that scope (e.g. attempting to access a {@link MemorySegment} instance)
- * will fail with {@link IllegalStateException}.
- *
- *
- *
- * Implicit deallocation
- *
- * Resource scopes can be associated with a {@link Cleaner} instance, so that they are also closed automatically,
- * once the scope instance becomes unreachable.
- * This can be useful to allow for predictable, deterministic resource deallocation, while still preventing accidental
- * native memory leaks. In case a managed resource scope is closed explicitly, no further action will be taken when
- * the scope becomes unreachable; that is, {@linkplain #addCloseAction(Runnable) close actions} associated with a
- * resource scope, whether managed or not, are called exactly once.
- *
- * Global scope
- *
- * An important implicit resource scope is the so called {@linkplain #globalScope() global scope}; the global scope is
- * a resource scope that cannot be closed, either explicitly or implicitly. As a result, the global scope will never
- * attempt to release resources associated with it. Examples of resources associated with the global scope are:
- *
- *
- * In other words, the global scope is used to indicate that the lifecycle of one or more resources must, where
- * needed, be managed independently by clients.
- *
- * Thread confinement
- *
- * Resource scopes can be divided into two categories: thread-confined resource scopes, and shared
- * resource scopes.
- * Temporal dependencies
- *
- * Resource scopes can depend on each other. More specifically, a scope can feature
- * {@linkplain #keepAlive(ResourceScope) temporal dependencies} on one or more other resource scopes.
- * Such a resource scope cannot be closed (either implicitly or explicitly) until all the scopes it depends on
- * have also been closed.
- *
- *
- * @throws UnsupportedOperationException if this resource scope is the {@linkplain #globalScope() global scope}.
- */
- void close();
-
- /**
- * Add a custom cleanup action which will be executed when the resource scope is closed.
- * The order in which custom cleanup actions are invoked once the scope is closed is unspecified.
- * @param runnable the custom cleanup action to be associated with this scope.
- * @throws IllegalStateException if this scope has been closed, or if access occurs from
- * a thread other than the thread owning this scope.
- */
- void addCloseAction(Runnable runnable);
-
- /**
- * Creates a temporal dependency between this scope and the target scope. As a result, the target scope cannot
- * be {@linkplain #close() closed} before this scope.
- * @implNote A given scope can support up to {@link Integer#MAX_VALUE} pending keep alive requests.
- * @param target the scope that needs to be kept alive.
- * @throws IllegalArgumentException if {@code target == this}.
- * @throws IllegalStateException if this scope or {@code target} have been closed, or if access occurs from
- * a thread other than the thread owning this scope or {@code target}.
- */
- void keepAlive(ResourceScope target);
-
- /**
- * Creates a new confined scope.
- * @return a new confined scope.
- */
- static ResourceScope newConfinedScope() {
- return ResourceScopeImpl.createConfined(Thread.currentThread(), null);
- }
-
- /**
- * Creates a new confined scope, managed by the provided cleaner instance.
- * @param cleaner the cleaner to be associated with the returned scope.
- * @return a new confined scope, managed by {@code cleaner}.
- */
- static ResourceScope newConfinedScope(Cleaner cleaner) {
- Objects.requireNonNull(cleaner);
- return ResourceScopeImpl.createConfined(Thread.currentThread(), cleaner);
- }
-
- /**
- * Creates a new shared scope.
- * @return a new shared scope.
- */
- static ResourceScope newSharedScope() {
- return ResourceScopeImpl.createShared(null);
- }
-
- /**
- * Creates a new shared scope, managed by the provided cleaner instance.
- * @param cleaner the cleaner to be associated with the returned scope.
- * @return a new shared scope, managed by {@code cleaner}.
- */
- static ResourceScope newSharedScope(Cleaner cleaner) {
- Objects.requireNonNull(cleaner);
- return ResourceScopeImpl.createShared(cleaner);
- }
-
- /**
- * Creates a new shared scope, managed by a private {@link Cleaner} instance. Equivalent to (but likely more efficient than)
- * the following code:
- * {@snippet lang=java :
- * newSharedScope(Cleaner.create());
- * }
- * @return a shared scope, managed by a private {@link Cleaner} instance.
- */
- static ResourceScope newImplicitScope() {
- return newSharedScope(CleanerFactory.cleaner());
- }
-
- /**
- * Returns the global scope.
- * @return the global scope.
- */
- static ResourceScope globalScope() {
- return ResourceScopeImpl.GLOBAL;
- }
-}
diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/SymbolLookup.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/SymbolLookup.java
deleted file mode 100644
index 5010703ba15..00000000000
--- a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/SymbolLookup.java
+++ /dev/null
@@ -1,87 +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.
- */
-package jdk.incubator.foreign;
-
-import jdk.internal.access.JavaLangAccess;
-import jdk.internal.access.SharedSecrets;
-import jdk.internal.foreign.ResourceScopeImpl;
-import jdk.internal.reflect.CallerSensitive;
-import jdk.internal.reflect.Reflection;
-
-import java.util.Objects;
-import java.util.Optional;
-
-/**
- * A symbol lookup. Exposes a lookup operation for searching symbol addresses by name, see {@link SymbolLookup#lookup(String)}.
- * A symbol lookup can be used to look up a symbol in a loaded library. Clients can obtain a {@linkplain #loaderLookup() loader lookup},
- * which can be used to search symbols in libraries loaded by the current classloader (e.g. using {@link System#load(String)},
- * or {@link System#loadLibrary(String)}).
- * Alternatively, clients can search symbols in the standard C library using a {@link CLinker}, which conveniently
- * implements this interface.
- *