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

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

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # This code is free software; you can redistribute it and/or modify it
@ -55,7 +55,6 @@ DOCS_MODULES= \
jdk.jsobject \ jdk.jsobject \
jdk.jshell \ jdk.jshell \
jdk.jstatd \ jdk.jstatd \
jdk.incubator.foreign \
jdk.localedata \ jdk.localedata \
jdk.management \ jdk.management \
jdk.management.agent \ jdk.management.agent \

View file

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

View file

@ -1,5 +1,5 @@
# #
# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # 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) TARGETS += $(COPY_TZMAPPINGS)
endif endif
################################################################################
# Create system lookup
$(eval $(call SetupJdkLibrary, BUILD_SYSLOOKUPLIB, \
NAME := syslookup, \
CFLAGS := $(CFLAGS_JDKLIB), \
CXXFLAGS := $(CXXFLAGS_JDKLIB), \
LDFLAGS := $(LDFLAGS_JDKLIB), \
LDFLAGS_linux := -Wl$(COMMA)--no-as-needed, \
LIBS := $(LIBCXX), \
LIBS_linux := -lc -lm -ldl, \
))
TARGETS += $(BUILD_SYSLOOKUPLIB)

View file

@ -160,14 +160,14 @@ endef
################################################################################ ################################################################################
################################################################################ ################################################################################
# Setup a rule for generating a memory access var handle helper classes # Setup a rule for generating a memory segment var handle view class
# Param 1 - Variable declaration prefix # Param 1 - Variable declaration prefix
# Param 2 - Type with first letter capitalized # Param 2 - Type with first letter capitalized
define GenerateVarHandleMemoryAccess define GenerateVarHandleMemorySegment
$1_Type := $2 $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) ifeq ($$($1_Type), Byte)
$1_type := byte $1_type := byte
@ -248,7 +248,7 @@ define GenerateVarHandleMemoryAccess
$1_ARGS += -KfloatingPoint $1_ARGS += -KfloatingPoint
endif 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)) $$(call MakeDir, $$(@D))
$(RM) $$@ $(RM) $$@
$(TOOL_SPP) -nel -K$$($1_type) \ $(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))) $(eval $(call GenerateVarHandleByteArray,VAR_HANDLE_BYTE_ARRAY_$t,$t)))
# List the types to generate source for, with capitalized first letter # List the types to generate source for, with capitalized first letter
VARHANDLES_MEMORY_ADDRESS_TYPES := Byte Short Char Int Long Float Double VARHANDLES_MEMORY_SEGMENT_TYPES := Byte Short Char Int Long Float Double
$(foreach t, $(VARHANDLES_MEMORY_ADDRESS_TYPES), \ $(foreach t, $(VARHANDLES_MEMORY_SEGMENT_TYPES), \
$(eval $(call GenerateVarHandleMemoryAccess,VAR_HANDLE_MEMORY_ADDRESS_$t,$t))) $(eval $(call GenerateVarHandleMemorySegment,VAR_HANDLE_MEMORY_SEGMENT_$t,$t)))
TARGETS += $(GENSRC_VARHANDLES) TARGETS += $(GENSRC_VARHANDLES)

View file

@ -1,62 +0,0 @@
#
# Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
include LibCommon.gmk
ifeq ($(call isTargetOs, linux), true)
$(eval $(call SetupJdkLibrary, BUILD_SYSLOOKUPLIB, \
NAME := syslookup, \
CFLAGS := $(CFLAGS_JDKLIB), \
CXXFLAGS := $(CXXFLAGS_JDKLIB), \
LDFLAGS := $(LDFLAGS_JDKLIB) -Wl$(COMMA)--no-as-needed, \
LIBS := $(LIBCXX) -lc -lm -ldl, \
))
else ifeq ($(call isTargetOs, windows), false)
$(eval $(call SetupJdkLibrary, BUILD_SYSLOOKUPLIB, \
NAME := syslookup, \
CFLAGS := $(CFLAGS_JDKLIB), \
CXXFLAGS := $(CXXFLAGS_JDKLIB), \
LDFLAGS := $(LDFLAGS_JDKLIB), \
LIBS := $(LIBCXX), \
))
else # windows
$(eval $(call SetupJdkLibrary, BUILD_SYSLOOKUPLIB, \
NAME := WinFallbackLookup, \
CFLAGS := $(CFLAGS_JDKLIB), \
CXXFLAGS := $(CXXFLAGS_JDKLIB), \
LDFLAGS := $(LDFLAGS_JDKLIB), \
LIBS := $(LIBCXX), \
))
endif
TARGETS += $(BUILD_SYSLOOKUPLIB)
################################################################################

View file

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

View file

@ -69,14 +69,23 @@ ifeq ($(call isTargetOs, windows), true)
BUILD_JDK_JTREG_EXECUTABLES_LIBS_exerevokeall := advapi32.lib BUILD_JDK_JTREG_EXECUTABLES_LIBS_exerevokeall := advapi32.lib
BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libAsyncStackWalk := /EHsc BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libAsyncStackWalk := /EHsc
BUILD_JDK_JTREG_LIBRARIES_CFLAGS_libAsyncInvokers := /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_libAsyncStackWalk := $(LIBCXX)
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncInvokers := $(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 else
BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava
BUILD_JDK_JTREG_LIBRARIES_LIBS_libDirectIO := -ljava BUILD_JDK_JTREG_LIBRARIES_LIBS_libDirectIO := -ljava
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libNativeThread := -pthread BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libNativeThread := -pthread
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncStackWalk := $(LIBCXX) -pthread BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncStackWalk := $(LIBCXX) -pthread
BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libAsyncInvokers := $(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 BUILD_JDK_JTREG_EXCLUDE += exerevokeall.c
ifeq ($(call isTargetOs, linux), true) ifeq ($(call isTargetOs, linux), true)
BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava

View file

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

View file

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

View file

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

View file

@ -36,6 +36,26 @@
extern struct JavaVM_ main_vm; 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) { void ProgrammableUpcallHandler::upcall_helper(JavaThread* thread, jobject rec, address buff) {
JavaThread* THREAD = thread; // For exception macros. JavaThread* THREAD = thread; // For exception macros.
ThreadInVMfromNative tiv(THREAD); 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); 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(); JavaThread* thread = JavaThread::current_or_null();
if (thread == nullptr) { if (thread == nullptr) {
JavaVM_ *vm = (JavaVM *)(&main_vm); JavaVM_ *vm = (JavaVM *)(&main_vm);
JNIEnv* p_env = nullptr; // unused 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); guarantee(result == JNI_OK, "Could not attach thread for upcall. JNI error code: %d", result);
*should_detach = true;
thread = JavaThread::current(); thread = JavaThread::current();
threadContext.attachedThread = thread;
assert(!thread->has_last_Java_frame(), "newly-attached thread not expected to have last Java frame"); assert(!thread->has_last_Java_frame(), "newly-attached thread not expected to have last Java frame");
} else {
*should_detach = false;
} }
return thread; return thread;
} }
void ProgrammableUpcallHandler::detach_current_thread() {
JavaVM_ *vm = (JavaVM *)(&main_vm);
vm->functions->DetachCurrentThread(vm);
}
// modelled after JavaCallWrapper::JavaCallWrapper // modelled after JavaCallWrapper::JavaCallWrapper
JavaThread* ProgrammableUpcallHandler::on_entry(OptimizedEntryBlob::FrameData* context) { 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; context->thread = thread;
assert(thread->can_call_java(), "must be able to call Java"); 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); JNIHandleBlock::release_block(context->new_handles, thread);
assert(!thread->has_pending_exception(), "Upcall can not throw an exception"); 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) { void ProgrammableUpcallHandler::attach_thread_and_do_upcall(jobject rec, address buff) {
bool should_detach = false; JavaThread* thread = maybe_attach_and_get_thread();
JavaThread* thread = maybe_attach_and_get_thread(&should_detach);
{ {
MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, thread)); MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, thread));
upcall_helper(thread, rec, buff); upcall_helper(thread, rec, buff);
} }
if (should_detach) {
detach_current_thread();
}
} }
const ProgrammableUpcallHandler& ProgrammableUpcallHandler::instance() { const ProgrammableUpcallHandler& ProgrammableUpcallHandler::instance() {

View file

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

View file

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

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,21 +23,22 @@
* questions. * questions.
*/ */
package jdk.incubator.foreign; package java.lang.foreign;
import jdk.internal.javac.PreviewFeature;
/** /**
* Represents a type which is <em>addressable</em>. An addressable type is one which can be projected down to * An object that may be projected down to a {@linkplain #address() memory address}.
* a {@linkplain #address() memory address}. Examples of addressable types are {@link MemorySegment}, * Examples of addressable types are {@link MemorySegment}, {@link MemoryAddress} and {@link VaList}.
* {@link MemoryAddress}, {@link VaList} and {@link NativeSymbol}.
* <p> * <p>
* The {@link Addressable} type is used by the {@link CLinker C linker} to model the types of * The {@link Addressable} type is used by a {@linkplain Linker linker} to model the types of
* {@link CLinker#downcallHandle(FunctionDescriptor) downcall handle} parameters that must be passed <em>by reference</em> * {@linkplain Linker#downcallHandle(FunctionDescriptor) downcall handle} parameters that must be passed <em>by reference</em>
* (e.g. memory addresses, va lists and upcall stubs). * (e.g. memory addresses, variable argument lists and upcall stubs).
* *
* @implSpec * @since 19
* Implementations of this interface are <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*/ */
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} * {@return the {@linkplain MemoryAddress memory address} associated with this addressable}

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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.foreign.MemoryAddressImpl;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.CallerSensitive;
import java.lang.invoke.MethodHandle; 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: * A memory address models a reference into a memory location. Memory addresses are typically obtained in one of the following ways:
* <ul> * <ul>
* <li>By calling {@link Addressable#address()} on an instance of type {@link Addressable} (e.g. a memory segment);</li> * <li>By calling {@link Addressable#address()} on an instance of type {@link Addressable} (e.g. a memory segment);</li>
* <li>By invoking a {@linkplain CLinker#downcallHandle(FunctionDescriptor) downcall method handle} which returns a pointer;</li> * <li>By invoking a {@linkplain Linker#downcallHandle(FunctionDescriptor) downcall method handle} which returns a pointer;</li>
* <li>By reading an address from memory, e.g. via {@link MemorySegment#get(ValueLayout.OfAddress, long)}.</li> * <li>By reading an address from memory, e.g. via {@link MemorySegment#get(ValueLayout.OfAddress, long)}; and</li>
* <li>By the invocation of an {@linkplain CLinker#upcallStub(MethodHandle, FunctionDescriptor, ResourceScope) upcall stub} which accepts a pointer. * <li>By the invocation of an {@linkplain Linker#upcallStub(MethodHandle, FunctionDescriptor, MemorySession) upcall stub} which accepts a pointer.</li>
* </ul> * </ul>
* A memory address is backed by a raw machine pointer, expressed as a {@linkplain #toRawLongValue() long value}. * A memory address is backed by a raw machine pointer, expressed as a {@linkplain #toRawLongValue() long value}.
* *
* <h2>Dereference</h2> * <h2>Dereferencing memory addresses</h2>
* *
* A memory address can be read or written using various methods provided in this class (e.g. {@link #get(ValueLayout.OfInt, long)}). * 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. * 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 : * {@snippet lang=java :
* MemoryAddress address = ... * MemoryAddress address = ...
* int value = address.get(ValueLayout.JAVA_INT, 0); * int value = address.get(ValueLayout.JAVA_INT, 0);
@ -63,18 +65,13 @@ import java.nio.ByteOrder;
* All the dereference methods in this class are <a href="package-summary.html#restricted"><em>restricted</em></a>: since * All the dereference methods in this class are <a href="package-summary.html#restricted"><em>restricted</em></a>: since
* a memory address does not feature temporal nor spatial bounds, the runtime has no way to check the correctness * a memory address does not feature temporal nor spatial bounds, the runtime has no way to check the correctness
* of the memory dereference operation. * of the memory dereference operation.
* <p>
* All implementations of this interface must be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>;
* programmers should treat instances that are {@linkplain #equals(Object) equal} as interchangeable and should not
* use instances for synchronization, or unpredictable behavior may occur. For example, in a future release,
* synchronization may fail. The {@code equals} method should be used for comparisons.
*
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
* *
* @implSpec * @implSpec
* Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>. * Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*
* @since 19
*/ */
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public sealed interface MemoryAddress extends Addressable permits MemoryAddressImpl { public sealed interface MemoryAddress extends Addressable permits MemoryAddressImpl {
/** /**
@ -83,14 +80,15 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
long toRawLongValue(); long toRawLongValue();
/** /**
* Creates a new memory address with given offset (in bytes), which might be negative, from current one. * Returns a memory address at given offset from this address.
* @param offset specified offset (in bytes), relative to this address, which should be used to create the new address. * @param offset specified offset (in bytes), relative to this address, which should be used to create the new address.
* @return a new memory address with given offset from current one. * Might be negative.
* @return a memory address with the given offset from current one.
*/ */
MemoryAddress addOffset(long offset); MemoryAddress addOffset(long offset);
/** /**
* Reads a UTF-8 encoded, null-terminated string from this address and offset. * Reads a UTF-8 encoded, null-terminated string from this address at the given offset.
* <p> * <p>
* This method always replaces malformed-input and unmappable-character * This method always replaces malformed-input and unmappable-character
* sequences with this charset's default replacement string. The {@link * 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 * 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. * 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}) * @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). * 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 * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
String getUtf8String(long offset); String getUtf8String(long offset);
/** /**
* Writes the given string to this address at given offset, converting it to a null-terminated byte sequence using UTF-8 encoding. * Writes the given string to this address at the given offset, converting it to a null-terminated byte sequence using UTF-8 encoding.
* <p> * <p>
* This method always replaces malformed-input and unmappable-character * This method always replaces malformed-input and unmappable-character
* sequences with this charset's default replacement string. The {@link * sequences with this charset's default replacement string. The {@link
* java.nio.charset.CharsetDecoder} class should be used when more control * java.nio.charset.CharsetDecoder} class should be used when more control
* over the decoding process is required. * over the decoding process is required.
* @param offset offset in bytes (relative to this address). The final address of this read operation can be expressed as {@code toRowLongValue() + offset}. * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash
* the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
* restricted methods, and use safe and supported functionalities, where possible.
* @param offset offset in bytes (relative to this address). Might be negative.
* The final address of this read operation can be expressed as {@code toRowLongValue() + offset}.
* @param str the Java string to be written at this address. * @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 * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
@ -146,14 +151,14 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
int hashCode(); 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); MemoryAddress NULL = new MemoryAddressImpl(0L);
/** /**
* Obtain a native memory address instance from given long address. * Creates a memory address from the given long value.
* @param value the long address. * @param value the long value representing a raw address.
* @return the new memory address instance. * @return a memory address with the given raw long value.
*/ */
static MemoryAddress ofLong(long value) { static MemoryAddress ofLong(long value) {
return value == 0 ? return value == 0 ?
@ -162,7 +167,7 @@ public sealed interface MemoryAddress extends Addressable permits MemoryAddressI
} }
/** /**
* Reads a byte from this address and offset with given layout. * Reads a byte at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be read. * @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. * @return a byte value read from this address.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
byte get(ValueLayout.OfByte layout, long offset); byte get(ValueLayout.OfByte layout, long offset);
/** /**
* Writes a byte to this address instance and offset with given layout. * Writes a byte at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be written. * @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. * @param value the byte value to be written.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
void set(ValueLayout.OfByte layout, long offset, byte value); void set(ValueLayout.OfByte layout, long offset, byte value);
/** /**
* Reads a boolean from this address and offset with given layout. * Reads a boolean at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be read. * @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. * @return a boolean value read from this address.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
boolean get(ValueLayout.OfBoolean layout, long offset); boolean get(ValueLayout.OfBoolean layout, long offset);
/** /**
* Writes a boolean to this address instance and offset with given layout. * Writes a boolean at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be written. * @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. * @param value the boolean value to be written.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
void set(ValueLayout.OfBoolean layout, long offset, boolean value); void set(ValueLayout.OfBoolean layout, long offset, boolean value);
/** /**
* Reads a char from this address and offset with given layout. * Reads a char at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be read. * @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. * @return a char value read from this address.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
char get(ValueLayout.OfChar layout, long offset); char get(ValueLayout.OfChar layout, long offset);
/** /**
* Writes a char to this address instance and offset with given layout. * Writes a char at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be written. * @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. * @param value the char value to be written.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
void set(ValueLayout.OfChar layout, long offset, char value); void set(ValueLayout.OfChar layout, long offset, char value);
/** /**
* Reads a short from this address and offset with given layout. * Reads a short at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be read. * @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. * @return a short value read from this address.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
short get(ValueLayout.OfShort layout, long offset); short get(ValueLayout.OfShort layout, long offset);
/** /**
* Writes a short to this address instance and offset with given layout. * Writes a short at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be written. * @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. * @param value the short value to be written.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
void set(ValueLayout.OfShort layout, long offset, short value); void set(ValueLayout.OfShort layout, long offset, short value);
/** /**
* Reads an int from this address and offset with given layout. * Reads an int at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be read. * @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. * @return an int value read from this address.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
int get(ValueLayout.OfInt layout, long offset); int get(ValueLayout.OfInt layout, long offset);
/** /**
* Writes an int to this address instance and offset with given layout. * Writes an int at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be written. * @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. * @param value the int value to be written.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
void set(ValueLayout.OfInt layout, long offset, int value); void set(ValueLayout.OfInt layout, long offset, int value);
/** /**
* Reads a float from this address and offset with given layout. * Reads a float at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be read. * @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. * @return a float value read from this address.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
float get(ValueLayout.OfFloat layout, long offset); float get(ValueLayout.OfFloat layout, long offset);
/** /**
* Writes a float to this address instance and offset with given layout. * Writes a float at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be written. * @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. * @param value the float value to be written.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
void set(ValueLayout.OfFloat layout, long offset, float value); void set(ValueLayout.OfFloat layout, long offset, float value);
/** /**
* Reads a long from this address and offset with given layout. * Reads a long at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be read. * @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. * @return a long value read from this address.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
long get(ValueLayout.OfLong layout, long offset); long get(ValueLayout.OfLong layout, long offset);
/** /**
* Writes a long to this address instance and offset with given layout. * Writes a long at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be written. * @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. * @param value the long value to be written.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
void set(ValueLayout.OfLong layout, long offset, long value); void set(ValueLayout.OfLong layout, long offset, long value);
/** /**
* Reads a double from this address and offset with given layout. * Reads a double at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be read. * @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. * @return a double value read from this address.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
double get(ValueLayout.OfDouble layout, long offset); double get(ValueLayout.OfDouble layout, long offset);
/** /**
* Writes a double to this address instance and offset with given layout. * Writes a double at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be written. * @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. * @param value the double value to be written.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
void set(ValueLayout.OfDouble layout, long offset, double value); void set(ValueLayout.OfDouble layout, long offset, double value);
/** /**
* Reads an address from this address and offset with given layout. * Reads an address at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be read. * @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. * @return an address value read from this address.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
MemoryAddress get(ValueLayout.OfAddress layout, long offset); MemoryAddress get(ValueLayout.OfAddress layout, long offset);
/** /**
* Writes an address to this address instance and offset with given layout. * Writes an address at the given offset from this address, with the given layout.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be written. * @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. * @param value the address value to be written.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout. * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout.
* @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
void set(ValueLayout.OfAddress layout, long offset, Addressable value); void set(ValueLayout.OfAddress layout, long offset, Addressable value);
/** /**
* Reads a char from this address and index, scaled by given layout size. * Reads a char from this address at the given index, scaled by the given layout size.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be read. * @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. * @return a char value read from this address.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout, * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size. * 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 * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
char getAtIndex(ValueLayout.OfChar layout, long index); char getAtIndex(ValueLayout.OfChar layout, long index);
/** /**
* Writes a char to this address instance and index, scaled by given layout size. * Writes a char to this address at the given index, scaled by the given layout size.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be written. * @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. * @param value the char value to be written.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout, * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size. * 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 * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
void setAtIndex(ValueLayout.OfChar layout, long index, char value); void setAtIndex(ValueLayout.OfChar layout, long index, char value);
/** /**
* Reads a short from this address and index, scaled by given layout size. * Reads a short from this address at the given index, scaled by the given layout size.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be read. * @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. * @return a short value read from this address.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout, * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size. * 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 * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
short getAtIndex(ValueLayout.OfShort layout, long index); short getAtIndex(ValueLayout.OfShort layout, long index);
/** /**
* Writes a short to this address instance and index, scaled by given layout size. * Writes a short to this address at the given index, scaled by the given layout size.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be written. * @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. * @param value the short value to be written.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout, * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size. * 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 * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
void setAtIndex(ValueLayout.OfShort layout, long index, short value); void setAtIndex(ValueLayout.OfShort layout, long index, short value);
/** /**
* Reads an int from this address and index, scaled by given layout size. * Reads an int from this address at the given index, scaled by the given layout size.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be read. * @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. * @return an int value read from this address.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout, * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size. * 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 * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
int getAtIndex(ValueLayout.OfInt layout, long index); int getAtIndex(ValueLayout.OfInt layout, long index);
/** /**
* Writes an int to this address instance and index, scaled by given layout size. * Writes an int to this address at the given index, scaled by the given layout size.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be written. * @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. * @param value the int value to be written.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout, * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size. * 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 * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
void setAtIndex(ValueLayout.OfInt layout, long index, int value); void setAtIndex(ValueLayout.OfInt layout, long index, int value);
/** /**
* Reads a float from this address and index, scaled by given layout size. * Reads a float from this address at the given index, scaled by the given layout size.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be read. * @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. * @return a float value read from this address.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout, * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size. * 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 * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
float getAtIndex(ValueLayout.OfFloat layout, long index); float getAtIndex(ValueLayout.OfFloat layout, long index);
/** /**
* Writes a float to this address instance and index, scaled by given layout size. * Writes a float to this address at the given index, scaled by the given layout size.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be written. * @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. * @param value the float value to be written.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout, * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size. * 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 * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
void setAtIndex(ValueLayout.OfFloat layout, long index, float value); void setAtIndex(ValueLayout.OfFloat layout, long index, float value);
/** /**
* Reads a long from this address and index, scaled by given layout size. * Reads a long from this address at the given index, scaled by the given layout size.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be read. * @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. * @return a long value read from this address.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout, * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size. * 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 * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
long getAtIndex(ValueLayout.OfLong layout, long index); long getAtIndex(ValueLayout.OfLong layout, long index);
/** /**
* Writes a long to this address instance and index, scaled by given layout size. * Writes a long to this address at the given index, scaled by the given layout size.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be written. * @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. * @param value the long value to be written.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout, * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size. * 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 * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
void setAtIndex(ValueLayout.OfLong layout, long index, long value); void setAtIndex(ValueLayout.OfLong layout, long index, long value);
/** /**
* Reads a double from this address and index, scaled by given layout size. * Reads a double from this address at the given index, scaled by the given layout size.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be read. * @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. * @return a double value read from this address.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout, * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size. * 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 * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
double getAtIndex(ValueLayout.OfDouble layout, long index); double getAtIndex(ValueLayout.OfDouble layout, long index);
/** /**
* Writes a double to this address instance and index, scaled by given layout size. * Writes a double to this address at the given index, scaled by the given layout size.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be written. * @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. * @param value the double value to be written.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout, * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size. * 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 * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
void setAtIndex(ValueLayout.OfDouble layout, long index, double value); void setAtIndex(ValueLayout.OfDouble layout, long index, double value);
/** /**
* Reads an address from this address and index, scaled by given layout size. * Reads an address from this address at the given index, scaled by the given layout size.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be read. * @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. * @return an address value read from this address.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout, * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size. * 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 * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive
MemoryAddress getAtIndex(ValueLayout.OfAddress layout, long index); MemoryAddress getAtIndex(ValueLayout.OfAddress layout, long index);
/** /**
* Writes an address to this address instance and index, scaled by given layout size. * Writes an address to this address at the given index, scaled by the given layout size.
* <p> * <p>
* This method is <a href="package-summary.html#restricted"><em>restricted</em></a>. * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
* Restricted methods are unsafe, and, if used incorrectly, their use might crash * 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. * restricted methods, and use safe and supported functionalities, where possible.
* *
* @param layout the layout of the memory region to be written. * @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. * @param value the address value to be written.
* @throws IllegalArgumentException if the dereference operation is * @throws IllegalArgumentException if the dereference operation is
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout, * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraints</a> in the provided layout,
* or if the layout alignment is greater than its size. * 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 * @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. * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
*/ */
@CallerSensitive @CallerSensitive

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -300,22 +300,17 @@ final class VarHandles {
} }
/** /**
* Creates a memory access VarHandle. * Creates a memory segment view var handle.
* *
* Resulting VarHandle will take a memory address as first argument, * The resulting var handle will take a memory segment as first argument (the segment to be dereferenced),
* and a certain number of coordinate {@code long} parameters, depending on the length * and a {@code long} as second argument (the offset into the segment).
* 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.
* *
* @param carrier the Java carrier type. * @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 alignmentMask alignment requirement to be checked upon access. In bytes. Expressed as a mask.
* @param byteOrder the byte order. * @param byteOrder the byte order.
* @return the created VarHandle. * @return the created VarHandle.
*/ */
static VarHandle makeMemoryAddressViewHandle(Class<?> carrier, boolean skipAlignmentMaskCheck, long alignmentMask, static VarHandle memorySegmentViewHandle(Class<?> carrier, long alignmentMask,
ByteOrder byteOrder) { ByteOrder byteOrder) {
if (!carrier.isPrimitive() || carrier == void.class || carrier == boolean.class) { if (!carrier.isPrimitive() || carrier == void.class || carrier == boolean.class) {
throw new IllegalArgumentException("Invalid carrier: " + carrier.getName()); throw new IllegalArgumentException("Invalid carrier: " + carrier.getName());
@ -325,19 +320,19 @@ final class VarHandles {
boolean exact = false; boolean exact = false;
if (carrier == byte.class) { 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) { } 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) { } 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) { } 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) { } 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) { } 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) { } else if (carrier == double.class) {
return maybeAdapt(new MemoryAccessVarHandleDoubleHelper(skipAlignmentMaskCheck, be, size, alignmentMask, exact)); return maybeAdapt(new VarHandleSegmentAsDoubles(be, size, alignmentMask, exact));
} else { } else {
throw new IllegalStateException("Cannot get here"); throw new IllegalStateException("Cannot get here");
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -33,7 +33,7 @@ class XXX {
private $type$ get$Type$(long a) { private $type$ get$Type$(long a) {
try { 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); return $fromBits$(x);
} finally { } finally {
Reference.reachabilityFence(this); Reference.reachabilityFence(this);
@ -62,7 +62,7 @@ class XXX {
#if[rw] #if[rw]
try { try {
$memtype$ y = $toBits$(x); $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 { } finally {
Reference.reachabilityFence(this); Reference.reachabilityFence(this);
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,9 +25,9 @@
package jdk.internal.foreign; package jdk.internal.foreign;
import jdk.incubator.foreign.MemorySegment; import java.lang.foreign.MemorySegment;
import jdk.incubator.foreign.SegmentAllocator; import java.lang.foreign.MemorySession;
import jdk.incubator.foreign.ResourceScope; import java.lang.foreign.SegmentAllocator;
public final class ArenaAllocator implements SegmentAllocator { public final class ArenaAllocator implements SegmentAllocator {
@ -39,12 +39,12 @@ public final class ArenaAllocator implements SegmentAllocator {
private long size = 0; private long size = 0;
private final long blockSize; private final long blockSize;
private final long arenaSize; private final long arenaSize;
private final ResourceScope scope; private final MemorySession session;
public ArenaAllocator(long blockSize, long arenaSize, ResourceScope scope) { public ArenaAllocator(long blockSize, long arenaSize, MemorySession session) {
this.blockSize = blockSize; this.blockSize = blockSize;
this.arenaSize = arenaSize; this.arenaSize = arenaSize;
this.scope = scope; this.session = session;
this.segment = newSegment(blockSize, 1); this.segment = newSegment(blockSize, 1);
} }
@ -60,17 +60,13 @@ public final class ArenaAllocator implements SegmentAllocator {
} }
} }
public ResourceScope scope() {
return scope;
}
private MemorySegment newSegment(long bytesSize, long bytesAlignment) { private MemorySegment newSegment(long bytesSize, long bytesAlignment) {
long allocatedSize = Utils.alignUp(bytesSize, bytesAlignment); long allocatedSize = Utils.alignUp(bytesSize, bytesAlignment);
if (size + allocatedSize > arenaSize) { if (size + allocatedSize > arenaSize) {
throw new OutOfMemoryError(); throw new OutOfMemoryError();
} }
size += allocatedSize; size += allocatedSize;
return MemorySegment.allocateNative(bytesSize, bytesAlignment, scope); return MemorySegment.allocateNative(bytesSize, bytesAlignment, session);
} }
@Override @Override

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,7 +25,7 @@
*/ */
package jdk.internal.foreign; package jdk.internal.foreign;
import static jdk.incubator.foreign.ValueLayout.ADDRESS; import static java.lang.foreign.ValueLayout.ADDRESS;
import static sun.security.action.GetPropertyAction.privilegedGetProperty; import static sun.security.action.GetPropertyAction.privilegedGetProperty;
public enum CABI { public enum CABI {
@ -56,7 +56,7 @@ public enum CABI {
current = LinuxAArch64; current = LinuxAArch64;
} }
} else { } else {
throw new ExceptionInInitializerError( throw new UnsupportedOperationException(
"Unsupported os, arch, or address size: " + os + ", " + arch + ", " + addressSize); "Unsupported os, arch, or address size: " + os + ", " + arch + ", " + addressSize);
} }
} }

View file

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

View file

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

View file

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

View file

@ -0,0 +1,122 @@
/*
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.internal.foreign;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
import java.nio.ByteBuffer;
import jdk.internal.access.foreign.UnmapperProxy;
import jdk.internal.misc.ScopedMemoryAccess;
/**
* Implementation for a mapped memory segments. A mapped memory segment is a native memory segment, which
* additionally features an {@link UnmapperProxy} object. This object provides detailed information about the
* memory mapped segment, such as the file descriptor associated with the mapping. This information is crucial
* in order to correctly reconstruct a byte buffer object from the segment (see {@link #makeByteBuffer()}).
*/
public class MappedMemorySegmentImpl extends NativeMemorySegmentImpl {
private final UnmapperProxy unmapper;
static ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
public MappedMemorySegmentImpl(long min, UnmapperProxy unmapper, long length, int mask, MemorySession session) {
super(min, length, mask, session);
this.unmapper = unmapper;
}
@Override
ByteBuffer makeByteBuffer() {
return nioAccess.newMappedByteBuffer(unmapper, min, (int)length, null,
session == MemorySessionImpl.GLOBAL ? null : this);
}
@Override
MappedMemorySegmentImpl dup(long offset, long size, int mask, MemorySession session) {
return new MappedMemorySegmentImpl(min + offset, unmapper, size, mask, session);
}
// mapped segment methods
@Override
public MappedMemorySegmentImpl asSlice(long offset, long newSize) {
return (MappedMemorySegmentImpl)super.asSlice(offset, newSize);
}
@Override
public boolean isMapped() {
return true;
}
// support for mapped segments
public MemorySegment segment() {
return MappedMemorySegmentImpl.this;
}
public void load() {
SCOPED_MEMORY_ACCESS.load(sessionImpl(), min, unmapper.isSync(), length);
}
public void unload() {
SCOPED_MEMORY_ACCESS.unload(sessionImpl(), min, unmapper.isSync(), length);
}
public boolean isLoaded() {
return SCOPED_MEMORY_ACCESS.isLoaded(sessionImpl(), min, unmapper.isSync(), length);
}
public void force() {
SCOPED_MEMORY_ACCESS.force(sessionImpl(), unmapper.fileDescriptor(), min, unmapper.isSync(), 0, length);
}
public static class EmptyMappedMemorySegmentImpl extends MappedMemorySegmentImpl {
public EmptyMappedMemorySegmentImpl(int modes, MemorySession session) {
super(0, null, 0, modes, session);
}
@Override
public void load() {
// do nothing
}
@Override
public void unload() {
// do nothing
}
@Override
public boolean isLoaded() {
return true;
}
@Override
public void force() {
// do nothing
}
}
}

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,8 +25,8 @@
*/ */
package jdk.internal.foreign; package jdk.internal.foreign;
import jdk.incubator.foreign.MemoryLayout; import java.lang.foreign.MemoryLayout;
import jdk.incubator.foreign.ValueLayout; import java.lang.foreign.ValueLayout;
public class PlatformLayouts { public class PlatformLayouts {
public static <Z extends MemoryLayout> Z pick(Z sysv, Z win64, Z aarch64) { public static <Z extends MemoryLayout> Z pick(Z sysv, Z win64, Z aarch64) {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,8 +25,6 @@
package jdk.internal.foreign; package jdk.internal.foreign;
import jdk.incubator.foreign.ResourceScope;
public interface Scoped { public interface Scoped {
ResourceScope scope(); MemorySessionImpl sessionImpl();
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -772,11 +772,23 @@ public final class ModuleBootstrap {
} }
} }
private static final boolean HAS_ENABLE_NATIVE_ACCESS_FLAG;
private static final Set<String> NATIVE_ACCESS_MODULES;
public static boolean hasEnableNativeAccessFlag() {
return HAS_ENABLE_NATIVE_ACCESS_FLAG;
}
static {
NATIVE_ACCESS_MODULES = decodeEnableNativeAccess();
HAS_ENABLE_NATIVE_ACCESS_FLAG = !NATIVE_ACCESS_MODULES.isEmpty();
}
/** /**
* Process the --enable-native-access option to grant access to restricted methods to selected modules. * Process the --enable-native-access option to grant access to restricted methods to selected modules.
*/ */
private static void addEnableNativeAccess(ModuleLayer layer) { private static void addEnableNativeAccess(ModuleLayer layer) {
for (String name : decodeEnableNativeAccess()) { for (String name : NATIVE_ACCESS_MODULES) {
if (name.equals("ALL-UNNAMED")) { if (name.equals("ALL-UNNAMED")) {
JLA.addEnableNativeAccessAllUnnamed(); JLA.addEnableNativeAccessAllUnnamed();
} else { } else {

View file

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

View file

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

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