From 2807388298a40b5426827a7876706d2c17fd84d4 Mon Sep 17 00:00:00 2001 From: Joachim Kern Date: Thu, 9 Nov 2023 08:56:00 +0000 Subject: [PATCH 1/9] 8319104: GtestWrapper crashes with SIGILL in AsyncLogTest::test_asynclog_raw on AIX opt Reviewed-by: mdoerr, stuefe --- test/hotspot/gtest/logging/test_logTagSet.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/test/hotspot/gtest/logging/test_logTagSet.cpp b/test/hotspot/gtest/logging/test_logTagSet.cpp index b6133673c45..2243762365b 100644 --- a/test/hotspot/gtest/logging/test_logTagSet.cpp +++ b/test/hotspot/gtest/logging/test_logTagSet.cpp @@ -32,7 +32,7 @@ #include "unittest.hpp" // Test the default level for each tagset -TEST(LogTagSet, defaults) { +TEST_VM(LogTagSet, defaults) { for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { char buf[256]; ts->label(buf, sizeof(buf)); @@ -45,7 +45,7 @@ TEST(LogTagSet, defaults) { } } -TEST(LogTagSet, has_output) { +TEST_VM(LogTagSet, has_output) { LogTagSet& ts = LogTagSetMapping::tagset(); ts.set_output_level(LogConfiguration::StderrLog, LogLevel::Trace); EXPECT_TRUE(ts.has_output(LogConfiguration::StderrLog)); @@ -54,14 +54,14 @@ TEST(LogTagSet, has_output) { EXPECT_FALSE(ts.has_output(LogConfiguration::StderrLog)); } -TEST(LogTagSet, ntags) { +TEST_VM(LogTagSet, ntags) { const LogTagSet& ts = LogTagSetMapping::tagset(); EXPECT_EQ(1u, ts.ntags()); const LogTagSet& ts2 = LogTagSetMapping::tagset(); EXPECT_EQ(5u, ts2.ntags()); } -TEST(LogTagSet, is_level) { +TEST_VM(LogTagSet, is_level) { LogTagSet& ts = LogTagSetMapping::tagset(); // Set info level on stdout and verify that is_level() reports correctly ts.set_output_level(LogConfiguration::StdoutLog, LogLevel::Info); @@ -72,9 +72,10 @@ TEST(LogTagSet, is_level) { EXPECT_FALSE(ts.is_level(LogLevel::Trace)); ts.set_output_level(LogConfiguration::StdoutLog, LogLevel::Default); EXPECT_TRUE(ts.is_level(LogLevel::Default)); + ts.set_output_level(LogConfiguration::StdoutLog, LogLevel::Off); } -TEST(LogTagSet, level_for) { +TEST_VM(LogTagSet, level_for) { LogOutput* output = LogConfiguration::StdoutLog; LogTagSet& ts = LogTagSetMapping::tagset(); for (uint i = 0; i < LogLevel::Count; i++) { @@ -83,10 +84,10 @@ TEST(LogTagSet, level_for) { ts.set_output_level(output, level); EXPECT_EQ(level, ts.level_for(output)); } - ts.set_output_level(output, LogLevel::Default); + ts.set_output_level(output, LogLevel::Off); } -TEST(LogTagSet, contains) { +TEST_VM(LogTagSet, contains) { // Verify that contains works as intended for a few predetermined tagsets const LogTagSet& ts = LogTagSetMapping::tagset(); EXPECT_TRUE(ts.contains(PREFIX_LOG_TAG(logging))); @@ -112,7 +113,7 @@ TEST(LogTagSet, contains) { EXPECT_TRUE(ts4.contains(PREFIX_LOG_TAG(heap))); } -TEST(LogTagSet, label) { +TEST_VM(LogTagSet, label) { char buf[256]; const LogTagSet& ts = LogTagSetMapping::tagset(); ASSERT_NE(-1, ts.label(buf, sizeof(buf))); @@ -138,7 +139,7 @@ TEST(LogTagSet, label) { } -TEST(LogTagSet, duplicates) { +TEST_VM(LogTagSet, duplicates) { for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { char ts_name[512]; ts->label(ts_name, sizeof(ts_name), ","); From 198009b468e8eb660ce55d5fed28e54e77e24d53 Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Thu, 9 Nov 2023 08:57:44 +0000 Subject: [PATCH 2/9] 8318962: Update ProcessTools javadoc with suggestions in 8315097 Reviewed-by: rriggs --- .../jdk/test/lib/process/ProcessTools.java | 94 +++++++++++++------ 1 file changed, 66 insertions(+), 28 deletions(-) diff --git a/test/lib/jdk/test/lib/process/ProcessTools.java b/test/lib/jdk/test/lib/process/ProcessTools.java index b4ee084d69f..db80a439f2b 100644 --- a/test/lib/jdk/test/lib/process/ProcessTools.java +++ b/test/lib/jdk/test/lib/process/ProcessTools.java @@ -492,12 +492,21 @@ private static void printStack(Thread t, StackTraceElement[] stack) { } /** - * Create ProcessBuilder using the java launcher from the jdk to be tested. - * The default jvm options from jtreg, test.vm.opts and test.java.opts, are added. - *

- * The command line will be like: - * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds - * Create ProcessBuilder using the java launcher from the jdk to be tested. + * Create ProcessBuilder using the java launcher from the jdk to + * be tested. The default jvm options from jtreg, test.vm.opts and + * test.java.opts, are added. + * + *

Unless the "test.noclasspath" property is "true" the + * classpath property "java.class.path" is appended to the command + * line and the environment of the ProcessBuilder is modified to + * remove "CLASSPATH". If the property "test.thread.factory" is + * provided the command args are updated and appended to invoke + * ProcessTools main() and provide the name of the thread factory. + * + *

The "-Dtest.thread.factory" is appended to the arguments + * with the thread factory value. The remaining command args are + * scanned for unsupported options and are appended to the + * ProcessBuilder. * * @param command Arguments to pass to the java command. * @return The ProcessBuilder instance representing the java command. @@ -507,12 +516,21 @@ public static ProcessBuilder createTestJavaProcessBuilder(List command) } /** - * Create ProcessBuilder using the java launcher from the jdk to be tested. - * The default jvm options from jtreg, test.vm.opts and test.java.opts, are added. - *

- * The command line will be like: - * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds - * Create ProcessBuilder using the java launcher from the jdk to be tested. + * Create ProcessBuilder using the java launcher from the jdk to + * be tested. The default jvm options from jtreg, test.vm.opts and + * test.java.opts, are added. + * + *

Unless the "test.noclasspath" property is "true" the + * classpath property "java.class.path" is appended to the command + * line and the environment of the ProcessBuilder is modified to + * remove "CLASSPATH". If the property "test.thread.factory" is + * provided the command args are updated and appended to invoke + * ProcessTools main() and provide the name of the thread factory. + * + *

The "-Dtest.thread.factory" is appended to the arguments + * with the thread factory value. The remaining command args are + * scanned for unsupported options and are appended to the + * ProcessBuilder. * * @param command Arguments to pass to the java command. * @return The ProcessBuilder instance representing the java command. @@ -536,6 +554,18 @@ public static ProcessBuilder createTestJavaProcessBuilder(String... command) { * it in combination with @requires vm.flagless JTREG * anotation as to not waste energy and test resources. * + *

Unless the "test.noclasspath" property is "true" the + * classpath property "java.class.path" is appended to the command + * line and the environment of the ProcessBuilder is modified to + * remove "CLASSPATH". If the property "test.thread.factory" is + * provided the command args are updated and appended to invoke + * ProcessTools main() and provide the name of the thread factory. + * + *

The "-Dtest.thread.factory" is appended to the arguments + * with the thread factory value. The remaining command args are + * scanned for unsupported options and are appended to the + * ProcessBuilder. + * * @param command Arguments to pass to the java command. * @return The ProcessBuilder instance representing the java command. */ @@ -558,6 +588,18 @@ public static ProcessBuilder createLimitedTestJavaProcessBuilder(List co * it in combination with @requires vm.flagless JTREG * anotation as to not waste energy and test resources. * + *

Unless the "test.noclasspath" property is "true" the + * classpath property "java.class.path" is appended to the command + * line and the environment of the ProcessBuilder is modified to + * remove "CLASSPATH". If the property "test.thread.factory" is + * provided the command args are updated and appended to invoke + * ProcessTools main() and provide the name of the thread factory. + * + *

The "-Dtest.thread.factory" is appended to the arguments + * with the thread factory value. The remaining command args are + * scanned for unsupported options and are appended to the + * ProcessBuilder. + * * @param command Arguments to pass to the java command. * @return The ProcessBuilder instance representing the java command. */ @@ -566,14 +608,12 @@ public static ProcessBuilder createLimitedTestJavaProcessBuilder(String... comma } /** - * Executes a test jvm process, waits for it to finish and returns the process output. - * The default jvm options from jtreg, test.vm.opts and test.java.opts, are added. - * The java from the test.jdk is used to execute the command. - *

- * The command line will be like: - * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds - *

- * The jvm process will have exited before this method returns. + * Executes a test jvm process, waits for it to finish and returns + * the process output. + * + *

The process is created using runtime flags set up by: + * {@link #createTestJavaProcessBuilder(String...)}. The + * jvm process will have exited before this method returns. * * @param cmds User specified arguments. * @return The output from the process. @@ -583,14 +623,12 @@ public static OutputAnalyzer executeTestJvm(List cmds) throws Exception } /** - * Executes a test jvm process, waits for it to finish and returns the process output. - * The default jvm options from jtreg, test.vm.opts and test.java.opts, are added. - * The java from the test.jdk is used to execute the command. - *

- * The command line will be like: - * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds - *

- * The jvm process will have exited before this method returns. + * Executes a test jvm process, waits for it to finish and returns + * the process output. + * + *

The process is created using runtime flags set up by: + * {@link #createTestJavaProcessBuilder(String...)}. The + * jvm process will have exited before this method returns. * * @param cmds User specified arguments. * @return The output from the process. From 7283bfd7c67172aea7c86ccfa05f3e9004af0ef3 Mon Sep 17 00:00:00 2001 From: Christian Hagedorn Date: Thu, 9 Nov 2023 09:31:54 +0000 Subject: [PATCH 3/9] 8310886: C2 SuperWord: Two nodes should be isomorphic if they are loop invariant but pinned at different nodes outside the loop Reviewed-by: kvn, epeter --- .../compiler/lib/ir_framework/IRNode.java | 16 ++++ .../ir_framework/test/IREncodingPrinter.java | 1 + .../loopopts/superword/TestMulAddS2I.java | 96 +++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 1778c2292df..58d17f3a0d4 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -927,6 +927,22 @@ public class IRNode { beforeMatchingNameRegex(MUL, "Mul(I|L|F|D)"); } + public static final String MUL_ADD_S2I = PREFIX + "MUL_ADD_S2I" + POSTFIX; + static { + beforeMatchingNameRegex(MUL_ADD_S2I, "MulAddS2I"); + } + + public static final String MUL_ADD_VS2VI = VECTOR_PREFIX + "MUL_ADD_VS2VI" + POSTFIX; + static { + vectorNode(MUL_ADD_VS2VI, "MulAddVS2VI", TYPE_INT); + } + + // Can only be used if avx512_vnni is available. + public static final String MUL_ADD_VS2VI_VNNI = PREFIX + "MUL_ADD_VS2VI_VNNI" + POSTFIX; + static { + machOnly(MUL_ADD_VS2VI_VNNI, "vmuladdaddS2I_reg"); + } + public static final String MUL_D = PREFIX + "MUL_D" + POSTFIX; static { beforeMatchingNameRegex(MUL_D, "MulD"); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java b/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java index 00698903482..939267234bd 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/test/IREncodingPrinter.java @@ -98,6 +98,7 @@ public class IREncodingPrinter { "avx512dq", "avx512vl", "avx512f", + "avx512_vnni", // AArch64 "sha3", "asimd", diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java new file mode 100644 index 00000000000..78e97f26817 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMulAddS2I.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023, 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. + * + * 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. + */ + +/** + * @test + * @bug 8310886 + * @requires os.arch == "x86_64" | os.arch == "aarch64" + * @summary Test MulAddS2I vectorization. + * @library /test/lib / + * @run driver compiler.loopopts.superword.TestMulAddS2I + */ + +package compiler.loopopts.superword; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; + +public class TestMulAddS2I { + static final int RANGE = 1024; + static final int ITER = RANGE/2 - 1; + + static short[] sArr1 = new short[RANGE]; + static short[] sArr2 = new short[RANGE]; + static final int[] GOLDEN; + + static { + for (int i = 0; i < RANGE; i++) { + sArr1[i] = (short)(AbstractInfo.getRandom().nextInt()); + sArr2[i] = (short)(AbstractInfo.getRandom().nextInt()); + } + GOLDEN = test(); + } + + + public static void main(String[] args) { + if (Platform.isX64() || Platform.isX86()) { + TestFramework.runWithFlags("-XX:+UseUnalignedLoadStores"); + TestFramework.runWithFlags("-XX:-UseUnalignedLoadStores"); + } else { + TestFramework.run(); + } + } + + @Run(test = "test") + @Warmup(0) + public static void run() { + compare(test()); + } + + public static void compare(int[] out) { + for (int i = 0; i < ITER; i++) { + Asserts.assertEQ(out[i], GOLDEN[i], "wrong result for out[" + i + "]"); + } + } + + @Test + @IR(applyIfCPUFeature = {"sse2", "true"}, applyIf = {"UseUnalignedLoadStores", "true"}, + counts = {IRNode.MUL_ADD_S2I, "> 0", IRNode.MUL_ADD_VS2VI, "> 0"}) + @IR(applyIfCPUFeature = {"sse2", "true"}, applyIf = {"UseUnalignedLoadStores", "false"}, + failOn = {IRNode.MUL_ADD_VS2VI}, // Can only pack LoadS if UseUnalignedLoadStores is true (default if sse4.2) + counts = {IRNode.MUL_ADD_S2I, "> 0"}) + @IR(applyIfCPUFeature = {"asimd", "true"}, applyIf = {"MaxVectorSize", "16"}, // AD file requires vector_length = 16 + counts = {IRNode.MUL_ADD_S2I, "> 0", IRNode.MUL_ADD_VS2VI, "> 0"}) + @IR(applyIfCPUFeature = {"avx512_vnni", "true"}, applyIf = {"UseUnalignedLoadStores", "true"}, + counts = {IRNode.MUL_ADD_S2I, "> 0", IRNode.MUL_ADD_VS2VI_VNNI, "> 0"}) + public static int[] test() { + int[] out = new int[ITER]; + int[] out2 = new int[ITER]; + for (int i = 0; i < ITER; i++) { + out[i] += ((sArr1[2*i] * sArr1[2*i]) + (sArr1[2*i+1] * sArr1[2*i+1])); + out2[i] += out[i]; + } + return out; + } +} From 39c4084b84a79a30142f3cda324b6d28630744d7 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Thu, 9 Nov 2023 10:14:03 +0000 Subject: [PATCH 4/9] 8316746: Top of lock-stack does not match the unlocked object Reviewed-by: rrich, lucy --- .../jtreg/compiler/locks/TestUnlockOSR.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/locks/TestUnlockOSR.java diff --git a/test/hotspot/jtreg/compiler/locks/TestUnlockOSR.java b/test/hotspot/jtreg/compiler/locks/TestUnlockOSR.java new file mode 100644 index 00000000000..f2133b49658 --- /dev/null +++ b/test/hotspot/jtreg/compiler/locks/TestUnlockOSR.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 SAP SE. 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. + * + * 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. + * + */ + +/* + * @test + * @bug 8316746 + * @summary During OSR, locks get transferred from interpreter frame. + * Check that unlocking 2 such locks works in the OSR compiled nmethod. + * Some platforms verify that the unlocking happens in the corrent order. + * + * @run main/othervm -Xbatch TestUnlockOSR + */ + +public class TestUnlockOSR { + static void test_method(Object a, Object b, int limit) { + synchronized(a) { // allocate space for monitors + synchronized(b) { + } + } // free space to test allocation in reused space + synchronized(a) { // reuse the space + synchronized(b) { + for (int i = 0; i < limit; i++) {} + } + } + } + + public static void main(String[] args) { + Object a = new TestUnlockOSR(), + b = new TestUnlockOSR(); + // avoid uncommon trap before last unlocks + for (int i = 0; i < 100; i++) { test_method(a, b, 0); } + // trigger OSR + test_method(a, b, 100000); + } +} From 792bd3dc5bf75dce3cb45329a37ead87d340bcc3 Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Thu, 9 Nov 2023 15:18:43 +0000 Subject: [PATCH 5/9] 8319324: FFM: Reformat javadocs Reviewed-by: mcimadamore --- .../java/lang/foreign/AddressLayout.java | 62 +- .../classes/java/lang/foreign/Arena.java | 198 +- .../java/lang/foreign/FunctionDescriptor.java | 80 +- .../java/lang/foreign/GroupLayout.java | 25 +- .../classes/java/lang/foreign/Linker.java | 711 ++--- .../java/lang/foreign/MemoryLayout.java | 792 +++--- .../java/lang/foreign/MemorySegment.java | 2312 ++++++++++------- .../java/lang/foreign/PaddingLayout.java | 8 +- .../java/lang/foreign/SegmentAllocator.java | 436 ++-- .../java/lang/foreign/SequenceLayout.java | 73 +- .../java/lang/foreign/StructLayout.java | 3 +- .../java/lang/foreign/SymbolLookup.java | 193 +- .../java/lang/foreign/UnionLayout.java | 3 +- .../java/lang/foreign/ValueLayout.java | 98 +- .../java/lang/foreign/package-info.java | 161 +- .../java/nio/channels/FileChannel.java | 26 +- 16 files changed, 3008 insertions(+), 2173 deletions(-) diff --git a/src/java.base/share/classes/java/lang/foreign/AddressLayout.java b/src/java.base/share/classes/java/lang/foreign/AddressLayout.java index 137152d78cc..49cab25a75f 100644 --- a/src/java.base/share/classes/java/lang/foreign/AddressLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/AddressLayout.java @@ -35,23 +35,27 @@ import java.util.Optional; /** - * A value layout used to model the address of some region of memory. The carrier associated with an address layout is - * {@code MemorySegment.class}. The size and alignment of an address layout are platform-dependent - * (e.g. on a 64-bit platform, the size and alignment of an address layout are set to 8 bytes). + * A value layout used to model the address of some region of memory. The carrier + * associated with an address layout is {@code MemorySegment.class}. The size and + * alignment of an address layout are platform-dependent (e.g. on a 64-bit platform, + * the size and alignment of an address layout are set to 8 bytes). *

- * An address layout may optionally feature a {@linkplain #targetLayout() target layout}. An address layout with - * target layout {@code T} can be used to model the address of a region of memory whose layout is {@code T}. - * For instance, an address layout with target layout {@link ValueLayout#JAVA_INT} can be used to model the address - * of a region of memory that is 4 bytes long. Specifying a target layout can be useful in the following situations: + * An address layout may optionally feature a {@linkplain #targetLayout() target layout}. + * An address layout with target layout {@code T} can be used to model the address of a + * region of memory whose layout is {@code T}. For instance, an address layout with + * target layout {@link ValueLayout#JAVA_INT} can be used to model the address of a + * region of memory that is 4 bytes long. Specifying a target layout can be useful in + * the following situations: *

    - *
  • When accessing a memory segment that has been obtained by reading an address from another - * memory segment, e.g. using {@link MemorySegment#getAtIndex(AddressLayout, long)};
  • + *
  • When accessing a memory segment that has been obtained by reading an address from + * another memory segment, e.g. using {@link MemorySegment#getAtIndex(AddressLayout, long)};
  • *
  • When creating a downcall method handle, using {@link Linker#downcallHandle(FunctionDescriptor, Option...)}; *
  • When creating an upcall stub, using {@link Linker#upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...)}. *
* * @implSpec - * Implementations of this interface are immutable, thread-safe and value-based. + * Implementations of this interface are immutable, thread-safe and + * value-based. * * @see #ADDRESS * @see #ADDRESS_UNALIGNED @@ -84,24 +88,28 @@ public sealed interface AddressLayout extends ValueLayout permits ValueLayouts.O AddressLayout withOrder(ByteOrder order); /** - * Returns an address layout with the same carrier, alignment constraint, name and order as this address layout, - * but associated with the specified target layout. The returned address layout allows raw addresses to be accessed - * as {@linkplain MemorySegment memory segments} whose size is set to the size of the specified layout. Moreover, - * if the accessed raw address is not compatible with the alignment constraint in the provided layout, - * {@linkplain IllegalArgumentException} will be thrown. + * Returns an address layout with the same carrier, alignment constraint, name and + * order as this address layout, but associated with the specified target layout. + * The returned address layout allows raw addresses to be accessed as + * {@linkplain MemorySegment memory segments} whose size is set to the size of the + * specified layout. Moreover, if the accessed raw address is not compatible with + * the alignment constraint in the provided layout, {@linkplain IllegalArgumentException} + * will be thrown. * @apiNote - * This method can also be used to create an address layout which, when used, creates native memory - * segments with maximal size (e.g. {@linkplain Long#MAX_VALUE}). This can be done by using a target sequence - * layout with unspecified size, as follows: + * This method can also be used to create an address layout which, when used, creates + * native memory segments with maximal size (e.g. {@linkplain Long#MAX_VALUE}). This + * can be done by using a target sequence layout with unspecified size, as follows: * {@snippet lang = java: * AddressLayout addressLayout = ... * AddressLayout unboundedLayout = addressLayout.withTargetLayout( * MemoryLayout.sequenceLayout(Long.MAX_VALUE, ValueLayout.JAVA_BYTE)); *} * - * @param layout the target layout. - * @return an address layout with the same characteristics as this layout, but with the provided target layout. - * @throws IllegalCallerException If the caller is in a module that does not have native access enabled + * @param layout the target layout + * @return an address layout with same characteristics as this layout, but with the + * provided target layout + * @throws IllegalCallerException If the caller is in a module that does not have + * native access enabled * @see #targetLayout() */ @CallerSensitive @@ -109,18 +117,20 @@ public sealed interface AddressLayout extends ValueLayout permits ValueLayouts.O AddressLayout withTargetLayout(MemoryLayout layout); /** - * Returns an address layout with the same carrier, alignment constraint, name and order as this address layout, - * but with no target layout. + * Returns an address layout with the same carrier, alignment constraint, name and + * order as this address layout, but with no target layout. * - * @apiNote This can be useful to compare two address layouts that have different target layouts, but are otherwise equal. + * @apiNote This can be useful to compare two address layouts that have different + * target layouts, but are otherwise equal. * - * @return an address layout with the same characteristics as this layout, but with no target layout. + * @return an address layout with same characteristics as this layout, but with no + * target layout * @see #targetLayout() */ AddressLayout withoutTargetLayout(); /** - * {@return the target layout associated with this address layout (if any)}. + * {@return the target layout associated with this address layout (if any)} */ Optional targetLayout(); diff --git a/src/java.base/share/classes/java/lang/foreign/Arena.java b/src/java.base/share/classes/java/lang/foreign/Arena.java index cdd5019b53d..adfc3a1fe6b 100644 --- a/src/java.base/share/classes/java/lang/foreign/Arena.java +++ b/src/java.base/share/classes/java/lang/foreign/Arena.java @@ -31,47 +31,53 @@ import java.lang.foreign.MemorySegment.Scope; /** - * An arena controls the lifecycle of native memory segments, providing both flexible allocation and timely deallocation. + * An arena controls the lifecycle of native memory segments, providing both flexible + * allocation and timely deallocation. *

- * An arena has a {@linkplain MemorySegment.Scope scope} - the arena scope. All the segments allocated - * by the arena are associated with the arena scope. As such, the arena determines the temporal bounds - * of all the memory segments allocated by it. + * An arena has a {@linkplain MemorySegment.Scope scope} - the arena scope. + * All the segments allocated by the arena are associated with the arena scope. As such, + * the arena determines the temporal bounds of all the memory segments allocated by it. *

- * Moreover, an arena also determines whether access to memory segments allocated by it should be - * {@linkplain MemorySegment#isAccessibleBy(Thread) restricted} to specific threads. - * An arena is a {@link SegmentAllocator} and features several allocation methods that can be used by clients - * to obtain native segments. + * Moreover, an arena also determines whether access to memory segments allocated by it + * should be {@linkplain MemorySegment#isAccessibleBy(Thread) restricted} to specific + * threads. An arena is a {@link SegmentAllocator} and features several allocation + * methods that can be used by clients to obtain native segments. *

* The simplest arena is the {@linkplain Arena#global() global arena}. The global arena - * features an unbounded lifetime. The scope of the global arena is the global scope. - * As such, native segments allocated with the global arena are always accessible and their backing regions - * of memory are never deallocated. - * Moreover, memory segments allocated with the global arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread. + * features an unbounded lifetime. The scope of the global arena is the global + * scope. As such, native segments allocated with the global arena are always accessible + * and their backing regions of memory are never deallocated. Moreover, memory segments + * allocated with the global arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} + * from any thread. * {@snippet lang = java: * MemorySegment segment = Arena.global().allocate(100, 1); // @highlight regex='global()' * ... * // segment is never deallocated! *} *

- * Alternatively, clients can obtain an {@linkplain Arena#ofAuto() automatic arena}, that is an arena - * which features a bounded lifetime that is managed, automatically, by the garbage collector. The scope - * of an automatic arena is an automatic scope. As such, the regions - * of memory backing memory segments allocated with the automatic arena are deallocated at some unspecified time - * after the automatic arena (and all the segments allocated by it) becomes - * unreachable, as shown below: + * Alternatively, clients can obtain an {@linkplain Arena#ofAuto() automatic arena}, that + * is an arena which features a bounded lifetime that is managed, automatically, + * by the garbage collector. The scope of an automatic arena is an automatic scope. As + * such, the regions of memory backing memory segments allocated with the automatic arena + * are deallocated at some unspecified time after the automatic arena (and all + * the segments allocated by it) becomes unreachable, + * as shown below: * {@snippet lang = java: * MemorySegment segment = Arena.ofAuto().allocate(100, 1); // @highlight regex='ofAuto()' * ... * segment = null; // the segment region becomes available for deallocation after this point *} - * Memory segments allocated with an automatic arena can also be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread. + * Memory segments allocated with an automatic arena can also be + * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread. *

- * Rather than leaving deallocation in the hands of the Java runtime, clients will often wish to exercise control over - * the timing of deallocation for regions of memory that back memory segments. Two kinds of arenas support this, - * namely {@linkplain #ofConfined() confined} and {@linkplain #ofShared() shared} arenas. They both feature - * bounded lifetimes that are managed manually. For instance, when a confined arena is {@linkplain #close() closed} - * successfully, its scope is {@linkplain Scope#isAlive() invalidated}. As a result, all the memory segments allocated - * by the arena can no longer be accessed, and their regions of memory are deallocated: + * Rather than leaving deallocation in the hands of the Java runtime, clients will often + * wish to exercise control over the timing of deallocation for regions of memory that + * back memory segments. Two kinds of arenas support this, namely {@linkplain #ofConfined() confined} + * and {@linkplain #ofShared() shared} arenas. They both feature bounded lifetimes that + * are managed manually. For instance, when a confined arena is {@linkplain #close() closed} + * successfully, its scope is {@linkplain Scope#isAlive() invalidated}. As a result, all + * the memory segments allocated by the arena can no longer be accessed, and their + * regions of memory are deallocated: * * {@snippet lang = java: * MemorySegment segment = null; @@ -82,9 +88,10 @@ * segment.get(ValueLayout.JAVA_BYTE, 0); // throws IllegalStateException *} * - * Memory segments allocated with a {@linkplain #ofConfined() confined arena} can only be accessed (and closed) by the - * thread that created the arena. If access to a memory segment from multiple threads is required, clients can allocate - * segments in a {@linkplain #ofShared() shared arena} instead. + * Memory segments allocated with a {@linkplain #ofConfined() confined arena} can only be + * accessed (and closed) by the thread that created the arena. If access to a memory + * segment from multiple threads is required, clients can allocate segments in a + * {@linkplain #ofShared() shared arena} instead. *

* The characteristics of the various arenas are summarized in the following table: * @@ -120,38 +127,45 @@ * *

Safety and thread-confinement

* - * Arenas provide strong temporal safety guarantees: a memory segment allocated by an arena cannot be accessed - * after the arena has been closed. The cost of providing this guarantee varies based on the - * number of threads that have access to the memory segments allocated by the arena. For instance, if an arena - * is always created and closed by one thread, and the memory segments allocated by the arena are always + * Arenas provide strong temporal safety guarantees: a memory segment allocated by an + * arena cannot be accessed after the arena has been closed. The cost of + * providing this guarantee varies based on the number of threads that have access to the + * memory segments allocated by the arena. For instance, if an arena is always created + * and closed by one thread, and the memory segments allocated by the arena are always * accessed by that same thread, then ensuring correctness is trivial. *

- * Conversely, if an arena allocates segments that can be accessed by multiple threads, or if the arena can be closed - * by a thread other than the accessing thread, then ensuring correctness is much more complex. For example, a segment - * allocated with the arena might be accessed while another thread attempts, concurrently, to close the arena. - * To provide the strong temporal safety guarantee without forcing every client, even simple ones, to incur a performance - * impact, arenas are divided into thread-confined arenas, and shared arenas. + * Conversely, if an arena allocates segments that can be accessed by multiple threads, + * or if the arena can be closed by a thread other than the accessing thread, then + * ensuring correctness is much more complex. For example, a segment allocated with the + * arena might be accessed while another thread attempts, concurrently, to close + * the arena. To provide the strong temporal safety guarantee without forcing every + * client, even simple ones, to incur a performance impact, arenas are divided into + * thread-confined arenas, and shared arenas. *

- * Confined arenas, support strong thread-confinement guarantees. Upon creation, they are assigned an - * owner thread, typically the thread which initiated the creation operation. - * The segments created by a confined arena can only be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} - * by the owner thread. Moreover, any attempt to close the confined arena from a thread other than the owner thread will - * fail with {@link WrongThreadException}. + * Confined arenas, support strong thread-confinement guarantees. Upon creation, they are + * assigned an owner thread, typically the thread which initiated the creation + * operation. The segments created by a confined arena can only be + * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the owner thread. + * Moreover, any attempt to close the confined arena from a thread other than the owner + * thread will fail with a {@link WrongThreadException}. *

- * Shared arenas, on the other hand, have no owner thread. The segments created by a shared arena - * can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. This might be useful when - * multiple threads need to access the same memory segment concurrently (e.g. in the case of parallel processing). - * Moreover, a shared arena can be closed by any thread. + * Shared arenas, on the other hand, have no owner thread. The segments created by a + * shared arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by + * any thread. This might be useful when multiple threads need to access the same memory + * segment concurrently (e.g. in the case of parallel processing). Moreover, a shared + * arena can be closed by any thread. * *

Custom arenas

* - * Clients can define custom arenas to implement more efficient allocation strategies, or to have better control over - * when (and by whom) an arena can be closed. As an example, the following code defines a slicing arena that behaves - * like a confined arena (i.e., single-threaded access), but internally uses a - * {@linkplain SegmentAllocator#slicingAllocator(MemorySegment) slicing allocator} to respond to allocation requests. - * When the slicing arena is closed, the underlying confined arena is also closed; this will invalidate all segments - * allocated with the slicing arena (since the scope of the slicing arena is the same as that of the underlying - * confined arena): + * Clients can define custom arenas to implement more efficient allocation strategies, + * or to have better control over when (and by whom) an arena can be closed. As an + * example, the following code defines a slicing arena that behaves like a + * confined arena (i.e., single-threaded access), but internally uses a + * {@linkplain SegmentAllocator#slicingAllocator(MemorySegment) slicing allocator} to + * respond to allocation requests. + * When the slicing arena is closed, the underlying confined arena is also closed; this + * will invalidate all segments allocated with the slicing arena (since the scope of the + * slicing arena is the same as that of the underlying confined arena): * * {@snippet lang = java: * class SlicingArena implements Arena { @@ -177,8 +191,9 @@ * } * } * - * In other words, a slicing arena provides a vastly more efficient and scalable allocation strategy, while still retaining - * the timely deallocation guarantee provided by the underlying confined arena: + * In other words, a slicing arena provides a vastly more efficient and scalable + * allocation strategy, while still retaining the timely deallocation guarantee provided + * by the underlying confined arena: * * {@snippet lang = java: * try (Arena slicingArena = new SlicingArena(1000)) { @@ -204,18 +219,17 @@ public interface Arena extends SegmentAllocator, AutoCloseable { * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. * Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}. * - * @return a new arena that is managed, automatically, by the garbage collector. + * @return a new arena that is managed, automatically, by the garbage collector */ static Arena ofAuto() { return MemorySessionImpl.createImplicit(CleanerFactory.cleaner()).asArena(); } /** - * Obtains the global arena. Segments allocated with the global arena can be - * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. - * Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}. - * - * @return the global arena. + * {@return the global arena} Segments allocated with the global arena can be + * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. + * Calling {@link #close()} on the returned arena will result in + * an {@link UnsupportedOperationException}. */ static Arena global() { class Holder { @@ -226,8 +240,8 @@ class Holder { /** * {@return a new confined arena} Segments allocated with the confined arena can be - * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the thread that created the arena, - * the arena's owner thread. + * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the thread + * that created the arena, the arena's owner thread. */ static Arena ofConfined() { return MemorySessionImpl.createConfined(Thread.currentThread()).asArena(); @@ -235,36 +249,40 @@ static Arena ofConfined() { /** * {@return a new shared arena} Segments allocated with the global arena can be - * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. + * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. */ static Arena ofShared() { return MemorySessionImpl.createShared().asArena(); } /** - * Returns a native memory segment with the given size (in bytes) and alignment constraint (in bytes). + * Returns a native memory segment with the given size (in bytes) and alignment + * constraint (in bytes). * The returned segment is associated with this {@linkplain #scope() arena scope}. - * The segment's {@link MemorySegment#address() address} is the starting address of the - * allocated off-heap region of memory backing the segment, and the address is - * aligned according to the provided alignment constraint. + * The segment's {@link MemorySegment#address() address} is the starting address of + * the allocated off-heap region of memory backing the segment, and the address is + * aligned according the provided alignment constraint. * * @implSpec - * Implementations of this method must return a native segment featuring the requested size, - * and that is compatible with the provided alignment constraint. Furthermore, for any two segments - * {@code S1, S2} returned by this method, the following invariant must hold: + * Implementations of this method must return a native segment featuring the + * requested size, and that is compatible with the provided alignment constraint. + * Furthermore, for any two segments {@code S1, S2} returned by this method, the + * following invariant must hold: * * {@snippet lang = java: * S1.asOverlappingSlice(S2).isEmpty() == true * } * - * @param byteSize the size (in bytes) of the off-heap region of memory backing the native memory segment. - * @param byteAlignment the alignment constraint (in bytes) of the off-heap region of memory backing the native memory segment. - * @return a new native memory segment. + * @param byteSize the size (in bytes) of the off-heap region of memory backing + * the native memory segment + * @param byteAlignment the alignment constraint (in bytes) of the off-heap region + * of memory backing the native memory segment + * @return a new native memory segment * @throws IllegalArgumentException if {@code bytesSize < 0}, {@code byteAlignment <= 0}, * or if {@code byteAlignment} is not a power of 2 * @throws IllegalStateException if this arena has already been {@linkplain #close() closed} - * @throws WrongThreadException if this arena is confined, and this method is called from a thread - * other than the arena's owner thread + * @throws WrongThreadException if this arena is confined, and this method is called + * from a thread other than the arena's owner thread */ @Override MemorySegment allocate(long byteSize, long byteAlignment); @@ -275,25 +293,29 @@ static Arena ofShared() { Scope scope(); /** - * Closes this arena. If this method completes normally, the arena scope is no longer {@linkplain Scope#isAlive() alive}, - * and all the memory segments associated with it can no longer be accessed. Furthermore, any off-heap region of memory backing the + * Closes this arena. If this method completes normally, the arena scope is no longer + * {@linkplain Scope#isAlive() alive}, and all the memory segments associated with it + * can no longer be accessed. Furthermore, any off-heap region of memory backing the * segments obtained from this arena are also released. * - * @apiNote This operation is not idempotent; that is, closing an already closed arena always results in an - * exception being thrown. This reflects a deliberate design choice: failure to close an arena might reveal a bug - * in the underlying application logic. + * @apiNote This operation is not idempotent; that is, closing an already closed arena + * always results in an exception being thrown. This reflects a + * deliberate design choice: failure to close an arena might reveal a bug + * in the underlying application logic. * - * @implSpec If this method completes normally, then {@code this.scope().isAlive() == false}. - * Implementations are allowed to throw {@link UnsupportedOperationException} if an explicit close operation is - * not supported. + * @implSpec If this method completes normally, then + * {@code this.scope().isAlive() == false}. + * Implementations are allowed to throw {@link UnsupportedOperationException} + * if an explicit close operation is not supported. * * @see Scope#isAlive() * * @throws IllegalStateException if the arena has already been closed - * @throws IllegalStateException if a segment associated with this arena is being accessed concurrently, e.g. - * by a {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle} - * @throws WrongThreadException if this arena is confined, and this method is called from a thread - * other than the arena's owner thread + * @throws IllegalStateException if a segment associated with this arena is being + * accessed concurrently, e.g. by a + * {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle} + * @throws WrongThreadException if this arena is confined, and this method is called + * from a thread other than the arena's owner thread * @throws UnsupportedOperationException if this arena cannot be closed explicitly */ @Override diff --git a/src/java.base/share/classes/java/lang/foreign/FunctionDescriptor.java b/src/java.base/share/classes/java/lang/foreign/FunctionDescriptor.java index ee42e991480..dd1ec8e1660 100644 --- a/src/java.base/share/classes/java/lang/foreign/FunctionDescriptor.java +++ b/src/java.base/share/classes/java/lang/foreign/FunctionDescriptor.java @@ -34,13 +34,16 @@ import jdk.internal.foreign.FunctionDescriptorImpl; /** - * A function descriptor models the signature of a foreign function. A function descriptor is made up of zero or more - * argument layouts, and zero or one return layout. A function descriptor is used to create - * {@linkplain Linker#downcallHandle(MemorySegment, FunctionDescriptor, Linker.Option...) downcall method handles} and + * A function descriptor models the signature of a foreign function. A function + * descriptor is made up of zero or more argument layouts, and zero or one return layout. + * A function descriptor is used to create + * {@linkplain Linker#downcallHandle(MemorySegment, FunctionDescriptor, Linker.Option...) downcall method handles} + * and * {@linkplain Linker#upcallStub(MethodHandle, FunctionDescriptor, Arena, Linker.Option...) upcall stubs}. * * @implSpec - * Implementing classes are immutable, thread-safe and value-based. + * Implementing classes are immutable, thread-safe and + * value-based. * * @see MemoryLayout * @since 22 @@ -53,35 +56,39 @@ public sealed interface FunctionDescriptor permits FunctionDescriptorImpl { Optional returnLayout(); /** - * {@return the argument layouts of this function descriptor (as an unmodifiable list)}. + * {@return the argument layouts of this function descriptor (as an unmodifiable list)} */ List argumentLayouts(); /** - * Returns a function descriptor with the given argument layouts appended to the argument layouts - * of this function descriptor. - * @param addedLayouts the argument layouts to append. - * @throws IllegalArgumentException if one of the layouts in {@code addedLayouts} is a padding layout - * @return a new function descriptor, with the provided additional argument layouts. + * Returns a function descriptor with the given argument layouts appended to the + * argument layouts of this function descriptor. + * + * @param addedLayouts the argument layouts to append + * @throws IllegalArgumentException if one of the layouts in {@code addedLayouts} is + * a padding layout + * @return a new function descriptor, with the provided additional argument layouts */ FunctionDescriptor appendArgumentLayouts(MemoryLayout... addedLayouts); /** - * Returns a function descriptor with the given argument layouts inserted at the given index, into the argument - * layout array of this function descriptor. + * Returns a function descriptor with the given argument layouts inserted at the + * given index, into the argument layout array of this function descriptor. + * * @param index the index at which to insert the arguments - * @param addedLayouts the argument layouts to insert at the given index. - * @return a new function descriptor, with the provided additional argument layouts. - * @throws IllegalArgumentException if one of the layouts in {@code addedLayouts} is a padding layout + * @param addedLayouts the argument layouts to insert at given index + * @return a new function descriptor, with the provided additional argument layouts + * @throws IllegalArgumentException if one of the layouts in {@code addedLayouts} + * is a padding layout * @throws IllegalArgumentException if {@code index < 0 || index > argumentLayouts().size()} */ FunctionDescriptor insertArgumentLayouts(int index, MemoryLayout... addedLayouts); /** * Returns a function descriptor with the provided return layout. - * @param newReturn the new return layout. + * @param newReturn the new return layout * @throws IllegalArgumentException if {@code newReturn} is a padding layout - * @return a new function descriptor, with the provided return layout. + * @return a new function descriptor, with the provided return layout */ FunctionDescriptor changeReturnLayout(MemoryLayout newReturn); @@ -91,28 +98,35 @@ public sealed interface FunctionDescriptor permits FunctionDescriptorImpl { FunctionDescriptor dropReturnLayout(); /** - * Returns the method type consisting of the carrier types of the layouts in this function descriptor. + * Returns the method type consisting of the carrier types of the layouts in this + * function descriptor. *

* The carrier type of a layout {@code L} is determined as follows: *

    - *
  • If {@code L} is a {@link ValueLayout} the carrier type is determined through {@link ValueLayout#carrier()}.
  • - *
  • If {@code L} is a {@link GroupLayout} or a {@link SequenceLayout}, the carrier type is {@link MemorySegment}.
  • + *
  • If {@code L} is a {@link ValueLayout} the carrier type is + * determined through {@link ValueLayout#carrier()}.
  • + *
  • If {@code L} is a {@link GroupLayout} or a {@link SequenceLayout}, + * the carrier type is {@link MemorySegment}.
  • *
* - * @apiNote A function descriptor cannot, by construction, contain any padding layouts. As such, it is not - * necessary to specify how padding layouts should be mapped to carrier types. + * @apiNote A function descriptor cannot, by construction, contain any padding + * layouts. As such, it is not necessary to specify how padding layout + * should be mapped to carrier types. * - * @return the method type consisting of the carrier types of the layouts in this function descriptor. + * @return the method type consisting of the carrier types of the layouts in this + * function descriptor */ MethodType toMethodType(); /** * Creates a function descriptor with the given return and argument layouts. - * @param resLayout the return layout. - * @param argLayouts the argument layouts. + * + * @param resLayout the return layout + * @param argLayouts the argument layouts * @throws IllegalArgumentException if {@code resLayout} is a padding layout - * @throws IllegalArgumentException if one of the layouts in {@code argLayouts} is a padding layout - * @return a new function descriptor with the provided return and argument layouts. + * @throws IllegalArgumentException if one of the layouts in {@code argLayouts} + * is a padding layout + * @return a new function descriptor with the provided return and argument layouts */ static FunctionDescriptor of(MemoryLayout resLayout, MemoryLayout... argLayouts) { Objects.requireNonNull(resLayout); @@ -121,11 +135,13 @@ static FunctionDescriptor of(MemoryLayout resLayout, MemoryLayout... argLayouts) } /** - * Creates a function descriptor with the given argument layouts and no return layout. This is useful for modeling functions - * that return no values. - * @param argLayouts the argument layouts. - * @throws IllegalArgumentException if one of the layouts in {@code argLayouts} is a padding layout - * @return a new function descriptor with the provided argument layouts. + * Creates a function descriptor with the given argument layouts and no return + * layout. This is useful to model functions that return no values. + * + * @param argLayouts the argument layouts + * @throws IllegalArgumentException if one of the layouts in {@code argLayouts} + * is a padding layout + * @return a new function descriptor with the provided argument layouts */ static FunctionDescriptor ofVoid(MemoryLayout... argLayouts) { // Null checks are implicit in List.of(argLayouts) diff --git a/src/java.base/share/classes/java/lang/foreign/GroupLayout.java b/src/java.base/share/classes/java/lang/foreign/GroupLayout.java index 24bec8f0439..03eb33c1644 100644 --- a/src/java.base/share/classes/java/lang/foreign/GroupLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/GroupLayout.java @@ -28,13 +28,16 @@ import java.util.List; /** - * A compound layout that is an aggregation of multiple, heterogeneous member layouts. 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 a - * {@linkplain StructLayout struct layout}; conversely, if all member layouts are laid out at the same starting offset, - * the resulting group layout is a {@linkplain UnionLayout union layout}. + * A compound layout that is an aggregation of multiple, heterogeneous + * member layouts. 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 a + * {@linkplain StructLayout struct layout}; conversely, if all member layouts are laid + * out at the same starting offset, the resulting group layout is a + * {@linkplain UnionLayout union layout}. * * @implSpec - * This class is immutable, thread-safe and value-based. + * This class is immutable, thread-safe and + * value-based. * * @sealedGraph * @since 22 @@ -44,9 +47,10 @@ public sealed interface GroupLayout extends MemoryLayout permits StructLayout, U /** * {@return the member layouts of this group layout} * - * @apiNote the order in which member layouts are returned in the same order in which member layouts have - * been passed to one of the group layout factory methods (see {@link MemoryLayout#structLayout(MemoryLayout...)}, - * {@link MemoryLayout#unionLayout(MemoryLayout...)}). + * @apiNote the order in which member layouts are returned is the same order in which + * member layouts have been passed to one of the group layout factory methods + * (see {@link MemoryLayout#structLayout(MemoryLayout...)} and + * {@link MemoryLayout#unionLayout(MemoryLayout...)}). */ List memberLayouts(); @@ -65,8 +69,9 @@ public sealed interface GroupLayout extends MemoryLayout permits StructLayout, U /** * {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} - * @throws IllegalArgumentException if {@code byteAlignment} is less than {@code M}, where {@code M} is - * the maximum alignment constraint in any of the member layouts associated with this group layout + * @throws IllegalArgumentException if {@code byteAlignment} is less than {@code M}, + * where {@code M} is the maximum alignment constraint in any of the + * member layouts associated with this group layout */ @Override GroupLayout withByteAlignment(long byteAlignment); diff --git a/src/java.base/share/classes/java/lang/foreign/Linker.java b/src/java.base/share/classes/java/lang/foreign/Linker.java index 604b1489239..0ca3470c479 100644 --- a/src/java.base/share/classes/java/lang/foreign/Linker.java +++ b/src/java.base/share/classes/java/lang/foreign/Linker.java @@ -41,42 +41,49 @@ import java.util.stream.Stream; /** - * A linker provides access to foreign functions from Java code, and access to Java code from foreign functions. + * A linker provides access to foreign functions from Java code, and access to Java code + * from foreign functions. *

- * 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. + * Foreign functions typically reside in libraries that can be loaded on demand. Each + * library conforms to a specific ABI (Application Binary Interface). An ABI is a set of + * calling conventions and data types associated with the compiler, OS, and processor where + * the library was built. For example, a C compiler on Linux/x64 usually builds libraries + * that conform to the SystemV ABI. *

- * A linker has detailed knowledge of the calling conventions and data types used by a specific ABI. - * For any library that conforms to that ABI, the linker can mediate between Java code running - * in the JVM and foreign functions in the library. In particular: + * A linker has detailed knowledge of the calling conventions and data types used by a + * specific ABI. For any library that conforms to that ABI, the linker can mediate + * between Java code running in the JVM and foreign functions in the library. In + * particular: *

    *
  • A linker allows Java code to link against foreign functions, via - * {@linkplain #downcallHandle(MemorySegment, FunctionDescriptor, Option...) downcall method handles}; and
  • - *
  • A linker allows foreign functions to call Java method handles, - * via the generation of {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...) upcall stubs}.
  • + * {@linkplain #downcallHandle(MemorySegment, FunctionDescriptor, Option...) downcall method handles}; + * and + *
  • A linker allows foreign functions to call Java method handles, via the generation + * of {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...) upcall stubs}.
  • *
- * A linker provides a way to look up the canonical layouts associated with the data types used by the ABI. - * For example, a linker implementing the C ABI might choose to provide a canonical layout for the C {@code size_t} - * type. On 64-bit platforms, this canonical layout might be equal to {@link ValueLayout#JAVA_LONG}. The canonical - * layouts supported by a linker are exposed via the {@link #canonicalLayouts()} method, which returns a map from - * type names to canonical layouts. + * A linker provides a way to look up the canonical layouts associated with the + * data types used by the ABI. For example, a linker implementing the C ABI might choose + * to provide a canonical layout for the C {@code size_t} type. On 64-bit platforms, + * this canonical layout might be equal to {@link ValueLayout#JAVA_LONG}. The canonical + * layouts supported by a linker are exposed via the {@link #canonicalLayouts()} method, + * which returns a map from type names to canonical layouts. *

- * 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}. + * 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}. * *

Calling native functions

* * The {@linkplain #nativeLinker() native linker} can be used to link against functions - * defined in C libraries (native functions). Suppose we wish to downcall from Java to the {@code strlen} function - * defined in the standard C library: + * defined in C libraries (native functions). Suppose we wish to downcall from Java to + * the {@code strlen} function defined in the standard C library: * {@snippet lang = c: * size_t strlen(const char *s); * } - * A downcall method handle that exposes {@code strlen} is obtained, using the native linker, as follows: + * A downcall method handle that exposes {@code strlen} is obtained, using the native + * linker, as follows: * * {@snippet lang = java: * Linker linker = Linker.nativeLinker(); @@ -87,12 +94,12 @@ * } * * Note how the native linker also provides access, via its {@linkplain #defaultLookup() default lookup}, - * to the native functions defined by the C libraries loaded with the Java runtime. Above, the default lookup - * is used to search the address of the {@code strlen} native function. That address is then passed, along with - * a platform-dependent description of the signature of the function expressed as a - * {@link FunctionDescriptor} (more on that below) to the native linker's - * {@link #downcallHandle(MemorySegment, FunctionDescriptor, Option...)} method. - * The obtained downcall method handle is then invoked as follows: + * to the native functions defined by the C libraries loaded with the Java runtime. + * Above, the default lookup is used to search the address of the {@code strlen} native + * function. That address is then passed, along with a platform-dependent description + * of the signature of the function expressed as a {@link FunctionDescriptor} (more on + * that below) to the native linker's {@link #downcallHandle(MemorySegment, FunctionDescriptor, Option...)} + * method. The obtained downcall method handle is then invoked as follows: * * {@snippet lang = java: * try (Arena arena = Arena.ofConfined()) { @@ -102,28 +109,34 @@ *} *

Describing C signatures

* - * When interacting with the native linker, clients must provide a platform-dependent description of the signature - * of the C function they wish to link against. This description, a {@link FunctionDescriptor function descriptor}, - * defines the layouts associated with the parameter types and return type (if any) of the C function. + * When interacting with the native linker, clients must provide a platform-dependent + * description of the signature of the C function they wish to link against. This + * description, a {@link FunctionDescriptor function descriptor}, defines the layouts + * associated with the parameter types and return type (if any) of the C function. *

- * Scalar C types such as {@code bool}, {@code int} are modeled as {@linkplain ValueLayout value layouts} - * of a suitable carrier. The {@linkplain #canonicalLayouts() mapping} between a scalar type and its corresponding + * Scalar C types such as {@code bool}, {@code int} are modeled as + * {@linkplain ValueLayout value layouts} of a suitable carrier. The + * {@linkplain #canonicalLayouts() mapping} between a scalar type and its corresponding * canonical layout is dependent on the ABI implemented by the native linker (see below). *

- * Composite types are modeled as {@linkplain GroupLayout group layouts}. More specifically, a C {@code struct} type - * maps to a {@linkplain StructLayout struct layout}, whereas a C {@code union} type maps to a {@link UnionLayout union - * layout}. When defining a struct or union layout, clients must pay attention to the size and alignment constraint - * of the corresponding composite type definition in C. For instance, padding between two struct fields - * must be modeled explicitly, by adding an adequately sized {@linkplain PaddingLayout padding layout} member - * to the resulting struct layout. + * Composite types are modeled as {@linkplain GroupLayout group layouts}. More + * specifically, a C {@code struct} type maps to a {@linkplain StructLayout struct layout}, + * whereas a C {@code union} type maps to a {@link UnionLayout union layout}. When defining + * a struct or union layout, clients must pay attention to the size and alignment constraint + * of the corresponding composite type definition in C. For instance, padding between two + * struct fields must be modeled explicitly, by adding an adequately sized + * {@linkplain PaddingLayout padding layout} member to the resulting struct layout. *

- * Finally, pointer types such as {@code int**} and {@code int(*)(size_t*, size_t*)} are modeled as - * {@linkplain AddressLayout address layouts}. When the spatial bounds of the pointer type are known statically, - * the address layout can be associated with a {@linkplain AddressLayout#targetLayout() target layout}. For instance, - * a pointer that is known to point to a C {@code int[2]} array can be modeled as an address layout whose - * target layout is a sequence layout whose element count is 2, and whose element type is {@link ValueLayout#JAVA_INT}. + * Finally, pointer types such as {@code int**} and {@code int(*)(size_t*, size_t*)} + * are modeled as {@linkplain AddressLayout address layouts}. When the spatial bounds of + * the pointer type are known statically, the address layout can be associated with a + * {@linkplain AddressLayout#targetLayout() target layout}. For instance, a pointer that + * is known to point to a C {@code int[2]} array can be modeled as an address layout + * whose target layout is a sequence layout whose element count is 2, and whose + * element type is {@link ValueLayout#JAVA_INT}. *

- * All native linker implementations are guaranteed to provide canonical layouts for the following set of types: + * All native linker implementations are guaranteed to provide canonical layouts for the + * following set of types: *

    *
  • {@code bool}
  • *
  • {@code char}
  • @@ -137,19 +150,23 @@ *
  • {@code wchar_t}
  • *
  • {@code void*}
  • *
- * As noted above, the specific canonical layout associated with each type can vary, depending on the data model - * supported by a given ABI. For instance, the C type {@code long} maps to the layout constant {@link ValueLayout#JAVA_LONG} - * on Linux/x64, but maps to the layout constant {@link ValueLayout#JAVA_INT} on Windows/x64. Similarly, the C type - * {@code size_t} maps to the layout constant {@link ValueLayout#JAVA_LONG} on 64-bit platforms, but maps to the layout - * constant {@link ValueLayout#JAVA_INT} on 32-bit platforms. + * As noted above, the specific canonical layout associated with each type can vary, + * depending on the data model supported by a given ABI. For instance, the C type + * {@code long} maps to the layout constant {@link ValueLayout#JAVA_LONG} on Linux/x64, + * but maps to the layout constant {@link ValueLayout#JAVA_INT} on Windows/x64. + * Similarly, the C type {@code size_t} maps to the layout constant + * {@link ValueLayout#JAVA_LONG} on 64-bit platforms, but maps to the layout constant + * {@link ValueLayout#JAVA_INT} on 32-bit platforms. *

- * A native linker typically does not provide canonical layouts for C's unsigned integral types. Instead, they are - * modeled using the canonical layouts associated with their corresponding signed integral types. For instance, - * the C type {@code unsigned long} maps to the layout constant {@link ValueLayout#JAVA_LONG} on Linux/x64, but maps to + * A native linker typically does not provide canonical layouts for C's unsigned integral + * types. Instead, they are modeled using the canonical layouts associated with their + * corresponding signed integral types. For instance, the C type {@code unsigned long} + * maps to the layout constant {@link ValueLayout#JAVA_LONG} on Linux/x64, but maps to * the layout constant {@link ValueLayout#JAVA_INT} on Windows/x64. *

- * The following table shows some examples of how C types are modeled in Linux/x64 according to the - * "System V Application Binary Interface" (all the examples provided here will assume these platform-dependent mappings): + * The following table shows some examples of how C types are modeled in Linux/x64 + * according to the "System V Application Binary Interface" + * (all the examples provided here will assume these platform-dependent mappings): * *

* @@ -230,24 +247,30 @@ *
  • {@code L} is a value layout {@code V} and {@code V.withoutName()} is a canonical layout
  • *
  • {@code L} is a sequence layout {@code S} and all the following conditions hold: *
      - *
    1. the alignment constraint of {@code S} is set to its natural alignment, and
    2. + *
    3. the alignment constraint of {@code S} is set to its + * natural alignment, and
    4. *
    5. {@code S.elementLayout()} is a layout supported by {@code NL}.
    6. *
    *
  • *
  • {@code L} is a group layout {@code G} and all the following conditions hold: *
      - *
    1. the alignment constraint of {@code G} is set to its natural alignment;
    2. + *
    3. the alignment constraint of {@code G} is set to its + * natural alignment;
    4. *
    5. the size of {@code G} is a multiple of its alignment constraint;
    6. - *
    7. each member layout in {@code G.memberLayouts()} is either a padding layout or a layout supported by {@code NL}, and
    8. - *
    9. {@code G} does not contain padding other than what is strictly required to align its non-padding layout elements, or to satisfy (2).
    10. + *
    11. each member layout in {@code G.memberLayouts()} is either a padding layout or + * a layout supported by {@code NL}, and
    12. + *
    13. {@code G} does not contain padding other than what is strictly required to align + * its non-padding layout elements, or to satisfy (2).
    14. *
    *
  • * * - * Linker implementations may optionally support additional layouts, such as packed struct layouts. - * A packed struct is a struct in which there is at least one member layout {@code L} that has an alignment - * constraint less strict than its natural alignment. This allows to avoid padding between member layouts, + * Linker implementations may optionally support additional layouts, such as + * packed struct layouts. A packed struct is a struct in which there is + * at least one member layout {@code L} that has an alignment constraint less strict + * than its natural alignment. This allows to avoid padding between member layouts, * as well as avoiding padding at the end of the struct layout. For example: + * {@snippet lang = java: * // No padding between the 2 element layouts: * MemoryLayout noFieldPadding = MemoryLayout.structLayout( @@ -260,23 +283,25 @@ * ValueLayout.JAVA_INT); * } *

    - * A native linker only supports function descriptors whose argument/return layouts are layouts supported by that linker - * and are not sequence layouts. + * A native linker only supports function descriptors whose argument/return layouts are + * layouts supported by that linker and are not sequence layouts. * *

    Function pointers

    * - * Sometimes, it is useful to pass Java code as a function pointer to some native function; this is achieved by using - * an {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...) upcall stub}. To demonstrate this, - * let's consider the following function from the C standard library: + * Sometimes, it is useful to pass Java code as a function pointer to some native + * function; this is achieved by using an + * {@linkplain #upcallStub(MethodHandle, FunctionDescriptor, Arena, Option...) upcall stub}. + * To demonstrate this, let's consider the following function from the C standard library: * * {@snippet lang = c: * void qsort(void *base, size_t nmemb, size_t size, * int (*compar)(const void *, const void *)); * } * - * The {@code qsort} function can be used to sort the contents of an array, using a custom comparator function which is - * passed as a function pointer (the {@code compar} parameter). To be able to call the {@code qsort} function from Java, - * we must first create a downcall method handle for it, as follows: + * The {@code qsort} function can be used to sort the contents of an array, using a + * custom comparator function which is passed as a function pointer + * (the {@code compar} parameter). To be able to call the {@code qsort} function from + * Java, we must first create a downcall method handle for it, as follows: * * {@snippet lang = java: * Linker linker = Linker.nativeLinker(); @@ -286,12 +311,14 @@ * ); * } * - * As before, we use {@link ValueLayout#JAVA_LONG} to map the C type {@code size_t} type, and {@link ValueLayout#ADDRESS} - * for both the first pointer parameter (the array pointer) and the last parameter (the function pointer). + * As before, we use {@link ValueLayout#JAVA_LONG} to map the C type {@code size_t} type, + * and {@link ValueLayout#ADDRESS} for both the first pointer parameter (the array + * pointer) and the last parameter (the function pointer). *

    - * To invoke the {@code qsort} downcall handle obtained above, we need a function pointer to be passed as the last - * parameter. That is, we need to create a function pointer out of an existing method handle. First, let's write a - * Java method that can compare two int elements passed as pointers (i.e. as {@linkplain MemorySegment memory segments}): + * To invoke the {@code qsort} downcall handle obtained above, we need a function pointer + * to be passed as the last parameter. That is, we need to create a function pointer out + * of an existing method handle. First, let's write a Java method that can compare two + * int elements passed as pointers (i.e. as {@linkplain MemorySegment memory segments}): * * {@snippet lang = java: * class Qsort { @@ -312,13 +339,16 @@ * comparDesc.toMethodType()); * } * - * First, we create a function descriptor for the function pointer type. Since we know that the parameters passed to - * the comparator method will be pointers to elements of a C {@code int[]} array, we can specify {@link ValueLayout#JAVA_INT} - * as the target layout for the address layouts of both parameters. This will allow the comparator method to access - * the contents of the array elements to be compared. We then {@linkplain FunctionDescriptor#toMethodType() turn} - * that function descriptor into a suitable {@linkplain java.lang.invoke.MethodType method type} which we then use to look up - * the comparator method handle. We can now create an upcall stub that points to that method, and pass it, as a function - * pointer, to the {@code qsort} downcall handle, as follows: + * First, we create a function descriptor for the function pointer type. Since we know + * that the parameters passed to the comparator method will be pointers to elements of + * a C {@code int[]} array, we can specify {@link ValueLayout#JAVA_INT} as the target + * layout for the address layouts of both parameters. This will allow the comparator + * method to access the contents of the array elements to be compared. We then + * {@linkplain FunctionDescriptor#toMethodType() turn} that function descriptor into + * a suitable {@linkplain java.lang.invoke.MethodType method type} which we then use to + * look up the comparator method handle. We can now create an upcall stub that points to + * that method, and pass it, as a function pointer, to the {@code qsort} downcall handle, + * as follows: * * {@snippet lang = java: * try (Arena arena = Arena.ofConfined()) { @@ -329,34 +359,39 @@ * } * } * - * This code creates an off-heap array, copies the contents of a Java array into it, and then passes the array to the - * {@code qsort} method handle along with the comparator function we obtained from the native linker. After the invocation, the contents - * of the off-heap array will be sorted according to our comparator function, written in Java. We then extract a - * new Java array from the segment, which contains the sorted elements. + * This code creates an off-heap array, copies the contents of a Java array into it, and + * then passes the array to the {@code qsort} method handle along with the comparator + * function we obtained from the native linker. After the invocation, the contents + * of the off-heap array will be sorted according to our comparator function, written in + * Java. We then extract a new Java array from the segment, which contains the sorted + * elements. * *

    Functions returning pointers

    * - * When interacting with native functions, it is common for those functions to allocate a region of memory and return - * a pointer to that region. Let's consider the following function from the C standard library: + * When interacting with native functions, it is common for those functions to allocate + * a region of memory and return a pointer to that region. Let's consider the following + * function from the C standard library: * * {@snippet lang = c: * void *malloc(size_t size); * } * * The {@code malloc} function allocates a region of memory with the given size, - * and returns a pointer to that region of memory, which is later deallocated using another function from - * the C standard library: + * and returns a pointer to that region of memory, which is later deallocated using + * another function from the C standard library: * * {@snippet lang = c: * void free(void *ptr); * } * - * The {@code free} function takes a pointer to a region of memory and deallocates that region. In this section we - * will show how to interact with these native functions, with the aim of providing a safe allocation - * API (the approach outlined below can of course be generalized to allocation functions other than {@code malloc} - * and {@code free}). + * The {@code free} function takes a pointer to a region of memory and deallocates that + * region. In this section we will show how to interact with these native functions, + * with the aim of providing a safe allocation API (the approach outlined below + * can of course be generalized to allocation functions other than {@code malloc} and + * {@code free}). *

    - * First, we need to create the downcall method handles for {@code malloc} and {@code free}, as follows: + * First, we need to create the downcall method handles for {@code malloc} and + * {@code free}, as follows: * * {@snippet lang = java: * Linker linker = Linker.nativeLinker(); @@ -372,8 +407,9 @@ * ); * } * - * When a native function returning a pointer (such as {@code malloc}) is invoked using a downcall method handle, - * the Java runtime has no insight into the size or the lifetime of the returned pointer. Consider the following code: + * When a native function returning a pointer (such as {@code malloc}) is invoked using + * a downcall method handle, the Java runtime has no insight into the size or the + * lifetime of the returned pointer. Consider the following code: * * {@snippet lang = java: * MemorySegment segment = (MemorySegment)malloc.invokeExact(100); @@ -382,11 +418,12 @@ * The size of the segment returned by the {@code malloc} downcall method handle is * zero. Moreover, the scope of the * returned segment is the global scope. To provide safe access to the segment, we must, - * unsafely, resize the segment to the desired size (100, in this case). It might also be desirable to - * attach the segment to some existing {@linkplain Arena arena}, so that the lifetime of the region of memory - * backing the segment can be managed automatically, as for any other native segment created directly from Java code. - * Both of these operations are accomplished using the restricted method {@link MemorySegment#reinterpret(long, Arena, Consumer)}, - * as follows: + * unsafely, resize the segment to the desired size (100, in this case). It might also + * be desirable to attach the segment to some existing {@linkplain Arena arena}, so that + * the lifetime of the region of memory backing the segment can be managed automatically, + * as for any other native segment created directly from Java code. Both of these + * operations are accomplished using the restricted method + * {@link MemorySegment#reinterpret(long, Arena, Consumer)}, as follows: * * {@snippet lang = java: * MemorySegment allocateMemory(long byteSize, Arena arena) throws Throwable { @@ -401,12 +438,14 @@ * } * } * - * The {@code allocateMemory} method defined above accepts two parameters: a size and an arena. The method calls the - * {@code malloc} downcall method handle, and unsafely reinterprets the returned segment, by giving it a new size - * (the size passed to the {@code allocateMemory} method) and a new scope (the scope of the provided arena). - * The method also specifies a cleanup action to be executed when the provided arena is closed. Unsurprisingly, - * the cleanup action passes the segment to the {@code free} downcall method handle, to deallocate the underlying - * region of memory. We can use the {@code allocateMemory} method as follows: + * The {@code allocateMemory} method defined above accepts two parameters: a size and an + * arena. The method calls the {@code malloc} downcall method handle, and unsafely + * reinterprets the returned segment, by giving it a new size (the size passed to the + * {@code allocateMemory} method) and a new scope (the scope of the provided arena). + * The method also specifies a cleanup action to be executed when the provided + * arena is closed. Unsurprisingly, the cleanup action passes the segment to the + * {@code free} downcall method handle, to deallocate the underlying region of memory. + * We can use the {@code allocateMemory} method as follows: * * {@snippet lang = java: * try (Arena arena = Arena.ofConfined()) { @@ -414,65 +453,79 @@ * } // 'free' called here * } * - * Note how the segment obtained from {@code allocateMemory} acts as any other segment managed by the confined arena. More - * specifically, the obtained segment has the desired size, can only be accessed by a single thread (the thread that created - * the confined arena), and its lifetime is tied to the surrounding try-with-resources block. + * Note how the segment obtained from {@code allocateMemory} acts as any other segment + * managed by the confined arena. More specifically, the obtained segment has the desired + * size, can only be accessed by a single thread (the thread that created the confined + * arena), and its lifetime is tied to the surrounding try-with-resources block. * *

    Variadic functions

    * - * Variadic functions are C functions that can accept a variable number and type of arguments. They are declared with a - * trailing ellipsis ({@code ...}) at the end of the formal parameter list, such as: {@code void foo(int x, ...);} - * The arguments passed in place of the ellipsis are called variadic arguments. Variadic functions are, - * essentially, templates that can be specialized into multiple non-variadic functions by replacing the - * {@code ...} with a list of variadic parameters of a fixed number and type. + * Variadic functions are C functions that can accept a variable number and type of + * arguments. They are declared with a trailing ellipsis ({@code ...}) at the end of the + * formal parameter list, such as: {@code void foo(int x, ...);} + * The arguments passed in place of the ellipsis are called variadic arguments. + * Variadic functions are, essentially, templates that can be specialized into + * multiple non-variadic functions by replacing the {@code ...} with a list of + * variadic parameters of a fixed number and type. *

    - * It should be noted that values passed as variadic arguments undergo default argument promotion in C. For instance, the - * following argument promotions are applied: + * It should be noted that values passed as variadic arguments undergo default argument + * promotion in C. For instance, the following argument promotions are applied: *

      *
    • {@code _Bool} -> {@code unsigned int}
    • *
    • {@code [signed] char} -> {@code [signed] int}
    • *
    • {@code [signed] short} -> {@code [signed] int}
    • *
    • {@code float} -> {@code double}
    • *
    - * whereby the signed-ness of the source type corresponds to the signed-ness of the promoted type. The complete process - * of default argument promotion is described in the C specification. In effect, these promotions place limits on the - * types that can be used to replace the {@code ...}, as the variadic parameters of the specialized form of a variadic - * function will always have a promoted type. + * whereby the signed-ness of the source type corresponds to the signed-ness of the + * promoted type. The complete process of default argument promotion is described in the + * C specification. In effect, these promotions place limits on the types that can be + * used to replace the {@code ...}, as the variadic parameters of the specialized form + * of a variadic function will always have a promoted type. *

    - * The native linker only supports linking the specialized form of a variadic function. A variadic function in its specialized - * form can be linked using a function descriptor describing the specialized form. Additionally, the - * {@link Linker.Option#firstVariadicArg(int)} linker option must be provided to indicate the first variadic parameter in - * the parameter list. The corresponding argument layout (if any), and all following argument layouts in the specialized - * function descriptor, are called variadic argument layouts. + * The native linker only supports linking the specialized form of a variadic function. + * A variadic function in its specialized form can be linked using a function descriptor + * describing the specialized form. Additionally, the {@link Linker.Option#firstVariadicArg(int)} + * linker option must be provided to indicate the first variadic parameter in the + * parameter list. The corresponding argument layout (if any), and all following + * argument layouts in the specialized function descriptor, are called + * variadic argument layouts. *

    - * The native linker does not automatically perform default argument promotions. However, since passing an argument of a - * non-promoted type as a variadic argument is not supported in C, the native linker will reject an attempt to link a - * specialized function descriptor with any variadic argument value layouts corresponding to a non-promoted C type. - * Since the size of the C {@code int} type is platform-specific, exactly which layouts will be rejected is - * platform-specific as well. As an example: on Linux/x64 the layouts corresponding to the C types {@code _Bool}, - * {@code (unsigned) char}, {@code (unsigned) short}, and {@code float} (among others), will be rejected by the linker. - * The {@link #canonicalLayouts()} method can be used to find which layout corresponds to a particular C type. + * The native linker does not automatically perform default argument promotions. However, + * since passing an argument of a non-promoted type as a variadic argument is not + * supported in C, the native linker will reject an attempt to link a specialized + * function descriptor with any variadic argument value layouts corresponding to a + * non-promoted C type. Since the size of the C {@code int} type is platform-specific, + * exactly which layouts will be rejected is platform-specific as well. As an example: + * on Linux/x64 the layouts corresponding to the C types {@code _Bool}, + * {@code (unsigned) char}, {@code (unsigned) short}, and {@code float} (among others), + * will be rejected by the linker. The {@link #canonicalLayouts()} method can be used to + * find which layout corresponds to a particular C type. *

    - * A well-known variadic function is the {@code printf} function, defined in the C standard library: + * A well-known variadic function is the {@code printf} function, defined in the + * C standard library: * * {@snippet lang = c: * int printf(const char *format, ...); * } * - * This function takes a format string, and a number of additional arguments (the number of such arguments is - * dictated by the format string). Consider the following variadic call: + * This function takes a format string, and a number of additional arguments (the number + * of such arguments is dictated by the format string). Consider the following + * variadic call: * * {@snippet lang = c: * printf("%d plus %d equals %d", 2, 2, 4); * } * - * To perform an equivalent call using a downcall method handle we must create a function descriptor which - * describes the specialized signature of the C function we want to call. This descriptor must include an additional layout - * for each variadic argument we intend to provide. In this case, the specialized signature of the C - * function is {@code (char*, int, int, int)} as the format string accepts three integer parameters. We then need to use - * a {@linkplain Linker.Option#firstVariadicArg(int) linker option} to specify the position of the first variadic layout - * in the provided function descriptor (starting from 0). In this case, since the first parameter is the format string - * (a non-variadic argument), the first variadic index needs to be set to 1, as follows: + * To perform an equivalent call using a downcall method handle we must create a function + * descriptor which describes the specialized signature of the C function we want to + * call. This descriptor must include an additional layout for each variadic argument we + * intend to provide. In this case, the specialized signature of the C function is + * {@code (char*, int, int, int)} as the format string accepts three integer parameters. + * We then need to use a {@linkplain Linker.Option#firstVariadicArg(int) linker option} + * to specify the position of the first variadic layout in the provided function + * descriptor (starting from 0). In this case, since the first parameter is the format + * string (a non-variadic argument), the first variadic index needs to be set to 1, as + * follows: * * {@snippet lang = java: * Linker linker = Linker.nativeLinker(); @@ -487,64 +540,81 @@ * * {@snippet lang = java: * try (Arena arena = Arena.ofConfined()) { - * int res = (int)printf.invokeExact(arena.allocateFrom("%d plus %d equals %d"), 2, 2, 4); //prints "2 plus 2 equals 4" + * //prints "2 plus 2 equals 4" + * int res = (int)printf.invokeExact(arena.allocateFrom("%d plus %d equals %d"), 2, 2, 4); * } *} * *

    Safety considerations

    * - * Creating a downcall method handle is intrinsically unsafe. A symbol in a foreign library does not, in general, - * contain enough signature information (e.g. arity and types of foreign function parameters). As a consequence, - * the linker runtime cannot validate linkage requests. When a client interacts with a downcall method handle obtained - * through an invalid linkage request (e.g. by specifying a function descriptor featuring too many argument layouts), - * the result of such interaction is unspecified and can lead to JVM crashes. + * 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. *

    - * When an upcall stub is passed to a foreign function, a JVM crash might occur, if the foreign code casts the function pointer - * associated with the upcall stub to a type that is incompatible with the type of the upcall stub, and then attempts to - * invoke the function through the resulting function pointer. Moreover, if the method - * handle associated with an upcall stub returns a {@linkplain MemorySegment memory segment}, clients must ensure - * that this address cannot become invalid after the upcall is completed. 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. + * When an upcall stub is passed to a foreign function, a JVM crash might occur, if the + * foreign code casts the function pointer associated with the upcall stub to a type that + * is incompatible with the type of the upcall stub, and then attempts to invoke the + * function through the resulting function pointer. Moreover, if the method handle + * associated with an upcall stub returns a {@linkplain MemorySegment memory segment}, + * clients must ensure that this address cannot become invalid after the upcall is + * completed. This can lead to unspecified behavior, and even JVM crashes, since an + * upcall is typically executed in the context of a downcall method handle invocation. * * @implSpec - * Implementations of this interface are immutable, thread-safe and value-based. + * Implementations of this interface are immutable, thread-safe and + * value-based. * * @since 22 */ public sealed interface Linker permits AbstractLinker { /** - * {@return 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. + * {@return 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. * - * @apiNote It is not currently possible to obtain a linker for a different combination of OS and processor. - * @implSpec A native linker implementation is guaranteed to provide canonical layouts for - * basic C types. - * @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}. + * @apiNote It is not currently possible to obtain a linker for a different + * combination of OS and processor. + * @implSpec A native linker implementation is guaranteed to provide canonical + * layouts for basic C types. + * @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}. */ static Linker nativeLinker() { return SharedUtils.getSystemLinker(); } /** - * Creates a method handle that is used to call a foreign function with the given signature and address. + * Creates a method handle that is used to call a foreign function with + * the given signature and address. *

    * Calling this method is equivalent to the following code: * {@snippet lang=java : * linker.downcallHandle(function).bindTo(symbol); * } * - * @param address the native memory segment whose {@linkplain MemorySegment#address() base address} is the - * address of the target foreign function. - * @param function the function descriptor of the target foreign function. - * @param options the linker options associated with this linkage request. - * @return a downcall method handle. - * @throws IllegalArgumentException if the provided function descriptor is not supported by this linker - * @throws IllegalArgumentException if {@code !address.isNative()}, or if {@code address.equals(MemorySegment.NULL)} - * @throws IllegalArgumentException if an invalid combination of linker options is given - * @throws IllegalCallerException If the caller is in a module that does not have native access enabled + * @param address the native memory segment whose + * {@linkplain MemorySegment#address() base address} is the address + * of the target foreign function + * @param function the function descriptor of the target foreign function + * @param options the linker options associated with this linkage request + * @return a downcall method handle + * @throws IllegalArgumentException if the provided function descriptor is not + * supported by this linker + * @throws IllegalArgumentException if {@code !address.isNative()}, or if + * {@code address.equals(MemorySegment.NULL)} + * @throws IllegalArgumentException if an invalid combination of linker options + * is given + * @throws IllegalCallerException If the caller is in a module that does not have + * native access enabled * * @see SymbolLookup */ @@ -555,87 +625,111 @@ MethodHandle downcallHandle(MemorySegment address, Option... options); /** - * Creates a method handle that is used to call a foreign function with the given signature. + * Creates a method handle that is used to call a foreign function with + * the given signature. *

    - * The Java {@linkplain java.lang.invoke.MethodType method type} associated with the returned method handle is - * {@linkplain FunctionDescriptor#toMethodType() derived} from the argument and return layouts in the function descriptor, - * but features an additional leading parameter of type {@link MemorySegment}, from which the address of the target - * foreign function is derived. Moreover, 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. + * The Java {@linkplain java.lang.invoke.MethodType method type} associated with the + * returned method handle is {@linkplain FunctionDescriptor#toMethodType() derived} + * from the argument and return layouts in the function descriptor, but features an + * additional leading parameter of type {@link MemorySegment}, from which the address + * of the target foreign function is derived. Moreover, 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. *

    - * Upon invoking a downcall method handle, the linker provides the following guarantees for any argument - * {@code A} of type {@link MemorySegment} whose corresponding layout is an {@linkplain AddressLayout address layout}: + * Upon invoking a downcall method handle, the linker provides the following + * guarantees for any argument {@code A} of type {@link MemorySegment} whose + * corresponding layout is an {@linkplain AddressLayout address layout}: *

      - *
    • {@code A.scope().isAlive() == true}. Otherwise, the invocation throws {@link IllegalStateException};
    • - *
    • The invocation occurs in a thread {@code T} such that {@code A.isAccessibleBy(T) == true}. - * Otherwise, the invocation throws {@link WrongThreadException}; and
    • - *
    • {@code A} is kept alive during the invocation. For instance, if {@code A} has been obtained using a - * {@linkplain Arena#ofShared() shared arena}, any attempt to {@linkplain Arena#close() close} - * the arena while the downcall method handle is still executing will result in an {@link IllegalStateException}.
    • + *
    • {@code A.scope().isAlive() == true}. Otherwise, the invocation + * throws {@link IllegalStateException};
    • + *
    • The invocation occurs in a thread {@code T} such that + * {@code A.isAccessibleBy(T) == true}. + * Otherwise, the invocation throws {@link WrongThreadException}; and
    • + *
    • {@code A} is kept alive during the invocation. For instance, + * if {@code A} has been obtained using a {@linkplain Arena#ofShared() shared arena}, + * any attempt to {@linkplain Arena#close() close} the arena while the + * downcall method handle is still executing will result in an + * {@link IllegalStateException}.
    • *
    *

    - * Moreover, if the provided function descriptor's return layout is an {@linkplain AddressLayout address layout}, - * invoking the returned method handle will return a native segment associated with - * the global scope. Under normal conditions, the size of the returned segment is {@code 0}. - * However, if the function descriptor's return layout has a {@linkplain AddressLayout#targetLayout() target layout} - * {@code T}, then the size of the returned segment is set to {@code T.byteSize()}. + * Moreover, if the provided function descriptor's return layout is an + * {@linkplain AddressLayout address layout}, invoking the returned method handle + * will return a native segment associated with the global scope. Under normal + * conditions, the size of the returned segment is {@code 0}. However, if the + * function descriptor's return layout has a + * {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size + * of the returned segment is set to {@code T.byteSize()}. *

    - * The returned method handle will throw an {@link IllegalArgumentException} if the {@link MemorySegment} - * representing the target address of the foreign function is the {@link MemorySegment#NULL} address. If an argument - * is a {@link MemorySegment}, whose corresponding layout is a {@linkplain GroupLayout group layout}, the linker - * might attempt to access the contents of the segment. As such, one of the exceptions specified by the - * {@link MemorySegment#get(ValueLayout.OfByte, long)} or the - * {@link MemorySegment#copy(MemorySegment, long, MemorySegment, long, long)} methods may be thrown. - * The returned method handle will additionally throw {@link NullPointerException} if any argument - * passed to it is {@code null}. + * The returned method handle will throw an {@link IllegalArgumentException} if the + * {@link MemorySegment} representing the target address of the foreign function is + * the {@link MemorySegment#NULL} address. If an argument is a {@link MemorySegment}, + * whose corresponding layout is a {@linkplain GroupLayout group layout}, the linker + * might attempt to access the contents of the segment. As such, one of the + * exceptions specified by the {@link MemorySegment#get(ValueLayout.OfByte, long)} or + * the {@link MemorySegment#copy(MemorySegment, long, MemorySegment, long, long)} + * methods may be thrown. The returned method handle will additionally throw + * {@link NullPointerException} if any argument passed to it is {@code null}. * - * @param function the function descriptor of the target foreign function. - * @param options the linker options associated with this linkage request. - * @return a downcall method handle. - * @throws IllegalArgumentException if the provided function descriptor is not supported by this linker - * @throws IllegalArgumentException if an invalid combination of linker options is given - * @throws IllegalCallerException If the caller is in a module that does not have native access enabled + * @param function the function descriptor of the target foreign function + * @param options the linker options associated with this linkage request + * @return a downcall method handle + * @throws IllegalArgumentException if the provided function descriptor is not + * supported by this linker + * @throws IllegalArgumentException if an invalid combination of linker options + * is given + * @throws IllegalCallerException If the caller is in a module that does not have + * native access enabled */ @CallerSensitive @Restricted MethodHandle downcallHandle(FunctionDescriptor function, Option... options); /** - * Creates an upcall stub which can be passed to other foreign functions as a function pointer, associated with the given - * arena. Calling such a function pointer from foreign code will result in the execution of the provided - * method handle. + * Creates an upcall stub which can be passed to other foreign functions as a + * function pointer, associated with the given arena. Calling such a function + * pointer from foreign code will result in the execution of the provided method + * handle. *

    - * The returned memory segment's address points to the newly allocated upcall stub, and is associated with - * the provided arena. As such, the lifetime of the returned upcall stub segment is controlled by the - * provided arena. For instance, if the provided arena is a confined arena, the returned - * upcall stub segment will be deallocated when the provided confined arena is {@linkplain Arena#close() closed}. + * The returned memory segment's address points to the newly allocated upcall stub, + * and is associated with the provided arena. As such, the lifetime of the returned + * upcall stub segment is controlled by the provided arena. For instance, if the + * provided arena is a confined arena, the returned upcall stub segment will be + * deallocated when the provided confined arena is {@linkplain Arena#close() closed}. *

    - * An upcall stub argument whose corresponding layout is an {@linkplain AddressLayout address layout} - * is a native segment associated with the global scope. - * Under normal conditions, the size of this segment argument is {@code 0}. - * However, if the address layout has a {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size of the - * segment argument is set to {@code T.byteSize()}. + * An upcall stub argument whose corresponding layout is an + * {@linkplain AddressLayout address layout} is a native segment associated with the + * global scope. Under normal conditions, the size of this segment argument is + * {@code 0}. However, if the address layout has a + * {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size + * of the segment argument is set to {@code T.byteSize()}. *

    - * The target method handle should not throw any exceptions. If the target method handle does throw an exception, - * the JVM will terminate abruptly. To avoid this, clients should wrap the code in the target method handle in a - * try/catch block to catch any unexpected exceptions. This can be done using the - * {@link java.lang.invoke.MethodHandles#catchException(MethodHandle, Class, MethodHandle)} method handle combinator, - * and handle exceptions as desired in the corresponding catch block. + * The target method handle should not throw any exceptions. If the target method + * handle does throw an exception, the JVM will terminate abruptly. To avoid this, + * clients should wrap the code in the target method handle in a try/catch block to + * catch any unexpected exceptions. This can be done 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 arena the arena associated with the returned upcall stub segment. - * @param options the linker options associated with this linkage request. - * @return a zero-length segment whose address is the address of the upcall stub. - * @throws IllegalArgumentException if the provided function descriptor is not supported by this linker - * @throws IllegalArgumentException if the type of {@code target} is incompatible with the - * type {@linkplain FunctionDescriptor#toMethodType() derived} from {@code function} - * @throws IllegalArgumentException if it is determined that the target method handle can throw an exception + * @param target the target method handle + * @param function the upcall stub function descriptor + * @param arena the arena associated with the returned upcall stub segment + * @param options the linker options associated with this linkage request + * @return a zero-length segment whose address is the address of the upcall stub + * @throws IllegalArgumentException if the provided function descriptor is not + * supported by this linker + * @throws IllegalArgumentException if the type of {@code target} is incompatible + * with the type {@linkplain FunctionDescriptor#toMethodType() derived} + * from {@code function} + * @throws IllegalArgumentException if it is determined that the target method handle + * can throw an exception * @throws IllegalStateException if {@code arena.scope().isAlive() == false} - * @throws WrongThreadException if {@code arena} is a confined arena, and this method is called from a - * thread {@code T}, other than the arena's owner thread - * @throws IllegalCallerException If the caller is in a module that does not have native access enabled + * @throws WrongThreadException if {@code arena} is a confined arena, and this method + * is called from a thread {@code T}, other than the arena's owner thread + * @throws IllegalCallerException If the caller is in a module that does not have + * native access enabled */ @CallerSensitive @Restricted @@ -647,31 +741,44 @@ MemorySegment upcallStub(MethodHandle target, /** * Returns a symbol lookup for symbols in a set of commonly used libraries. *

    - * Each {@link Linker} is responsible for choosing libraries that are widely recognized as useful on the OS - * and processor combination supported by the {@link Linker}. Accordingly, the precise set of symbols exposed by the - * symbol lookup is unspecified; it varies from one {@link Linker} to another. - * @implNote It is strongly recommended that the result of {@link #defaultLookup} exposes a set of symbols that is stable over time. - * Clients of {@link #defaultLookup()} are likely to fail if a symbol that was previously exposed by the symbol lookup is no longer exposed. - *

    If an implementer provides {@link Linker} implementations for multiple OS and processor combinations, then it is strongly - * recommended that the result of {@link #defaultLookup()} exposes, as much as possible, a consistent set of symbols - * across all the OS and processor combinations. - * @return a symbol lookup for symbols in a set of commonly used libraries. + * Each {@link Linker} is responsible for choosing libraries that are widely + * recognized as useful on the OS and processor combination supported by the + * {@link Linker}. Accordingly, the precise set of symbols exposed by the symbol + * lookup is unspecified; it varies from one {@link Linker} to another. + * + * @implNote It is strongly recommended that the result of {@link #defaultLookup} + * exposes a set of symbols that is stable over time. Clients of + * {@link #defaultLookup()} are likely to fail if a symbol that was + * previously exposed by the symbol lookup is no longer exposed. + *

    If an implementer provides {@link Linker} implementations for + * multiple OS and processor combinations, then it is strongly + * recommended that the result of {@link #defaultLookup()} exposes, as much + * as possible, a consistent set of symbols across all the OS and processor + * combinations. + * + * @return a symbol lookup for symbols in a set of commonly used libraries */ SymbolLookup defaultLookup(); /** - * {@return an unmodifiable mapping between the names of data types used by the ABI implemented by this linker and their - * canonical layouts} + * {@return an unmodifiable mapping between the names of data types used by the ABI + * implemented by this linker and their canonical layouts} *

    - * Each {@link Linker} is responsible for choosing the data types that are widely recognized as useful on the OS - * and processor combination supported by the {@link Linker}. Accordingly, the precise set of data type names - * and canonical layouts exposed by the linker are unspecified; they vary from one {@link Linker} to another. - * @implNote It is strongly recommended that the result of {@link #canonicalLayouts()} exposes a set of symbols that is stable over time. - * Clients of {@link #canonicalLayouts()} are likely to fail if a data type that was previously exposed by the linker - * is no longer exposed, or if its canonical layout is updated. - *

    If an implementer provides {@link Linker} implementations for multiple OS and processor combinations, then it is strongly - * recommended that the result of {@link #canonicalLayouts()} exposes, as much as possible, a consistent set of symbols - * across all the OS and processor combinations. + * Each {@link Linker} is responsible for choosing the data types that are widely + * recognized as useful on the OS and processor combination supported by the + * {@link Linker}. Accordingly, the precise set of data type names and canonical + * layouts exposed by the linker are unspecified; they vary from one {@link Linker} + * to another. + * + * @implNote It is strongly recommended that the result of {@link #canonicalLayouts()} + * exposes a set of symbols that is stable over time. Clients of + * {@link #canonicalLayouts()} are likely to fail if a data type that was + * previously exposed by the linker is no longer exposed, or if its + * canonical layout is updated. + *

    If an implementer provides {@link Linker} implementations for multiple + * OS and processor combinations, then it is strongly recommended that the + * result of {@link #canonicalLayouts()} exposes, as much as possible, + * a consistent set of symbols across all the OS and processor combinations. */ Map canonicalLayouts(); @@ -683,49 +790,57 @@ sealed interface Option permits LinkerOptions.LinkerOptionImpl { /** - * {@return a linker option used to denote the index indicating the start of the variadic arguments passed to the - * function described by the function descriptor associated with a downcall linkage request} + * {@return a linker option used to denote the index indicating the start of the + * variadic arguments passed to the function described by the function + * descriptor associated with a downcall linkage request} *

    - * The {@code index} value must conform to {@code 0 <= index <= N}, where {@code N} is the number of argument - * layouts of the function descriptor used in conjunction with this linker option. When the {@code index} is: + * The {@code index} value must conform to {@code 0 <= index <= N}, where + * {@code N} is the number of argument layouts of the function descriptor used in + * conjunction with this linker option. When the {@code index} is: *

      - *
    • {@code 0}, all arguments passed to the function are passed as variadic arguments
    • - *
    • {@code N}, none of the arguments passed to the function are passed as variadic arguments
    • - *
    • {@code n}, where {@code 0 < m < N}, the arguments {@code m..N} are passed as variadic arguments
    • + *
    • {@code 0}, all arguments passed to the function are passed as variadic + * arguments
    • + *
    • {@code N}, none of the arguments passed to the function are passed as + * variadic arguments
    • + *
    • {@code n}, where {@code 0 < m < N}, the arguments {@code m..N} are passed + * as variadic arguments
    • *
    - * It is important to always use this linker option when linking a variadic - * function, even if no variadic argument is passed (the second case in the list - * above), as this might still affect the calling convention on certain platforms. + * It is important to always use this linker option when linking a + * variadic function, even if no variadic + * argument is passed (the second case in the list above), as this might still + * affect the calling convention on certain platforms. * - * @implNote The index value is validated when making a linkage request, which is when the function descriptor - * against which the index is validated is available. + * @implNote The index value is validated when making a linkage request, which is + * when the function descriptor against which the index is validated is + * available. * - * @param index the index of the first variadic argument layout in the function descriptor associated - * with a downcall linkage request. + * @param index the index of the first variadic argument layout in the function + * descriptor associated with a downcall linkage request */ static Option firstVariadicArg(int index) { return new LinkerOptions.FirstVariadicArg(index); } /** - * {@return a linker option used to save portions of the execution state immediately after - * calling a foreign function associated with a downcall method handle, - * before it can be overwritten by the Java runtime, or read through conventional means} + * {@return a linker option used to save portions of the execution state + * immediately after calling a foreign function associated with a + * downcall method handle, before it can be overwritten by the Java + * runtime, or read through conventional means} *

    - * Execution state is captured by a downcall method handle on invocation, by writing it - * to a native segment provided by the user to the downcall method handle. - * For this purpose, a downcall method handle linked with this - * option will feature an additional {@link MemorySegment} parameter directly - * following the target address, and optional {@link SegmentAllocator} parameters. - * This parameter, the capture state segment, represents the native segment into which - * the captured state is written. + * Execution state is captured by a downcall method handle on invocation, by + * writing it to a native segment provided by the user to the downcall method + * handle. For this purpose, a downcall method handle linked with this option + * will feature an additional {@link MemorySegment} parameter directly following + * the target address, and optional {@link SegmentAllocator} parameters. This + * parameter, the capture state segment, represents the native segment + * into which the captured state is written. *

    - * The capture state segment must have size and alignment compatible with the layout returned by - * {@linkplain #captureStateLayout}. This layout is a struct layout which has a named field for - * each captured value. + * The capture state segment must have size and alignment compatible with the + * layout returned by {@linkplain #captureStateLayout}. This layout is a struct + * layout which has a named field for each captured value. *

    - * Captured state can be retrieved from the capture state segment by constructing var handles - * from the {@linkplain #captureStateLayout capture state layout}. + * Captured state can be retrieved from the capture state segment by constructing + * var handles from the {@linkplain #captureStateLayout capture state layout}. *

    * The following example demonstrates the use of this linker option: * {@snippet lang = "java": @@ -745,9 +860,9 @@ static Option firstVariadicArg(int index) { *

    * This linker option can not be combined with {@link #critical}. * - * @param capturedState the names of the values to save. - * @throws IllegalArgumentException if at least one of the provided {@code capturedState} names - * is unsupported on the current platform + * @param capturedState the names of the values to save + * @throws IllegalArgumentException if at least one of the provided + * {@code capturedState} names is unsupported on the current platform * @see #captureStateLayout() */ static Option captureCallState(String... capturedState) { @@ -759,8 +874,9 @@ static Option captureCallState(String... capturedState) { } /** - * {@return a struct layout that represents the layout of the capture state segment that is passed - * to a downcall handle linked with {@link #captureCallState(String...)}} + * {@return a struct layout that represents the layout of the capture state + * segment that is passed to a downcall handle linked with + * {@link #captureCallState(String...)}} *

    * The capture state layout is platform-dependent but is guaranteed to be * a {@linkplain StructLayout struct layout} containing only {@linkplain ValueLayout value layouts} @@ -789,14 +905,15 @@ static StructLayout captureStateLayout() { /** * {@return a linker option used to mark a foreign function as critical} *

    - * A critical function is a function that has an extremely short running time in all cases - * (similar to calling an empty function), and does not call back into Java (e.g. using an upcall stub). + * A critical function is a function that has an extremely short running time in + * all cases (similar to calling an empty function), and does not call back into + * Java (e.g. using an upcall stub). *

    * Using this linker option is a hint that some implementations may use to apply * optimizations that are only valid for critical functions. *

    - * Using this linker option when linking non-critical functions is likely to have adverse effects, - * such as loss of performance or JVM crashes. + * Using this linker option when linking non-critical functions is likely to have + * adverse effects, such as loss of performance or JVM crashes. */ static Option critical() { return LinkerOptions.Critical.INSTANCE; diff --git a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java index 71193a02212..0933c637acb 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java @@ -43,21 +43,26 @@ /** * A memory layout describes the contents of a memory segment. *

    - * There are two leaves in the layout hierarchy, {@linkplain ValueLayout value layouts}, which are used to represent values of given size and kind - * and {@linkplain PaddingLayout padding layouts} which are used, as the name suggests, to represent a portion of a memory - * segment whose contents should be ignored, and which are primarily present for alignment reasons. - * Some common value layout constants, such as {@link ValueLayout#JAVA_INT} and {@link ValueLayout#JAVA_FLOAT_UNALIGNED} - * are defined in the {@link ValueLayout} class. A special kind of value layout, namely an {@linkplain AddressLayout address layout}, - * is used to model values that denote the address of a region of memory. + * There are two leaves in the layout hierarchy, {@linkplain ValueLayout value layouts}, + * which are used to represent values of given size and kind and + * {@linkplain PaddingLayout padding layouts} which are used, as the name suggests, to + * represent a portion of a memory segment whose contents should be ignored, and which + * are primarily present for alignment reasons. Some common value layout constants, such + * as {@link ValueLayout#JAVA_INT} and {@link ValueLayout#JAVA_FLOAT_UNALIGNED} are + * defined in the {@link ValueLayout} class. A special kind of value layout, namely an + * {@linkplain AddressLayout address layout}, is used to model values that denote the + * address of a region of memory. *

    - * More complex layouts can be derived from simpler ones: a {@linkplain SequenceLayout sequence layout} denotes a - * homogeneous repetition of zero or more occurrences of an element layout; a {@linkplain GroupLayout group layout} - * denotes a heterogeneous aggregation of zero or more member layouts. Group layouts come in two - * flavors: {@linkplain StructLayout struct layouts}, where member layouts are laid out one after the other, and - * {@linkplain UnionLayout union layouts} where member layouts are laid out at the same starting offset. + * More complex layouts can be derived from simpler ones: a + * {@linkplain SequenceLayout sequence layout} denotes a homogeneous repetition of zero + * or more occurrences of an element layout; a {@linkplain GroupLayout group layout} + * denotes a heterogeneous aggregation of zero or more member layouts. Group layouts + * come in two flavors: {@linkplain StructLayout struct layouts}, where member layouts + * are laid out one after the other, and {@linkplain UnionLayout union layouts} where + * member layouts are laid out at the same starting offset. *

    - * Layouts can be optionally associated with a name. A layout name can be referred to when - * constructing layout paths. + * Layouts can be optionally associated with a name. A layout name can be + * referred to when constructing layout paths. *

    * Consider the following struct declaration in C: * @@ -85,46 +90,58 @@ * All layouts have a size (expressed in bytes), which is defined as follows: *

      *
    • The size of a value layout is determined by the {@linkplain ValueLayout#carrier()} - * associated with the value layout. That is, the constant {@link ValueLayout#JAVA_INT} has carrier {@code int}, and - * size of 4 bytes;
    • - *
    • The size of an address layout is platform-dependent. That is, the constant {@link ValueLayout#ADDRESS} - * has a size of 8 bytes on a 64-bit platform;
    • - *
    • The size of a padding layout is always provided explicitly, on {@linkplain MemoryLayout#paddingLayout(long) construction};
    • - *
    • The size of a sequence layout whose element layout is E and element count is L, - * is the size of E, multiplied by L;
    • - *
    • The size of a struct layout with member layouts M1, M2, ... Mn whose sizes are - * S1, S2, ... Sn, respectively, is S1 + S2 + ... + Sn;
    • - *
    • The size of a union layout U with member layouts M1, M2, ... Mn whose sizes are + * associated with the value layout. That is, the constant {@link ValueLayout#JAVA_INT} + * has carrier {@code int}, and size of 4 bytes;
    • + *
    • The size of an address layout is platform-dependent. That is, the constant + * {@link ValueLayout#ADDRESS} has a size of 8 bytes on a 64-bit platform;
    • + *
    • The size of a padding layout is always provided explicitly, on + * {@linkplain MemoryLayout#paddingLayout(long) construction};
    • + *
    • The size of a sequence layout whose element layout is E + * and element count is L, is the size of E, + * multiplied by L;
    • + *
    • The size of a struct layout with member layouts M1, M2, ... Mn + * whose sizes are S1, S2, ... Sn, respectively, + * is S1 + S2 + ... + Sn;
    • + *
    • The size of a union layout U with member layouts + * M1, M2, ... Mn whose sizes are * S1, S2, ... Sn, respectively, is max(S1, S2, ... Sn).
    • *
    *

    - * Furthermore, all layouts have a natural alignment (expressed in bytes) which is defined as follows: + * Furthermore, all layouts have a natural alignment (expressed in bytes) which + * is defined as follows: *

      *
    • The natural alignment of a padding layout is 1;
    • - *
    • The natural alignment of a value layout whose size is N is N;
    • - *
    • The natural alignment of a sequence layout whose element layout is E is the alignment of E;
    • - *
    • The natural alignment of a group layout with member layouts M1, M2, ... Mn whose - * alignments are A1, A2, ... An, respectively, is max(A1, A2 ... An).
    • + *
    • The natural alignment of a value layout whose size is N is + * N;
    • + *
    • The natural alignment of a sequence layout whose element layout is + * E is the alignment of E;
    • + *
    • The natural alignment of a group layout with member layouts + * M1, M2, ... Mn whose alignments are + * A1, A2, ... An, respectively, is max(A1, A2 ... An).
    • *
    - * A layout's alignment can be overridden if needed (see {@link MemoryLayout#withByteAlignment(long)}), which can be useful to describe + * A layout's alignment can be overridden if needed + * (see {@link MemoryLayout#withByteAlignment(long)}), which can be useful to describe * layouts with weaker or stronger alignment constraints. * *

    Layout paths

    * - * A layout path is used to unambiguously select a layout that is nested in some other layout. - * Layout paths are typically expressed as a sequence of one or more {@linkplain PathElement path elements}. - * (A more formal definition of layout paths is provided below). + * A layout path is used to unambiguously select a layout that is nested in some + * other layout. Layout paths are typically expressed as a sequence of one or more + * {@linkplain PathElement path elements}. (A more formal definition of layout paths is + * provided below). *

    * Layout paths can be used to: *

      - *
    • obtain {@linkplain MemoryLayout#byteOffset(PathElement...) offsets} of arbitrarily nested layouts;
    • - *
    • obtain a {@linkplain #varHandle(PathElement...) var handle} that can be used to access the value corresponding - * to the selected layout;
    • + *
    • obtain {@linkplain MemoryLayout#byteOffset(PathElement...) offsets} of + * arbitrarily nested layouts;
    • + *
    • obtain a {@linkplain #varHandle(PathElement...) var handle} that can be used + * to access the value corresponding to the selected layout;
    • *
    • {@linkplain #select(PathElement...) select} an arbitrarily nested layout.
    • *
    *

    - * For instance, given the {@code taggedValues} sequence layout constructed above, we can obtain the offset, - * in bytes, of the member layout named value in the first sequence element, as follows: + * For instance, given the {@code taggedValues} sequence layout constructed above, we can + * obtain the offset, in bytes, of the member layout named value in the + * first sequence element, as follows: * {@snippet lang=java : * long valueOffset = TAGGED_VALUES.byteOffset(PathElement.sequenceElement(0), * PathElement.groupElement("value")); // yields 4 @@ -138,11 +155,13 @@ * *

    Open path elements

    * - * Some layout path elements, said open path elements, can select multiple layouts at once. For instance, - * the open path elements {@link PathElement#sequenceElement()}, {@link PathElement#sequenceElement(long, long)} select - * an unspecified element in a sequence layout. A var handle derived from a layout path containing one or more - * open path element features additional coordinates of type {@code long}, which can be used by clients to bind - * the open elements in the path: + * Some layout path elements, said open path elements, can select multiple + * layouts at once. For instance, the open path elements + * {@link PathElement#sequenceElement()}, {@link PathElement#sequenceElement(long, long)} + * select an unspecified element in a sequence layout. A var handle derived from a + * layout path containing one or more open path element features additional coordinates + * of type {@code long}, which can be used by clients to bind the open elements + * in the path: * * {@snippet lang=java : * VarHandle valueHandle = TAGGED_VALUES.varHandle(PathElement.sequenceElement(), @@ -156,9 +175,10 @@ * *

    * Open path elements also affect the creation of - * {@linkplain #byteOffsetHandle(PathElement...) offset-computing method handles}. Each open path element becomes - * an additional {@code long} parameter in the obtained method handle. This parameter can be used to specify the index - * of the sequence element whose offset is to be computed: + * {@linkplain #byteOffsetHandle(PathElement...) offset-computing method handles}. Each + * open path element becomes an additional {@code long} parameter in the obtained method + * handle. This parameter can be used to specify the index of the sequence element whose + * offset is to be computed: * * {@snippet lang=java : * MethodHandle offsetHandle = TAGGED_VALUES.byteOffsetHandle(PathElement.sequenceElement(), @@ -169,8 +189,8 @@ * *

    Dereference path elements

    * - * A special kind of path element, called dereference path element, allows var handles obtained from - * memory layouts to follow pointers. Consider the following layout: + * A special kind of path element, called dereference path element, allows var + * handles obtained from memory layouts to follow pointers. Consider the following layout: * * {@snippet lang=java : * StructLayout RECTANGLE = MemoryLayout.structLayout( @@ -185,10 +205,12 @@ * ); * } * - * This layout is a struct layout describing a rectangle. It contains a single field, namely {@code points}, - * an address layout whose {@linkplain AddressLayout#targetLayout() target layout} is a sequence layout of four - * struct layouts. Each struct layout describes a two-dimensional point, and is defined as a pair or - * {@link ValueLayout#JAVA_INT} coordinates, with names {@code x} and {@code y}, respectively. + * This layout is a struct layout describing a rectangle. It contains a single field, + * namely {@code points}, an address layout whose + * {@linkplain AddressLayout#targetLayout() target layout} is a sequence layout of four + * struct layouts. Each struct layout describes a two-dimensional point, and is defined + * as a pair or {@link ValueLayout#JAVA_INT} coordinates, with names {@code x} and + * {@code y}, respectively. *

    * With dereference path elements, we can obtain a var handle that accesses the {@code y} coordinate of one of the * point in the rectangle, as follows: @@ -210,40 +232,50 @@ * *

    Layout path well-formedness

    * - * A layout path is applied to a layout {@code C_0}, also called the initial layout. Each path element in a - * layout path can be thought of as a function that updates the current layout {@code C_i-1} to some other layout - * {@code C_i}. That is, for each path element {@code E1, E2, ... En}, in a layout path {@code P}, we compute - * {@code C_i = f_i(C_i-1)}, where {@code f_i} is the selection function associated with the path element under consideration, - * denoted as {@code E_i}. The final layout {@code C_i} is also called the selected layout. + * A layout path is applied to a layout {@code C_0}, also called the + * initial layout. Each path element in a layout path can be thought of as a + * function that updates the current layout {@code C_i-1} to some other layout + * {@code C_i}. That is, for each path element {@code E1, E2, ... En}, in a layout path + * {@code P}, we compute {@code C_i = f_i(C_i-1)}, where {@code f_i} is the selection + * function associated with the path element under consideration, denoted as {@code E_i}. + * The final layout {@code C_i} is also called the selected layout. *

    - * A layout path {@code P} is considered well-formed for an initial layout {@code C_0} if all its path elements - * {@code E1, E2, ... En} are well-formed for their corresponding input layouts {@code C_0, C_1, ... C_n-1}. - * A path element {@code E} is considered well-formed for a layout {@code L} if any of the following is true: + * A layout path {@code P} is considered well-formed for an initial layout {@code C_0} + * if all its path elements {@code E1, E2, ... En} are well-formed for their + * corresponding input layouts {@code C_0, C_1, ... C_n-1}. A path element {@code E} is + * considered well-formed for a layout {@code L} if any of the following is true: *

      - *
    • {@code L} is a sequence layout and {@code E} is a sequence path element (one of {@link PathElement#sequenceElement(long)}, - * {@link PathElement#sequenceElement(long, long)} or {@link PathElement#sequenceElement()}). Moreover, if {@code E} - * contains one or more sequence indices, such indices have to be compatible with the sequence layout's element count;
    • - *
    • {@code L} is a group layout and {@code E} is a group path element (one of {@link PathElement#groupElement(String)} - * or {@link PathElement#groupElement(long)}). Moreover, the group path element must refer to a valid member layout in + *
    • {@code L} is a sequence layout and {@code E} is a sequence path element + * (one of {@link PathElement#sequenceElement(long)}, {@link PathElement#sequenceElement(long, long)} + * or {@link PathElement#sequenceElement()}). Moreover, if {@code E} contains one or + * more sequence indices, such indices have to be compatible with the sequence layout's + * element count;
    • + *
    • {@code L} is a group layout and {@code E} is a group path element (one of + * {@link PathElement#groupElement(String)} or {@link PathElement#groupElement(long)}). + * Moreover, the group path element must refer to a valid member layout in * {@code L}, either by name, or index;
    • - *
    • {@code L} is an address layout and {@code E} is a {@linkplain PathElement#dereferenceElement() dereference path element}. + *
    • {@code L} is an address layout and {@code E} is a {@linkplain PathElement#dereferenceElement() + * dereference path element}. * Moreover, {@code L} must define some {@linkplain AddressLayout#targetLayout() target layout}.
    • *
    - * Any attempt to provide a layout path {@code P} that is not well-formed for an initial layout {@code C_0} will result - * in an {@link IllegalArgumentException}. + * Any attempt to provide a layout path {@code P} that is not well-formed for an initial + * layout {@code C_0} will result in an {@link IllegalArgumentException}. * *

    Access mode restrictions

    * - * A var handle returned by {@link #varHandle(PathElement...)} or {@link ValueLayout#varHandle()} features certain - * access characteristics, which are derived from the selected layout {@code L}: + * A var handle returned by {@link #varHandle(PathElement...)} or + * {@link ValueLayout#varHandle()} features certain access characteristics, which are + * derived from the selected layout {@code L}: *
      *
    • A carrier type {@code T}, derived from {@code L.carrier()}
    • *
    • An alignment constraint {@code A}, derived from {@code L.byteAlignment()}
    • *
    • An access size {@code S}, derived from {@code L.byteSize()}
    • *
    - * Depending on the above characteristics, the returned var handle might feature certain access mode restrictions. - * We say that a var handle is aligned if its alignment constraint {@code A} is compatible with the access size - * {@code S}, that is if {@code A >= S}. An aligned var handle is guaranteed to support the following access modes: + * Depending on the above characteristics, the returned var handle might feature certain + * access mode restrictions. We say that a var handle is aligned if its + * alignment constraint {@code A} is compatible with the access size {@code S}, that is + * if {@code A >= S}. An aligned var handle is guaranteed to support the following + * access modes: *
      *
    • read write access modes for all {@code T}. On 32-bit platforms, access modes * {@code get} and {@code set} for {@code long}, {@code double} and {@code MemorySegment} @@ -260,26 +292,33 @@ * (Future major platform releases of the JDK may support additional * numeric types for certain currently unsupported access modes.) *
    - * If {@code T} is {@code float}, {@code double} or {@link MemorySegment} then atomic update access modes compare - * values using their bitwise representation (see {@link Float#floatToRawIntBits}, {@link Double#doubleToRawLongBits} + * If {@code T} is {@code float}, {@code double} or {@link MemorySegment} then atomic + * update access modes compare values using their bitwise representation + * (see {@link Float#floatToRawIntBits}, {@link Double#doubleToRawLongBits} * and {@link MemorySegment#address()}, respectively). *

    - * Alternatively, a var handle is unaligned if its alignment constraint {@code A} is incompatible with the - * access size {@code S}, that is, if {@code A < S}. An unaligned var handle only supports the {@code get} and {@code set} - * access modes. All other access modes will result in {@link UnsupportedOperationException} being thrown. Moreover, - * while supported, access modes {@code get} and {@code set} might lead to word tearing. + * Alternatively, a var handle is unaligned if its alignment constraint {@code A} + * is incompatible with the access size {@code S}, that is, if {@code A < S}. An + * unaligned var handle only supports the {@code get} and {@code set} access modes. All + * other access modes will result in {@link UnsupportedOperationException} being thrown. + * Moreover, while supported, access modes {@code get} and {@code set} might lead to + * word tearing. * *

    Working with variable-length arrays

    * - * We have seen how sequence layouts are used to describe the contents of an array whose size is known statically. - * There are cases, however, where the array size is only known dynamically. We call such arrays variable-length arrays. + * We have seen how sequence layouts are used to describe the contents of an array whose + * size is known statically. There are cases, however, where the array size is + * only known dynamically. We call such arrays variable-length arrays. * There are two common kinds of variable-length arrays: *
      - *
    • a toplevel variable-length array whose size depends on the value of some unrelated variable, or parameter;
    • - *
    • an variable-length array nested in a struct, whose size depends on the value of some other field in the enclosing struct.
    • + *
    • a toplevel variable-length array whose size depends on the value of + * some unrelated variable, or parameter;
    • + *
    • an variable-length array nested in a struct, whose size depends on + * the value of some other field in the enclosing struct.
    • *
    - * While variable-length arrays cannot be modeled directly using sequence layouts, clients can still enjoy structured - * access to elements of variable-length arrays using var handles as demonstrated in the following sections. + * While variable-length arrays cannot be modeled directly using sequence layouts, + * clients can still enjoy structured access to elements of variable-length arrays + * using var handles as demonstrated in the following sections. * *

    Toplevel variable-length arrays

    * @@ -292,8 +331,8 @@ * } Point; * } * - * In the above code, a point is modeled as two coordinates ({@code x} and {@code y} respectively). Now consider - * the following snippet of C code: + * In the above code, a point is modeled as two coordinates ({@code x} and + * {@code y} respectively). Now consider the following snippet of C code: * * {@snippet lang=c : * int size = ... @@ -303,10 +342,12 @@ * } * } * - * Here, we allocate an array of points ({@code points}). Crucially, the size of the array is dynamically bound to the value - * of the {@code size} variable. Inside the loop, the {@code x} coordinate of all the points in the array is accessed. + * Here, we allocate an array of points ({@code points}). Crucially, the size of + * the array is dynamically bound to the value of the {@code size} variable. Inside + * the loop, the {@code x} coordinate of all the points in the array is accessed. *

    - * To model this code in Java, let's start by defining a layout for the {@code Point} struct, as follows: + * To model this code in Java, let's start by defining a layout for the {@code Point} + * struct, as follows: * * {@snippet lang=java : * StructLayout POINT = MemoryLayout.structLayout( @@ -315,10 +356,12 @@ * ); * } * - * Since we know we need to create and access an array of points, it would be tempting to create a sequence layout modelling - * the variable-length array, and then derive the necessary access var handles from the sequence layout. But this approach - * is problematic, as the size of the variable-length array is not known. Instead, a var handle that provides structured - * access to the elements of a variable-length array can be obtained directly from the layout describing the array elements + * Since we know we need to create and access an array of points, it would be tempting to + * create a sequence layout modelling the variable-length array, and then derive the + * necessary access var handles from the sequence layout. But this approach is + * problematic, as the size of the variable-length array is not known. Instead, a + * var handle that provides structured access to the elements of a variable-length array + * can be obtained directly from the layout describing the array elements * (e.g. the point layout), as demonstrated below: * * {@snippet lang=java : @@ -331,15 +374,19 @@ * } * } * - * Here, the coordinate {@code x} of subsequent point in the array is accessed using the {@code POINT_ARR_X} var - * handle, which is obtained using the {@link #arrayElementVarHandle(PathElement...)} method. This var handle - * features two {@code long} coordinates: the first is a base offset (set to {@code 0L}), while the - * second is a logical index that can be used to stride over all the elements of the point array. + * Here, the coordinate {@code x} of subsequent point in the array is accessed using the + * {@code POINT_ARR_X} var handle, which is obtained using the + * {@link #arrayElementVarHandle(PathElement...)} method. This var handle features two + * {@code long} coordinates: the first is a base offset (set to {@code 0L}), while the + * second is a logical index that can be used to stride over all the elements of the + * point array. *

    - * The base offset coordinate allows clients to express complex access operations, by injecting additional offset - * computation into the var handle (we will see an example of that below). In cases where the base offset is constant - * (as in the previous example) clients can, if desired, drop the base offset parameter and make the access expression - * simpler. This is achieved using the {@link java.lang.invoke.MethodHandles#insertCoordinates(VarHandle, int, Object...)} + * The base offset coordinate allows clients to express complex access operations, by + * injecting additional offset computation into the var handle (we will see an example + * of that below). In cases where the base offset is constant (as in the previous + * example) clients can, if desired, drop the base offset parameter and make the access + * expression simpler. This is achieved using the + * {@link java.lang.invoke.MethodHandles#insertCoordinates(VarHandle, int, Object...)} * var handle adapter. * *

    Nested variable-length arrays

    @@ -353,13 +400,15 @@ * } Polygon; * } * - * In the above code, a polygon is modeled as a size (the number of edges in the polygon) and an array of points - * (one for each vertex in the polygon). The number of vertices depends on the number of edges in the polygon. As such, - * the size of the {@code points} array is left unspecified in the C declaration, using a Flexible Array Member - * (a feature standardized in C99). + * In the above code, a polygon is modeled as a size (the number of edges in the polygon) + * and an array of points (one for each vertex in the polygon). The number of vertices + * depends on the number of edges in the polygon. As such, the size of the {@code points} + * array is left unspecified in the C declaration, using a + * Flexible Array Member (a feature standardized in C99). *

    - * Again, clients can perform structured access to elements in the nested variable-length array using the - * {@link #arrayElementVarHandle(PathElement...)} method, as demonstrated below: + * Again, clients can perform structured access to elements in the nested variable-length + * array using the {@link #arrayElementVarHandle(PathElement...)} method, as demonstrated + * below: * * {@snippet lang=java : * StructLayout POLYGON = MemoryLayout.structLayout( @@ -371,12 +420,14 @@ * long POINTS_OFFSET = POLYGON.byteOffset(PathElement.groupElement("points")); * } * - * The {@code POLYGON} layout contains a sequence layout of size zero. The element layout of the sequence layout - * is the {@code POINT} layout, shown previously. The polygon layout is used to obtain a var handle - * that provides access to the polygon size, as well as an offset ({@code POINTS_OFFSET}) to the start of the - * variable-length {@code points} array. + * The {@code POLYGON} layout contains a sequence layout of size zero. The + * element layout of the sequence layout is the {@code POINT} layout, shown previously. + * The polygon layout is used to obtain a var handle that provides access to the polygon + * size, as well as an offset ({@code POINTS_OFFSET}) to the start of the variable-length + * {@code points} array. *

    - * The {@code x} coordinates of all the points in a polygon can then be accessed as follows: + * The {@code x} coordinates of all the points in a polygon can then be accessed as + * follows: * {@snippet lang=java : * MemorySegment polygon = ... * int size = POLYGON_SIZE.get(polygon, 0L); @@ -384,14 +435,16 @@ * ... POINT_ARR_X.get(polygon, POINTS_OFFSET, (long)i) ... * } * } - * Here, we first obtain the polygon size, using the {@code POLYGON_SIZE} var handle. Then, in a loop, we read - * the {@code x} coordinates of all the points in the polygon. This is done by providing a custom offset - * (namely, {@code POINTS_OFFSET}) to the offset coordinate of the {@code POINT_ARR_X} var handle. As before, - * the loop induction variable {@code i} is passed as the index of the {@code POINT_ARR_X} var handle, - * to stride over all the elements of the variable-length array. + * Here, we first obtain the polygon size, using the {@code POLYGON_SIZE} var handle. + * Then, in a loop, we read the {@code x} coordinates of all the points in the polygon. + * This is done by providing a custom offset (namely, {@code POINTS_OFFSET}) to the + * offset coordinate of the {@code POINT_ARR_X} var handle. As before, the loop + * induction variable {@code i} is passed as the index of the {@code POINT_ARR_X} + * var handle, to stride over all the elements of the variable-length array. * * @implSpec - * Implementations of this interface are immutable, thread-safe and value-based. + * Implementations of this interface are immutable, thread-safe and + * value-based. * * @sealedGraph * @since 22 @@ -411,42 +464,51 @@ public sealed interface MemoryLayout Optional name(); /** - * {@return a memory layout with the same characteristics as this layout, but with the given name} + * {@return a memory layout with the same characteristics as this layout, but with + * the given name} * - * @param name the layout name. + * @param name the layout name * @see MemoryLayout#name() */ MemoryLayout withName(String name); /** - * {@return a memory layout with the same characteristics as this layout, but with no name} + * {@return a memory layout with the same characteristics as this layout, but with + * no name} * - * @apiNote This can be useful to compare two layouts that have different names, but are otherwise equal. + * @apiNote This can be useful to compare two layouts that have different names, but + * are otherwise equal. * @see MemoryLayout#name() */ MemoryLayout withoutName(); /** - * {@return the alignment constraint associated with this layout, expressed in bytes} Layout alignment defines a power - * of two {@code A} which is the byte-wise alignment of the layout, where {@code A} is the number of bytes that must be aligned - * for any pointer that correctly points to this layout. Thus: + * {@return the alignment constraint associated with this layout, expressed in bytes} + *

    + * Layout alignment defines a power of two {@code A} which is the byte-wise alignment + * of the layout, where {@code A} is the number of bytes that must be aligned for any + * pointer that correctly points to this layout. Thus: * *

      *
    • {@code A=1} means unaligned (in the usual sense), which is common in packets.
    • - *
    • {@code A=8} means word aligned (on LP64), {@code A=4} int aligned, {@code A=2} short aligned, etc.
    • - *
    • {@code A=64} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).
    • + *
    • {@code A=8} means word aligned (on LP64), {@code A=4} int aligned, + * {@code A=2} short aligned, etc.
    • + *
    • {@code A=64} is the most strict alignment required by the x86/SV ABI + * (for AVX-512 data).
    • *
    * - * If no explicit alignment constraint was set on this layout (see {@link #withByteAlignment(long)}), - * then this method returns the natural alignment constraint (in bytes) associated with this layout. + * If no explicit alignment constraint was set on this layout ( + * see {@link #withByteAlignment(long)}), then this method returns the + * natural alignment constraint (in bytes) associated + * with this layout. */ long byteAlignment(); /** - * {@return a memory layout with the same characteristics as this layout, but with the given - * alignment constraint (in bytes)} + * {@return a memory layout with the same characteristics as this layout, but with + * the given alignment constraint (in bytes)} * - * @param byteAlignment the layout alignment constraint, expressed in bytes. + * @param byteAlignment the layout alignment constraint, expressed in bytes * @throws IllegalArgumentException if {@code byteAlignment} is not a power of two */ MemoryLayout withByteAlignment(long byteAlignment); @@ -462,19 +524,24 @@ public sealed interface MemoryLayout long scale(long offset, long index); /** - *{@return a method handle that can be used to invoke {@link #scale(long, long)} on this layout} + *{@return a method handle that can be used to invoke {@link #scale(long, long)} + * on this layout} */ MethodHandle scaleHandle(); /** - * Computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the - * path is this layout. - * - * @param elements the layout path elements. - * @return The offset, in bytes, of the layout selected by the layout path in {@code elements}. - * @throws IllegalArgumentException if the layout path is not well-formed for this layout - * @throws IllegalArgumentException if the layout path contains one or more open path elements - * @throws IllegalArgumentException if the layout path contains one or more dereference path elements + * Computes the offset, in bytes, of the layout selected by the given layout path, + * where the initial layout in the path is this layout. + * + * @param elements the layout path elements + * @return The offset, in bytes, of the layout selected by the layout path in + * {@code elements} + * @throws IllegalArgumentException if the layout path is not + * well-formed for this layout + * @throws IllegalArgumentException if the layout path contains one or more + * open path elements + * @throws IllegalArgumentException if the layout path contains one or more + * dereference path elements */ long byteOffset(PathElement... elements); @@ -486,9 +553,10 @@ public sealed interface MemoryLayout *
      *
    • its return type is {@code long};
    • *
    • it has one leading {@code long} parameter representing the base offset;
    • - *
    • it has as zero or more trailing parameters of type {@code long}, one for each open path element - * in the provided layout path. The order of these parameters corresponds to the order in which the open path - * elements occur in the provided layout path. + *
    • it has as zero or more trailing parameters of type {@code long}, one for + * each open path element in the provided layout + * path. The order of these parameters corresponds to the order in which the + * open path elements occur in the provided layout path. *
    *

    * The final offset returned by the method handle is computed as follows: @@ -497,79 +565,99 @@ public sealed interface MemoryLayout * offset = b + c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n) * } * - * where {@code b} represents the base offset provided as a dynamic {@code long} argument, {@code x_1}, {@code x_2}, - * ... {@code x_n} represent indices into sequences provided as dynamic {@code long} arguments, whereas - * {@code s_1}, {@code s_2}, ... {@code s_n} are static stride constants derived from the size of the element - * layout of a sequence, and {@code c_1}, {@code c_2}, ... {@code c_m} are other static offset constants - * (such as field offsets) which are derived from the layout path. + * where {@code b} represents the base offset provided as a dynamic + * {@code long} argument, {@code x_1}, {@code x_2}, ... {@code x_n} represent indices + * into sequences provided as dynamic {@code long} arguments, whereas + * {@code s_1}, {@code s_2}, ... {@code s_n} are static stride constants + * derived from the size of the element layout of a sequence, and + * {@code c_1}, {@code c_2}, ... {@code c_m} are other static offset + * constants (such as field offsets) which are derived from the layout path. * - * @apiNote The returned method handle can be used to compute a layout offset, similarly to {@link #byteOffset(PathElement...)}, - * but more flexibly, as some indices can be specified when invoking the method handle. + * @apiNote The returned method handle can be used to compute a layout offset, + * similarly to {@link #byteOffset(PathElement...)}, but more flexibly, as + * some indices can be specified when invoking the method handle. * - * @param elements the layout path elements. - * @return a method handle that computes the offset, in bytes, of the layout selected by the given layout path. - * @throws IllegalArgumentException if the layout path is not well-formed for this layout - * @throws IllegalArgumentException if the layout path contains one or more dereference path elements + * @param elements the layout path elements + * @return a method handle that computes the offset, in bytes, of the layout selected + * by the given layout path + * @throws IllegalArgumentException if the layout path is not + * well-formed for this layout + * @throws IllegalArgumentException if the layout path contains one or more + * dereference path elements */ MethodHandle byteOffsetHandle(PathElement... elements); /** - * Creates a var handle that accesses a memory segment at the offset selected by the given layout path, - * where the initial layout in the path is this layout. + * Creates a var handle that accesses a memory segment at the offset selected by the + * given layout path, where the initial layout in the path is this layout. *

    * The returned var handle has the following characteristics: *

      *
    • its type is derived from the {@linkplain ValueLayout#carrier() carrier} of the * selected value layout;
    • - *
    • it has a leading parameter of type {@code MemorySegment} representing the accessed segment
    • - *
    • a following {@code long} parameter, corresponding to the base offset, denoted as {@code B};
    • - *
    • it has zero or more trailing access coordinates of type {@code long}, one for each - * open path element in the provided layout path, denoted as - * {@code I1, I2, ... In}, respectively. The order of these access coordinates corresponds to the order - * in which the open path elements occur in the provided layout path. + *
    • it has a leading parameter of type {@code MemorySegment} representing the + * accessed segment
    • + *
    • a following {@code long} parameter, corresponding to the base offset, + * denoted as {@code B};
    • + *
    • it has zero or more trailing access coordinates of type {@code long}, + * one for each open path element in the provided + * layout path, denoted as {@code I1, I2, ... In}, respectively. The order of + * these access coordinates corresponds to the order in which the open path + * elements occur in the provided layout path. *
    *

    - * If the provided layout path {@code P} contains no dereference elements, then the offset {@code O} of the access - * operation is computed as follows: + * If the provided layout path {@code P} contains no dereference elements, then the + * offset {@code O} of the access operation is computed as follows: * * {@snippet lang = "java": * O = this.offsetHandle(P).invokeExact(B, I1, I2, ... In); * } *

    - * Accessing a memory segment using the var handle returned by this method is subject to the following checks: + * Accessing a memory segment using the var handle returned by this method is subject + * to the following checks: *

      - *
    • The physical address of the accessed memory segment must be aligned - * according to the {@linkplain #byteAlignment() alignment constraint} of the root layout (this layout), or - * an {@link IllegalArgumentException} will be issued. Note that the alignment constraint of the root layout - * can be more strict (but not less) than the alignment constraint of the selected value layout.
    • - *
    • The offset of the access operation (computed as above) must fall inside the spatial bounds of the - * accessed memory segment, or an {@link IndexOutOfBoundsException} is thrown. This is the case when {@code O + A <= S}, - * where {@code O} is the accessed offset (computed as above), {@code A} is the size of the selected layout and {@code S} - * is the size of the accessed memory segment.
    • - *
    • The accessed memory segment must be {@link MemorySegment#isAccessibleBy(Thread) accessible} from the - * thread performing the access operation, or a {@link WrongThreadException} is thrown.
    • - *
    • The {@linkplain MemorySegment#scope() scope} associated with the accessed segment must be - * {@linkplain MemorySegment.Scope#isAlive() alive}, or an {@link IllegalStateException} is thrown.
    • + *
    • The physical address of the accessed memory segment must be + * aligned according to the + * {@linkplain #byteAlignment() alignment constraint} of the root layout + * (this layout), or an {@link IllegalArgumentException} is thrown. Note + * that the alignment constraint of the root layout can be more strict + * (but not less) than the alignment constraint of the selected value layout.
    • + *
    • The offset of the access operation (computed as above) must fall inside + * the spatial bounds of the accessed memory segment, or an + * {@link IndexOutOfBoundsException} is thrown. This is the case when + * {@code O + A <= S}, where {@code O} is the accessed offset (computed as above), + * {@code A} is the size of the selected layout and {@code S} is the size of the + * accessed memory segment.
    • + *
    • The accessed memory segment must be + * {@link MemorySegment#isAccessibleBy(Thread) accessible} from the thread + * performing the access operation, or a {@link WrongThreadException} is thrown.
    • + *
    • The {@linkplain MemorySegment#scope() scope} associated with the accessed + * segment must be {@linkplain MemorySegment.Scope#isAlive() alive}, or an + * {@link IllegalStateException} is thrown.
    • *
    *

    - * If the selected layout is an {@linkplain AddressLayout address layout}, calling {@link VarHandle#get(Object...)} - * on the returned var handle will return a new memory segment. The segment is associated with the global scope. - * Moreover, the size of the segment depends on whether the address layout has a + * If the selected layout is an {@linkplain AddressLayout address layout}, calling + * {@link VarHandle#get(Object...)} on the returned var handle will return a new + * memory segment. The segment is associated with the global scope. Moreover, the + * size of the segment depends on whether the address layout has a * {@linkplain AddressLayout#targetLayout() target layout}. More specifically: *

      - *
    • If the address layout has a target layout {@code T}, then the size of the returned segment - * is {@code T.byteSize()};
    • - *
    • Otherwise, the address layout has no target layout and the size of the returned segment + *
    • If the address layout has a target layout {@code T}, then the size + * of the returned segment is {@code T.byteSize()};
    • + *
    • Otherwise, the address layout has no target layout and the size + * of the returned segment * is zero.
    • *
    - * Moreover, if the selected layout is an {@linkplain AddressLayout address layout}, calling {@link VarHandle#set(Object...)} - * can throw {@link IllegalArgumentException} if the memory segment representing the address to be written is not a + * Moreover, if the selected layout is an {@linkplain AddressLayout address layout}, + * calling {@link VarHandle#set(Object...)} can throw {@link IllegalArgumentException} + * if the memory segment representing the address to be written is not a * {@linkplain MemorySegment#isNative() native} memory segment. *

    - * If the provided layout path has size {@code m} and contains a dereference path element in position {@code k} - * (where {@code k <= m}) then two layout paths {@code P} and {@code P'} are derived, where P contains all the path - * elements from 0 to {@code k - 1} and {@code P'} contains all the path elements from {@code k + 1} to - * {@code m} (if any). Then, the returned var handle is computed as follows: + * If the provided layout path has size {@code m} and contains a dereference path + * element in position {@code k} (where {@code k <= m}) then two layout paths + * {@code P} and {@code P'} are derived, where P contains all the path elements from + * 0 to {@code k - 1} and {@code P'} contains all the path elements from {@code k + 1} + * to {@code m} (if any). Then, the returned var handle is computed as follows: * * {@snippet lang = "java": * VarHandle baseHandle = this.varHandle(P); @@ -580,153 +668,195 @@ public sealed interface MemoryLayout * baseHandle.toMethodHandle(VarHandle.AccessMode.GET)); * } * - * (The above can be trivially generalized to cases where the provided layout path contains more than one dereference - * path elements). + * (The above can be trivially generalized to cases where the provided layout path + * contains more than one dereference path elements). *

    - * As an example, consider the memory layout expressed by a {@link GroupLayout} instance constructed as follows: + * As an example, consider the memory layout expressed by a {@link GroupLayout} + * instance constructed as follows: * {@snippet lang = "java": * GroupLayout grp = java.lang.foreign.MemoryLayout.structLayout( * MemoryLayout.paddingLayout(4), * ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value") * ); * } - * To access the member layout named {@code value}, we can construct a var handle as follows: + * To access the member layout named {@code value}, we can construct a var handle as + * follows: * {@snippet lang = "java": * VarHandle handle = grp.varHandle(PathElement.groupElement("value")); //(MemorySegment, long) -> int * } * - * @apiNote The resulting var handle features certain access mode restrictions, - * which are common to all var handles derived from memory layouts. + * @apiNote The resulting var handle features certain + * access mode restrictions, which + * are common to all var handles derived from memory layouts. * - * @param elements the layout path elements. - * @return a var handle that accesses a memory segment at the offset selected by the given layout path. - * @throws IllegalArgumentException if the layout path is not well-formed for this layout - * @throws IllegalArgumentException if the layout selected by the provided path is not a {@linkplain ValueLayout value layout} + * @param elements the layout path elements + * @return a var handle that accesses a memory segment at the offset selected by the + * given layout path + * @throws IllegalArgumentException if the layout path is not + * well-formed for this layout + * @throws IllegalArgumentException if the layout selected by the provided path is not a + * {@linkplain ValueLayout value layout} */ VarHandle varHandle(PathElement... elements); /** - * Creates a var handle that accesses adjacent elements in a memory segment at offsets selected by the given layout path, - * where the accessed elements have this layout, and where the initial layout in the path is this layout. + * Creates a var handle that accesses adjacent elements in a memory segment at + * offsets selected by the given layout path, where the accessed elements have this + * layout, and where the initial layout in the path is this layout. *

    * The returned var handle has the following characteristics: *

      *
    • its type is derived from the {@linkplain ValueLayout#carrier() carrier} of the * selected value layout;
    • - *
    • it has a leading parameter of type {@code MemorySegment} representing the accessed segment
    • - *
    • a following {@code long} parameter, corresponding to the base offset, denoted as {@code B};
    • - *
    • a following {@code long} parameter, corresponding to the array index, denoted as {@code I0}. The array - * index is used to scale the accessed offset by this layout size;
    • - *
    • it has zero or more trailing access coordinates of type {@code long}, one for each - * open path element in the provided layout path, denoted as - * {@code I1, I2, ... In}, respectively. The order of these access coordinates corresponds to the order - * in which the open path elements occur in the provided layout path. + *
    • it has a leading parameter of type {@code MemorySegment} representing + * the accessed segment
    • + *
    • a following {@code long} parameter, corresponding to the base offset, + * denoted as {@code B};
    • + *
    • a following {@code long} parameter, corresponding to the array index, + * denoted as {@code I0}. The array index is used to scale the accessed offset + * by this layout size;
    • + *
    • it has zero or more trailing access coordinates of type {@code long}, + * one for each open path element in the provided + * layout path, denoted as {@code I1, I2, ... In}, respectively. The order of + * these access coordinates corresponds to the order in which the open path + * elements occur in the provided layout path. *
    *

    - * If the provided layout path {@code P} contains no dereference elements, then the offset {@code O} of the access - * operation is computed as follows: + * If the provided layout path {@code P} contains no dereference elements, then the + * offset {@code O} of the access operation is computed as follows: * * {@snippet lang = "java": * O = this.offsetHandle(P).invokeExact(this.scale(B, I0), I1, I2, ... In); * } *

    - * More formally, this method can be obtained from the {@link #varHandle(PathElement...)}, as follows: + * More formally, this method can be obtained from the {@link #varHandle(PathElement...)}, + * as follows: * {@snippet lang = "java": * MethodHandles.collectCoordinates(varHandle(elements), 1, scaleHandle()) * } * * @apiNote - * As the leading index coordinate {@code I0} is not bound by any sequence layout, it can assume any non-negative - * value - provided that the resulting offset computation does not overflow, or that the computed offset does not fall - * outside the spatial bound of the accessed memory segment. As such, the var handles returned from this method can - * be especially useful when accessing variable-length arrays. - * - * @param elements the layout path elements. - * @return a var handle that accesses adjacent elements in a memory segment at offsets selected by the given layout path. - * @throws IllegalArgumentException if the layout path is not well-formed for this layout - * @throws IllegalArgumentException if the layout selected by the provided path is not a {@linkplain ValueLayout value layout} + * As the leading index coordinate {@code I0} is not bound by any sequence layout, it + * can assume any non-negative value - provided that the resulting offset + * computation does not overflow, or that the computed offset does not fall outside + * the spatial bound of the accessed memory segment. As such, the var handles + * returned from this method can be especially useful when accessing + * variable-length arrays. + * + * @param elements the layout path elements + * @return a var handle that accesses adjacent elements in a memory segment at + * offsets selected by the given layout path + * @throws IllegalArgumentException if the layout path is not + * well-formed for this layout + * @throws IllegalArgumentException if the layout selected by the provided path is + * not a {@linkplain ValueLayout value layout} */ VarHandle arrayElementVarHandle(PathElement... elements); /** - * Creates a method handle which, given a memory segment, returns a {@linkplain MemorySegment#asSlice(long, long) slice} - * corresponding to the layout selected by the given layout path, where the initial layout in the path is this layout. + * Creates a method handle which, given a memory segment, returns a + * {@linkplain MemorySegment#asSlice(long, long) slice} corresponding to + * the layout selected by the given layout path, where the initial layout in + * the path is this layout. *

    * The returned method handle has the following characteristics: *

      *
    • its return type is {@code MemorySegment};
    • - *
    • it has a leading parameter of type {@code MemorySegment} corresponding to the memory segment to be sliced
    • + *
    • it has a leading parameter of type {@code MemorySegment} corresponding to + * the memory segment to be sliced
    • *
    • a following {@code long} parameter, corresponding to the base offset
    • - *
    • it has as zero or more trailing parameters of type {@code long}, one for each open path element - * in the provided layout path. The order of these parameters corresponds to the order in which the open path - * elements occur in the provided layout path. + *
    • it has as zero or more trailing parameters of type {@code long}, one for + * each open path element in the provided + * layout path. The order of these parameters corresponds to the order in which + * the open path elements occur in the provided layout path. *
    *

    * The offset {@code O} of the returned segment is computed as if by a call to a - * {@linkplain #byteOffsetHandle(PathElement...) byte offset handle} constructed using the given path elements. + * {@linkplain #byteOffsetHandle(PathElement...) byte offset handle} constructed + * using the given path elements. *

    - * Computing a slice of a memory segment using the method handle returned by this method is subject to the following checks: + * Computing a slice of a memory segment using the method handle returned by this + * method is subject to the following checks: *

      - *
    • The physical address of the accessed memory segment must be aligned - * according to the {@linkplain #byteAlignment() alignment constraint} of the root layout (this layout), or - * an {@link IllegalArgumentException} will be issued. Note that the alignment constraint of the root layout - * can be more strict (but not less) than the alignment constraint of the selected layout.
    • - *
    • The start offset of the slicing operation (computed as above) must fall inside the spatial bounds of the - * accessed memory segment, or an {@link IndexOutOfBoundsException} is thrown. This is the case when {@code O + A <= S}, - * where {@code O} is the start offset of the slicing operation (computed as above), {@code A} is the size of the - * selected layout and {@code S} is the size of the accessed memory segment.
    • + *
    • The physical address of the accessed memory segment must be + * aligned according to the + * {@linkplain #byteAlignment() alignment constraint} of the root layout + * (this layout), or an {@link IllegalArgumentException} will be issued. Note + * that the alignment constraint of the root layout can be more strict + * (but not less) than the alignment constraint of the selected layout.
    • + *
    • The start offset of the slicing operation (computed as above) must fall + * inside the spatial bounds of the accessed memory segment, or an + * {@link IndexOutOfBoundsException} is thrown. This is the case when + * {@code O + A <= S}, where {@code O} is the start offset of + * the slicing operation (computed as above), {@code A} is the size of the + * selected layout and {@code S} is the size of the accessed memory segment.
    • *
    * - * @apiNote The returned method handle can be used to obtain a memory segment slice, similarly to {@link MemorySegment#asSlice(long, long)}, - * but more flexibly, as some indices can be specified when invoking the method handle. + * @apiNote The returned method handle can be used to obtain a memory segment slice, + * similarly to {@link MemorySegment#asSlice(long, long)}, but more flexibly, + * as some indices can be specified when invoking the method handle. * - * @param elements the layout path elements. - * @return a method handle that is used to slice a memory segment at the offset selected by the given layout path. - * @throws IllegalArgumentException if the layout path is not well-formed for this layout - * @throws IllegalArgumentException if the layout path contains one or more dereference path elements + * @param elements the layout path elements + * @return a method handle that is used to slice a memory segment at + * the offset selected by the given layout path + * @throws IllegalArgumentException if the layout path is not + * well-formed for this layout + * @throws IllegalArgumentException if the layout path contains one or more + * dereference path elements */ MethodHandle sliceHandle(PathElement... elements); /** - * Returns the layout selected from the provided path, where the initial layout in the path is this layout. - * - * @param elements the layout path elements. - * @return the layout selected by the layout path in {@code elements}. - * @throws IllegalArgumentException if the layout path is not well-formed for this layout - * @throws IllegalArgumentException if the layout path contains one or more dereference path elements - * @throws IllegalArgumentException if the layout path contains one or more path elements that select one or more - * sequence element indices, such as {@link PathElement#sequenceElement(long)} and {@link PathElement#sequenceElement(long, long)}) + * Returns the layout selected from the provided path, where the initial layout in + * the path is this layout. + * + * @param elements the layout path elements + * @return the layout selected by the layout path in {@code elements} + * @throws IllegalArgumentException if the layout path is not + * well-formed for this layout + * @throws IllegalArgumentException if the layout path contains one or more + * dereference path elements + * @throws IllegalArgumentException if the layout path contains one or more path + * elements that select one or more sequence element indices, such as + * {@link PathElement#sequenceElement(long)} and + * {@link PathElement#sequenceElement(long, long)}) */ MemoryLayout select(PathElement... elements); /** - * An element in a layout path. There - * are three kinds of path elements: + * An element in a layout path. + * There are three kinds of path elements: *
      - *
    • group path elements, used to select a member layout within a {@link GroupLayout}, either by name or by index;
    • - *
    • sequence path elements, used to select one or more sequence element layouts within a {@link SequenceLayout}; and
    • - *
    • dereference path elements, used to dereference - * an address layout as its target layout.
    • + *
    • group path elements, used to select a member layout within a + * {@link GroupLayout}, either by name or by index;
    • + *
    • sequence path elements, used to select one or more + * sequence element layouts within a {@link SequenceLayout}; and
    • + *
    • dereference path elements, used to + * dereference an address + * layout as its target layout.
    • *
    * Sequence path elements selecting more than one sequence element layout are called * open path elements. * * @implSpec - * Implementations of this interface are immutable, thread-safe and value-based. + * Implementations of this interface are immutable, thread-safe and + * value-based. * * @since 22 */ sealed interface PathElement permits LayoutPath.PathElementImpl { /** - * Returns a path element that selects a member layout with the given name in a group layout. + * {@return a path element which selects a member layout with the given name in a + * group layout} * - * @implSpec in case multiple group elements with a matching name exist, the path element returned by this - * method will select the first one; that is, the group element with the lowest offset from the current path is selected. - * In such cases, using {@link #groupElement(long)} might be preferable. + * @implSpec in case multiple group elements with a matching name exist, the path + * element returned by this method will select the first one; that is, + * the group element with the lowest offset from the current path is + * selected. In such cases, using {@link #groupElement(long)} might be + * preferable. * - * @param name the name of the member layout to be selected. - * @return a path element that selects the group member layout with the given name. + * @param name the name of the member layout to be selected */ static PathElement groupElement(String name) { Objects.requireNonNull(name); @@ -735,10 +865,10 @@ static PathElement groupElement(String name) { } /** - * Returns a path element that selects a member layout with the given index in a group layout. + * {@return a path element that selects a member layout with the given index in a + * group layout} * - * @param index the index of the member layout element to be selected. - * @return a path element which selects the group member layout with the given index. + * @param index the index of the member layout element to be selected * @throws IllegalArgumentException if {@code index < 0} */ static PathElement groupElement(long index) { @@ -750,10 +880,10 @@ static PathElement groupElement(long index) { } /** - * Returns a path element that selects the element layout at the specified position in a sequence layout. + * {@return a path element which selects the element layout at the specified + * index in a sequence layout} * - * @param index the index of the sequence element to be selected. - * @return a path element that selects the sequence element layout with the given index. + * @param index the index of the sequence element to be selected * @throws IllegalArgumentException if {@code index < 0} */ static PathElement sequenceElement(long index) { @@ -765,20 +895,25 @@ static PathElement sequenceElement(long index) { } /** - * Returns an open path element that selects the element - * layout in a range of positions in a sequence layout. The range is expressed as a pair of starting - * index (inclusive) {@code S} and step factor (which can also be negative) {@code F}. + * Returns an open path element + * that selects the element layout in a range of positions in a sequence + * layout. The range is expressed as a pair of starting index (inclusive) + * {@code S} and step factor (which can also be negative) {@code F}. *

    - * The exact sequence element selected by this layout is expressed as an index {@code I}. If {@code C} is the - * sequence element count, it follows that {@code 0 <= I < B}, where {@code B} is computed as follows: + * The exact sequence element selected by this layout is expressed as an index + * {@code I}. If {@code C} is the + * sequence element count, it follows that {@code 0 <= I < B}, where {@code B} + * is computed as follows: *

      *
    • if {@code F > 0}, then {@code B = ceilDiv(C - S, F)}
    • *
    • if {@code F < 0}, then {@code B = ceilDiv(-(S + 1), -F)}
    • *
    * - * @param start the index of the first sequence element to be selected. - * @param step the step factor at which subsequence sequence elements are to be selected. - * @return a path element that selects the sequence element layout with the given index. + * @param start the index of the first sequence element to be selected + * @param step the step factor at which subsequence sequence elements are to be + * selected + * @return a path element that selects the sequence element layout with the + * given index. * @throws IllegalArgumentException if {@code start < 0}, or {@code step == 0} */ static PathElement sequenceElement(long start, long step) { @@ -793,13 +928,12 @@ static PathElement sequenceElement(long start, long step) { } /** - * Returns an open path element that selects an unspecified - * element layout in a sequence layout. + * {@return an open path element + * that selects an unspecified element layout in a sequence layout} *

    - * The exact sequence element selected by this layout is expressed as an index {@code I}. If {@code C} is the - * sequence element count, it follows that {@code 0 <= I < C}. - * - * @return a path element which selects an unspecified sequence element layout. + * The exact sequence element selected by this layout is expressed as an index + * {@code I}. If {@code C} is the sequence element count, it follows that + * {@code 0 <= I < C}. */ static PathElement sequenceElement() { return new LayoutPath.PathElementImpl(PathKind.SEQUENCE_ELEMENT, @@ -807,10 +941,8 @@ static PathElement sequenceElement() { } /** - * Returns a path element that dereferences an address layout as its - * {@linkplain AddressLayout#targetLayout() target layout} (where set). - * - * @return a path element that dereferences an address layout. + * {@return a path element that dereferences an address layout as its + * {@linkplain AddressLayout#targetLayout() target layout} (where set)} */ static PathElement dereferenceElement() { return new LayoutPath.PathElementImpl(PathKind.DEREF_ELEMENT, @@ -819,22 +951,27 @@ static PathElement dereferenceElement() { } /** - * 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 constraint. Furthermore, depending on the layout kind, additional - * conditions must be satisfied: + * 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 constraint. Furthermore, depending on the + * layout kind, additional conditions must be satisfied: *

      - *
    • two value layouts are considered equal if they have the same {@linkplain ValueLayout#order() order}, - * and {@linkplain ValueLayout#carrier() carrier}. Additionally, two address layouts are considered equal if they - * also have the same {@linkplain AddressLayout#targetLayout() target layout};
    • - *
    • 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;
    • - *
    • two group layouts are considered equal if they are of the same type (see {@link StructLayout}, - * {@link UnionLayout}) and if their member layouts (see {@link GroupLayout#memberLayouts()}) are also equal.
    • + *
    • two value layouts are considered equal if they have the same + * {@linkplain ValueLayout#order() order}, and + * {@linkplain ValueLayout#carrier() carrier}. Additionally, two address + * layouts are considered equal if they also have the same + * {@linkplain AddressLayout#targetLayout() target layout};
    • + *
    • 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;
    • + *
    • two group layouts are considered equal if they are of the same type + * (see {@link StructLayout}, {@link UnionLayout}) and if their member layouts + * (see {@link GroupLayout#memberLayouts()}) are also equal.
    • *
    * - * @param other the object to be compared for equality with this layout. - * @return {@code true} if the specified object is equal to this layout. + * @param other the object to be compared for equality with this layout + * @return {@code true} if the specified object is equal to this layout */ boolean equals(Object other); @@ -850,13 +987,14 @@ static PathElement dereferenceElement() { String toString(); /** - * Creates a padding layout with the given byte size. The alignment constraint of the returned layout - * is 1. As such, regardless of its size, in the absence of an {@linkplain #withByteAlignment(long) explicit} - * alignment constraint, a padding layout does not affect the natural alignment of the group or sequence layout - * it is nested into. + * Creates a padding layout with the given byte size. The alignment constraint of the + * returned layout is 1. As such, regardless of its size, in the absence of an + * {@linkplain #withByteAlignment(long) explicit} alignment constraint, a padding + * layout does not affect the natural alignment of the group or sequence layout it is + * nested into. * - * @param byteSize the padding size (expressed in bytes). - * @return the new selector layout. + * @param byteSize the padding size (expressed in bytes) + * @return the new selector layout * @throws IllegalArgumentException if {@code byteSize <= 0} */ static PaddingLayout paddingLayout(long byteSize) { @@ -866,11 +1004,12 @@ static PaddingLayout paddingLayout(long byteSize) { /** * Creates a sequence layout with the given element layout and element count. * - * @param elementCount the sequence element count. - * @param elementLayout the sequence element layout. - * @return the new sequence layout with the given element layout and size. + * @param elementCount the sequence element count + * @param elementLayout the sequence element layout + * @return the new sequence layout with the given element layout and size * @throws IllegalArgumentException if {@code elementCount} is negative - * @throws IllegalArgumentException if {@code elementLayout.byteSize() * elementCount} overflows + * @throws IllegalArgumentException if {@code elementLayout.byteSize() * elementCount} + * overflows * @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0} */ static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) { @@ -885,28 +1024,31 @@ static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayo /** * Creates a struct layout with the given member layouts. * - * @param elements The member layouts of the struct layout. - * @return a struct layout with the given member layouts. - * @throws IllegalArgumentException if the sum of the {@linkplain #byteSize() byte sizes} of the member - * layouts overflows - * @throws IllegalArgumentException if a member layout in {@code elements} occurs at an offset - * (relative to the start of the struct layout) which is not compatible with its alignment constraint + * @param elements The member layouts of the struct layout + * @return a struct layout with the given member layouts + * @throws IllegalArgumentException if the sum of the {@linkplain #byteSize() byte sizes} + * of the member layouts overflows + * @throws IllegalArgumentException if a member layout in {@code elements} occurs at + * an offset (relative to the start of the struct layout) which is not + * compatible with its alignment constraint * - * @apiNote This factory does not automatically align element layouts, by inserting additional {@linkplain PaddingLayout - * padding layout} elements. As such, the following struct layout creation will fail with an exception: + * @apiNote This factory does not automatically align element layouts, by inserting + * additional {@linkplain PaddingLayout padding layout} elements. As such, + * the following struct layout creation will fail with an exception: * * {@snippet lang = java: * structLayout(JAVA_SHORT, JAVA_INT); * } * - * To avoid the exception, clients can either insert additional padding layout elements: + * To avoid the exception, clients can either insert additional padding layout + * elements: * * {@snippet lang = java: * structLayout(JAVA_SHORT, MemoryLayout.paddingLayout(2), JAVA_INT); * } * - * Or, alternatively, they can use a member layout that features a smaller alignment constraint. This will result - * in a packed struct layout: + * Or, alternatively, they can use a member layout that features a smaller alignment + * constraint. This will result in a packed struct layout: * * {@snippet lang = java: * structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2)); @@ -923,8 +1065,8 @@ static StructLayout structLayout(MemoryLayout... elements) { /** * Creates a union layout with the given member layouts. * - * @param elements The member layouts of the union layout. - * @return a union layout with the given member layouts. + * @param elements The member layouts of the union layout + * @return a union layout with the given member layouts */ static UnionLayout unionLayout(MemoryLayout... elements) { Objects.requireNonNull(elements); diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java index ad00dbe11b1..0b0a2e136cb 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -53,85 +53,101 @@ *

    * There are two kinds of memory segments: *

      - *
    • A heap segment is backed by, and provides access to, a region of memory inside the Java heap (an "on-heap" region).
    • - *
    • A native segment is backed by, and provides access to, a region of memory outside the Java heap (an "off-heap" region).
    • + *
    • A heap segment is backed by, and provides access to, a region of + * memory inside the Java heap (an "on-heap" region).
    • + *
    • A native segment is backed by, and provides access to, a region of + * memory outside the Java heap (an "off-heap" region).
    • *
    - * Heap segments can be obtained by calling one of the {@link MemorySegment#ofArray(int[])} factory methods. - * These methods return a memory segment backed by the on-heap region that holds the specified Java array. + * Heap segments can be obtained by calling one of the {@link MemorySegment#ofArray(int[])} + * factory methods. These methods return a memory segment backed by the on-heap region + * that holds the specified Java array. *

    * Native segments can be obtained by calling one of the {@link Arena#allocate(long, long)} - * factory methods, which return a memory segment backed by a newly allocated off-heap region with the given size - * and aligned to the given alignment constraint. Alternatively, native segments can be obtained by - * {@link FileChannel#map(MapMode, long, long, Arena) mapping} a file into a new off-heap region - * (in some systems, this operation is sometimes referred to as {@code mmap}). - * Segments obtained in this way are called mapped segments, and their contents can be {@linkplain #force() persisted} and - * {@linkplain #load() loaded} to and from the underlying memory-mapped file. + * factory methods, which return a memory segment backed by a newly allocated off-heap + * region with the given size and aligned to the given alignment constraint. + * Alternatively, native segments can be obtained by + * {@link FileChannel#map(MapMode, long, long, Arena) mapping} a file into a new off-heap + * region (in some systems, this operation is sometimes referred to as {@code mmap}). + * Segments obtained in this way are called mapped segments, and their contents + * can be {@linkplain #force() persisted} and {@linkplain #load() loaded} to and from the + * underlying memory-mapped file. *

    - * Both kinds of segments are read and written using the same methods, known as access operations. - * An access operation on a memory segment always and only provides access to the region for which the segment was obtained. + * Both kinds of segments are read and written using the same methods, known as + * access operations. An access operation on a memory + * segment always and only provides access to the region for which the segment was + * obtained. * *

    Characteristics of memory segments

    * - * Every memory segment has an {@linkplain #address() address}, expressed as a {@code long} value. - * The nature of a segment's address depends on the kind of the segment: + * Every memory segment has an {@linkplain #address() address}, expressed as a + * {@code long} value. The nature of a segment's address depends on the kind of the + * segment: *
      - *
    • The address of a heap segment is not a physical address, but rather an offset within the region of memory - * which backs the segment. The region is inside the Java heap, so garbage collection might cause the region to be - * relocated in physical memory over time, but this is not exposed to clients of the {@code MemorySegment} API who + *
    • The address of a heap segment is not a physical address, but rather an offset + * within the region of memory which backs the segment. The region is inside the Java + * heap, so garbage collection might cause the region to be relocated in physical memory + * over time, but this is not exposed to clients of the {@code MemorySegment} API who * see a stable virtualized address for a heap segment backed by the region. - * A heap segment obtained from one of the {@link #ofArray(int[])} factory methods has an address of zero.
    • - *
    • The address of a native segment (including mapped segments) denotes the physical address of the region of - * memory which backs the segment.
    • + * A heap segment obtained from one of the {@link #ofArray(int[])} factory methods has + * an address of zero. + *
    • The address of a native segment (including mapped segments) denotes the physical + * address of the region of memory which backs the segment.
    • *
    *

    - * Every memory segment has a {@linkplain #byteSize() size}. The size of a heap segment is derived from the Java array - * from which it is obtained. This size is predictable across Java runtimes. - * The size of a native segment is either passed explicitly + * Every memory segment has a {@linkplain #byteSize() size}. The size of a heap segment + * is derived from the Java array from which it is obtained. This size is predictable + * across Java runtimes. The size of a native segment is either passed explicitly * (as in {@link Arena#allocate(long, long)}) or derived from a {@link MemoryLayout} * (as in {@link Arena#allocate(MemoryLayout)}). The size of a memory segment is typically * a positive number but may be zero, but never negative. *

    - * The address and size of a memory segment jointly ensure that access operations on the segment cannot fall - * outside the boundaries of the region of memory that backs the segment. - * That is, a memory segment has spatial bounds. + * The address and size of a memory segment jointly ensure that access operations on the + * segment cannot fall outside the boundaries of the region of memory that backs + * the segment. That is, a memory segment has spatial bounds. *

    - * Every memory segment is associated with a {@linkplain Scope scope}. This ensures that access operations - * on a memory segment cannot occur when the region of memory that backs the memory segment is no longer available - * (e.g., after the scope associated with the accessed memory segment is no longer {@linkplain Scope#isAlive() alive}). + * Every memory segment is associated with a {@linkplain Scope scope}. This ensures that + * access operations on a memory segment cannot occur when the region of memory that + * backs the memory segment is no longer available (e.g., after the scope associated + * with the accessed memory segment is no longer {@linkplain Scope#isAlive() alive}). * That is, a memory segment has temporal bounds. *

    - * Finally, access operations on a memory segment can be subject to additional thread-confinement checks. - * Heap segments can be accessed from any thread. Conversely, native segments can only be accessed compatibly with the - * confinement characteristics of the arena used to obtain them. + * Finally, access operations on a memory segment can be subject to additional + * thread-confinement checks. Heap segments can be accessed from any thread. + * Conversely, native segments can only be accessed compatibly with the + * confinement characteristics of the arena + * used to obtain them. * *

    Accessing memory segments

    * - * A memory segment can be read or written using various access operations provided in this class (e.g. {@link #get(ValueLayout.OfInt, long)}). - * Each access operation takes a {@linkplain ValueLayout value layout}, which specifies the size and shape of the value, - * and an offset, expressed in bytes. - * For instance, to read an int from a segment, using {@linkplain ByteOrder#nativeOrder() default endianness}, the following code can be used: + * A memory segment can be read or written using various access operations provided in + * this class (e.g. {@link #get(ValueLayout.OfInt, long)}). Each access operation takes + * a {@linkplain ValueLayout value layout}, which specifies the size and shape of the + * value, and an offset, expressed in bytes. For instance, to read an {@code int} from + * a segment, using {@linkplain ByteOrder#nativeOrder() default endianness}, the + * following code can be used: * {@snippet lang=java : * MemorySegment segment = ... * int value = segment.get(ValueLayout.JAVA_INT, 0); * } * - * If the value to be read is stored in memory using {@linkplain ByteOrder#BIG_ENDIAN big-endian} encoding, the access operation - * can be expressed as follows: + * If the value to be read is stored in memory using {@linkplain ByteOrder#BIG_ENDIAN big-endian} + * encoding, the access operation can be expressed as follows: * {@snippet lang=java : * int value = segment.get(ValueLayout.JAVA_INT.withOrder(BIG_ENDIAN), 0); * } * - * Access operations on memory segments are implemented using var handles. The {@link ValueLayout#varHandle()} - * method can be used to obtain a var handle that can be used to get/set values represented by the given value layout - * on a memory segment at the given offset: + * Access operations on memory segments are implemented using var handles. The + * {@link ValueLayout#varHandle()} method can be used to obtain a var handle that can be + * used to get/set values represented by the given value layout on a memory segment at + * the given offset: * * {@snippet lang=java: * VarHandle intAtOffsetHandle = ValueLayout.JAVA_INT.varHandle(); // (MemorySegment, long) * int value = (int) intAtOffsetHandle.get(segment, 10L); // segment.get(ValueLayout.JAVA_INT, 10L) * } * - * Alternatively, a var handle that can be used to access an element of an {@code int} array at a given logical - * index can be created as follows: + * Alternatively, a var handle that can be used to access an element of an {@code int} + * array at a given logical index can be created as follows: * * {@snippet lang=java: * VarHandle intAtOffsetAndIndexHandle = @@ -140,8 +156,9 @@ * } * *

    - * Clients can also drop the base offset parameter, in order to make the access expression simpler. This can be used to - * implement access operations such as {@link #getAtIndex(OfInt, long)}: + * Clients can also drop the base offset parameter, in order to make the access + * expression simpler. This can be used to implement access operations such as + * {@link #getAtIndex(OfInt, long)}: * * {@snippet lang=java: * VarHandle intAtIndexHandle = @@ -149,16 +166,20 @@ * int value = (int) intAtIndexHandle.get(segment, 3L); // segment.getAtIndex(ValueLayout.JAVA_INT, 3L); * } * - * Var handles for more complex access expressions (e.g. struct field access, pointer dereference) can be created directly - * from memory layouts, using layout paths. + * Var handles for more complex access expressions (e.g. struct field access, pointer + * dereference) can be created directly from memory layouts, using + * layout paths. * *

    Slicing memory segments

    * - * Memory segments support {@linkplain MemorySegment#asSlice(long, long) slicing}. Slicing a memory segment - * returns a new memory segment that is backed by the same region of memory as the original. The address of the sliced - * segment is derived from the address of the original segment, by adding an offset (expressed in bytes). The size of - * the sliced segment is either derived implicitly (by subtracting the specified offset from the size of the original segment), - * or provided explicitly. In other words, a sliced segment has stricter spatial bounds than those of the original segment: + * Memory segments support {@linkplain MemorySegment#asSlice(long, long) slicing}. + * Slicing a memory segment returns a new memory segment that is backed by the same + * region of memory as the original. The address of the sliced segment is derived from + * the address of the original segment, by adding an offset (expressed in bytes). The + * size of the sliced segment is either derived implicitly (by subtracting the specified + * offset from the size of the original segment), or provided explicitly. In other words, + * a sliced segment has stricter spatial bounds than those of the original + * segment: * {@snippet lang = java: * Arena arena = ... * MemorySegment segment = arena.allocate(100); @@ -167,17 +188,20 @@ * arena.close(); * slice.get(ValueLayout.JAVA_INT, 0); // Already closed! *} - * The above code creates a native segment that is 100 bytes long; then, it creates a slice that starts at offset 50 - * of {@code segment}, and is 10 bytes long. That is, the address of the {@code slice} is {@code segment.address() + 50}, - * and its size is 10. As a result, attempting to read an int value at offset 20 of the - * {@code slice} segment will result in an exception. The {@linkplain Arena temporal bounds} of the original segment - * is inherited by its slices; that is, when the scope associated with {@code segment} is no longer {@linkplain Scope#isAlive() alive}, - * {@code slice} will also become inaccessible. + * The above code creates a native segment that is 100 bytes long; then, it creates a + * slice that starts at offset 50 of {@code segment}, and is 10 bytes long. That is, the + * address of the {@code slice} is {@code segment.address() + 50}, and its size is 10. + * As a result, attempting to read an int value at offset 20 of the {@code slice} segment + * will result in an exception. The {@linkplain Arena temporal bounds} of the original + * segment is inherited by its slices; that is, when the scope associated with + * {@code segment} is no longer {@linkplain Scope#isAlive() alive}, {@code slice} will + * also become inaccessible. *

    - * A client might obtain a {@link Stream} from a segment, which can then be used to slice the segment (according to a given - * element layout) and even allow multiple threads to work in parallel on disjoint segment slices - * (to do this, the segment has to be {@linkplain MemorySegment#isAccessibleBy(Thread) accessible} - * from multiple threads). The following code can be used to sum all int values in a memory segment in parallel: + * A client might obtain a {@link Stream} from a segment, which can then be used to slice + * the segment (according to a given element layout) and even allow multiple threads to + * work in parallel on disjoint segment slices (to do this, the segment has to be + * {@linkplain MemorySegment#isAccessibleBy(Thread) accessible} from multiple threads). + * The following code can be used to sum all int values in a memory segment in parallel: * * {@snippet lang = java: * try (Arena arena = Arena.ofShared()) { @@ -191,22 +215,29 @@ * *

    Alignment

    * - * Access operations on a memory segment are constrained not only by the spatial and temporal bounds of the segment, - * but also by the alignment constraint of the value layout specified to the operation. An access operation can - * access only those offsets in the segment that denote addresses in physical memory that are aligned according - * to the layout. An address in physical memory is aligned according to a layout if the address is an integer - * multiple of the layout's alignment constraint. For example, the address 1000 is aligned according to an 8-byte alignment - * constraint (because 1000 is an integer multiple of 8), and to a 4-byte alignment constraint, and to a 2-byte alignment - * constraint; in contrast, the address 1004 is aligned according to a 4-byte alignment constraint, and to a 2-byte alignment - * constraint, but not to an 8-byte alignment constraint. - * Access operations are required to respect alignment because it can impact the performance of access operations, and - * can also determine which access operations are available at a given physical address. For instance, - * {@linkplain java.lang.invoke.VarHandle#compareAndSet(Object...) atomic access operations} operations using - * {@link java.lang.invoke.VarHandle} are only permitted at aligned addresses. In addition, alignment - * applies to an access operation whether the segment being accessed is a native segment or a heap segment. + * Access operations on a memory segment are constrained not only by the spatial and + * temporal bounds of the segment, but also by the alignment constraint of the + * value layout specified to the operation. An access operation can access only those + * offsets in the segment that denote addresses in physical memory that are + * aligned according to the layout. An address in physical memory is + * aligned according to a layout if the address is an integer multiple of + * the layout's alignment constraint. For example, the address 1000 is aligned according + * to an 8-byte alignment constraint (because 1000 is an integer multiple of 8), and to + * a 4-byte alignment constraint, and to a 2-byte alignment constraint; in contrast, + * the address 1004 is aligned according to a 4-byte alignment constraint, and to + * a 2-byte alignment constraint, but not to an 8-byte alignment constraint. + * Access operations are required to respect alignment because it can impact + * the performance of access operations, and can also determine which access operations + * are available at a given physical address. For instance, + * {@linkplain java.lang.invoke.VarHandle#compareAndSet(Object...) atomic access operations} + * operations using {@link java.lang.invoke.VarHandle} are only permitted at aligned + * addresses. In addition, alignment applies to an access operation whether the segment + * being accessed is a native segment or a heap segment. *

    - * If the segment being accessed is a native segment, then its {@linkplain #address() address} in physical memory can be - * combined with the offset to obtain the target address in physical memory. The pseudo-function below demonstrates this: + * If the segment being accessed is a native segment, then its + * {@linkplain #address() address} in physical memory can be combined with the offset to + * obtain the target address in physical memory. The pseudo-function below + * demonstrates this: * * {@snippet lang = java: * boolean isAligned(MemorySegment segment, long offset, MemoryLayout layout) { @@ -216,76 +247,105 @@ * * For example: *

      - *
    • A native segment with address 1000 can be accessed at offsets 0, 8, 16, 24, etc under an 8-byte alignment constraint, - * because the target addresses (1000, 1008, 1016, 1024) are 8-byte aligned. - * Access at offsets 1-7 or 9-15 or 17-23 is disallowed because the target addresses would not be 8-byte aligned.
    • - *
    • A native segment with address 1000 can be accessed at offsets 0, 4, 8, 12, etc under a 4-byte alignment constraint, - * because the target addresses (1000, 1004, 1008, 1012) are 4-byte aligned. - * Access at offsets 1-3 or 5-7 or 9-11 is disallowed because the target addresses would not be 4-byte aligned.
    • - *
    • A native segment with address 1000 can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint, - * because the target addresses (1000, 1002, 1004, 1006) are 2-byte aligned. - * Access at offsets 1 or 3 or 5 is disallowed because the target addresses would not be 2-byte aligned.
    • - *
    • A native segment with address 1004 can be accessed at offsets 0, 4, 8, 12, etc under a 4-byte alignment constraint, - * and at offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint. - * Under an 8-byte alignment constraint, it can be accessed at offsets 4, 12, 20, 28, etc.
    • - *
    • A native segment with address 1006 can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint. - * Under a 4-byte alignment constraint, it can be accessed at offsets 2, 6, 10, 14, etc. - * Under an 8-byte alignment constraint, it can be accessed at offsets 2, 10, 18, 26, etc. - *
    • A native segment with address 1007 can be accessed at offsets 0, 1, 2, 3, etc under a 1-byte alignment constraint. - * Under a 2-byte alignment constraint, it can be accessed at offsets 1, 3, 5, 7, etc. - * Under a 4-byte alignment constraint, it can be accessed at offsets 1, 5, 9, 13, etc. - * Under an 8-byte alignment constraint, it can be accessed at offsets 1, 9, 17, 25, etc.
    • + *
    • A native segment with address 1000 can be accessed at offsets 0, 8, 16, 24, etc + * under an 8-byte alignment constraint, because the target addresses + * (1000, 1008, 1016, 1024) are 8-byte aligned. + * Access at offsets 1-7 or 9-15 or 17-23 is disallowed because the target addresses + * would not be 8-byte aligned.
    • + *
    • A native segment with address 1000 can be accessed at offsets 0, 4, 8, 12, etc + * under a 4-byte alignment constraint, because the target addresses + * (1000, 1004, 1008, 1012) are 4-byte aligned. + * Access at offsets 1-3 or 5-7 or 9-11 is disallowed because the target addresses + * would not be 4-byte aligned.
    • + *
    • A native segment with address 1000 can be accessed at offsets 0, 2, 4, 6, etc + * under a 2-byte alignment constraint, because the target addresses + * (1000, 1002, 1004, 1006) are 2-byte aligned. + * Access at offsets 1 or 3 or 5 is disallowed because the target addresses would + * not be 2-byte aligned.
    • + *
    • A native segment with address 1004 can be accessed at offsets 0, 4, 8, 12, etc + * under a 4-byte alignment constraint, and at offsets 0, 2, 4, 6, etc + * under a 2-byte alignment constraint. Under an 8-byte alignment constraint, + * it can be accessed at offsets 4, 12, 20, 28, etc.
    • + *
    • A native segment with address 1006 can be accessed at offsets 0, 2, 4, 6, etc + * under a 2-byte alignment constraint. + * Under a 4-byte alignment constraint, it can be accessed at offsets 2, 6, 10, 14, etc. + * Under an 8-byte alignment constraint, it can be accessed at offsets 2, 10, 18, 26, etc. + *
    • A native segment with address 1007 can be accessed at offsets 0, 1, 2, 3, etc + * under a 1-byte alignment constraint. + * Under a 2-byte alignment constraint, it can be accessed at offsets 1, 3, 5, 7, etc. + * Under a 4-byte alignment constraint, it can be accessed at offsets 1, 5, 9, 13, etc. + * Under an 8-byte alignment constraint, it can be accessed at offsets 1, 9, 17, 25, etc.
    • *
    *

    - * The alignment constraint used to access a segment is typically dictated by the shape of the data structure stored - * in the segment. For example, if the programmer wishes to store a sequence of 8-byte values in a native segment, then - * the segment should be allocated by specifying an 8-byte alignment constraint, either via {@link Arena#allocate(long, long)} - * or {@link Arena#allocate(MemoryLayout)}. These factories ensure that the off-heap region of memory backing - * the returned segment has a starting address that is 8-byte aligned. Subsequently, the programmer can access the - * segment at the offsets of interest -- 0, 8, 16, 24, etc -- in the knowledge that every such access is aligned. + * The alignment constraint used to access a segment is typically dictated by the shape + * of the data structure stored in the segment. For example, if the programmer wishes to + * store a sequence of 8-byte values in a native segment, then the segment should be + * allocated by specifying an 8-byte alignment constraint, either via + * {@link Arena#allocate(long, long)} or {@link Arena#allocate(MemoryLayout)}. These + * factories ensure that the off-heap region of memory backing the returned segment + * has a starting address that is 8-byte aligned. Subsequently, the programmer can access + * the segment at the offsets of interest -- 0, 8, 16, 24, etc -- in the knowledge that + * every such access is aligned. *

    - * If the segment being accessed is a heap segment, then determining whether access is aligned is more complex. - * The address of the segment in physical memory is not known and is not even fixed (it may change when the segment - * is relocated during garbage collection). This means that the address cannot be combined with the specified offset to - * determine a target address in physical memory. Since the alignment constraint always refers to alignment of - * addresses in physical memory, it is not possible in principle to determine if any offset in a heap segment is aligned. + * If the segment being accessed is a heap segment, then determining whether access is + * aligned is more complex. The address of the segment in physical memory is not known + * and is not even fixed (it may change when the segment is relocated during garbage + * collection). This means that the address cannot be combined with the specified offset + * to determine a target address in physical memory. Since the alignment constraint + * always refers to alignment of addresses in physical memory, it is not + * possible in principle to determine if any offset in a heap segment is aligned. * For example, suppose the programmer chooses an 8-byte alignment constraint and tries - * to access offset 16 in a heap segment. If the heap segment's address 0 corresponds to physical address 1000, - * then the target address (1016) would be aligned, but if address 0 corresponds to physical address 1004, - * then the target address (1020) would not be aligned. It is undesirable to allow access to target addresses that are - * aligned according to the programmer's chosen alignment constraint, but might not be predictably aligned in physical memory - * (e.g. because of platform considerations and/or garbage collection behavior). + * to access offset 16 in a heap segment. If the heap segment's address 0 corresponds to + * physical address 1000, then the target address (1016) would be aligned, but if + * address 0 corresponds to physical address 1004, then the target address (1020) would + * not be aligned. It is undesirable to allow access to target addresses that are + * aligned according to the programmer's chosen alignment constraint, but might not be + * predictably aligned in physical memory (e.g. because of platform considerations + * and/or garbage collection behavior). *

    - * In practice, the Java runtime lays out arrays in memory so that each n-byte element occurs at an n-byte - * aligned physical address (except for {@code long[]} and {@code double[]}, where alignment is platform-dependent, as explained - * below). The runtime preserves this invariant even if the array is relocated during garbage collection. - * Access operations rely on this invariant to determine if the specified offset in a heap segment refers to an aligned - * address in physical memory. For example: + * In practice, the Java runtime lays out arrays in memory so that each n-byte element + * occurs at an n-byte aligned physical address (except for {@code long[]} and + * {@code double[]}, where alignment is platform-dependent, as explained below). The + * runtime preserves this invariant even if the array is relocated during garbage + * collection. Access operations rely on this invariant to determine if the specified + * offset in a heap segment refers to an aligned address in physical memory. + * For example: *

      - *
    • The starting physical address of a {@code short[]} array will be 2-byte aligned (e.g. 1006) so that successive - * short elements occur at 2-byte aligned addresses (e.g. 1006, 1008, 1010, 1012, etc). A heap segment backed by a - * {@code short[]} array can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint. The segment cannot - * be accessed at any offset under a 4-byte alignment constraint, because there is no guarantee that the target - * address would be 4-byte aligned, e.g., offset 0 would correspond to physical address 1006 while offset 1 would correspond - * to physical address 1007. Similarly, the segment cannot be accessed at any offset under an 8-byte alignment constraint, - * because there is no guarantee that the target address would be 8-byte aligned, e.g., offset 2 would correspond - * to physical address 1008 but offset 4 would correspond to physical address 1010.
    • - *
    • The starting physical address of a {@code long[]} array will be 8-byte aligned (e.g. 1000) on 64-bit platforms, - * so that successive long elements occur at 8-byte aligned addresses (e.g., 1000, 1008, 1016, 1024, etc.) On 64-bit platforms, - * a heap segment backed by a {@code long[]} array can be accessed at offsets 0, 8, 16, 24, etc under an 8-byte alignment - * constraint. In addition, the segment can be accessed at offsets 0, 4, 8, 12, etc under a 4-byte alignment constraint, - * because the target addresses (1000, 1004, 1008, 1012) are 4-byte aligned. And, the segment can be accessed at offsets - * 0, 2, 4, 6, etc under a 2-byte alignment constraint, because the target addresses (e.g. 1000, 1002, 1004, 1006) are 2-byte aligned.
    • - *
    • The starting physical address of a {@code long[]} array will be 4-byte aligned (e.g. 1004) on 32-bit platforms, - * so that successive long elements occur at 4-byte aligned addresses (e.g., 1004, 1008, 1012, 1016, etc.) On 32-bit - * platforms, a heap segment backed by a {@code long[]} array can be accessed at offsets 0, 4, 8, 12, etc under a 4-byte - * alignment constraint, because the target addresses (1004, 1008, 1012, 1016) are 4-byte aligned. And, the segment - * can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint, because the target addresses - * (e.g. 1000, 1002, 1004, 1006) are 2-byte aligned.
    • + *
    • The starting physical address of a {@code short[]} array will be 2-byte aligned + * (e.g. 1006) so that successive short elements occur at 2-byte aligned addresses + * (e.g. 1006, 1008, 1010, 1012, etc). A heap segment backed by a {@code short[]} + * array can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment + * constraint. The segment cannot be accessed at any offset under a 4-byte + * alignment constraint, because there is no guarantee that the target address would + * be 4-byte aligned, e.g., offset 0 would correspond to physical address 1006 while + * offset 1 would correspond to physical address 1007. Similarly, the segment cannot + * be accessed at any offset under an 8-byte alignment constraint, because there is + * no guarantee that the target address would be 8-byte aligned, e.g., offset 2 + * would correspond to physical address 1008 but offset 4 would correspond to + * physical address 1010.
    • + *
    • The starting physical address of a {@code long[]} array will be 8-byte aligned + * (e.g. 1000) on 64-bit platforms, so that successive long elements occur at + * 8-byte aligned addresses (e.g., 1000, 1008, 1016, 1024, etc.) On 64-bit platforms, + * a heap segment backed by a {@code long[]} array can be accessed at offsets + * 0, 8, 16, 24, etc under an 8-byte alignment constraint. In addition, the segment + * can be accessed at offsets 0, 4, 8, 12, etc under a 4-byte alignment constraint, + * because the target addresses (1000, 1004, 1008, 1012) are 4-byte aligned. And, + * the segment can be accessed at offsets 0, 2, 4, 6, etc under a 2-byte alignment + * constraint, because the target addresses (e.g. 1000, 1002, 1004, 1006) are + * 2-byte aligned.
    • + *
    • The starting physical address of a {@code long[]} array will be 4-byte aligned + * (e.g. 1004) on 32-bit platforms, so that successive long elements occur at 4-byte + * aligned addresses (e.g., 1004, 1008, 1012, 1016, etc.) On 32-bit platforms, a heap + * segment backed by a {@code long[]} array can be accessed at offsets + * 0, 4, 8, 12, etc under a 4-byte alignment constraint, because the target addresses + * (1004, 1008, 1012, 1016) are 4-byte aligned. And, the segment can be accessed at + * offsets 0, 2, 4, 6, etc under a 2-byte alignment constraint, because the target + * addresses (e.g. 1000, 1002, 1004, 1006) are 2-byte aligned.
    • *
    *

    - * In other words, heap segments feature a (platform-dependent) maximum alignment which is derived from the - * size of the elements of the Java array backing the segment, as shown in the following table: + * In other words, heap segments feature a (platform-dependent) maximum + * alignment which is derived from the size of the elements of the Java array backing the + * segment, as shown in the following table: * *

    Mapping C types
    * @@ -315,21 +375,23 @@ * *
    Maximum alignment of heap segments
    * - * Heap segments can only be accessed using a layout whose alignment is smaller or equal to the - * maximum alignment associated with the heap segment. Attempting to access a heap segment using a layout - * whose alignment is greater than the maximum alignment associated with the heap segment will fail, - * as demonstrated in the following example: + * Heap segments can only be accessed using a layout whose alignment is smaller or equal + * to the maximum alignment associated with the heap segment. Attempting to access a + * heap segment using a layout whose alignment is greater than the maximum alignment + * associated with the heap segment will fail, as demonstrated in the following example: * * {@snippet lang=java : * MemorySegment byteSegment = MemorySegment.ofArray(new byte[10]); * byteSegment.get(ValueLayout.JAVA_INT, 0); // fails: ValueLayout.JAVA_INT.byteAlignment() > ValueLayout.JAVA_BYTE.byteAlignment() * } * - * In such circumstances, clients have two options. They can use a heap segment backed by a different array - * type (e.g. {@code long[]}), capable of supporting greater maximum alignment. More specifically, the maximum alignment - * associated with {@code long[]} is set to {@code ValueLayout.JAVA_LONG.byteAlignment()} which is a platform-dependent - * value (set to {@code ValueLayout.ADDRESS.byteSize()}). That is, {@code long[]}) is guaranteed to provide at least - * 8-byte alignment in 64-bit platforms, but only 4-byte alignment in 32-bit platforms: + * In such circumstances, clients have two options. They can use a heap segment backed + * by a different array type (e.g. {@code long[]}), capable of supporting greater maximum + * alignment. More specifically, the maximum alignment associated with {@code long[]} is + * set to {@code ValueLayout.JAVA_LONG.byteAlignment()} which is a platform-dependent + * value (set to {@code ValueLayout.ADDRESS.byteSize()}). That is, {@code long[]}) is + * guaranteed to provide at least 8-byte alignment in 64-bit platforms, but only 4-byte + * alignment in 32-bit platforms: * * {@snippet lang=java : * MemorySegment longSegment = MemorySegment.ofArray(new long[10]); @@ -337,7 +399,8 @@ * } * * Alternatively, they can invoke the access operation with an unaligned layout. - * All unaligned layout constants (e.g. {@link ValueLayout#JAVA_INT_UNALIGNED}) have their alignment constraint set to 1: + * All unaligned layout constants (e.g. {@link ValueLayout#JAVA_INT_UNALIGNED}) have + * their alignment constraint set to 1: * {@snippet lang=java : * MemorySegment byteSegment = MemorySegment.ofArray(new byte[10]); * byteSegment.get(ValueLayout.JAVA_INT_UNALIGNED, 0); // ok: ValueLayout.JAVA_INT_UNALIGNED.byteAlignment() == ValueLayout.JAVA_BYTE.byteAlignment() @@ -345,46 +408,56 @@ * *

    Zero-length memory segments

    * - * When interacting with foreign functions, it is common for those functions - * to allocate a region of memory and return a pointer to that region. Modeling the region of memory with a memory segment - * is challenging because the Java runtime has no insight into the size of the region. Only the address of the start of - * the region, stored in the pointer, is available. For example, a C function with return type {@code char*} might return - * a pointer to a region containing a single {@code char} value, or to a region containing an array of {@code char} values, - * where the size of the array might be provided in a separate parameter. The size of the array is not readily apparent - * to the code calling the foreign function and hoping to use its result. In addition to having no insight - * into the size of the region of memory backing a pointer returned from a foreign function, it also has no insight - * into the lifetime intended for said region of memory by the foreign function that allocated it. + * When interacting with foreign functions, it is + * common for those functions to allocate a region of memory and return a pointer to that + * region. Modeling the region of memory with a memory segment is challenging because + * the Java runtime has no insight into the size of the region. Only the address of the + * start of the region, stored in the pointer, is available. For example, a C function + * with return type {@code char*} might return a pointer to a region containing a single + * {@code char} value, or to a region containing an array of {@code char} values, where + * the size of the array might be provided in a separate parameter. The size of the + * array is not readily apparent to the code calling the foreign function and hoping to + * use its result. In addition to having no insight into the size of the region of + * memory backing a pointer returned from a foreign function, it also has no insight + * into the lifetime intended for said region of memory by the foreign function that + * allocated it. *

    * The {@code MemorySegment} API uses zero-length memory segments to represent: *

    - * The address of the zero-length segment is the address stored in the pointer. The spatial and temporal bounds of the - * zero-length segment are as follows: + * The address of the zero-length segment is the address stored in the pointer. + * The spatial and temporal bounds of the zero-length segment are as follows: *
      - *
    • The size of the segment is zero. any attempt to access these segments will fail with {@link IndexOutOfBoundsException}. - * This is a crucial safety feature: as these segments are associated with a region - * of memory whose size is not known, any access operations involving these segments cannot be validated. - * In effect, a zero-length memory segment wraps an address, and it cannot be used without explicit intent - * (see below);
    • + *
    • The size of the segment is zero. Any attempt to access these segments will + * fail with {@link IndexOutOfBoundsException}. This is a crucial safety feature: as + * these segments are associated with a region of memory whose size is not known, any + * access operations involving these segments cannot be validated. In effect, a + * zero-length memory segment wraps an address, and it cannot be used + * without explicit intent (see below);
    • *
    • The segment is associated with the global scope. Thus, while zero-length - * memory segments cannot be accessed directly, they can be passed, opaquely, to other pointer-accepting foreign functions.
    • + * memory segments cannot be accessed directly, they can be passed, opaquely, to + * other pointer-accepting foreign functions. *
    *

    - * To demonstrate how clients can work with zero-length memory segments, consider the case of a client that wants - * to read a pointer from some memory segment. This can be done via the - * {@linkplain MemorySegment#get(AddressLayout, long)} access method. This method accepts an - * {@linkplain AddressLayout address layout} (e.g. {@link ValueLayout#ADDRESS}), the layout of the pointer - * to be read. For instance, on a 64-bit platform, the size of an address layout is 8 bytes. The access operation - * also accepts an offset, expressed in bytes, which indicates the position (relative to the start of the memory segment) - * at which the pointer is stored. The access operation returns a zero-length native memory segment, backed by a region + * To demonstrate how clients can work with zero-length memory segments, consider the + * case of a client that wants to read a pointer from some memory segment. This can be + * done via the {@linkplain MemorySegment#get(AddressLayout, long)} access method. This + * method accepts an {@linkplain AddressLayout address layout} + * (e.g. {@link ValueLayout#ADDRESS}), the layout of the pointer to be read. For instance, + * on a 64-bit platform, the size of an address layout is 8 bytes. The access operation + * also accepts an offset, expressed in bytes, which indicates the position (relative to + * the start of the memory segment) at which the pointer is stored. The access operation + * returns a zero-length native memory segment, backed by a region * of memory whose starting address is the 64-bit value read at the specified offset. *

    - * The returned zero-length memory segment cannot be accessed directly by the client: since the size of the segment - * is zero, any access operation would result in out-of-bounds access. Instead, the client must, unsafely, - * assign new spatial bounds to the zero-length memory segment. This can be done via the + * The returned zero-length memory segment cannot be accessed directly by the client: + * since the size of the segment is zero, any access operation would result in + * out-of-bounds access. Instead, the client must, unsafely, assign new spatial + * bounds to the zero-length memory segment. This can be done via the * {@link #reinterpret(long)} method, as follows: * * {@snippet lang = java: @@ -393,9 +466,10 @@ * int x = ptr.getAtIndex(ValueLayout.JAVA_INT, 3); // ok *} *

    - * In some cases, the client might additionally want to assign new temporal bounds to a zero-length memory segment. - * This can be done via the {@link #reinterpret(long, Arena, Consumer)} method, which returns a - * new native segment with the desired size and the same temporal bounds as those of the provided arena: + * In some cases, the client might additionally want to assign new temporal bounds to a + * zero-length memory segment. This can be done via the + * {@link #reinterpret(long, Arena, Consumer)} method, which returns a new native segment + * with the desired size and the same temporal bounds as those of the provided arena: * * {@snippet lang = java: * MemorySegment ptr = null; @@ -407,12 +481,14 @@ * int x = ptr.getAtIndex(ValueLayout.JAVA_INT, 3); // throws IllegalStateException *} * - * Alternatively, if the size of the region of memory backing the zero-length memory segment is known statically, - * the client can overlay a {@linkplain AddressLayout#withTargetLayout(MemoryLayout) target layout} on the address + * Alternatively, if the size of the region of memory backing the zero-length memory + * segment is known statically, the client can overlay a + * {@linkplain AddressLayout#withTargetLayout(MemoryLayout) target layout} on the address * layout used when reading a pointer. The target layout is then used to dynamically - * expand the size of the native memory segment returned by the access operation, so that the size - * of the segment is the same as the size of the target layout. In other words, the returned segment is no - * longer a zero-length memory segment, and the pointer it represents can be dereferenced directly: + * expand the size of the native memory segment returned by the access operation + * so that the size of the segment is the same as the size of the target layout . In other + * words, the returned segment is no longer a zero-length memory segment, and the pointer + * it represents can be dereferenced directly: * * {@snippet lang = java: * AddressLayout intArrPtrLayout = ValueLayout.ADDRESS.withTargetLayout( @@ -424,12 +500,13 @@ * All the methods that can be used to manipulate zero-length memory segments * ({@link #reinterpret(long)}, {@link #reinterpret(Arena, Consumer)}, {@link #reinterpret(long, Arena, Consumer)} and * {@link AddressLayout#withTargetLayout(MemoryLayout)}) are - * restricted methods, and should be used with caution: - * assigning a segment incorrect spatial and/or temporal bounds could result in a VM crash when attempting to access - * the memory segment. + * restricted methods, and should + * be used with caution: assigning a segment incorrect spatial and/or temporal bounds + * could result in a VM crash when attempting to access the memory segment. * * @implSpec - * Implementations of this interface are immutable, thread-safe and value-based. + * Implementations of this interface are immutable, thread-safe and + * value-based. * * @since 22 */ @@ -438,61 +515,73 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { /** * {@return the address of this memory segment} * - * @apiNote When using this method to pass a segment address to some external operation (e.g. a JNI function), - * clients must ensure that the segment is kept reachable - * for the entire duration of the operation. A failure to do so might result in the premature deallocation of the - * region of memory backing the memory segment, in case the segment has been allocated with an - * {@linkplain Arena#ofAuto() automatic arena}. + * @apiNote When using this method to pass a segment address to some external + * operation (e.g. a JNI function), clients must ensure that the segment is + * kept reachable + * for the entire duration of the operation. A failure to do so might result + * in the premature deallocation of the region of memory backing the memory + * segment, in case the segment has been allocated with an + * {@linkplain Arena#ofAuto() automatic arena}. */ long address(); /** - * Returns the Java object stored in the on-heap region of memory backing this memory segment, if any. For instance, if this - * memory segment is a heap segment created with the {@link #ofArray(byte[])} factory method, this method will return the - * {@code byte[]} object which was used to obtain the segment. This method returns an empty {@code Optional} value - * if either this segment is a {@linkplain #isNative() native} segment, or if this segment is {@linkplain #isReadOnly() read-only}. - * @return the Java object associated with this memory segment, if any. + * Returns the Java object stored in the on-heap region of memory backing this memory + * segment, if any. For instance, if this memory segment is a heap segment created + * with the {@link #ofArray(byte[])} factory method, this method will return the + * {@code byte[]} object which was used to obtain the segment. This method returns + * an empty {@code Optional} value if either this segment is a + * {@linkplain #isNative() native} segment, or if this segment is + * {@linkplain #isReadOnly() read-only}. + * + * @return the Java object associated with this memory segment, if any */ Optional heapBase(); /** - * Returns a spliterator for this memory segment. The returned spliterator reports {@link Spliterator#SIZED}, - * {@link Spliterator#SUBSIZED}, {@link Spliterator#IMMUTABLE}, {@link Spliterator#NONNULL} and {@link Spliterator#ORDERED} - * characteristics. + * Returns a spliterator for this memory segment. The returned spliterator reports + * {@link Spliterator#SIZED}, {@link Spliterator#SUBSIZED}, {@link Spliterator#IMMUTABLE}, + * {@link Spliterator#NONNULL} and {@link Spliterator#ORDERED} characteristics. *

    - * The returned spliterator splits this segment according to the specified element layout; that is, - * if the supplied layout has size N, then calling {@link Spliterator#trySplit()} will result in a spliterator serving - * approximately {@code S/N} elements (depending on whether N is even or not), where {@code S} is the size of - * this segment. As such, splitting is possible as long as {@code S/N >= 2}. The spliterator returns segments that - * have the same lifetime as that of this segment. + * The returned spliterator splits this segment according to the specified element + * layout; that is, if the supplied layout has size N, then calling + * {@link Spliterator#trySplit()} will result in a spliterator serving approximately + * {@code S/N} elements (depending on whether N is even or not), where {@code S} is + * the size of this segment. As such, splitting is possible as long as + * {@code S/N >= 2}. The spliterator returns segments that have the same lifetime as + * that of this segment. *

    - * The returned spliterator effectively allows to slice this segment into disjoint {@linkplain #asSlice(long, long) slices}, - * which can then be processed in parallel by multiple threads. + * The returned spliterator effectively allows to slice this segment into disjoint + * {@linkplain #asSlice(long, long) slices}, which can then be processed in parallel + * by multiple threads. * - * @param elementLayout the layout to be used for splitting. + * @param elementLayout the layout to be used for splitting * @return the element spliterator for this segment * @throws IllegalArgumentException if {@code elementLayout.byteSize() == 0} * @throws IllegalArgumentException if {@code byteSize() % elementLayout.byteSize() != 0} * @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0} - * @throws IllegalArgumentException if this segment is incompatible - * with the alignment constraint in the provided layout. + * @throws IllegalArgumentException if this segment is + * incompatible with the alignment constraint + * in the provided layout. */ Spliterator spliterator(MemoryLayout elementLayout); /** - * Returns a sequential {@code Stream} over disjoint slices (whose size matches that of the specified layout) - * in this segment. Calling this method is equivalent to the following code: + * Returns a sequential {@code Stream} over disjoint slices (whose size matches that + * of the specified layout) in this segment. Calling this method is equivalent to + * the following code: * {@snippet lang=java : * StreamSupport.stream(segment.spliterator(elementLayout), false); * } * - * @param elementLayout the layout to be used for splitting. - * @return a sequential {@code Stream} over disjoint slices in this segment. + * @param elementLayout the layout to be used for splitting + * @return a sequential {@code Stream} over disjoint slices in this segment * @throws IllegalArgumentException if {@code elementLayout.byteSize() == 0} * @throws IllegalArgumentException if {@code byteSize() % elementLayout.byteSize() != 0} * @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0} - * @throws IllegalArgumentException if this segment is incompatible - * with the alignment constraint in the provided layout. + * @throws IllegalArgumentException if this segment is + * incompatible with the alignment constraint + * in the provided layout */ Stream elements(MemoryLayout elementLayout); @@ -503,7 +592,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { /** * {@return {@code true} if this segment can be accessed from the provided thread} - * @param thread the thread to be tested. + * @param thread the thread to be tested */ boolean isAccessibleBy(Thread thread); @@ -513,8 +602,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { long byteSize(); /** - * Returns a slice of this memory segment, at the given offset. The returned segment's address is the address - * of this segment plus the given offset; its size is specified by the given argument. + * Returns a slice of this memory segment, at the given offset. The returned + * segment's address is the address of this segment plus the given offset; + * its size is specified by the given argument. *

    * Equivalent to the following code: * {@snippet lang=java : @@ -523,33 +613,38 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * * @see #asSlice(long, long, long) * - * @param offset The new segment base offset (relative to the address of this segment), specified in bytes. - * @param newSize The new segment size, specified in bytes. - * @return a slice of this memory segment. - * @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}, {@code newSize < 0}, - * or {@code newSize > byteSize() - offset} + * @param offset The new segment base offset (relative to the address of this segment), + * specified in bytes + * @param newSize The new segment size, specified in bytes + * @return a slice of this memory segment + * @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}, + * {@code newSize < 0}, or {@code newSize > byteSize() - offset} */ MemorySegment asSlice(long offset, long newSize); /** - * Returns a slice of this memory segment, at the given offset, with the provided alignment constraint. - * The returned segment's address is the address of this segment plus the given offset; its size is specified by the given argument. + * Returns a slice of this memory segment, at the given offset, with the provided + * alignment constraint. The returned segment's address is the address of this + * segment plus the given offset; its size is specified by the given argument. * - * @param offset The new segment base offset (relative to the address of this segment), specified in bytes. - * @param newSize The new segment size, specified in bytes. - * @param byteAlignment The alignment constraint (in bytes) of the returned slice. - * @return a slice of this memory segment. - * @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}, {@code newSize < 0}, - * or {@code newSize > byteSize() - offset} + * @param offset The new segment base offset (relative to the address of this segment), + * specified in bytes + * @param newSize The new segment size, specified in bytes + * @param byteAlignment The alignment constraint (in bytes) of the returned slice + * @return a slice of this memory segment + * @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}, + * {@code newSize < 0}, or {@code newSize > byteSize() - offset} * @throws IllegalArgumentException if this segment cannot be accessed at {@code offset} under * the provided alignment constraint - * @throws IllegalArgumentException if {@code byteAlignment <= 0}, or if {@code byteAlignment} is not a power of 2 + * @throws IllegalArgumentException if {@code byteAlignment <= 0}, or if + * {@code byteAlignment} is not a power of 2 */ MemorySegment asSlice(long offset, long newSize, long byteAlignment); /** - * Returns a slice of this memory segment with the given layout, at the given offset. The returned segment's address is the address - * of this segment plus the given offset; its size is the same as the size of the provided layout. + * Returns a slice of this memory segment with the given layout, at the given offset. + * The returned segment's address is the address of this segment plus the given + * offset; its size is the same as the size of the provided layout. *

    * Equivalent to the following code: * {@snippet lang=java : @@ -558,19 +653,21 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * * @see #asSlice(long, long, long) * - * @param offset The new segment base offset (relative to the address of this segment), specified in bytes. - * @param layout The layout of the segment slice. + * @param offset The new segment base offset (relative to the address of this segment), + * specified in bytes + * @param layout The layout of the segment slice * @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}, * or {@code layout.byteSize() > byteSize() - offset} - * @throws IllegalArgumentException if this segment cannot be accessed at {@code offset} under - * the alignment constraint specified by {@code layout} - * @return a slice of this memory segment. + * @throws IllegalArgumentException if this segment cannot be accessed at {@code offset} + * under the alignment constraint specified by {@code layout} + * @return a slice of this memory segment */ MemorySegment asSlice(long offset, MemoryLayout layout); /** - * Returns a slice of this memory segment, at the given offset. The returned segment's address is the address - * of this segment plus the given offset; its size is computed by subtracting the specified offset from this segment size. + * Returns a slice of this memory segment, at the given offset. The returned + * segment's address is the address of this segment plus the given offset; its size + * is computed by subtracting the specified offset from this segment size. *

    * Equivalent to the following code: * {@snippet lang=java : @@ -579,94 +676,118 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * * @see #asSlice(long, long) * - * @param offset The new segment base offset (relative to the address of this segment), specified in bytes. - * @return a slice of this memory segment. + * @param offset The new segment base offset (relative to the address of this segment), + * specified in bytes + * @return a slice of this memory segment * @throws IndexOutOfBoundsException if {@code offset < 0}, or {@code offset > byteSize()} */ MemorySegment asSlice(long offset); /** - * Returns a new memory segment that has the same address and scope as this segment, but with the provided size. + * Returns a new memory segment that has the same address and scope as this segment, + * but with the provided size. * - * @param newSize the size of the returned segment. - * @return a new memory segment that has the same address and scope as this segment, but the new - * provided size. + * @param newSize the size of the returned segment + * @return a new memory segment that has the same address and scope as + * this segment, but the new provided size * @throws IllegalArgumentException if {@code newSize < 0} - * @throws UnsupportedOperationException if this segment is not a {@linkplain #isNative() native} segment - * @throws IllegalCallerException if the caller is in a module that does not have native access enabled + * @throws UnsupportedOperationException if this segment is not a + * {@linkplain #isNative() native} segment + * @throws IllegalCallerException if the caller is in a module that does not have + * native access enabled */ @CallerSensitive @Restricted MemorySegment reinterpret(long newSize); /** - * Returns a new memory segment with the same address and size as this segment, but with the provided scope. - * As such, the returned segment cannot be accessed after the provided arena has been closed. - * Moreover, the returned segment can be accessed compatibly with the confinement restrictions associated with the - * provided arena: that is, if the provided arena is a {@linkplain Arena#ofConfined() confined arena}, - * the returned segment can only be accessed by the arena's owner thread, regardless of the confinement restrictions - * associated with this segment. In other words, this method returns a segment that behaves as if it had been allocated - * using the provided arena. + * Returns a new memory segment with the same address and size as this segment, but + * with the provided scope. As such, the returned segment cannot be accessed after + * the provided arena has been closed. Moreover, the returned segment can be + * accessed compatibly with the confinement restrictions associated with the provided + * arena: that is, if the provided arena is a {@linkplain Arena#ofConfined() confined arena}, + * the returned segment can only be accessed by the arena's owner thread, regardless + * of the confinement restrictions associated with this segment. In other words, this + * method returns a segment that behaves as if it had been allocated using the + * provided arena. *

    - * Clients can specify an optional cleanup action that should be executed when the provided scope becomes - * invalid. This cleanup action receives a fresh memory segment that is obtained from this segment as follows: + * Clients can specify an optional cleanup action that should be executed when the + * provided scope becomes invalid. This cleanup action receives a fresh memory + * segment that is obtained from this segment as follows: * {@snippet lang=java : * MemorySegment cleanupSegment = MemorySegment.ofAddress(this.address()) * .reinterpret(byteSize()); * } - * That is, the cleanup action receives a segment that is associated with the global scope, - * and is accessible from any thread. The size of the segment accepted by the cleanup action is {@link #byteSize()}. - * - * @apiNote The cleanup action (if present) should take care not to leak the received segment to external - * clients that might access the segment after its backing region of memory is no longer available. Furthermore, - * if the provided scope is the scope of an {@linkplain Arena#ofAuto() automatic arena}, the cleanup action - * must not prevent the scope from becoming unreachable. - * A failure to do so will permanently prevent the regions of memory allocated by the automatic arena from being deallocated. - * - * @param arena the arena to be associated with the returned segment. - * @param cleanup the cleanup action that should be executed when the provided arena is closed (can be {@code null}). - * @return a new memory segment with unbounded size. + * That is, the cleanup action receives a segment that is associated with the global + * scope, and is accessible from any thread. The size of the segment accepted by the + * cleanup action is {@link #byteSize()}. + * + * @apiNote The cleanup action (if present) should take care not to leak the received + * segment to external clients that might access the segment after its + * backing region of memory is no longer available. Furthermore, if the + * provided scope is the scope of an {@linkplain Arena#ofAuto() automatic arena}, + * the cleanup action must not prevent the scope from becoming + * unreachable. + * A failure to do so will permanently prevent the regions of memory + * allocated by the automatic arena from being deallocated. + * + * @param arena the arena to be associated with the returned segment + * @param cleanup the cleanup action that should be executed when the provided arena + * is closed (can be {@code null}) + * @return a new memory segment with unbounded size * @throws IllegalStateException if {@code arena.scope().isAlive() == false} - * @throws UnsupportedOperationException if this segment is not a {@linkplain #isNative() native} segment - * @throws IllegalCallerException if the caller is in a module that does not have native access enabled + * @throws UnsupportedOperationException if this segment is not a + * {@linkplain #isNative() native} segment + * @throws IllegalCallerException if the caller is in a module that does not have + * native access enabled */ @CallerSensitive @Restricted MemorySegment reinterpret(Arena arena, Consumer cleanup); /** - * Returns a new segment with the same address as this segment, but with the provided size and scope. - * As such, the returned segment cannot be accessed after the provided arena has been closed. - * Moreover, if the returned segment can be accessed compatibly with the confinement restrictions associated with the - * provided arena: that is, if the provided arena is a {@linkplain Arena#ofConfined() confined arena}, - * the returned segment can only be accessed by the arena's owner thread, regardless of the confinement restrictions - * associated with this segment. In other words, this method returns a segment that behaves as if it had been allocated - * using the provided arena. + * Returns a new segment with the same address as this segment, but with the provided + * size and scope. As such, the returned segment cannot be accessed after the + * provided arena has been closed. Moreover, if the returned segment can be accessed + * compatibly with the confinement restrictions associated with the provided arena: + * that is, if the provided arena is a {@linkplain Arena#ofConfined() confined arena}, + * the returned segment can only be accessed by the arena's owner thread, regardless + * of the confinement restrictions associated with this segment. In other words, + * this method returns a segment that behaves as if it had been allocated using the + * provided arena. *

    - * Clients can specify an optional cleanup action that should be executed when the provided scope becomes - * invalid. This cleanup action receives a fresh memory segment that is obtained from this segment as follows: + * Clients can specify an optional cleanup action that should be executed when the + * provided scope becomes invalid. This cleanup action receives a fresh memory + * segment that is obtained from this segment as follows: * {@snippet lang=java : * MemorySegment cleanupSegment = MemorySegment.ofAddress(this.address()) * .reinterpret(newSize); * } - * That is, the cleanup action receives a segment that is associated with the global scope, - * and is accessible from any thread. The size of the segment accepted by the cleanup action is {@code newSize}. - * - * @apiNote The cleanup action (if present) should take care not to leak the received segment to external - * clients that might access the segment after its backing region of memory is no longer available. Furthermore, - * if the provided scope is the scope of an {@linkplain Arena#ofAuto() automatic arena}, the cleanup action - * must not prevent the scope from becoming unreachable. - * A failure to do so will permanently prevent the regions of memory allocated by the automatic arena from being deallocated. - * - * @param newSize the size of the returned segment. - * @param arena the arena to be associated with the returned segment. - * @param cleanup the cleanup action that should be executed when the provided arena is closed (can be {@code null}). - * @return a new segment that has the same address as this segment, but with the new size and its scope set to - * that of the provided arena. - * @throws UnsupportedOperationException if this segment is not a {@linkplain #isNative() native} segment + * That is, the cleanup action receives a segment that is associated with the global + * scope, and is accessible from any thread. The size of the segment accepted by the + * cleanup action is {@code newSize}. + * + * @apiNote The cleanup action (if present) should take care not to leak the received + * segment to external clients that might access the segment after its + * backing region of memory is no longer available. Furthermore, if the + * provided scope is the scope of an {@linkplain Arena#ofAuto() automatic arena}, + * the cleanup action must not prevent the scope from becoming + * unreachable. + * A failure to do so will permanently prevent the regions of memory + * allocated by the automatic arena from being deallocated. + * + * @param newSize the size of the returned segment + * @param arena the arena to be associated with the returned segment + * @param cleanup the cleanup action that should be executed when the provided arena + * is closed (can be {@code null}). + * @return a new segment that has the same address as this segment, but with the new + * size and its scope set to that of the provided arena. + * @throws UnsupportedOperationException if this segment is not a + * {@linkplain #isNative() native} segment * @throws IllegalArgumentException if {@code newSize < 0} * @throws IllegalStateException if {@code arena.scope().isAlive() == false} - * @throws IllegalCallerException if the caller is in a module that does not have native access enabled + * @throws IllegalCallerException if the caller is in a module that does not have + * native access enabled */ @CallerSensitive @Restricted @@ -681,41 +802,47 @@ MemorySegment reinterpret(long newSize, boolean isReadOnly(); /** - * Returns a read-only view of this segment. The resulting segment will be identical to this one, but - * attempts to overwrite the contents of the returned segment will cause runtime exceptions. - * @return a read-only view of this segment + * {@return a read-only view of this segment} + * + * The resulting segment will be identical to this one, but attempts to overwrite the + * contents of the returned segment will cause runtime exceptions. + * * @see #isReadOnly() */ MemorySegment asReadOnly(); /** - * Returns {@code true} if this segment is a native segment. A native segment is - * created e.g. using the {@link Arena#allocate(long, long)} (and related) factory, or by - * {@linkplain #ofBuffer(Buffer) wrapping} a {@linkplain ByteBuffer#allocateDirect(int) direct buffer}. - * @return {@code true} if this segment is a native segment. + * {@return {@code true} if this segment is a native segment} + *

    + * A native segment is created e.g. using the {@link Arena#allocate(long, long)} + * (and related) factory, or by {@linkplain #ofBuffer(Buffer) wrapping} a + * {@linkplain ByteBuffer#allocateDirect(int) direct buffer}. */ boolean isNative(); /** - * Returns {@code true} if this segment is a mapped segment. A mapped memory segment is created e.g. using the + * {@return {@code true} if this segment is a mapped segment} + * + * A mapped memory segment is created e.g. using the * {@link FileChannel#map(FileChannel.MapMode, long, long, Arena)} factory, or by - * {@linkplain #ofBuffer(Buffer) wrapping} a {@linkplain java.nio.MappedByteBuffer mapped byte buffer}. - * @return {@code true} if this segment is a mapped segment. + * {@linkplain #ofBuffer(Buffer) wrapping} a + * {@linkplain java.nio.MappedByteBuffer mapped byte buffer}. */ boolean isMapped(); /** - * Returns a slice of this segment that is the overlap between this and - * the provided segment. + * Returns a slice of this segment that is the overlap between this and the provided + * segment. * - *

    Two segments {@code S1} and {@code S2} are said to overlap if it is possible to find - * at least two slices {@code L1} (from {@code S1}) and {@code L2} (from {@code S2}) that are backed by the - * same region of memory. As such, it is not possible for a - * {@linkplain #isNative() native} segment to overlap with a heap segment; in - * this case, or when no overlap occurs, an empty {@code Optional} is returned. + *

    Two segments {@code S1} and {@code S2} are said to overlap if it is possible to + * find at least two slices {@code L1} (from {@code S1}) and {@code L2} + * (from {@code S2}) that are backed by the same region of memory. As such, it is + * not possible for a {@linkplain #isNative() native} segment to overlap with a heap + * segment; in this case, or when no overlap occurs, an empty {@code Optional} is + * returned. * - * @param other the segment to test for an overlap with this segment. - * @return a slice of this segment (where overlapping occurs). + * @param other the segment to test for an overlap with this segment + * @return a slice of this segment (where overlapping occurs) */ Optional asOverlappingSlice(MemorySegment other); @@ -736,37 +863,40 @@ MemorySegment reinterpret(long newSize, *

    * This method can be useful to initialize or reset the contents of a memory segment. * - * @param value the value to write into this segment. - * @return this memory segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param value the value to write into this segment + * @return this memory segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} + * @throws UnsupportedOperationException if this segment is + * {@linkplain #isReadOnly() read-only} */ MemorySegment fill(byte value); /** - * Performs a bulk copy from the given source segment to this segment. More specifically, the bytes at - * offset {@code 0} through {@code src.byteSize() - 1} in the source segment are copied into this segment - * at offset {@code 0} through {@code src.byteSize() - 1}. + * Performs a bulk copy from the given source segment to this segment. More specifically, + * the bytes at offset {@code 0} through {@code src.byteSize() - 1} in the source + * segment are copied into this segment at offset {@code 0} through + * {@code src.byteSize() - 1}. *

    * Calling this method is equivalent to the following code: * {@snippet lang=java : * MemorySegment.copy(src, 0, this, 0, src.byteSize()); * } - * @param src the source segment. + * @param src the source segment * @throws IndexOutOfBoundsException if {@code src.byteSize() > this.byteSize()} - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with {@code src} is not - * {@linkplain Scope#isAlive() alive} + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * {@code src} is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code src.isAccessibleBy(T) == false} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} - * @return this segment. + * @throws UnsupportedOperationException if this segment is + * {@linkplain #isReadOnly() read-only} + * @return this segment */ MemorySegment copyFrom(MemorySegment src); @@ -785,15 +915,15 @@ MemorySegment reinterpret(long newSize, * valid for the larger segment. Otherwise, there is no mismatch and {@code * -1} is returned. * - * @param other the segment to be tested for a mismatch with this segment. + * @param other the segment to be tested for a mismatch with this segment * @return the relative offset, in bytes, of the first mismatch between this - * and the given other segment, otherwise -1 if no mismatch. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * and the given other segment, otherwise -1 if no mismatch + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with {@code other} is not - * {@linkplain Scope#isAlive() alive} + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * {@code other} is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code other.isAccessibleBy(T) == false} */ @@ -806,7 +936,7 @@ MemorySegment reinterpret(long newSize, *

    A return value of {@code true} implies that it is highly likely * that all the data in this segment is resident in physical memory and * may therefore be accessed without incurring any virtual-memory page - * faults or I/O operations. A return value of {@code false} does not + * faults or I/O operations. A return value of {@code false} does not * necessarily imply that this segment's contents are not resident in physical * memory. * @@ -817,68 +947,66 @@ MemorySegment reinterpret(long newSize, * @return {@code true} if it is likely that the contents of this segment * are resident in physical memory * - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} - * @throws UnsupportedOperationException if this segment is not a mapped memory segment, e.g. if - * {@code isMapped() == false}. + * @throws UnsupportedOperationException if this segment is not a mapped memory + * segment, e.g. if {@code isMapped() == false} */ boolean isLoaded(); /** * Loads the contents of this mapped segment into physical memory. - * - *

    This method makes a best effort to ensure that, when it returns, + *

    + * This method makes a best effort to ensure that, when it returns, * the contents of this segment are resident in physical memory. Invoking this * method may cause some number of page faults and I/O operations to * occur.

    * - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} - * @throws WrongThreadException if this method is called from a thread {@code T}, - * such that {@code isAccessibleBy(T) == false} - * @throws UnsupportedOperationException if this segment is not a mapped memory segment, e.g. if - * {@code isMapped() == false} + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} + * @throws WrongThreadException if this method is called from a thread + * {@code T}, such that {@code isAccessibleBy(T) == false} + * @throws UnsupportedOperationException if this segment is not a mapped memory + * segment, e.g. if {@code isMapped() == false} */ void load(); /** * Unloads the contents of this mapped segment from physical memory. + *

    + * This method makes a best effort to ensure that the contents of this segment + * are no longer resident in physical memory. Accessing this segment's contents + * after invoking this method may cause some number of page faults and I/O operations + * to occur (as this segment's contents might need to be paged back in).

    * - *

    This method makes a best effort to ensure that the contents of this segment are - * no longer resident in physical memory. Accessing this segment's contents - * after invoking this method may cause some number of page faults and I/O operations to - * occur (as this segment's contents might need to be paged back in).

    - * - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} - * @throws UnsupportedOperationException if this segment is not a mapped memory segment, e.g. if - * {@code isMapped() == false} + * @throws UnsupportedOperationException if this segment is not a mapped memory + * segment, e.g. if {@code isMapped() == false} */ void unload(); /** - * Forces any changes made to the contents of this mapped segment to be written to the - * storage device described by the mapped segment's file descriptor. - * - *

    If the file descriptor associated with this mapped segment resides on a local storage - * device then when this method returns it is guaranteed that all changes - * made to this segment since it was created, or since this method was last - * invoked, will have been written to that device. - * - *

    If the file descriptor associated with this mapped segment does not reside on a local device then - * no such guarantee is made. - * - *

    If this segment was not mapped in read/write mode ({@link - * java.nio.channels.FileChannel.MapMode#READ_WRITE}) then - * invoking this method may have no effect. In particular, the - * method has no effect for segments mapped in read-only or private - * mapping modes. This method may or may not have an effect for - * implementation-specific mapping modes. - *

    + * Forces any changes made to the contents of this mapped segment to be written to + * the storage device described by the mapped segment's file descriptor. + *

    + * If the file descriptor associated with this mapped segment resides on a local + * storage device then when this method returns it is guaranteed that all changes + * made to this segment since it was created, or since this method was last invoked, + * will have been written to that device. + *

    + * If the file descriptor associated with this mapped segment does not reside on + * a local device then no such guarantee is made. + *

    + * If this segment was not mapped in read/write mode + * ({@link java.nio.channels.FileChannel.MapMode#READ_WRITE}) then invoking this + * method may have no effect. In particular, the method has no effect for segments + * mapped in read-only or private mapping modes. This method may or may not have an + * effect for implementation-specific mapping modes. * * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not * {@linkplain Scope#isAlive() alive} @@ -892,133 +1020,168 @@ MemorySegment reinterpret(long newSize, void force(); /** - * Wraps this segment in a {@link ByteBuffer}. Some properties of the returned buffer are linked to - * the properties of this segment. More specifically, the resulting buffer has the following characteristics: + * Wraps this segment in a {@link ByteBuffer}. Some properties of the returned buffer + * are linked to the properties of this segment. More specifically, the resulting + * buffer has the following characteristics: *

      *
    • It is {@linkplain ByteBuffer#isReadOnly() read-only}, if this segment is a * {@linkplain #isReadOnly() read-only segment};
    • *
    • Its {@linkplain ByteBuffer#position() position} is set to zero; - *
    • Its {@linkplain ByteBuffer#capacity() capacity} and {@linkplain ByteBuffer#limit() limit} - * are both set to this segment' {@linkplain MemorySegment#byteSize() size}. For this reason, a byte buffer - * cannot be returned if this segment's size is greater than {@link Integer#MAX_VALUE};
    • - *
    • It is a {@linkplain ByteBuffer#isDirect() direct buffer}, if this is a native segment.
    • + *
    • Its {@linkplain ByteBuffer#capacity() capacity} and + * {@linkplain ByteBuffer#limit() limit} are both set to this segment's + * {@linkplain MemorySegment#byteSize() size}. For this reason, a byte buffer cannot + * be returned if this segment's size is greater than {@link Integer#MAX_VALUE};
    • + *
    • It is a {@linkplain ByteBuffer#isDirect() direct buffer}, if this is a + * native segment.
    • *
    *

    - * The life-cycle of the returned buffer is tied to that of this segment. That is, accessing the returned buffer - * after the scope associated with this segment is no longer {@linkplain Scope#isAlive() alive}, will - * throw an {@link IllegalStateException}. Similarly, accessing the returned buffer from a thread {@code T} - * such that {@code isAccessible(T) == false} will throw a {@link WrongThreadException}. + * The life-cycle of the returned buffer is tied to that of this segment. That is, + * accessing the returned buffer after the scope associated with this segment is no + * longer {@linkplain Scope#isAlive() alive}, will throw an + * {@link IllegalStateException}. Similarly, accessing the returned buffer from a + * thread {@code T} such that {@code isAccessible(T) == false} will throw a + * {@link WrongThreadException}. *

    - * If this segment is {@linkplain #isAccessibleBy(Thread) accessible} from a single thread, calling read/write I/O - * operations on the resulting buffer might result in unspecified exceptions being thrown. Examples of such problematic operations are + * If this segment is {@linkplain #isAccessibleBy(Thread) accessible} from a single + * thread, calling read/write I/O operations on the resulting buffer might result in + * unspecified exceptions being thrown. Examples of such problematic operations are * {@link java.nio.channels.AsynchronousSocketChannel#read(ByteBuffer)} and * {@link java.nio.channels.AsynchronousSocketChannel#write(ByteBuffer)}. *

    - * Finally, the resulting buffer's byte order is {@link java.nio.ByteOrder#BIG_ENDIAN}; this can be changed using + * Finally, the resulting buffer's byte order is + * {@link java.nio.ByteOrder#BIG_ENDIAN}; this can be changed using * {@link ByteBuffer#order(java.nio.ByteOrder)}. * - * @return a {@link ByteBuffer} view of this memory segment. - * @throws UnsupportedOperationException if this segment cannot be mapped onto a {@link ByteBuffer} instance, - * e.g. if it is a heap segment backed by an array other than {@code byte[]}), or if its size is greater - * than {@link Integer#MAX_VALUE} + * @return a {@link ByteBuffer} view of this memory segment + * @throws UnsupportedOperationException if this segment cannot be mapped onto a + * {@link ByteBuffer} instance, e.g. if it is a heap segment backed by an + * array other than {@code byte[]}), or if its size is greater than + * {@link Integer#MAX_VALUE} */ ByteBuffer asByteBuffer(); /** * Copy the contents of this memory segment into a new byte array. - * @param elementLayout the source element layout. If the byte order associated with the layout is - * different from the {@linkplain ByteOrder#nativeOrder native order}, a byte swap operation will be performed on each array element. - * @return a new byte array whose contents are copied from this memory segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * + * @param elementLayout the source element layout. If the byte order associated with + * the layout is different from the + * {@linkplain ByteOrder#nativeOrder native order}, a byte swap + * operation will be performed on each array element + * @return a new byte array whose contents are copied from this memory segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} - * @throws IllegalStateException if this segment's contents cannot be copied into a {@code byte[]} instance, - * e.g. its size is greater than {@link Integer#MAX_VALUE} + * @throws IllegalStateException if this segment's contents cannot be copied into a + * {@code byte[]} instance, e.g. its size is greater than {@link Integer#MAX_VALUE} */ byte[] toArray(ValueLayout.OfByte elementLayout); /** * Copy the contents of this memory segment into a new short array. - * @param elementLayout the source element layout. If the byte order associated with the layout is - * different from the {@linkplain ByteOrder#nativeOrder native order}, a byte swap operation will be performed on each array element. - * @return a new short array whose contents are copied from this memory segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * + * @param elementLayout the source element layout. If the byte order associated with + * the layout is different from the + * {@linkplain ByteOrder#nativeOrder native order}, a byte swap + * operation will be performed on each array element + * @return a new short array whose contents are copied from this memory segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} - * @throws IllegalStateException if this segment's contents cannot be copied into a {@code short[]} instance, - * e.g. because {@code byteSize() % 2 != 0}, or {@code byteSize() / 2 > Integer.MAX_VALUE} + * @throws IllegalStateException if this segment's contents cannot be copied into a + * {@code short[]} instance, e.g. because {@code byteSize() % 2 != 0}, or + * {@code byteSize() / 2 > Integer.MAX_VALUE} */ short[] toArray(ValueLayout.OfShort elementLayout); /** * Copy the contents of this memory segment into a new char array. - * @param elementLayout the source element layout. If the byte order associated with the layout is - * different from the {@linkplain ByteOrder#nativeOrder native order}, a byte swap operation will be performed on each array element. - * @return a new char array whose contents are copied from this memory segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * + * @param elementLayout the source element layout. If the byte order associated with + * the layout is different from the + * {@linkplain ByteOrder#nativeOrder native order}, a byte swap + * operation will be performed on each array element + * @return a new char array whose contents are copied from this memory segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} - * @throws IllegalStateException if this segment's contents cannot be copied into a {@code char[]} instance, - * e.g. because {@code byteSize() % 2 != 0}, or {@code byteSize() / 2 > Integer.MAX_VALUE} + * @throws IllegalStateException if this segment's contents cannot be copied into a + * {@code char[]} instance, e.g. because {@code byteSize() % 2 != 0}, or + * {@code byteSize() / 2 > Integer.MAX_VALUE} */ char[] toArray(ValueLayout.OfChar elementLayout); /** * Copy the contents of this memory segment into a new int array. - * @param elementLayout the source element layout. If the byte order associated with the layout is - * different from the {@linkplain ByteOrder#nativeOrder native order}, a byte swap operation will be performed on each array element. - * @return a new int array whose contents are copied from this memory segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * + * @param elementLayout the source element layout. If the byte order associated with + * the layout is different from the + * {@linkplain ByteOrder#nativeOrder native order}, a byte swap + * operation will be performed on each array element. + * @return a new int array whose contents are copied from this memory segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} - * @throws IllegalStateException if this segment's contents cannot be copied into a {@code int[]} instance, - * e.g. because {@code byteSize() % 4 != 0}, or {@code byteSize() / 4 > Integer.MAX_VALUE} + * @throws IllegalStateException if this segment's contents cannot be copied into a + * {@code int[]} instance, e.g. because {@code byteSize() % 4 != 0}, or + * {@code byteSize() / 4 > Integer.MAX_VALUE} */ int[] toArray(ValueLayout.OfInt elementLayout); /** * Copy the contents of this memory segment into a new float array. - * @param elementLayout the source element layout. If the byte order associated with the layout is - * different from the {@linkplain ByteOrder#nativeOrder native order}, a byte swap operation will be performed on each array element. - * @return a new float array whose contents are copied from this memory segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * + * @param elementLayout the source element layout. If the byte order associated with + * the layout is different from the + * {@linkplain ByteOrder#nativeOrder native order}, a byte swap + * operation will be performed on each array element + * @return a new float array whose contents are copied from this memory segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} - * @throws IllegalStateException if this segment's contents cannot be copied into a {@code float[]} instance, - * e.g. because {@code byteSize() % 4 != 0}, or {@code byteSize() / 4 > Integer.MAX_VALUE}. + * @throws IllegalStateException if this segment's contents cannot be copied into a + * {@code float[]} instance, e.g. because {@code byteSize() % 4 != 0}, or + * {@code byteSize() / 4 > Integer.MAX_VALUE} */ float[] toArray(ValueLayout.OfFloat elementLayout); /** * Copy the contents of this memory segment into a new long array. - * @param elementLayout the source element layout. If the byte order associated with the layout is - * different from the {@linkplain ByteOrder#nativeOrder native order}, a byte swap operation will be performed on each array element. - * @return a new long array whose contents are copied from this memory segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * + * @param elementLayout the source element layout. If the byte order associated with + * the layout is different from the + * {@linkplain ByteOrder#nativeOrder native order}, a byte swap + * operation will be performed on each array element + * @return a new long array whose contents are copied from this memory segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} - * @throws IllegalStateException if this segment's contents cannot be copied into a {@code long[]} instance, - * e.g. because {@code byteSize() % 8 != 0}, or {@code byteSize() / 8 > Integer.MAX_VALUE} + * @throws IllegalStateException if this segment's contents cannot be copied into a + * {@code long[]} instance, e.g. because {@code byteSize() % 8 != 0}, or + * {@code byteSize() / 8 > Integer.MAX_VALUE} */ long[] toArray(ValueLayout.OfLong elementLayout); /** * Copy the contents of this memory segment into a new double array. - * @param elementLayout the source element layout. If the byte order associated with the layout is - * different from the {@linkplain ByteOrder#nativeOrder native order}, a byte swap operation will be performed on each array element. - * @return a new double array whose contents are copied from this memory segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * + * @param elementLayout the source element layout. If the byte order associated with + * the layout is different from the + * {@linkplain ByteOrder#nativeOrder native order}, a byte swap + * operation will be performed on each array element + * @return a new double array whose contents are copied from this memory segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, - * such that {@code isAccessibleBy(T) == false}. - * @throws IllegalStateException if this segment's contents cannot be copied into a {@code double[]} instance, - * e.g. because {@code byteSize() % 8 != 0}, or {@code byteSize() / 8 > Integer.MAX_VALUE}. + * such that {@code isAccessibleBy(T) == false} + * @throws IllegalStateException if this segment's contents cannot be copied into a + * {@code double[]} instance, e.g. because {@code byteSize() % 8 != 0}, or + * {@code byteSize() / 8 > Integer.MAX_VALUE} */ double[] toArray(ValueLayout.OfDouble elementLayout); @@ -1031,78 +1194,90 @@ MemorySegment reinterpret(long newSize, * getString(offset, StandardCharsets.UTF_8); *} * - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * @return a Java string constructed from the bytes read from the given starting address up to (but not including) - * the first {@code '\0'} terminator character (assuming one is found). - * @throws IllegalArgumentException if the size of the string is greater than the largest string - * supported by the platform. + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur + * @return a Java string constructed from the bytes read from the given starting + * address up to (but not including) the first {@code '\0'} terminator + * character (assuming one is found) + * @throws IllegalArgumentException if the size of the string is greater than the + * largest string supported by the platform * @throws IndexOutOfBoundsException if {@code offset < 0} - * @throws IndexOutOfBoundsException if {@code offset > byteSize() - (B + 1)}, where {@code B} is the size, - * in bytes, of the string encoded using UTF-8 charset {@code str.getBytes(StandardCharsets.UTF_8).length}) - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @throws IndexOutOfBoundsException if {@code offset > byteSize() - (B + 1)}, where + * {@code B} is the size, in bytes, of the string encoded using UTF-8 charset + * {@code str.getBytes(StandardCharsets.UTF_8).length}) + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} */ String getString(long offset); /** - * Reads a null-terminated string from this segment at the given offset, using the provided charset. + * Reads a null-terminated string from this segment at the given offset, using the + * provided charset. *

    * 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 * over the decoding process is required. * - * @param offset offset in bytes (relative to this segment address) at which this access operation will occur. - * @param charset the charset used to {@linkplain Charset#newDecoder() decode} the string bytes. - * @return a Java string constructed from the bytes read from the given starting address up to (but not including) - * the first {@code '\0'} terminator character (assuming one is found). - * @throws IllegalArgumentException if the size of the string is greater than the largest string - * supported by the platform + * @param offset offset in bytes (relative to this segment address) at which this + * access operation will occur + * @param charset the charset used to {@linkplain Charset#newDecoder() decode} the + * string bytes + * @return a Java string constructed from the bytes read from the given starting + * address up to (but not including) the first {@code '\0'} terminator + * character (assuming one is found) + * @throws IllegalArgumentException if the size of the string is greater than the + * largest string supported by the platform * @throws IndexOutOfBoundsException if {@code offset < 0} * @throws IndexOutOfBoundsException if {@code offset > byteSize() - (B + N)}, where: *

      - *
    • {@code B} is the size, in bytes, of the string encoded using the provided charset - * (e.g. {@code str.getBytes(charset).length});
    • - *
    • {@code N} is the size (in bytes) of the terminator char according to the provided charset. For instance, - * this is 1 for {@link StandardCharsets#US_ASCII} and 2 for {@link StandardCharsets#UTF_16}.
    • + *
    • {@code B} is the size, in bytes, of the string encoded using the + * provided charset (e.g. {@code str.getBytes(charset).length});
    • + *
    • {@code N} is the size (in bytes) of the terminator char according + * to the provided charset. For instance, this is 1 for + * {@link StandardCharsets#US_ASCII} and 2 for {@link StandardCharsets#UTF_16}.
    • *
    - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} - * @throws IllegalArgumentException if {@code charset} is not a {@linkplain StandardCharsets standard charset} + * @throws IllegalArgumentException if {@code charset} is not a + * {@linkplain StandardCharsets standard charset} */ String getString(long offset, Charset charset); /** - * Writes the given string into this segment at the given offset, converting it to a null-terminated byte sequence - * using the {@linkplain StandardCharsets#UTF_8 UTF-8} charset. + * Writes the given string into this segment at the given offset, converting it to + * a null-terminated byte sequence using the {@linkplain StandardCharsets#UTF_8 UTF-8} + * charset. *

    * Calling this method is equivalent to the following code: * {@snippet lang = java: * setString(offset, str, StandardCharsets.UTF_8); *} - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * the final address of this write operation can be expressed as {@code address() + offset}. - * @param str the Java string to be written into this segment. + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur, the final address of this write + * operation can be expressed as {@code address() + offset}. + * @param str the Java string to be written into this segment * @throws IndexOutOfBoundsException if {@code offset < 0} - * @throws IndexOutOfBoundsException if {@code offset > byteSize() - (B + 1)}, where {@code B} is the size, - * in bytes, of the string encoded using UTF-8 charset {@code str.getBytes(StandardCharsets.UTF_8).length}) - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @throws IndexOutOfBoundsException if {@code offset > byteSize() - (B + 1)}, where + * {@code B} is the size, in bytes, of the string encoded using UTF-8 charset + * {@code str.getBytes(StandardCharsets.UTF_8).length}) + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, - * such that {@code isAccessibleBy(T) == false}. + * such that {@code isAccessibleBy(T) == false} */ void setString(long offset, String str); /** - * Writes the given string into this segment at the given offset, converting it to a null-terminated byte sequence - * using the provided charset. + * Writes the given string into this segment at the given offset, converting it to a + * null-terminated byte sequence using the provided charset. *

    * 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 * over the decoding process is required. *

    @@ -1111,190 +1286,215 @@ MemorySegment reinterpret(long newSize, * the string, such as {@link MemorySegment#getString(long)}, the string * will appear truncated when read again. * - * @param offset offset in bytes (relative to this segment address) at which this access operation will occur. - * the final address of this write operation can be expressed as {@code address() + offset}. - * @param str the Java string to be written into this segment. - * @param charset the charset used to {@linkplain Charset#newEncoder() encode} the string bytes. + * @param offset offset in bytes (relative to this segment address) at which this + * access operation will occur, the final address of this write + * operation can be expressed as {@code address() + offset} + * @param str the Java string to be written into this segment + * @param charset the charset used to {@linkplain Charset#newEncoder() encode} the string bytes * @throws IndexOutOfBoundsException if {@code offset < 0} * @throws IndexOutOfBoundsException if {@code offset > byteSize() - (B + N)}, where: *

      - *
    • {@code B} is the size, in bytes, of the string encoded using the provided charset - * (e.g. {@code str.getBytes(charset).length});
    • - *
    • {@code N} is the size (in bytes) of the terminator char according to the provided charset. For - * instance, this is 1 for {@link StandardCharsets#US_ASCII} and 2 for {@link StandardCharsets#UTF_16}.
    • + *
    • {@code B} is the size, in bytes, of the string encoded using the + * provided charset (e.g. {@code str.getBytes(charset).length});
    • + *
    • {@code N} is the size (in bytes) of the terminator char according + * to the provided charset. For instance, this is 1 for + * {@link StandardCharsets#US_ASCII} and 2 for {@link StandardCharsets#UTF_16}.
    • *
    - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} - * @throws IllegalArgumentException if {@code charset} is not a {@linkplain StandardCharsets standard charset} + * @throws IllegalArgumentException if {@code charset} is not a + * {@linkplain StandardCharsets standard charset} */ void setString(long offset, String str, Charset charset); /** - * Creates a memory segment that is backed by the same region of memory that backs the given {@link Buffer} instance. - * The segment starts relative to the buffer's position (inclusive) and ends relative to the buffer's limit (exclusive). + * Creates a memory segment that is backed by the same region of memory that backs + * the given {@link Buffer} instance. The segment starts relative to the buffer's + * position (inclusive) and ends relative to the buffer's limit (exclusive). *

    - * If the buffer is {@linkplain Buffer#isReadOnly() read-only}, the resulting segment is also - * {@linkplain ByteBuffer#isReadOnly() read-only}. Moreover, if the buffer is a {@linkplain Buffer#isDirect() direct buffer}, - * the returned segment is a native segment; otherwise, the returned memory segment is a heap segment. + * If the buffer is {@linkplain Buffer#isReadOnly() read-only}, the resulting segment + * is also {@linkplain ByteBuffer#isReadOnly() read-only}. Moreover, if the buffer + * is a {@linkplain Buffer#isDirect() direct buffer}, the returned segment is a + * native segment; otherwise, the returned memory segment is a heap segment. *

    - * If the provided buffer has been obtained by calling {@link #asByteBuffer()} on a memory segment whose - * {@linkplain Scope scope} is {@code S}, the returned segment will be associated with the - * same scope {@code S}. Otherwise, the scope of the returned segment is an automatic scope that keeps the provided - * buffer reachable. As such, if the provided buffer is a direct buffer, its backing memory region will not be - * deallocated as long as the returned segment, or any of its slices, are kept reachable. - * - * @param buffer the buffer instance to be turned into a new memory segment. - * @return a memory segment, derived from the given buffer instance. - * @throws IllegalArgumentException if the provided {@code buffer} is a heap buffer but is not backed by an array; - * For example, buffers directly or indirectly obtained via ({@link CharBuffer#wrap(CharSequence)} or - * {@link CharBuffer#wrap(char[], int, int)} are not backed by an array + * If the provided buffer has been obtained by calling {@link #asByteBuffer()} on a + * memory segment whose {@linkplain Scope scope} is {@code S}, the returned segment + * will be associated with the same scope {@code S}. Otherwise, the scope of the + * returned segment is an automatic scope that keeps the provided buffer reachable. + * As such, if the provided buffer is a direct buffer, its backing memory region will + * not be deallocated as long as the returned segment, or any of its slices, are kept + * reachable. + * + * @param buffer the buffer instance to be turned into a new memory segment + * @return a memory segment, derived from the given buffer instance + * @throws IllegalArgumentException if the provided {@code buffer} is a heap buffer + * but is not backed by an array; For example, buffers directly or indirectly + * obtained via ({@link CharBuffer#wrap(CharSequence)} or + * {@link CharBuffer#wrap(char[], int, int)} are not backed by an array. */ static MemorySegment ofBuffer(Buffer buffer) { return AbstractMemorySegmentImpl.ofBuffer(buffer); } /** - * Creates a heap segment backed by the on-heap region of memory that holds the given byte array. - * The scope of the returned segment is an automatic scope that keeps the given array reachable. - * The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero. + * Creates a heap segment backed by the on-heap region of memory that holds the given + * byte array. The scope of the returned segment is an automatic scope that keeps + * the given array reachable. The returned segment is always accessible, from any + * thread. Its {@link #address()} is set to zero. * - * @param byteArray the primitive array backing the heap memory segment. - * @return a heap memory segment backed by a byte array. + * @param byteArray the primitive array backing the heap memory segment + * @return a heap memory segment backed by a byte array */ static MemorySegment ofArray(byte[] byteArray) { return SegmentFactories.fromArray(byteArray); } /** - * Creates a heap segment backed by the on-heap region of memory that holds the given char array. - * The scope of the returned segment is an automatic scope that keeps the given array reachable. - * The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero. + * Creates a heap segment backed by the on-heap region of memory that holds the given + * char array. The scope of the returned segment is an automatic scope that keeps + * the given array reachable. The returned segment is always accessible, from any + * thread. Its {@link #address()} is set to zero. * - * @param charArray the primitive array backing the heap segment. - * @return a heap memory segment backed by a char array. + * @param charArray the primitive array backing the heap segment + * @return a heap memory segment backed by a char array */ static MemorySegment ofArray(char[] charArray) { return SegmentFactories.fromArray(charArray); } /** - * Creates a heap segment backed by the on-heap region of memory that holds the given short array. - * The scope of the returned segment is an automatic scope that keeps the given array reachable. - * The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero. + * Creates a heap segment backed by the on-heap region of memory that holds the given + * short array. The scope of the returned segment is an automatic scope that keeps + * the given array reachable. The returned segment is always accessible, from any + * thread. Its {@link #address()} is set to zero. * - * @param shortArray the primitive array backing the heap segment. - * @return a heap memory segment backed by a short array. + * @param shortArray the primitive array backing the heap segment + * @return a heap memory segment backed by a short array */ static MemorySegment ofArray(short[] shortArray) { return SegmentFactories.fromArray(shortArray); } /** - * Creates a heap segment backed by the on-heap region of memory that holds the given int array. - * The scope of the returned segment is an automatic scope that keeps the given array reachable. - * The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero. + * Creates a heap segment backed by the on-heap region of memory that holds the given + * int array. The scope of the returned segment is an automatic scope that keeps + * the given array reachable. The returned segment is always accessible, from any + * thread. Its {@link #address()} is set to zero. * - * @param intArray the primitive array backing the heap segment. - * @return a heap memory segment backed by an int array. + * @param intArray the primitive array backing the heap segment + * @return a heap memory segment backed by an int array */ static MemorySegment ofArray(int[] intArray) { return SegmentFactories.fromArray(intArray); } /** - * Creates a heap segment backed by the on-heap region of memory that holds the given float array. - * The scope of the returned segment is an automatic scope that keeps the given array reachable. - * The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero. + * Creates a heap segment backed by the on-heap region of memory that holds the given + * float array. The scope of the returned segment is an automatic scope that keeps + * the given array reachable. The returned segment is always accessible, from any + * thread. Its {@link #address()} is set to zero. * - * @param floatArray the primitive array backing the heap segment. - * @return a heap memory segment backed by a float array. + * @param floatArray the primitive array backing the heap segment + * @return a heap memory segment backed by a float array */ static MemorySegment ofArray(float[] floatArray) { return SegmentFactories.fromArray(floatArray); } /** - * Creates a heap segment backed by the on-heap region of memory that holds the given long array. - * The scope of the returned segment is an automatic scope that keeps the given array reachable. - * The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero. + * Creates a heap segment backed by the on-heap region of memory that holds the given + * long array. The scope of the returned segment is an automatic scope that keeps + * the given array reachable. The returned segment is always accessible, from any + * thread. Its {@link #address()} is set to zero. * - * @param longArray the primitive array backing the heap segment. - * @return a heap memory segment backed by a long array. + * @param longArray the primitive array backing the heap segment + * @return a heap memory segment backed by a long array */ static MemorySegment ofArray(long[] longArray) { return SegmentFactories.fromArray(longArray); } /** - * Creates a heap segment backed by the on-heap region of memory that holds the given double array. - * The scope of the returned segment is an automatic scope that keeps the given array reachable. - * The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero. + * Creates a heap segment backed by the on-heap region of memory that holds the given + * double array. The scope of the returned segment is an automatic scope that keeps + * the given array reachable. The returned segment is always accessible, from any + * thread. Its {@link #address()} is set to zero. * - * @param doubleArray the primitive array backing the heap segment. - * @return a heap memory segment backed by a double array. + * @param doubleArray the primitive array backing the heap segment + * @return a heap memory segment backed by a double array */ static MemorySegment ofArray(double[] doubleArray) { return SegmentFactories.fromArray(doubleArray); } /** - * A zero-length native segment modelling the {@code NULL} address. Equivalent to {@code MemorySegment.ofAddress(0L)}. + * A zero-length native segment modelling the {@code NULL} address. Equivalent to + * {@code MemorySegment.ofAddress(0L)}. */ MemorySegment NULL = MemorySegment.ofAddress(0L); /** - * Creates a zero-length native segment from the given {@linkplain #address() address value}. - * The returned segment is associated with the global scope and is accessible from any thread. + * Creates a zero-length native segment from the given + * {@linkplain #address() address value}. + *

    + * The returned segment is associated with the global scope and is accessible from + * any thread. *

    * On 32-bit platforms, the given address value will be normalized such that the * highest-order ("leftmost") 32 bits of the {@link MemorySegment#address() address} * of the returned memory segment are set to zero. * - * @param address the address of the returned native segment. - * @return a zero-length native segment with the given address. + * @param address the address of the returned native segment + * @return a zero-length native segment with the given address */ static MemorySegment ofAddress(long address) { return SegmentFactories.makeNativeSegmentUnchecked(address, 0); } /** - * Performs a bulk copy from source segment to destination segment. More specifically, the bytes at offset - * {@code srcOffset} through {@code srcOffset + bytes - 1} in the source segment are copied into the destination - * segment at offset {@code dstOffset} through {@code dstOffset + bytes - 1}. + * Performs a bulk copy from source segment to destination segment. More + * specifically, the bytes at offset {@code srcOffset} through + * {@code srcOffset + bytes - 1} in the source segment are copied into the + * destination segment at offset {@code dstOffset} through + * {@code dstOffset + bytes - 1}. *

    - * If the source segment overlaps with the destination segment, then the copying is performed as if the bytes at - * offset {@code srcOffset} through {@code srcOffset + bytes - 1} in the source segment were first copied into a - * temporary segment with size {@code bytes}, and then the contents of the temporary segment were copied into - * the destination segment at offset {@code dstOffset} through {@code dstOffset + bytes - 1}. + * If the source segment overlaps with the destination segment, then the copying is + * performed as if the bytes at offset {@code srcOffset} through + * {@code srcOffset + bytes - 1} in the source segment were first copied into a + * temporary segment with size {@code bytes}, and then the contents of the temporary + * segment were copied into the destination segment at offset {@code dstOffset} + * through {@code dstOffset + bytes - 1}. *

    - * The result of a bulk copy is unspecified if, in the uncommon case, the source segment and the destination segment - * do not overlap, but refer to overlapping regions of the same backing storage using different addresses. - * For example, this may occur if the same file is {@linkplain FileChannel#map mapped} to two segments. + * The result of a bulk copy is unspecified if, in the uncommon case, the source + * segment and the destination segment do not overlap, but refer to overlapping + * regions of the same backing storage using different addresses. For example, this + * may occur if the same file is {@linkplain FileChannel#map mapped} to two segments. *

    * Calling this method is equivalent to the following code: * {@snippet lang=java : * MemorySegment.copy(srcSegment, ValueLayout.JAVA_BYTE, srcOffset, dstSegment, ValueLayout.JAVA_BYTE, dstOffset, bytes); * } - * @param srcSegment the source segment. - * @param srcOffset the starting offset, in bytes, of the source segment. - * @param dstSegment the destination segment. - * @param dstOffset the starting offset, in bytes, of the destination segment. - * @param bytes the number of bytes to be copied. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with {@code srcSegment} is not - * {@linkplain Scope#isAlive() alive} + * @param srcSegment the source segment + * @param srcOffset the starting offset, in bytes, of the source segment + * @param dstSegment the destination segment + * @param dstOffset the starting offset, in bytes, of the destination segment + * @param bytes the number of bytes to be copied + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * {@code srcSegment} is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code srcSegment.isAccessibleBy(T) == false} - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with {@code dstSegment} is not - * {@linkplain Scope#isAlive() alive} + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * {@code dstSegment} is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code dstSegment.isAccessibleBy(T) == false} * @throws IndexOutOfBoundsException if {@code srcOffset > srcSegment.byteSize() - bytes} * @throws IndexOutOfBoundsException if {@code dstOffset > dstSegment.byteSize() - bytes} - * @throws IndexOutOfBoundsException if either {@code srcOffset}, {@code dstOffset} - * or {@code bytes} are {@code < 0} - * @throws UnsupportedOperationException if {@code dstSegment} is {@linkplain #isReadOnly() read-only} + * @throws IndexOutOfBoundsException if either {@code srcOffset}, + * {@code dstOffset} or {@code bytes} are {@code < 0} + * @throws UnsupportedOperationException if {@code dstSegment} is + * {@linkplain #isReadOnly() read-only} */ @ForceInline static void copy(MemorySegment srcSegment, long srcOffset, @@ -1305,42 +1505,51 @@ static void copy(MemorySegment srcSegment, long srcOffset, } /** - * Performs a bulk copy from source segment to destination segment. More specifically, if {@code S} is the byte size - * of the element layouts, the bytes at offset {@code srcOffset} through {@code srcOffset + (elementCount * S) - 1} - * in the source segment are copied into the destination segment at offset {@code dstOffset} through {@code dstOffset + (elementCount * S) - 1}. + * Performs a bulk copy from source segment to destination segment. More + * specifically, if {@code S} is the byte size of the element layouts, the bytes at + * offset {@code srcOffset} through {@code srcOffset + (elementCount * S) - 1} + * in the source segment are copied into the destination segment at offset + * {@code dstOffset} through {@code dstOffset + (elementCount * S) - 1}. *

    - * The copy occurs in an element-wise fashion: the bytes in the source segment are interpreted as a sequence of elements - * whose layout is {@code srcElementLayout}, whereas the bytes in the destination segment are interpreted as a sequence of - * elements whose layout is {@code dstElementLayout}. Both element layouts must have the same size {@code S}. - * If the byte order of the two provided element layouts differs, the bytes corresponding to each element to be copied - * are swapped accordingly during the copy operation. + * The copy occurs in an element-wise fashion: the bytes in the source segment are + * interpreted as a sequence of elements whose layout is {@code srcElementLayout}, + * whereas the bytes in the destination segment are interpreted as a sequence of + * elements whose layout is {@code dstElementLayout}. Both element layouts must have + * the same size {@code S}. If the byte order of the two provided element layouts + * differs, the bytes corresponding to each element to be copied are swapped + * accordingly during the copy operation. *

    - * If the source segment overlaps with the destination segment, then the copying is performed as if the bytes at - * offset {@code srcOffset} through {@code srcOffset + (elementCount * S) - 1} in the source segment were first copied into a - * temporary segment with size {@code bytes}, and then the contents of the temporary segment were copied into - * the destination segment at offset {@code dstOffset} through {@code dstOffset + (elementCount * S) - 1}. + * If the source segment overlaps with the destination segment, then the copying is + * performed as if the bytes at offset {@code srcOffset} through + * {@code srcOffset + (elementCount * S) - 1} in the source segment were first copied + * into a temporary segment with size {@code bytes}, and then the contents of the + * temporary segment were copied into the destination segment at offset + * {@code dstOffset} through {@code dstOffset + (elementCount * S) - 1}. *

    - * The result of a bulk copy is unspecified if, in the uncommon case, the source segment and the destination segment - * do not overlap, but refer to overlapping regions of the same backing storage using different addresses. - * For example, this may occur if the same file is {@linkplain FileChannel#map mapped} to two segments. - * @param srcSegment the source segment. - * @param srcElementLayout the element layout associated with the source segment. - * @param srcOffset the starting offset, in bytes, of the source segment. - * @param dstSegment the destination segment. - * @param dstElementLayout the element layout associated with the destination segment. - * @param dstOffset the starting offset, in bytes, of the destination segment. - * @param elementCount the number of elements to be copied. - * @throws IllegalArgumentException if the element layouts have different sizes, if the source (resp. destination) - * segment/offset are incompatible with the + * The result of a bulk copy is unspecified if, in the uncommon case, the source + * segment and the destination segment do not overlap, but refer to overlapping + * regions of the same backing storage using different addresses. For example, + * this may occur if the same file is {@linkplain FileChannel#map mapped} to two + * segments. + * @param srcSegment the source segment + * @param srcElementLayout the element layout associated with the source segment + * @param srcOffset the starting offset, in bytes, of the source segment + * @param dstSegment the destination segment + * @param dstElementLayout the element layout associated with the destination segment + * @param dstOffset the starting offset, in bytes, of the destination segment + * @param elementCount the number of elements to be copied + * @throws IllegalArgumentException if the element layouts have different sizes, if + * the source (resp. destination) segment/offset are + * incompatible with the * alignment constraint in the source (resp. destination) element layout * @throws IllegalArgumentException if {@code srcElementLayout.byteAlignment() > srcElementLayout.byteSize()} * @throws IllegalArgumentException if {@code dstElementLayout.byteAlignment() > dstElementLayout.byteSize()} - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with {@code srcSegment} is not - * {@linkplain Scope#isAlive() alive}. + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * {@code srcSegment} is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code srcSegment.isAccessibleBy(T) == false} - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with {@code dstSegment} is not - * {@linkplain Scope#isAlive() alive} + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * {@code dstSegment} is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code dstSegment.isAccessibleBy(T) == false} * @throws UnsupportedOperationException if {@code dstSegment} is {@linkplain #isReadOnly() read-only} @@ -1366,15 +1575,17 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr /** * Reads a byte from this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be read. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * @return a byte value read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive}. + * @param layout the layout of the region of memory to be read + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur. + * @return a byte value read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, - * such that {@code isAccessibleBy(T) == false}. + * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} */ byte get(ValueLayout.OfByte layout, long offset); @@ -1382,32 +1593,37 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr /** * Writes a byte into this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be written. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. + * @param layout the layout of the region of memory to be written + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur. * @param value the byte value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} + * @throws UnsupportedOperationException if this segment is + * {@linkplain #isReadOnly() read-only} */ void set(ValueLayout.OfByte layout, long offset, byte value); /** * Reads a boolean from this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be read. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * @return a boolean value read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be read + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur + * @return a boolean value read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} */ boolean get(ValueLayout.OfBoolean layout, long offset); @@ -1415,32 +1631,37 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr /** * Writes a boolean into this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be written. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * @param value the boolean value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive}. + * @param layout the layout of the region of memory to be written + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur + * @param value the boolean value to be written + * @throws IllegalStateException if the {@linkplain #scope() scope} associated + * with this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, - * such that {@code isAccessibleBy(T) == false}. + * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} + * @throws UnsupportedOperationException if this segment is + * {@linkplain #isReadOnly() read-only} */ void set(ValueLayout.OfBoolean layout, long offset, boolean value); /** * Reads a char from this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be read. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * @return a char value read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be read + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur + * @return a char value read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} */ char get(ValueLayout.OfChar layout, long offset); @@ -1448,32 +1669,37 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr /** * Writes a char into this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be written. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * @param value the char value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be written + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur. + * @param value the char value to be written + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} + * @throws UnsupportedOperationException if this segment is + * {@linkplain #isReadOnly() read-only} */ void set(ValueLayout.OfChar layout, long offset, char value); /** * Reads a short from this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be read. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * @return a short value read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be read + * @param offset the offset in bytes (relative to this segment address) at which this + * access operation will occur + * @return a short value read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} */ short get(ValueLayout.OfShort layout, long offset); @@ -1481,32 +1707,37 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr /** * Writes a short into this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be written. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * @param value the short value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be written + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur. + * @param value the short value to be written + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} + * @throws UnsupportedOperationException if this segment is + * {@linkplain #isReadOnly() read-only} */ void set(ValueLayout.OfShort layout, long offset, short value); /** * Reads an int from this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be read. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * @return an int value read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be read + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur. + * @return an int value read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} */ int get(ValueLayout.OfInt layout, long offset); @@ -1514,32 +1745,37 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr /** * Writes an int into this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be written. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * @param value the int value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be written + * @param offset the offset in bytes (relative to this segment address) at which this + * access operation will occur + * @param value the int value to be written + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} + * @throws UnsupportedOperationException if this segment is + * {@linkplain #isReadOnly() read-only} */ void set(ValueLayout.OfInt layout, long offset, int value); /** * Reads a float from this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be read. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * @return a float value read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be read + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur + * @return a float value read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} */ float get(ValueLayout.OfFloat layout, long offset); @@ -1547,32 +1783,37 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr /** * Writes a float into this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be written. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * @param value the float value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be written + * @param offset the offset in bytes (relative to this segment address) at which this + * access operation will occur + * @param value the float value to be written + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} + * @throws UnsupportedOperationException if this segment is + * {@linkplain #isReadOnly() read-only} */ void set(ValueLayout.OfFloat layout, long offset, float value); /** * Reads a long from this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be read. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * @return a long value read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be read + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur. + * @return a long value read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated + * with this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} */ long get(ValueLayout.OfLong layout, long offset); @@ -1580,32 +1821,37 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr /** * Writes a long into this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be written. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. + * @param layout the layout of the region of memory to be written + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur. * @param value the long value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} + * @throws UnsupportedOperationException if this segment is + * {@linkplain #isReadOnly() read-only} */ void set(ValueLayout.OfLong layout, long offset, long value); /** * Reads a double from this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be read. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * @return a double value read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be read + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur + * @return a double value read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} */ double get(ValueLayout.OfDouble layout, long offset); @@ -1613,38 +1859,47 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr /** * Writes a double into this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be written. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * @param value the double value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be written + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur + * @param value the double value to be written + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} + * @throws UnsupportedOperationException if this segment is + * {@linkplain #isReadOnly() read-only} */ void set(ValueLayout.OfDouble layout, long offset, double value); /** - * Reads an address from this segment at the given offset, with the given layout. The read address is wrapped in - * a native segment, associated with the global scope. Under normal conditions, - * the size of the returned segment is {@code 0}. However, if the provided address layout has a - * {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size of the returned segment - * is set to {@code T.byteSize()}. - * @param layout the layout of the region of memory to be read. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. - * @return a native segment wrapping an address read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * Reads an address from this segment at the given offset, with the given layout. + * The read address is wrapped in a native segment, associated with the global scope. + * Under normal conditions, the size of the returned segment is {@code 0}. However, + * if the provided address layout has a + * {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size + * of the returned segment is set to {@code T.byteSize()}. + * + * @param layout the layout of the region of memory to be read + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur + * @return a native segment wrapping an address read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout - * @throws IllegalArgumentException if provided address layout has a {@linkplain AddressLayout#targetLayout() target layout} + * incompatible with the alignment constraint + * in the provided layout + * @throws IllegalArgumentException if provided address layout has a + * {@linkplain AddressLayout#targetLayout() target layout} * {@code T}, and the address of the returned segment - * incompatible with the alignment constraint in {@code T} + * incompatible with the alignment constraint + * in {@code T} * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} */ MemorySegment get(AddressLayout layout, long offset); @@ -1652,34 +1907,41 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr /** * Writes an address into this segment at the given offset, with the given layout. * - * @param layout the layout of the region of memory to be written. - * @param offset the offset in bytes (relative to this segment address) at which this access operation will occur. + * @param layout the layout of the region of memory to be written + * @param offset the offset in bytes (relative to this segment address) at which + * this access operation will occur. * @param value the address value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout. + * incompatible with the alignment constraint + * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} - * @throws UnsupportedOperationException if {@code value} is not a {@linkplain #isNative() native} segment + * @throws UnsupportedOperationException if this segment is + * {@linkplain #isReadOnly() read-only} + * @throws UnsupportedOperationException if {@code value} is not a + * {@linkplain #isNative() native} segment */ void set(AddressLayout layout, long offset, MemorySegment value); /** - * Reads a byte from this segment at the given index, scaled by the given layout size. + * Reads a byte from this segment at the given index, scaled by the given + * layout size. * - * @param layout the layout of the region of memory to be read. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @return a byte value read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be read + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @return a byte value read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} @@ -1687,18 +1949,21 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr byte getAtIndex(ValueLayout.OfByte layout, long index); /** - * Reads a boolean from this segment at the given index, scaled by the given layout size. + * Reads a boolean from this segment at the given index, scaled by the given + * layout size. * - * @param layout the layout of the region of memory to be read. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @return a boolean value read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be read + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @return a boolean value read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} @@ -1706,18 +1971,21 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr boolean getAtIndex(ValueLayout.OfBoolean layout, long index); /** - * Reads a char from this segment at the given index, scaled by the given layout size. + * Reads a char from this segment at the given index, scaled by the given + * layout size. * - * @param layout the layout of the region of memory to be read. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @return a char value read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be read + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @return a char value read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} @@ -1725,18 +1993,21 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr char getAtIndex(ValueLayout.OfChar layout, long index); /** - * Writes a char into this segment at the given index, scaled by the given layout size. + * Writes a char into this segment at the given index, scaled by the given + * layout size. * - * @param layout the layout of the region of memory to be written. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @param value the char value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be written + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @param value the char value to be written + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} @@ -1745,18 +2016,21 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr void setAtIndex(ValueLayout.OfChar layout, long index, char value); /** - * Reads a short from this segment at the given index, scaled by the given layout size. + * Reads a short from this segment at the given index, scaled by the given + * layout size. * - * @param layout the layout of the region of memory to be read. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @return a short value read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be read + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @return a short value read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} @@ -1766,16 +2040,18 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr /** * Writes a byte into this segment at the given index, scaled by the given layout size. * - * @param layout the layout of the region of memory to be written. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @param value the short value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be written + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @param value the short value to be written + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} @@ -1784,18 +2060,21 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr void setAtIndex(ValueLayout.OfByte layout, long index, byte value); /** - * Writes a boolean into this segment at the given index, scaled by the given layout size. + * Writes a boolean into this segment at the given index, scaled by the given + * layout size. * - * @param layout the layout of the region of memory to be written. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @param value the short value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be written + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @param value the short value to be written + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} @@ -1804,18 +2083,21 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr void setAtIndex(ValueLayout.OfBoolean layout, long index, boolean value); /** - * Writes a short into this segment at the given index, scaled by the given layout size. + * Writes a short into this segment at the given index, scaled by the given + * layout size. * - * @param layout the layout of the region of memory to be written. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @param value the short value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be written + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @param value the short value to be written + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} @@ -1824,18 +2106,21 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr void setAtIndex(ValueLayout.OfShort layout, long index, short value); /** - * Reads an int from this segment at the given index, scaled by the given layout size. + * Reads an int from this segment at the given index, scaled by the given + * layout size. * * @param layout the layout of the region of memory to be read. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @return an int value read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @return an int value read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} @@ -1843,18 +2128,21 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr int getAtIndex(ValueLayout.OfInt layout, long index); /** - * Writes an int into this segment at the given index, scaled by the given layout size. + * Writes an int into this segment at the given index, scaled by the given + * layout size. * - * @param layout the layout of the region of memory to be written. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation + * @param layout the layout of the region of memory to be written + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation * will occur can be expressed as {@code (index * layout.byteSize())}. - * @param value the int value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param value the int value to be written + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} @@ -1863,18 +2151,21 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr void setAtIndex(ValueLayout.OfInt layout, long index, int value); /** - * Reads a float from this segment at the given index, scaled by the given layout size. + * Reads a float from this segment at the given index, scaled by the given + * layout size. * - * @param layout the layout of the region of memory to be read. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @return a float value read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be read + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @return a float value read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} @@ -1882,18 +2173,21 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr float getAtIndex(ValueLayout.OfFloat layout, long index); /** - * Writes a float into this segment at the given index, scaled by the given layout size. + * Writes a float into this segment at the given index, scaled by the given + * layout size. * - * @param layout the layout of the region of memory to be written. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @param value the float value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be written + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @param value the float value to be written + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} @@ -1902,18 +2196,21 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr void setAtIndex(ValueLayout.OfFloat layout, long index, float value); /** - * Reads a long from this segment at the given index, scaled by the given layout size. + * Reads a long from this segment at the given index, scaled by the given + * layout size. * - * @param layout the layout of the region of memory to be read. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @return a long value read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be read + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @return a long value read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} @@ -1921,18 +2218,21 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr long getAtIndex(ValueLayout.OfLong layout, long index); /** - * Writes a long into this segment at the given index, scaled by the given layout size. + * Writes a long into this segment at the given index, scaled by the given + * layout size. * - * @param layout the layout of the region of memory to be written. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @param value the long value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be written + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @param value the long value to be written + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} @@ -1941,18 +2241,21 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr void setAtIndex(ValueLayout.OfLong layout, long index, long value); /** - * Reads a double from this segment at the given index, scaled by the given layout size. + * Reads a double from this segment at the given index, scaled by the given + * layout size. * - * @param layout the layout of the region of memory to be read. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @return a double value read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be read + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @return a double value read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} @@ -1960,18 +2263,21 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr double getAtIndex(ValueLayout.OfDouble layout, long index); /** - * Writes a double into this segment at the given index, scaled by the given layout size. + * Writes a double into this segment at the given index, scaled by the given + * layout size. * - * @param layout the layout of the region of memory to be written. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @param value the double value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * @param layout the layout of the region of memory to be written + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @param value the double value to be written + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout + * incompatible with the alignment constraint + * in the provided layout * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} @@ -1980,70 +2286,86 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr void setAtIndex(ValueLayout.OfDouble layout, long index, double value); /** - * Reads an address from this segment at the given at the given index, scaled by the given layout size. The read address is wrapped in - * a native segment, associated with the global scope. Under normal conditions, - * the size of the returned segment is {@code 0}. However, if the provided address layout has a - * {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size of the returned segment - * is set to {@code T.byteSize()}. - * @param layout the layout of the region of memory to be read. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @return a native segment wrapping an address read from this segment. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive} + * Reads an address from this segment at the given at the given index, scaled by the + * given layout size. The read address is wrapped in a native segment, associated + * with the global scope. Under normal conditions, the size of the returned segment + * is {@code 0}. However, if the provided address layout has a + * {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size + * of the returned segment is set to {@code T.byteSize()}. + * + * @param layout the layout of the region of memory to be read + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @return a native segment wrapping an address read from this segment + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout. + * incompatible with the alignment constraint + * in the provided layout. * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} - * @throws IllegalArgumentException if provided address layout has a {@linkplain AddressLayout#targetLayout() target layout} - * {@code T}, and the address of the returned segment - * incompatible with the alignment constraint in {@code T} + * @throws IllegalArgumentException if provided address layout has a + * {@linkplain AddressLayout#targetLayout() target layout} {@code T}, and the + * address of the returned segment is + * incompatible with the alignment constraint + * in {@code T} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} */ MemorySegment getAtIndex(AddressLayout layout, long index); /** - * Writes an address into this segment at the given index, scaled by the given layout size. + * Writes an address into this segment at the given index, scaled by the given + * layout size. * - * @param layout the layout of the region of memory to be written. - * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation - * will occur can be expressed as {@code (index * layout.byteSize())}. - * @param value the address value to be written. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with this segment is not - * {@linkplain Scope#isAlive() alive}. + * @param layout the layout of the region of memory to be written + * @param index a logical index. The offset in bytes (relative to this + * segment address) at which the access operation will occur can be + * expressed as {@code (index * layout.byteSize())}. + * @param value the address value to be written + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * this segment is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, - * such that {@code isAccessibleBy(T) == false}. + * such that {@code isAccessibleBy(T) == false} * @throws IllegalArgumentException if the access operation is - * incompatible with the alignment constraint in the provided layout. - * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()}. - * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows. - * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}. - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. - * @throws UnsupportedOperationException if {@code value} is not a {@linkplain #isNative() native} segment. + * incompatible with the alignment constraint + * in the provided layout. + * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} + * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows + * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} + * @throws UnsupportedOperationException if {@code value} is not a {@linkplain #isNative() native} segment */ void setAtIndex(AddressLayout layout, long index, MemorySegment value); /** - * Compares the specified object with this memory segment for equality. Returns {@code true} if and only if the specified - * object is also a memory segment, and if the two segments refer to the same location, in some region of memory. - * More specifically, for two segments {@code s1} and {@code s2} to be considered equals, all the following must be true: + * Compares the specified object with this memory segment for equality. Returns + * {@code true} if and only if the specified object is also a memory segment, and if + * the two segments refer to the same location, in some region of memory. + *

    + * More specifically, for two segments {@code s1} and {@code s2} to be considered + * equal, all the following must be true: *

      - *
    • {@code s1.heapBase().equals(s2.heapBase())}, that is, the two segments must be of the same kind; - * either both are {@linkplain #isNative() native segments}, backed by off-heap memory, or both are backed by - * the same on-heap {@linkplain #heapBase() Java object}; - *
    • {@code s1.address() == s2.address()}, that is, the address of the two segments should be the same. - * This means that the two segments either refer to the same location in some off-heap region, or they refer - * to the same offset inside their associated {@linkplain #heapBase() Java object}.
    • + *
    • {@code s1.heapBase().equals(s2.heapBase())}, that is, the two segments + * must be of the same kind; either both are {@linkplain #isNative() native segments}, + * backed by off-heap memory, or both are backed by the same on-heap + * {@linkplain #heapBase() Java object}; + *
    • {@code s1.address() == s2.address()}, that is, the address of the two + * segments should be the same. This means that the two segments either refer to + * the same location in some off-heap region, or they refer to the same offset + * inside their associated {@linkplain #heapBase() Java object}.
    • *
    - * @apiNote This method does not perform a structural comparison of the contents of the two memory segments. Clients can - * compare memory segments structurally by using the {@link #mismatch(MemorySegment)} method instead. Note that this - * method does not compare the temporal and spatial bounds of two segments. As such it is suitable - * to check whether two segments have the same address. - * - * @param that the object to be compared for equality with this memory segment. - * @return {@code true} if the specified object is equal to this memory segment. + * @apiNote This method does not perform a structural comparison of the contents of + * the two memory segments. Clients can compare memory segments structurally + * by using the {@link #mismatch(MemorySegment)} method instead. Note that + * this method does not compare the temporal and spatial bounds of + * two segments. As such, it is suitable to check whether two segments have + * the same address. + * + * @param that the object to be compared for equality with this memory segment + * @return {@code true} if the specified object is equal to this memory segment * @see #mismatch(MemorySegment) */ @Override @@ -2057,25 +2379,36 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr /** - * Copies a number of elements from a source memory segment to a destination array. The elements, whose size and alignment - * constraints are specified by the given layout, are read from the source segment, starting at the given offset - * (expressed in bytes), and are copied into the destination array, at the given index. - * Supported array types are {@code byte[]}, {@code char[]}, {@code short[]}, {@code int[]}, {@code float[]}, {@code long[]} and {@code double[]}. - * @param srcSegment the source segment. - * @param srcLayout the source element layout. If the byte order associated with the layout is - * different from the {@linkplain ByteOrder#nativeOrder native order}, a byte swap operation will be performed on each array element. - * @param srcOffset the starting offset, in bytes, of the source segment. - * @param dstArray the destination array. - * @param dstIndex the starting index of the destination array. - * @param elementCount the number of array elements to be copied. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with {@code srcSegment} is not - * {@linkplain Scope#isAlive() alive} + * Copies a number of elements from a source memory segment to a destination array. + * The elements, whose size and alignment constraints are specified by the given + * layout, are read from the source segment, starting at the given offset + * (expressed in bytes), and are copied into the destination array, at the + * given index. + *

    + * Supported array types are : + * {@code byte[]}, {@code char[]}, {@code short[]}, + * {@code int[]}, {@code float[]}, {@code long[]} and {@code double[]}. + * + * @param srcSegment the source segment + * @param srcLayout the source element layout. If the byte order associated with the + * layout is different from the + * {@linkplain ByteOrder#nativeOrder native order}, a byte swap + * operation will be performed on each array element + * @param srcOffset the starting offset, in bytes, of the source segment + * @param dstArray the destination array + * @param dstIndex the starting index of the destination array + * @param elementCount the number of array elements to be copied + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * {@code srcSegment} is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code srcSegment.isAccessibleBy(T) == false} - * @throws IllegalArgumentException if {@code dstArray} is not an array, or if it is an array but whose type is not supported - * @throws IllegalArgumentException if the destination array component type does not match {@code srcLayout.carrier()} - * @throws IllegalArgumentException if {@code offset} is incompatible - * with the alignment constraint in the source element layout + * @throws IllegalArgumentException if {@code dstArray} is not an array, or if it is + * an array but whose type is not supported + * @throws IllegalArgumentException if the destination array component type does not + * match {@code srcLayout.carrier()} + * @throws IllegalArgumentException if {@code offset} is + * incompatible with the alignment constraint + * in the source element layout * @throws IllegalArgumentException if {@code srcLayout.byteAlignment() > srcLayout.byteSize()} * @throws IndexOutOfBoundsException if {@code elementCount * srcLayout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code srcOffset > srcSegment.byteSize() - (elementCount * srcLayout.byteSize())} @@ -2096,25 +2429,36 @@ static void copy(MemorySegment srcSegment, ValueLayout srcLayout, long srcOffset } /** - * Copies a number of elements from a source array to a destination memory segment. The elements, whose size and alignment - * constraints are specified by the given layout, are read from the source array, starting at the given index, - * and are copied into the destination segment, at the given offset (expressed in bytes). - * Supported array types are {@code byte[]}, {@code char[]}, {@code short[]}, {@code int[]}, {@code float[]}, {@code long[]} and {@code double[]}. - * @param srcArray the source array. - * @param srcIndex the starting index of the source array. - * @param dstSegment the destination segment. - * @param dstLayout the destination element layout. If the byte order associated with the layout is - * different from the {@linkplain ByteOrder#nativeOrder native order}, a byte swap operation will be performed on each array element. - * @param dstOffset the starting offset, in bytes, of the destination segment. - * @param elementCount the number of array elements to be copied. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with {@code dstSegment} is not - * {@linkplain Scope#isAlive() alive} + * Copies a number of elements from a source array to a destination memory segment. + *

    + * The elements, whose size and alignment constraints are specified by the given + * layout, are read from the source array, starting at the given index, and are + * copied into the destination segment, at the given offset (expressed in bytes). + *

    + * Supported array types are + * {@code byte[]}, {@code char[]}, {@code short[]}, + * {@code int[]}, {@code float[]}, {@code long[]} and {@code double[]}. + * + * @param srcArray the source array + * @param srcIndex the starting index of the source array + * @param dstSegment the destination segment + * @param dstLayout the destination element layout. If the byte order associated + * with the layout is different from the + * {@linkplain ByteOrder#nativeOrder native order}, a byte swap + * operation will be performed on each array element. + * @param dstOffset the starting offset, in bytes, of the destination segment + * @param elementCount the number of array elements to be copied + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * {@code dstSegment} is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code dstSegment.isAccessibleBy(T) == false} - * @throws IllegalArgumentException if {@code srcArray} is not an array, or if it is an array but whose type is not supported - * @throws IllegalArgumentException if the source array component type does not match {@code srcLayout.carrier()} - * @throws IllegalArgumentException if {@code offset} is incompatible - * with the alignment constraint in the source element layout + * @throws IllegalArgumentException if {@code srcArray} is not an array, or if it is + * an array but whose type is not supported + * @throws IllegalArgumentException if the source array component type does not + * match {@code srcLayout.carrier()} + * @throws IllegalArgumentException if {@code offset} is + * incompatible with the alignment constraint + * in the source element layout * @throws IllegalArgumentException if {@code dstLayout.byteAlignment() > dstLayout.byteSize()} * @throws UnsupportedOperationException if {@code dstSegment} is {@linkplain #isReadOnly() read-only} * @throws IndexOutOfBoundsException if {@code elementCount * dstLayout.byteSize()} overflows @@ -2136,36 +2480,45 @@ static void copy(Object srcArray, int srcIndex, } /** - * Finds and returns the relative offset, in bytes, of the first mismatch between the source and the destination - * segments. More specifically, the bytes at offset {@code srcFromOffset} through {@code srcToOffset - 1} in the - * source segment are compared against the bytes at offset {@code dstFromOffset} through {@code dstToOffset - 1} + * Finds and returns the relative offset, in bytes, of the first mismatch between the + * source and the destination segments. More specifically, the bytes at offset + * {@code srcFromOffset} through {@code srcToOffset - 1} in the source segment are + * compared against the bytes at offset {@code dstFromOffset} through {@code dstToOffset - 1} * in the destination segment. *

    - * If the two segments, over the specified ranges, share a common prefix then the returned offset is the length - * of the common prefix, and it follows that there is a mismatch between the two segments at that relative offset - * within the respective segments. If one segment is a proper prefix of the other, over the specified ranges, - * then the returned offset is the smallest range, and it follows that the relative offset is only - * valid for the segment with the larger range. Otherwise, there is no mismatch and {@code -1} is returned. + * If the two segments, over the specified ranges, share a common prefix then the + * returned offset is the length of the common prefix, and it follows that there is a + * mismatch between the two segments at that relative offset within the respective + * segments. If one segment is a proper prefix of the other, over the specified + * ranges, then the returned offset is the smallest range, and it follows that the + * relative offset is only valid for the segment with the larger range. Otherwise, + * there is no mismatch and {@code -1} is returned. * * @param srcSegment the source segment. - * @param srcFromOffset the offset (inclusive) of the first byte in the source segment to be tested. - * @param srcToOffset the offset (exclusive) of the last byte in the source segment to be tested. - * @param dstSegment the destination segment. - * @param dstFromOffset the offset (inclusive) of the first byte in the destination segment to be tested. - * @param dstToOffset the offset (exclusive) of the last byte in the destination segment to be tested. - * @return the relative offset, in bytes, of the first mismatch between the source and destination segments, - * otherwise -1 if no mismatch. - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with {@code srcSegment} is not - * {@linkplain Scope#isAlive() alive} + * @param srcFromOffset the offset (inclusive) of the first byte in the + * source segment to be tested + * @param srcToOffset the offset (exclusive) of the last byte in the + * source segment to be tested + * @param dstSegment the destination segment + * @param dstFromOffset the offset (inclusive) of the first byte in the + * destination segment to be tested + * @param dstToOffset the offset (exclusive) of the last byte in the + * destination segment to be tested + * @return the relative offset, in bytes, of the first mismatch between the + * source and destination segments, otherwise -1 if no mismatch + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * {@code srcSegment} is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code srcSegment.isAccessibleBy(T) == false} - * @throws IllegalStateException if the {@linkplain #scope() scope} associated with {@code dstSegment} is not - * {@linkplain Scope#isAlive() alive} + * @throws IllegalStateException if the {@linkplain #scope() scope} associated with + * {@code dstSegment} is not {@linkplain Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code dstSegment.isAccessibleBy(T) == false} - * @throws IndexOutOfBoundsException if {@code srcFromOffset < 0}, {@code srcToOffset < srcFromOffset} or + * @throws IndexOutOfBoundsException if {@code srcFromOffset < 0}, + * {@code srcToOffset < srcFromOffset} or * {@code srcToOffset > srcSegment.byteSize()} - * @throws IndexOutOfBoundsException if {@code dstFromOffset < 0}, {@code dstToOffset < dstFromOffset} or + * @throws IndexOutOfBoundsException if {@code dstFromOffset < 0}, + * {@code dstToOffset < dstFromOffset} or * {@code dstToOffset > dstSegment.byteSize()} * * @see MemorySegment#mismatch(MemorySegment) @@ -2178,32 +2531,42 @@ static long mismatch(MemorySegment srcSegment, long srcFromOffset, long srcToOff } /** - * A scope models the lifetime of all the memory segments associated with it. That is, a memory segment - * cannot be accessed if its associated scope is not {@linkplain #isAlive() alive}. Scope instances can be compared - * for equality. That is, two scopes are considered {@linkplain #equals(Object) equal} if they denote the same lifetime. + * A scope models the lifetime of all the memory segments associated with it. + *

    + * That is, a memory segment cannot be accessed if its associated scope is not + * {@linkplain #isAlive() alive}. Scope instances can be compared for equality. + * That is, two scopes are considered {@linkplain #equals(Object) equal} if they + * denote the same lifetime. *

    - * The lifetime of a memory segment can be either unbounded or bounded. An unbounded lifetime - * is modeled with the global scope. The global scope is always {@link #isAlive() alive}. As such, a segment - * associated with the global scope features trivial temporal bounds and is always accessible. + * The lifetime of a memory segment can be either unbounded or + * bounded. An unbounded lifetime is modeled with the global scope. + * The global scope is always {@link #isAlive() alive}. As such, a segment associated + * with the global scope features trivial temporal bounds and is always accessible. * Segments associated with the global scope are: *

      *
    • Segments obtained from the {@linkplain Arena#global() global arena};
    • - *
    • Segments obtained from a raw address, using the {@link MemorySegment#ofAddress(long)} factory; and
    • + *
    • Segments obtained from a raw address, using the + * {@link MemorySegment#ofAddress(long)} factory; and
    • *
    • Zero-length memory segments.
    • *
    *

    - * Conversely, a bounded lifetime is modeled with a segment scope that can be invalidated, either {@link Arena#close() explicitly}, - * or automatically, by the garbage collector. A segment scope that is invalidated automatically is an automatic scope. - * An automatic scope is always {@link #isAlive() alive} as long as it is reachable. + * Conversely, a bounded lifetime is modeled with a segment scope that can be + * invalidated, either {@link Arena#close() explicitly}, or automatically, by the + * garbage collector. A segment scope that is invalidated automatically is an + * automatic scope. An automatic scope is always {@link #isAlive() alive} + * as long as it is reachable. * Segments associated with an automatic scope are: *

      *
    • Segments obtained from an {@linkplain Arena#ofAuto() automatic arena};
    • - *
    • Segments obtained from a Java array, e.g. using the {@link MemorySegment#ofArray(int[])} factory;
    • - *
    • Segments obtained from a buffer, using the {@link MemorySegment#ofBuffer(Buffer)} factory; and
    • + *
    • Segments obtained from a Java array, e.g. using the + * {@link MemorySegment#ofArray(int[])} factory;
    • + *
    • Segments obtained from a buffer, using the + * {@link MemorySegment#ofBuffer(Buffer)} factory; and
    • *
    • Segments obtained from {@linkplain SymbolLookup#loaderLookup() loader lookup}.
    • *
    - * If two memory segments are obtained from the same {@linkplain #ofBuffer(Buffer) buffer} - * or {@linkplain #ofArray(int[]) array}, the automatic scopes associated with said segments are considered + * If two memory segments are obtained from the same + * {@linkplain #ofBuffer(Buffer) buffer} or {@linkplain #ofArray(int[]) array}, the + * automatic scopes associated with said segments are considered * {@linkplain #equals(Object) equal}, as the two segments have the same lifetime: * {@snippet lang=java : * byte[] arr = new byte[10]; @@ -2214,24 +2577,27 @@ static long mismatch(MemorySegment srcSegment, long srcFromOffset, long srcToOff */ sealed interface Scope permits MemorySessionImpl { /** - * {@return {@code true}, if the regions of memory backing the memory segments associated with this scope are - * still valid} + * {@return {@code true}, if the regions of memory backing the memory segments + * associated with this scope are still valid} */ boolean isAlive(); /** - * {@return {@code true}, if the provided object is also a scope, which models the same lifetime as that - * modeled by this scope}. In that case, it is always the case that - * {@code this.isAlive() == ((Scope)that).isAlive()}. - * @param that the object to be tested. + * {@return {@code true}, if the provided object is also a scope, which models + * the same lifetime as that modeled by this scope}. In that case, it is always + * the case that {@code this.isAlive() == ((Scope)that).isAlive()}. + * + * @param that the object to be tested */ @Override boolean equals(Object that); /** - * Returns the hash code of this scope object. - * @implSpec Implementations of this method obey the general contract of {@link Object#hashCode}. - * @return the hash code of this scope object. + * {@return the hash code of this scope object} + * + * @implSpec Implementations of this method obey the general contract of + * {@link Object#hashCode}. + * * @see #equals(Object) */ @Override diff --git a/src/java.base/share/classes/java/lang/foreign/PaddingLayout.java b/src/java.base/share/classes/java/lang/foreign/PaddingLayout.java index 921ef9c8479..8441b703f6f 100644 --- a/src/java.base/share/classes/java/lang/foreign/PaddingLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/PaddingLayout.java @@ -28,11 +28,13 @@ import jdk.internal.foreign.layout.PaddingLayoutImpl; /** - * 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. + * A padding layout. A padding layout specifies the size of extra space which is + * typically not accessed by applications, and is typically used for aligning member + * layouts around word boundaries. * * @implSpec - * Implementing classes are immutable, thread-safe and value-based. + * Implementing classes are immutable, thread-safe and + * value-based. * * @since 22 */ diff --git a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java index 318f44eb822..a4977d62d00 100644 --- a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java +++ b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java @@ -36,12 +36,14 @@ import jdk.internal.vm.annotation.ForceInline; /** - * An object that may be used to allocate {@linkplain MemorySegment memory segments}. Clients implementing this interface - * must implement the {@link #allocate(long, long)} method. A segment allocator defines several methods - * which can be useful to create segments from several kinds of Java values such as primitives and arrays. + * An object that may be used to allocate {@linkplain MemorySegment memory segments}. + * Clients implementing this interface must implement the {@link #allocate(long, long)} + * method. A segment allocator defines several methods which can be useful to create + * segments from several kinds of Java values such as primitives and arrays. *

    - * {@code SegmentAllocator} is a {@linkplain FunctionalInterface functional interface}. Clients can easily obtain a new - * segment allocator by using either a lambda expression or a method reference: + * {@code SegmentAllocator} is a {@linkplain FunctionalInterface functional interface}. + * Clients can easily obtain a new segment allocator by using either a lambda expression + * or a method reference: * * {@snippet lang=java : * SegmentAllocator autoAllocator = (byteSize, byteAlignment) -> Arena.ofAuto().allocate(byteSize, byteAlignment); @@ -49,25 +51,29 @@ *

    * This interface defines factories for commonly used allocators: *

      - *
    • {@link #slicingAllocator(MemorySegment)} obtains an efficient slicing allocator, where memory - * is allocated by repeatedly slicing the provided memory segment;
    • - *
    • {@link #prefixAllocator(MemorySegment)} obtains an allocator which wraps a segment - * and recycles its content upon each new allocation request.
    • + *
    • {@link #slicingAllocator(MemorySegment)} obtains an efficient slicing + * allocator, where memory is allocated by repeatedly slicing the provided + * memory segment;
    • + *
    • {@link #prefixAllocator(MemorySegment)} obtains an allocator which wraps a + * segment and recycles its content upon each new allocation request.
    • *
    *

    - * Passing a segment allocator to an API can be especially useful in circumstances where a client wants to communicate where - * the results of a certain operation (performed by the API) should be stored, as a memory segment. For instance, - * {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handles} can accept an additional - * {@link SegmentAllocator} parameter if the underlying foreign function is known to return a struct by-value. Effectively, - * the allocator parameter tells the linker where to store the return value of the foreign function. + * Passing a segment allocator to an API can be especially useful in circumstances where + * a client wants to communicate where the results of a certain operation + * (performed by the API) should be stored, as a memory segment. For instance, + * {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handles} + * can accept an additional {@link SegmentAllocator} parameter if the underlying + * foreign function is known to return a struct by-value. Effectively, the allocator + * parameter tells the linker where to store the return value of the foreign function. * - * @apiNote Unless otherwise specified, the {@link #allocate(long, long)} method is not thread-safe. - * Furthermore, memory segments allocated by a segment allocator can be associated with different - * lifetimes, and can even be backed by overlapping regions of memory. For these reasons, clients should generally - * only interact with a segment allocator they own. + * @apiNote Unless otherwise specified, the {@link #allocate(long, long)} method is + * not thread-safe. Furthermore, memory segments allocated by a segment + * allocator can be associated with different lifetimes, and can even be backed + * by overlapping regions of memory. For these reasons, clients should + * generally only interact with a segment allocator they own. *

    - * Clients should consider using an {@linkplain Arena arena} instead, which, provides strong thread-safety, - * lifetime and non-overlapping guarantees. + * Clients should consider using an {@linkplain Arena arena} instead, which, provides + * strong thread-safety, lifetime and non-overlapping guarantees. * * @since 22 */ @@ -75,16 +81,17 @@ public interface SegmentAllocator { /** - * Converts a Java string into a null-terminated C string using the {@linkplain StandardCharsets#UTF_8 UTF-8} charset, - * storing the result into a memory segment. + * Converts a Java string into a null-terminated C string using the + * {@linkplain StandardCharsets#UTF_8 UTF-8} charset, storing the result into a + * memory segment. *

    * Calling this method is equivalent to the following code: * {@snippet lang = java: * allocateFrom(str, StandardCharsets.UTF_8); *} * - * @param str the Java string to be converted into a C string. - * @return a new native segment containing the converted C string. + * @param str the Java string to be converted into a C string + * @return a new native segment containing the converted C string */ @ForceInline default MemorySegment allocateFrom(String str) { @@ -97,7 +104,7 @@ default MemorySegment allocateFrom(String str) { * and storing the result into a memory segment. *

    * This method always replaces malformed-input and unmappable-character - * sequences with this charset's default replacement byte array. The + * sequences with this charset's default replacement byte array. The * {@link java.nio.charset.CharsetEncoder} class should be used when more * control over the encoding process is required. *

    @@ -106,17 +113,21 @@ default MemorySegment allocateFrom(String str) { * the string, such as {@link MemorySegment#getString(long)}, the string * will appear truncated when read again. * - * @param str the Java string to be converted into a C string. - * @param charset the charset used to {@linkplain Charset#newEncoder() encode} the string bytes. - * @return a new native segment containing the converted C string. - * @throws IllegalArgumentException if {@code charset} is not a {@linkplain StandardCharsets standard charset} - * @implSpec The default implementation for this method copies the contents of the provided Java string - * into a new memory segment obtained by calling {@code this.allocate(B + N)}, where: + * @param str the Java string to be converted into a C string + * @param charset the charset used to {@linkplain Charset#newEncoder() encode} the + * string bytes + * @return a new native segment containing the converted C string + * @throws IllegalArgumentException if {@code charset} is not a + * {@linkplain StandardCharsets standard charset} + * @implSpec The default implementation for this method copies the contents of the + * provided Java string into a new memory segment obtained by calling + * {@code this.allocate(B + N)}, where: *

      - *
    • {@code B} is the size, in bytes, of the string encoded using the provided charset - * (e.g. {@code str.getBytes(charset).length});
    • - *
    • {@code N} is the size (in bytes) of the terminator char according to the provided charset. For instance, - * this is 1 for {@link StandardCharsets#US_ASCII} and 2 for {@link StandardCharsets#UTF_16}.
    • + *
    • {@code B} is the size, in bytes, of the string encoded using the + * provided charset (e.g. {@code str.getBytes(charset).length});
    • + *
    • {@code N} is the size (in bytes) of the terminator char according to the + * provided charset. For instance, this is 1 for {@link StandardCharsets#US_ASCII} + * and 2 for {@link StandardCharsets#UTF_16}.
    • *
    */ @ForceInline @@ -143,11 +154,12 @@ default MemorySegment allocateFrom(String str, Charset charset) { } /** - * {@return a new memory segment initialized with the provided byte value.} + * {@return a new memory segment initialized with the provided byte value} *

    - * The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout. - * The given value is written into the segment according to the byte order and alignment constraint of the - * given layout. + * The size of the allocated memory segment is the + * {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is + * written into the segment according to the byte order and alignment constraint of + * the given layout. * * @implSpec The default implementation is equivalent to: * {@snippet lang=java : @@ -156,8 +168,8 @@ default MemorySegment allocateFrom(String str, Charset charset) { * return seg; * } * - * @param layout the layout of the block of memory to be allocated. - * @param value the value to be set in the newly allocated memory segment. + * @param layout the layout of the block of memory to be allocated + * @param value the value to be set in the newly allocated memory segment */ default MemorySegment allocateFrom(ValueLayout.OfByte layout, byte value) { Objects.requireNonNull(layout); @@ -167,11 +179,12 @@ default MemorySegment allocateFrom(ValueLayout.OfByte layout, byte value) { } /** - * {@return a new memory segment initialized with the provided char value.} + * {@return a new memory segment initialized with the provided char value} *

    - * The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout. - * The given value is written into the segment according to the byte order and alignment constraint of the - * given layout. + * The size of the allocated memory segment is the + * {@linkplain MemoryLayout#byteSize() size} of the given layout. + * The given value is written into the segment according to the byte order and + * alignment constraint of the given layout. * * @implSpec The default implementation is equivalent to: * {@snippet lang=java : @@ -180,8 +193,8 @@ default MemorySegment allocateFrom(ValueLayout.OfByte layout, byte value) { * return seg; * } * - * @param layout the layout of the block of memory to be allocated. - * @param value the value to be set in the newly allocated memory segment. + * @param layout the layout of the block of memory to be allocated + * @param value the value to be set in the newly allocated memory segment */ default MemorySegment allocateFrom(ValueLayout.OfChar layout, char value) { Objects.requireNonNull(layout); @@ -191,11 +204,12 @@ default MemorySegment allocateFrom(ValueLayout.OfChar layout, char value) { } /** - * {@return a new memory segment initialized with the provided short value.} + * {@return a new memory segment initialized with the provided short value} *

    - * The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout. - * The given value is written into the segment according to the byte order and alignment constraint of the - * given layout. + * The size of the allocated memory segment is the + * {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is + * written into the segment according to the byte order and alignment constraint of + * the given layout. * * @implSpec The default implementation is equivalent to: * {@snippet lang=java : @@ -204,8 +218,8 @@ default MemorySegment allocateFrom(ValueLayout.OfChar layout, char value) { * return seg; * } * - * @param layout the layout of the block of memory to be allocated. - * @param value the value to be set in the newly allocated memory segment. + * @param layout the layout of the block of memory to be allocated + * @param value the value to be set in the newly allocated memory segment */ default MemorySegment allocateFrom(ValueLayout.OfShort layout, short value) { Objects.requireNonNull(layout); @@ -215,11 +229,12 @@ default MemorySegment allocateFrom(ValueLayout.OfShort layout, short value) { } /** - * {@return a new memory segment initialized with the provided int value.} + * {@return a new memory segment initialized with the provided int value} *

    - * The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout. - * The given value is written into the segment according to the byte order and alignment constraint of the - * given layout. + * The size of the allocated memory segment is the + * {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is + * written into the segment according to the byte order and alignment constraint of + * the given layout. * * @implSpec The default implementation is equivalent to: * {@snippet lang=java : @@ -228,8 +243,8 @@ default MemorySegment allocateFrom(ValueLayout.OfShort layout, short value) { * return seg; * } * - * @param layout the layout of the block of memory to be allocated. - * @param value the value to be set in the newly allocated memory segment. + * @param layout the layout of the block of memory to be allocated + * @param value the value to be set in the newly allocated memory segment */ default MemorySegment allocateFrom(ValueLayout.OfInt layout, int value) { Objects.requireNonNull(layout); @@ -239,11 +254,12 @@ default MemorySegment allocateFrom(ValueLayout.OfInt layout, int value) { } /** - * {@return a new memory segment initialized with the provided float value.} + * {@return a new memory segment initialized with the provided float value} *

    - * The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout. - * The given value is written into the segment according to the byte order and alignment constraint of the - * given layout. + * The size of the allocated memory segment is the + * {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is + * written into the segment according to the byte order and alignment constraint of + * the given layout. * * @implSpec The default implementation is equivalent to: * {@snippet lang=java : @@ -252,8 +268,8 @@ default MemorySegment allocateFrom(ValueLayout.OfInt layout, int value) { * return seg; * } * - * @param layout the layout of the block of memory to be allocated. - * @param value the value to be set in the newly allocated memory segment. + * @param layout the layout of the block of memory to be allocated + * @param value the value to be set in the newly allocated memory segment */ default MemorySegment allocateFrom(ValueLayout.OfFloat layout, float value) { Objects.requireNonNull(layout); @@ -263,11 +279,12 @@ default MemorySegment allocateFrom(ValueLayout.OfFloat layout, float value) { } /** - * {@return a new memory segment initialized with the provided long value.} + * {@return a new memory segment initialized with the provided long value} *

    - * The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout. - * The given value is written into the segment according to the byte order and alignment constraint of the - * given layout. + * The size of the allocated memory segment is the + * {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is + * written into the segment according to the byte order and alignment constraint of + * the given layout. * * @implSpec The default implementation is equivalent to: * {@snippet lang=java : @@ -276,8 +293,8 @@ default MemorySegment allocateFrom(ValueLayout.OfFloat layout, float value) { * return seg; * } * - * @param layout the layout of the block of memory to be allocated. - * @param value the value to be set in the newly allocated memory segment. + * @param layout the layout of the block of memory to be allocated + * @param value the value to be set in the newly allocated memory segment */ default MemorySegment allocateFrom(ValueLayout.OfLong layout, long value) { Objects.requireNonNull(layout); @@ -287,11 +304,12 @@ default MemorySegment allocateFrom(ValueLayout.OfLong layout, long value) { } /** - * {@return a new memory segment initialized with the provided double value.} + * {@return a new memory segment initialized with the provided double value} *

    - * The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout. - * The given value is written into the segment according to the byte order and alignment constraint of the - * given layout. + * The size of the allocated memory segment is the + * {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is + * written into the segment according to the byte order and alignment constraint of + * the given layout. * * @implSpec The default implementation is equivalent to: * {@snippet lang=java : @@ -300,8 +318,8 @@ default MemorySegment allocateFrom(ValueLayout.OfLong layout, long value) { * return seg; * } * - * @param layout the layout of the block of memory to be allocated. - * @param value the value to be set in the newly allocated memory segment. + * @param layout the layout of the block of memory to be allocated + * @param value the value to be set in the newly allocated memory segment */ default MemorySegment allocateFrom(ValueLayout.OfDouble layout, double value) { Objects.requireNonNull(layout); @@ -311,13 +329,16 @@ default MemorySegment allocateFrom(ValueLayout.OfDouble layout, double value) { } /** - * {@return a new memory segment initialized with the {@linkplain MemorySegment#address() address} of the provided memory segment.} + * {@return a new memory segment initialized with the + * {@linkplain MemorySegment#address() address} of the provided memory segment} *

    - * 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}). *

    - * The size of the allocated memory segment is the {@linkplain MemoryLayout#byteSize() size} of the given layout. - * The given value is written into the segment according to the byte order and alignment constraint of the - * given layout. + * The size of the allocated memory segment is the + * {@linkplain MemoryLayout#byteSize() size} of the given layout. The given value is + * written into the segment according to the byte order and alignment constraint of + * the given layout. * * @implSpec The default implementation is equivalent to: * {@snippet lang=java : @@ -327,9 +348,10 @@ default MemorySegment allocateFrom(ValueLayout.OfDouble layout, double value) { * return seg; * } * - * @param layout the layout of the block of memory to be allocated. - * @param value the value to be set in the newly allocated memory segment. - * @throws UnsupportedOperationException if {@code value} is not a {@linkplain MemorySegment#isNative() native} segment + * @param layout the layout of the block of memory to be allocated + * @param value the value to be set in the newly allocated memory segment + * @throws UnsupportedOperationException if {@code value} is not + * a {@linkplain MemorySegment#isNative() native} segment */ default MemorySegment allocateFrom(AddressLayout layout, MemorySegment value) { Objects.requireNonNull(value); @@ -340,11 +362,12 @@ default MemorySegment allocateFrom(AddressLayout layout, MemorySegment value) { } /** - * {@return a new memory segment initialized with the contents of the provided segment.} + * {@return a new memory segment initialized with the contents of the provided segment} *

    - * The size of the allocated memory segment is the {@code elementLayout.byteSize() * elementCount}. - * The contents of the source segment is copied into the result segment element by element, according to the byte - * order and alignment constraint of the given element layout. + * The size of the allocated memory segment is the + * {@code elementLayout.byteSize() * elementCount}. The contents of the + * source segment is copied into the result segment element by element, according + * to the byte order and alignment constraint of the given element layout. * * @implSpec The default implementation for this method is equivalent to the following code: * {@snippet lang = java: @@ -352,19 +375,19 @@ default MemorySegment allocateFrom(AddressLayout layout, MemorySegment value) { * MemorySegment.copy(source, sourceElementLayout, sourceOffset, dest, elementLayout, 0, elementCount); * return dest; * } - * @param elementLayout the element layout of the allocated array. - * @param source the source segment. - * @param sourceElementLayout the element layout of the source segment. - * @param sourceOffset the starting offset, in bytes, of the source segment. - * @param elementCount the number of elements in the source segment to be copied. + * @param elementLayout the element layout of the allocated array + * @param source the source segment + * @param sourceElementLayout the element layout of the source segment + * @param sourceOffset the starting offset, in bytes, of the source segment + * @param elementCount the number of elements in the source segment to be copied * @throws IllegalArgumentException if {@code elementLayout.byteSize() != sourceElementLayout.byteSize()} * @throws IllegalArgumentException if the source segment/offset * are incompatible with the alignment constraint - * in the source element layout. + * in the source element layout * @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()} * @throws IllegalArgumentException if {@code sourceElementLayout.byteAlignment() > sourceElementLayout.byteSize()} - * @throws IllegalStateException if the {@linkplain MemorySegment#scope() scope} associated with {@code source} is not - * {@linkplain MemorySegment.Scope#isAlive() alive} + * @throws IllegalStateException if the {@linkplain MemorySegment#scope() scope} associated + * with {@code source} is not {@linkplain MemorySegment.Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code source.isAccessibleBy(T) == false} * @throws IndexOutOfBoundsException if {@code elementCount * sourceElementLayout.byteSize()} overflows @@ -386,20 +409,25 @@ default MemorySegment allocateFrom(ValueLayout elementLayout, } /** - * {@return a new memory segment initialized with the elements in the provided byte array.} + * {@return a new memory segment initialized with the elements in the provided + * byte array} *

    - * The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}. - * The contents of the source array is copied into the result segment element by element, according to the byte - * order and alignment constraint of the given element layout. + * The size of the allocated memory segment is + * {@code elementLayout.byteSize() * elements.length}. The contents of the + * source array is copied into the result segment element by element, according + * to the byte order and alignment constraint of the given element layout. * - * @implSpec The default implementation for this method is equivalent to the following code: + * @implSpec The default implementation for this method is equivalent to the + * following code: * {@snippet lang = java: * this.allocateFrom(layout, MemorySegment.ofArray(array), * ValueLayout.JAVA_BYTE, 0, array.length) *} - * @param elementLayout the element layout of the array to be allocated. - * @param elements the byte elements to be copied to the newly allocated memory block. - * @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()} + * @param elementLayout the element layout of the array to be allocated + * @param elements the byte elements to be copied to the newly allocated + * memory block + * @throws IllegalArgumentException if + * {@code elementLayout.byteAlignment() > elementLayout.byteSize()} */ @ForceInline default MemorySegment allocateFrom(ValueLayout.OfByte elementLayout, byte... elements) { @@ -408,20 +436,25 @@ default MemorySegment allocateFrom(ValueLayout.OfByte elementLayout, byte... ele } /** - * {@return a new memory segment initialized with the elements in the provided short array.} + * {@return a new memory segment initialized with the elements in the provided + * short array} *

    - * The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}. - * The contents of the source array are copied into the result segment element by element, according to the byte - * order and alignment constraint of the given element layout. + * The size of the allocated memory segment is + * {@code elementLayout.byteSize() * elements.length}. The contents of the + * source array are copied into the result segment element by element, according + * to the byte order and alignment constraint of the given element layout. * - * @implSpec The default implementation for this method is equivalent to the following code: + * @implSpec The default implementation for this method is equivalent to the + * following code: * {@snippet lang = java: * this.allocateFrom(layout, MemorySegment.ofArray(array), * ValueLayout.JAVA_SHORT, 0, array.length) *} - * @param elementLayout the element layout of the array to be allocated. - * @param elements the short elements to be copied to the newly allocated memory block. - * @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()} + * @param elementLayout the element layout of the array to be allocated + * @param elements the short elements to be copied to the newly allocated + * memory block + * @throws IllegalArgumentException if + * {@code elementLayout.byteAlignment() > elementLayout.byteSize()} */ @ForceInline default MemorySegment allocateFrom(ValueLayout.OfShort elementLayout, short... elements) { @@ -430,20 +463,25 @@ default MemorySegment allocateFrom(ValueLayout.OfShort elementLayout, short... e } /** - * {@return a new memory segment initialized with the elements in the provided char array.} + * {@return a new memory segment initialized with the elements in the provided + * char array} *

    - * The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}. - * The contents of the source array is copied into the result segment element by element, according to the byte - * order and alignment constraint of the given element layout. + * The size of the allocated memory segment is + * {@code elementLayout.byteSize() * elements.length}. The contents of the + * source array is copied into the result segment element by element, according + * to the byte order and alignment constraint of the given element layout. * - * @implSpec The default implementation for this method is equivalent to the following code: + * @implSpec The default implementation for this method is equivalent to the + * following code: * {@snippet lang = java: * this.allocateFrom(layout, MemorySegment.ofArray(array), * ValueLayout.JAVA_CHAR, 0, array.length) *} - * @param elementLayout the element layout of the array to be allocated. - * @param elements the char elements to be copied to the newly allocated memory block. - * @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()} + * @param elementLayout the element layout of the array to be allocated + * @param elements the char elements to be copied to the newly allocated + * memory block + * @throws IllegalArgumentException if + * {@code elementLayout.byteAlignment() > elementLayout.byteSize()} */ @ForceInline default MemorySegment allocateFrom(ValueLayout.OfChar elementLayout, char... elements) { @@ -452,20 +490,25 @@ default MemorySegment allocateFrom(ValueLayout.OfChar elementLayout, char... ele } /** - * {@return a new memory segment initialized with the elements in the provided int array.} + * {@return a new memory segment initialized with the elements in the provided + * int array} *

    - * The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}. - * The contents of the source array is copied into the result segment element by element, according to the byte - * order and alignment constraint of the given element layout. + * The size of the allocated memory segment is + * {@code elementLayout.byteSize() * elements.length}. The contents of the + * source array is copied into the result segment element by element, according + * to the byte order and alignment constraint of the given element layout. * - * @implSpec The default implementation for this method is equivalent to the following code: + * @implSpec The default implementation for this method is equivalent to the + * following code: * {@snippet lang = java: * this.allocateFrom(layout, MemorySegment.ofArray(array), * ValueLayout.JAVA_INT, 0, array.length) *} - * @param elementLayout the element layout of the array to be allocated. - * @param elements the int elements to be copied to the newly allocated memory block. - * @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()} + * @param elementLayout the element layout of the array to be allocated + * @param elements the int elements to be copied to the newly allocated + * memory block + * @throws IllegalArgumentException if + * {@code elementLayout.byteAlignment() > elementLayout.byteSize()} */ @ForceInline default MemorySegment allocateFrom(ValueLayout.OfInt elementLayout, int... elements) { @@ -474,20 +517,25 @@ default MemorySegment allocateFrom(ValueLayout.OfInt elementLayout, int... eleme } /** - * {@return a new memory segment initialized with the elements in the provided float array.} + * {@return a new memory segment initialized with the elements in the provided + * float array} *

    - * The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}. - * The contents of the source array is copied into the result segment element by element, according to the byte - * order and alignment constraint of the given element layout. + * The size of the allocated memory segment is + * {@code elementLayout.byteSize() * elements.length}. The contents of + * the source array is copied into the result segment element by element, according + * to the byte order and alignment constraint of the given element layout. * - * @implSpec The default implementation for this method is equivalent to the following code: + * @implSpec The default implementation for this method is equivalent to the + * following code: * {@snippet lang = java: * this.allocateFrom(layout, MemorySegment.ofArray(array), * ValueLayout.JAVA_FLOAT, 0, array.length) *} - * @param elementLayout the element layout of the array to be allocated. - * @param elements the float elements to be copied to the newly allocated memory block. - * @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()} + * @param elementLayout the element layout of the array to be allocated + * @param elements the float elements to be copied to the newly allocated + * memory block + * @throws IllegalArgumentException if + * {@code elementLayout.byteAlignment() > elementLayout.byteSize()} */ @ForceInline default MemorySegment allocateFrom(ValueLayout.OfFloat elementLayout, float... elements) { @@ -496,20 +544,25 @@ default MemorySegment allocateFrom(ValueLayout.OfFloat elementLayout, float... e } /** - * {@return a new memory segment initialized with the elements in the provided long array.} + * {@return a new memory segment initialized with the elements in the provided + * long array} *

    - * The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}. - * The contents of the source array is copied into the result segment element by element, according to the byte - * order and alignment constraint of the given element layout. + * The size of the allocated memory segment is + * {@code elementLayout.byteSize() * elements.length}. The contents of + * the source array is copied into the result segment element by element, according + * to the byte order and alignment constraint of the given element layout. * - * @implSpec The default implementation for this method is equivalent to the following code: + * @implSpec The default implementation for this method is equivalent to the + * following code: * {@snippet lang = java: * this.allocateFrom(layout, MemorySegment.ofArray(array), * ValueLayout.JAVA_LONG, 0, array.length) *} - * @param elementLayout the element layout of the array to be allocated. - * @param elements the long elements to be copied to the newly allocated memory block. - * @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()} + * @param elementLayout the element layout of the array to be allocated + * @param elements the long elements to be copied to the newly allocated + * memory block + * @throws IllegalArgumentException if + * {@code elementLayout.byteAlignment() > elementLayout.byteSize()} */ @ForceInline default MemorySegment allocateFrom(ValueLayout.OfLong elementLayout, long... elements) { @@ -518,20 +571,25 @@ default MemorySegment allocateFrom(ValueLayout.OfLong elementLayout, long... ele } /** - * {@return a new memory segment initialized with the elements in the provided double array.} + * {@return a new memory segment initialized with the elements in the provided + * double array} *

    - * The size of the allocated memory segment is {@code elementLayout.byteSize() * elements.length}. - * The contents of the source array is copied into the result segment element by element, according to the byte - * order and alignment constraint of the given element layout. + * The size of the allocated memory segment is + * {@code elementLayout.byteSize() * elements.length}. The contents of + * the source array is copied into the result segment element by element, according + * to the byte order and alignment constraint of the given element layout. * - * @implSpec The default implementation for this method is equivalent to the following code: + * @implSpec The default implementation for this method is equivalent to the + * following code: * {@snippet lang = java: * this.allocateFrom(layout, MemorySegment.ofArray(array), * ValueLayout.JAVA_DOUBLE, 0, array.length) *} - * @param elementLayout the element layout of the array to be allocated. - * @param elements the double elements to be copied to the newly allocated memory block. - * @throws IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()} + * @param elementLayout the element layout of the array to be allocated + * @param elements the double elements to be copied to the newly allocated + * memory block + * @throws IllegalArgumentException if + * {@code elementLayout.byteAlignment() > elementLayout.byteSize()} */ @ForceInline default MemorySegment allocateFrom(ValueLayout.OfDouble elementLayout, double... elements) { @@ -543,9 +601,9 @@ default MemorySegment allocateFrom(ValueLayout.OfDouble elementLayout, double... * {@return a new memory segment with the given layout} * * @implSpec The default implementation for this method calls - * {@code this.allocate(layout.byteSize(), layout.byteAlignment())}. + * {@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 */ default MemorySegment allocate(MemoryLayout layout) { Objects.requireNonNull(layout); @@ -556,11 +614,12 @@ default MemorySegment allocate(MemoryLayout layout) { * {@return a new memory segment with the given {@code elementLayout} and {@code count}} * * @implSpec The default implementation for this method calls - * {@code this.allocate(MemoryLayout.sequenceLayout(count, elementLayout))}. + * {@code this.allocate(MemoryLayout.sequenceLayout(count, elementLayout))}. * - * @param elementLayout the array element layout. - * @param count the array element count. - * @throws IllegalArgumentException if {@code elementLayout.byteSize() * count} overflows + * @param elementLayout the array element layout + * @param count the array element count + * @throws IllegalArgumentException if {@code elementLayout.byteSize() * count} + * overflows * @throws IllegalArgumentException if {@code count < 0} */ default MemorySegment allocate(MemoryLayout elementLayout, long count) { @@ -575,9 +634,9 @@ default MemorySegment allocate(MemoryLayout elementLayout, long count) { * {@return a new memory segment with the given {@code byteSize}} * * @implSpec The default implementation for this method calls - * {@code this.allocate(byteSize, 1)}. + * {@code this.allocate(byteSize, 1)}. * - * @param byteSize the size (in bytes) of the block of memory to be allocated. + * @param byteSize the size (in bytes) of the block of memory to be allocated * @throws IllegalArgumentException if {@code byteSize < 0} */ default MemorySegment allocate(long byteSize) { @@ -585,26 +644,31 @@ default MemorySegment allocate(long byteSize) { } /** - * {@return a new memory segment with the given {@code byteSize} and {@code byteAlignment}} - * - * @param byteSize the size (in bytes) of the block of memory to be allocated. - * @param byteAlignment the alignment (in bytes) of the block of memory to be allocated. - * @throws IllegalArgumentException if {@code byteSize < 0}, {@code byteAlignment <= 0}, + * {@return a new memory segment with the given {@code byteSize} and + * {@code byteAlignment}} + * + * @param byteSize the size (in bytes) of the block of memory + * to be allocated + * @param byteAlignment the alignment (in bytes) of the block of memory + * to be allocated + * @throws IllegalArgumentException if {@code byteSize < 0}, + * {@code byteAlignment <= 0}, * or if {@code byteAlignment} is not a power of 2 */ MemorySegment allocate(long byteSize, long byteAlignment); /** - * Returns a segment allocator that responds to allocation requests by returning consecutive slices - * obtained from the provided segment. Each new allocation request will return a new slice starting at the - * current offset (modulo additional padding to satisfy alignment constraint), with given size. + * Returns a segment allocator that responds to allocation requests by returning + * consecutive slices obtained from the provided segment. Each new allocation + * request will return a new slice starting at the current offset (modulo additional + * padding to satisfy alignment constraint), with given size. *

    - * The returned allocator throws {@link IndexOutOfBoundsException} when a slice of the provided - * segment with the requested size and alignment cannot be found. + * The returned allocator throws {@link IndexOutOfBoundsException} when a slice of + * the provided segment with the requested size and alignment cannot be found. * * @implNote A slicing allocator is not thread-safe. * - * @param segment the segment from which the returned allocator should slice from. + * @param segment the segment from which the returned allocator should slice from * @return a new slicing allocator */ static SegmentAllocator slicingAllocator(MemorySegment segment) { @@ -613,25 +677,29 @@ static SegmentAllocator slicingAllocator(MemorySegment segment) { } /** - * Returns a segment allocator that responds to allocation requests by recycling a single segment. Each - * new allocation request will return a new slice starting at the segment offset {@code 0}, hence the name - * prefix allocator. + * Returns a segment allocator that responds to allocation requests by recycling a + * single segment. Each new allocation request will return a new slice starting at + * the segment offset {@code 0}, hence the name prefix allocator. + *

    * Equivalent to (but likely more efficient than) the following code: * {@snippet lang=java : * MemorySegment segment = ... * SegmentAllocator prefixAllocator = (size, align) -> segment.asSlice(0, size, align); * } - * The returned allocator throws {@link IndexOutOfBoundsException} when a slice of the provided - * segment with the requested size and alignment cannot be found. + * The returned allocator throws {@link IndexOutOfBoundsException} when a slice of + * the provided segment with the requested size and alignment cannot be found. + * + * @apiNote A prefix allocator can be useful to limit allocation requests in case a + * client knows that they have fully processed the contents of the allocated + * segment before the subsequent allocation request takes place. * - * @apiNote A prefix allocator can be useful to limit allocation requests in case a client - * knows that they have fully processed the contents of the allocated segment before the subsequent allocation request - * takes place. - * @implNote While a prefix allocator is thread-safe, concurrent access on the same recycling - * allocator might cause a thread to overwrite contents written to the underlying segment by a different thread. + * @implNote While a prefix allocator is thread-safe, concurrent access on + * the same recycling allocator might cause a thread to overwrite contents + * written to the underlying segment by a different thread. * - * @param segment the memory segment to be recycled by the returned allocator. - * @return an allocator that recycles an existing segment upon each new allocation request. + * @param segment the memory segment to be recycled by the returned allocator + * @return an allocator that recycles an existing segment upon each new + * allocation request */ static SegmentAllocator prefixAllocator(MemorySegment segment) { return (AbstractMemorySegmentImpl)Objects.requireNonNull(segment); diff --git a/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java b/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java index 82a08938c4d..f5d1b774061 100644 --- a/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/SequenceLayout.java @@ -28,10 +28,11 @@ import jdk.internal.foreign.layout.SequenceLayoutImpl; /** - * A compound layout that denotes a homogeneous repetition of a given element layout. - * The repetition count is said to be the sequence layout's element count. A sequence layout can be thought of as a - * struct layout where the sequence layout's element layout is repeated a number of times that is equal to the sequence - * layout's element count. In other words this layout: + * A compound layout that denotes a homogeneous repetition of a given + * element layout. The repetition count is said to be the sequence layout's + * element count. A sequence layout can be thought of as a struct layout where + * the sequence layout's element layout is repeated a number of times that is equal to + * the sequence layout's element count. In other words this layout: * * {@snippet lang=java : * MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN)); @@ -47,7 +48,8 @@ * } * * @implSpec - * This class is immutable, thread-safe and value-based. + * This class is immutable, thread-safe and + * value-based. * * @since 22 */ @@ -65,18 +67,21 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo long elementCount(); /** - * {@return a sequence layout with the same characteristics of this layout, but with the given element count} - * @param elementCount the new element count. + * {@return a sequence layout with the same characteristics of this layout, but with + * the given element count} + * @param elementCount the new element count * @throws IllegalArgumentException if {@code elementCount} is negative - * @throws IllegalArgumentException if {@code elementLayout.bitSize() * elementCount} overflows + * @throws IllegalArgumentException if {@code elementLayout.bitSize() * elementCount} + * overflows */ SequenceLayout withElementCount(long elementCount); /** - * Rearranges the elements in this sequence layout into a multi-dimensional sequence layout. - * The resulting layout is a sequence layout where element layouts in the {@linkplain #flatten() flattened projection} - * of this sequence layout are rearranged into one or more nested sequence layouts - * according to the provided element counts. This transformation preserves the layout size; + * Rearranges the elements in this sequence layout into a multidimensional sequence + * layout. The resulting layout is a sequence layout where element layouts in the + * {@linkplain #flatten() flattened projection} of this sequence layout are + * rearranged into one or more nested sequence layouts according to the provided + * element counts. This transformation preserves the layout size; * that is, multiplying the provided element counts must yield the same element count * as the flattened projection of this sequence layout. *

    @@ -89,27 +94,32 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo * var reshapeSeq = MemoryLayout.sequenceLayout(2, MemoryLayout.sequenceLayout(6, ValueLayout.JAVA_INT)); * } *

    - * If one of the provided element counts is the special value {@code -1}, then the element - * count in that position will be inferred from the remaining element counts and the - * element count of the flattened projection of this layout. For instance, a layout equivalent to - * the above {@code reshapeSeq} can also be computed in the following ways: + * If one of the provided element counts is the special value {@code -1}, then + * the element count in that position will be inferred from the remaining element + * counts and the element count of the flattened projection of this layout. + * For instance, a layout equivalent to the above {@code reshapeSeq} can also be + * computed in the following ways: * {@snippet lang=java : * var reshapeSeqImplicit1 = seq.reshape(-1, 6); * var reshapeSeqImplicit2 = seq.reshape(2, -1); * } - * @param elementCounts an array of element counts, of which at most one can be {@code -1}. - * @return a sequence layout where element layouts in the {@linkplain #flatten() flattened projection} of this - * sequence layout (see {@link #flatten()}) are re-arranged into one or more nested sequence layouts. - * @throws IllegalArgumentException if two or more element counts are set to {@code -1}, or if one - * or more element count is {@code <= 0} (but other than {@code -1}) or, if, after any required inference, - * multiplying the element counts does not yield the same element count as the flattened projection of this + * @param elementCounts an array of element counts, of which at most one can be {@code -1} + * @return a sequence layout where element layouts in the + * {@linkplain #flatten() flattened projection} of this sequence layout + * (see {@link #flatten()}) are re-arranged into one or more nested + * sequence layouts + * @throws IllegalArgumentException if two or more element counts are set to {@code -1}, + * or if one or more element count is {@code <= 0} (but other than {@code -1}) or, + * if, after any required inference, multiplying the element counts does not + * yield the same element count as the flattened projection of this * sequence layout */ SequenceLayout reshape(long... elementCounts); /** - * Returns a flattened sequence layout. The element layout of the returned sequence layout - * is the first non-sequence layout found by inspecting (recursively, if needed) the element layout of this sequence layout: + * Returns a flattened sequence layout. The element layout of the returned + * sequence layout is the first non-sequence layout found by inspecting + * (recursively, if needed) the element layout of this sequence layout: * {@snippet lang=java : * MemoryLayout flatElementLayout(SequenceLayout sequenceLayout) { * return switch (sequenceLayout.elementLayout()) { @@ -119,9 +129,10 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo * } * } *

    - * This transformation preserves the layout size; nested sequence layout in this sequence layout will - * be dropped and their element counts will be incorporated into that of the returned sequence layout. - * For instance, given a sequence layout of the kind: + * This transformation preserves the layout size; nested sequence layout in this + * sequence layout will be dropped and their element counts will be incorporated + * into that of the returned sequence layout. For instance, given a + * sequence layout of the kind: * {@snippet lang=java : * var seq = MemoryLayout.sequenceLayout(4, MemoryLayout.sequenceLayout(3, ValueLayout.JAVA_INT)); * } @@ -129,8 +140,9 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo * {@snippet lang=java : * var flattenedSeq = MemoryLayout.sequenceLayout(12, ValueLayout.JAVA_INT); * } - * @return a sequence layout with the same size as this layout (but, possibly, with different - * element count), whose element layout is not a sequence layout. + * @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 */ SequenceLayout flatten(); @@ -149,7 +161,8 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo /** * {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} - * @throws IllegalArgumentException if {@code byteAlignment < elementLayout().byteAlignment()} + * @throws IllegalArgumentException if + * {@code byteAlignment < elementLayout().byteAlignment()} */ SequenceLayout withByteAlignment(long byteAlignment); } diff --git a/src/java.base/share/classes/java/lang/foreign/StructLayout.java b/src/java.base/share/classes/java/lang/foreign/StructLayout.java index c0800bb6b1c..9d2b6f3d13f 100644 --- a/src/java.base/share/classes/java/lang/foreign/StructLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/StructLayout.java @@ -31,7 +31,8 @@ * A group layout whose member layouts are laid out one after the other. * * @implSpec - * Implementing classes are immutable, thread-safe and value-based. + * Implementing classes are immutable, thread-safe and + * value-based. * * @since 22 */ diff --git a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java index fa694b4ee7d..1d04032a1ff 100644 --- a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java +++ b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java @@ -46,26 +46,34 @@ * A symbol lookup retrieves the address of a symbol in one or more libraries. * A symbol is a named entity, such as a function or a global variable. *

    - * A symbol lookup is created with respect to a particular library (or libraries). Subsequently, the {@link SymbolLookup#find(String)} - * method takes the name of a symbol and returns the address of the symbol in that library. + * A symbol lookup is created with respect to a particular library (or libraries). + * Subsequently, the {@link SymbolLookup#find(String)} method takes the name of a symbol + * and returns the address of the symbol in that library. *

    - * The address of a symbol is modeled as a zero-length {@linkplain MemorySegment memory segment}. The segment can be used in different ways: + * The address of a symbol is modeled as a zero-length + * {@linkplain MemorySegment memory segment}. The segment can be used in different ways: *

      - *
    • It can be passed to a {@link Linker} to create a downcall method handle, which can then be used to call the foreign function at the segment's address.
    • - *
    • It can be passed to an existing {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle}, as an argument to the underlying foreign function.
    • - *
    • It can be {@linkplain MemorySegment#set(AddressLayout, long, MemorySegment) stored} inside another memory segment.
    • - *
    • It can be used to access the region of memory backing a global variable (this requires - * {@linkplain MemorySegment#reinterpret(long) resizing} the segment first).
    • + *
    • It can be passed to a {@link Linker} to create a downcall method handle, which + * can then be used to call the foreign function at the segment's address.
    • + *
    • It can be passed to an existing + * {@linkplain Linker#downcallHandle(FunctionDescriptor, Linker.Option...) downcall method handle}, + * as an argument to the underlying foreign function.
    • + *
    • It can be {@linkplain MemorySegment#set(AddressLayout, long, MemorySegment) stored} + * inside another memory segment.
    • + *
    • It can be used to access the region of memory backing a global variable + * (this requires {@linkplain MemorySegment#reinterpret(long) resizing} + * the segment first).
    • *
    * *

    Obtaining a symbol lookup

    * - * The factory methods {@link #libraryLookup(String, Arena)} and {@link #libraryLookup(Path, Arena)} - * create a symbol lookup for a library known to the operating system. The library is specified by either its name or a path. - * The library is loaded if not already loaded. The symbol lookup, which is known as a library lookup, and its - * lifetime is controlled by an {@linkplain Arena arena}. For instance, if the provided arena is a - * confined arena, the library associated with the symbol lookup is unloaded when the confined arena - * is {@linkplain Arena#close() closed}: + * The factory methods {@link #libraryLookup(String, Arena)} and + * {@link #libraryLookup(Path, Arena)} create a symbol lookup for a library known to + * the operating system. The library is specified by either its name or a path. + * The library is loaded if not already loaded. The symbol lookup, which is known as a + * library lookup, and its lifetime is controlled by an {@linkplain Arena arena}. + * For instance, if the provided arena is a confined arena, the library associated with + * the symbol lookup is unloaded when the confined arena is {@linkplain Arena#close() closed}: * * {@snippet lang = java: * try (Arena arena = Arena.ofConfined()) { @@ -76,8 +84,9 @@ *} *

    * 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: + * 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 @@ -86,21 +95,24 @@ * MemorySegment glGetString = libGL.find("glGetString").orElseThrow(); * } * - * This symbol lookup, which is known as a loader lookup, is dynamic with respect to the libraries associated - * with the class loader. If other libraries are subsequently loaded through JNI and associated with the class loader, - * then the loader lookup will expose their symbols automatically. + * This symbol lookup, which is known as a loader lookup, is dynamic with + * respect to the libraries associated with the class loader. If other libraries are + * subsequently loaded through JNI and associated with the class loader, then the loader + * lookup will expose their symbols automatically. *

    - * Note that a loader lookup only exposes symbols in libraries that were previously loaded through JNI, i.e., - * by {@link System#load(String)} or {@link System#loadLibrary(String)}. A loader lookup does not expose symbols in libraries - * that were loaded in the course of creating a library lookup: + * 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", arena).find("glGetString").isPresent(); // true * loaderLookup().find("glGetString").isPresent(); // false *} * - * Note also that a library lookup for library {@code L} exposes symbols in {@code L} even if {@code L} was previously loaded - * through JNI (the association with a class loader is immaterial to the library lookup): + * 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 @@ -108,10 +120,11 @@ *} * *

    - * Finally, each {@link Linker} provides a symbol lookup for libraries that are commonly used on the OS and processor - * combination supported by that {@link Linker}. This symbol lookup, which is known as a default lookup, - * helps clients to quickly find addresses of well-known symbols. For example, a {@link Linker} for Linux/x64 might choose to - * expose symbols in {@code libc} through the default lookup: + * Finally, each {@link Linker} provides a symbol lookup for libraries that are commonly + * used on the OS and processor combination supported by that {@link Linker}. This + * symbol lookup, which is known as a default lookup, helps clients to quickly + * find addresses of well-known symbols. For example, a {@link Linker} for Linux/x64 + * might choose to expose symbols in {@code libc} through the default lookup: * * {@snippet lang = java: * Linker nativeLinker = Linker.nativeLinker(); @@ -126,27 +139,33 @@ 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 address indicates the address of the symbol, if found. + * + * @param name the symbol name + * @return a zero-length memory segment whose address indicates the address of + * the symbol, if found */ Optional find(String name); /** - * {@return a composed symbol lookup that returns the result of finding the symbol with this lookup if found, - * otherwise returns the result of finding the symbol with the other lookup} + * {@return a composed symbol lookup that returns the result of finding the symbol + * with this lookup if found, otherwise returns the result of finding + * the symbol with the other lookup} * - * @apiNote This method could be used to chain multiple symbol lookups together, e.g. so that symbols could - * be retrieved, in order, from multiple libraries: + * @apiNote This method could be used to chain multiple symbol lookups together, + * e.g. so that symbols could be retrieved, in order, from multiple + * libraries: * {@snippet lang = java: * var lookup = SymbolLookup.libraryLookup("foo", arena) * .or(SymbolLookup.libraryLookup("bar", arena)) * .or(SymbolLookup.loaderLookup()); *} - * The above code creates a symbol lookup that first searches for symbols in the "foo" library. If no symbol is found - * in "foo" then "bar" is searched. Finally, if a symbol is neither found in "foo" nor in "bar", the {@linkplain - * SymbolLookup#loaderLookup() loader lookup} is used. + * The above code creates a symbol lookup that first searches for symbols in + * the "foo" library. If no symbol is found in "foo" then "bar" is searched. + * Finally, if a symbol is neither found in "foo" nor in "bar", the + * {@linkplain SymbolLookup#loaderLookup() loader lookup} is used. * - * @param other the symbol lookup that should be used to look for symbols not found in this lookup. + * @param other the symbol lookup that should be used to look for symbols not found + * in this lookup */ default SymbolLookup or(SymbolLookup other) { Objects.requireNonNull(other); @@ -154,27 +173,33 @@ default SymbolLookup or(SymbolLookup other) { } /** - * Returns a symbol lookup for symbols in the libraries associated with the caller's class loader. + * Returns a symbol lookup for symbols in the libraries associated with the caller's + * class loader. *

    - * 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. + * A library is associated with a class loader {@code CL} when the library is loaded + * via an invocation of {@link System#load(String)} or + * {@link System#loadLibrary(String)} from code in a class defined by {@code CL}. + * If that code makes further invocations of {@link System#load(String)} or + * {@link System#loadLibrary(String)} then more libraries are loaded and associated + * with {@code CL}. The symbol lookup returned by this method is always current: it + * reflects all the libraries associated with the relevant class loader, even if they + * were loaded after this method returned. *

    * Libraries associated with a class loader are unloaded when the class loader becomes - * unreachable. The symbol lookup - * returned by this method is associated with an automatic {@linkplain MemorySegment.Scope scope} 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, or any of the segments - * obtained by it, is reachable. + * unreachable. The + * symbol lookup returned by this method is associated with an automatic + * {@linkplain MemorySegment.Scope scope} 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, or any of the segments obtained by it, is reachable. *

    - * In cases where this method is called from a context where there is no caller frame on the stack - * (e.g. when called directly from a JNI attached thread), the caller's class loader defaults to the + * 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. + * @return a symbol lookup for symbols in the libraries associated with + * the caller's class loader * @see System#load(String) * @see System#loadLibrary(String) */ @@ -206,24 +231,28 @@ static SymbolLookup loaderLookup() { } /** - * Loads a library with the given name (if not already loaded) and creates a symbol lookup for symbols in that library. - * The lifetime of the returned library lookup is controlled by the provided arena. - * For instance, if the provided arena is a confined arena, the library - * associated with the returned lookup will be unloaded when the provided confined arena is - * {@linkplain Arena#close() closed}. + * Loads a library with the given name (if not already loaded) and creates a symbol + * lookup for symbols in that library. The lifetime of the returned library lookup + * is controlled by the provided arena. For instance, if the provided arena is a + * confined arena, the library associated with the returned lookup will be unloaded + * when the provided confined arena is {@linkplain Arena#close() closed}. * - * @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. + * @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. * - * @param name the name of the library in which symbols should be looked up. - * @param arena the arena associated with symbols obtained from the returned lookup. - * @return a new symbol lookup suitable to find symbols in a library with the given name. + * @param name the name of the library in which symbols should be looked up + * @param arena the arena associated with symbols obtained from the returned lookup + * @return a new symbol lookup suitable to find symbols in a library with the + * given name * @throws IllegalStateException if {@code arena.scope().isAlive() == false} - * @throws WrongThreadException if {@code arena} is a confined arena, and this method is called from a - * thread {@code T}, other than the arena's owner thread + * @throws WrongThreadException if {@code arena} is a confined arena, and this method + * is called from a thread {@code T}, other than the arena's owner thread * @throws IllegalArgumentException if {@code name} does not identify a valid library - * @throws IllegalCallerException If the caller is in a module that does not have native access enabled + * @throws IllegalCallerException If the caller is in a module that does not have + * native access enabled */ @CallerSensitive @Restricted @@ -237,22 +266,26 @@ static SymbolLookup libraryLookup(String name, Arena arena) { } /** - * Loads a library from the given path (if not already loaded) and creates a symbol lookup for symbols - * in that library. The lifetime of the returned library lookup is controlled by the provided arena. - * For instance, if the provided arena is a confined arena, the library - * associated with the returned lookup will be unloaded when the provided confined arena is - * {@linkplain Arena#close() closed}. + * Loads a library from the given path (if not already loaded) and creates a symbol + * lookup for symbols in that library. The lifetime of the returned library lookup + * is controlled by the provided arena. For instance, if the provided arena is a + * confined arena, the library associated with the returned lookup will be unloaded + * when the provided confined arena is {@linkplain Arena#close() closed}. + * + * @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. * - * @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 arena the arena associated with symbols obtained from the returned lookup. - * @return a new symbol lookup suitable to find symbols in a library with the given path. + * @param path the path of the library in which symbols should be looked up + * @param arena the arena associated with symbols obtained from the returned lookup + * @return a new symbol lookup suitable to find symbols in a library with the given + * path * @throws IllegalStateException if {@code arena.scope().isAlive() == false} - * @throws WrongThreadException if {@code arena} is a confined arena, and this method is called from a - * thread {@code T}, other than the arena's owner thread + * @throws WrongThreadException if {@code arena} is a confined arena, and this method + * is called from a thread {@code T}, other than the arena's owner thread * @throws IllegalArgumentException if {@code path} does not point to a valid library - * @throws IllegalCallerException If the caller is in a module that does not have native access enabled + * @throws IllegalCallerException If the caller is in a module that does not have + * native access enabled */ @CallerSensitive @Restricted diff --git a/src/java.base/share/classes/java/lang/foreign/UnionLayout.java b/src/java.base/share/classes/java/lang/foreign/UnionLayout.java index ddd33aeeba5..da102d84e76 100644 --- a/src/java.base/share/classes/java/lang/foreign/UnionLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/UnionLayout.java @@ -31,7 +31,8 @@ * A group layout whose member layouts are laid out at the same starting offset. * * @implSpec - * Implementing classes are immutable, thread-safe and value-based. + * Implementing classes are immutable, thread-safe and + * value-based. * * @since 22 */ diff --git a/src/java.base/share/classes/java/lang/foreign/ValueLayout.java b/src/java.base/share/classes/java/lang/foreign/ValueLayout.java index 3464950fca5..e8740be387c 100644 --- a/src/java.base/share/classes/java/lang/foreign/ValueLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/ValueLayout.java @@ -30,22 +30,29 @@ import jdk.internal.foreign.layout.ValueLayouts; /** - * A layout that models values of basic data types. Examples of values modeled by a value layout are - * integral values (either signed or unsigned), floating-point values and - * address values. + * A layout that models values of basic data types. Examples of values modeled by + * a value layout are integral values (either signed or unsigned), + * floating-point values and address values. *

    * Each value layout has a size, an alignment (both expressed in bytes), - * a {@linkplain ByteOrder byte order}, and a carrier, that is, the Java type that should be used when - * {@linkplain MemorySegment#get(OfInt, long) accessing} a region of memory using the value layout. + * a {@linkplain ByteOrder byte order}, and a carrier, that is, the Java type + * that should be used when {@linkplain MemorySegment#get(OfInt, long) accessing} a + * region of memory using the value layout. *

    - * This class defines useful value layout constants for Java primitive types and addresses. - * @apiNote Some characteristics of the Java layout constants are platform-dependent. For instance, the byte order of - * these constants is set to the {@linkplain ByteOrder#nativeOrder() native byte order}, thus making it easy to work - * with other APIs, such as arrays and {@link java.nio.ByteBuffer}. Moreover, the alignment constraint of - * {@link ValueLayout#JAVA_LONG} and {@link ValueLayout#JAVA_DOUBLE} are set to 8 bytes on 64-bit platforms, but only to - * 4 bytes on 32-bit platforms. + + * This class defines useful value layout constants for Java primitive types and + * addresses. + * + * @apiNote Some characteristics of the Java layout constants are platform-dependent. + * For instance, the byte order of these constants is set to the + * {@linkplain ByteOrder#nativeOrder() native byte order}, thus making it easy + * to work with other APIs, such as arrays and {@link java.nio.ByteBuffer}. + * Moreover, the alignment constraint of {@link ValueLayout#JAVA_LONG} and + * {@link ValueLayout#JAVA_DOUBLE} is set to 8 bytes on 64-bit platforms, + * but only to 4 bytes on 32-bit platforms. * - * @implSpec implementing classes and subclasses are immutable, thread-safe and value-based. + * @implSpec implementing classes and subclasses are immutable, thread-safe and + * value-based. * * @sealedGraph * @since 22 @@ -63,7 +70,7 @@ public sealed interface ValueLayout extends MemoryLayout /** * {@return a value layout with the same characteristics as this layout, but with the given byte order} * - * @param order the desired byte order. + * @param order the desired byte order */ ValueLayout withOrder(ByteOrder order); @@ -93,21 +100,26 @@ public sealed interface ValueLayout extends MemoryLayout ValueLayout withByteAlignment(long byteAlignment); /** - * {@return a var handle which can be used to access values described by this value layout, in a given memory segment.} + * {@return a var handle which can be used to access values described by this value + * layout, in a given memory segment} *

    - * The returned var handle's {@linkplain VarHandle#varType() var type} is the {@linkplain ValueLayout#carrier() carrier type} of - * this value layout, and the list of coordinate types is {@code (MemorySegment, long)}, where the memory segment coordinate - * corresponds to the memory segment to be accessed, and the {@code long} coordinate corresponds to the byte offset - * into the accessed memory segment at which the access occurs. + * The returned var handle's {@linkplain VarHandle#varType() var type} is the + * {@linkplain ValueLayout#carrier() carrier type} of this value layout, and the + * list of coordinate types is {@code (MemorySegment, long)}, where the + * memory segment coordinate corresponds to the memory segment to be accessed, and + * the {@code long} coordinate corresponds to the byte offset into the accessed + * memory segment at which the access occurs. *

    - * The returned var handle checks that accesses are aligned according to this value layout's - * {@linkplain MemoryLayout#byteAlignment() alignment constraint}. + * The returned var handle checks that accesses are aligned according to + * this value layout's {@linkplain MemoryLayout#byteAlignment() alignment constraint}. * - * @apiNote This method is similar, but more efficient than calling {@code MemoryLayout#varHandle(PathElement...)} - * with an empty path element array, as it avoids the creation of the var args array. + * @apiNote This method is similar, but more efficient than calling + * {@code MemoryLayout#varHandle(PathElement...)} with an empty path + * element array, as it avoids the creation of the var args array. * - * @apiNote The returned var handle features certain access mode - * restrictions common to all memory access var handles derived from memory layouts. + * @apiNote The returned var handle features certain + * access mode restrictions + * common to all memory access var handles derived from memory layouts. * * @see MemoryLayout#varHandle(PathElement...) */ @@ -399,8 +411,9 @@ sealed interface OfDouble extends ValueLayout permits ValueLayouts.OfDoubleImpl } /** - * An address layout constant whose size is the same as that of a machine address ({@code size_t}), - * byte alignment set to {@code sizeof(size_t)}, byte order set to {@link ByteOrder#nativeOrder()}. + * An address layout constant whose size is the same as that of a + * machine address ({@code size_t}), byte alignment set to {@code sizeof(size_t)}, + * byte order set to {@link ByteOrder#nativeOrder()}. */ AddressLayout ADDRESS = ValueLayouts.OfAddressImpl.of(ByteOrder.nativeOrder()); @@ -455,14 +468,15 @@ sealed interface OfDouble extends ValueLayout permits ValueLayouts.OfDoubleImpl OfDouble JAVA_DOUBLE = ValueLayouts.OfDoubleImpl.of(ByteOrder.nativeOrder()); /** - * An unaligned address layout constant whose size is the same as that of a machine address ({@code size_t}), - * and byte order set to {@link ByteOrder#nativeOrder()}. + * An unaligned address layout constant whose size is the same as that of a + * machine address ({@code size_t}), and byte order set to + * {@link ByteOrder#nativeOrder()}. * Equivalent to the following code: * {@snippet lang=java : * ADDRESS.withByteAlignment(1); * } - * @apiNote Care should be taken when using unaligned value layouts as they may induce - * performance and portability issues. + * @apiNote Care should be taken when using unaligned value layouts as they may + * induce performance and portability issues. */ AddressLayout ADDRESS_UNALIGNED = ADDRESS.withByteAlignment(1); @@ -473,8 +487,8 @@ sealed interface OfDouble extends ValueLayout permits ValueLayouts.OfDoubleImpl * {@snippet lang=java : * JAVA_CHAR.withByteAlignment(1); * } - * @apiNote Care should be taken when using unaligned value layouts as they may induce - * performance and portability issues. + * @apiNote Care should be taken when using unaligned value layouts as they may + * induce performance and portability issues. */ OfChar JAVA_CHAR_UNALIGNED = JAVA_CHAR.withByteAlignment(1); @@ -485,8 +499,8 @@ sealed interface OfDouble extends ValueLayout permits ValueLayouts.OfDoubleImpl * {@snippet lang=java : * JAVA_SHORT.withByteAlignment(1); * } - * @apiNote Care should be taken when using unaligned value layouts as they may induce - * performance and portability issues. + * @apiNote Care should be taken when using unaligned value layouts as they may + * induce performance and portability issues. */ OfShort JAVA_SHORT_UNALIGNED = JAVA_SHORT.withByteAlignment(1); @@ -497,8 +511,8 @@ sealed interface OfDouble extends ValueLayout permits ValueLayouts.OfDoubleImpl * {@snippet lang=java : * JAVA_INT.withByteAlignment(1); * } - * @apiNote Care should be taken when using unaligned value layouts as they may induce - * performance and portability issues. + * @apiNote Care should be taken when using unaligned value layouts as they may + * induce performance and portability issues. */ OfInt JAVA_INT_UNALIGNED = JAVA_INT.withByteAlignment(1); @@ -509,8 +523,8 @@ sealed interface OfDouble extends ValueLayout permits ValueLayouts.OfDoubleImpl * {@snippet lang=java : * JAVA_LONG.withByteAlignment(1); * } - * @apiNote Care should be taken when using unaligned value layouts as they may induce - * performance and portability issues. + * @apiNote Care should be taken when using unaligned value layouts as they may + * induce performance and portability issues. */ OfLong JAVA_LONG_UNALIGNED = JAVA_LONG.withByteAlignment(1); @@ -521,8 +535,8 @@ sealed interface OfDouble extends ValueLayout permits ValueLayouts.OfDoubleImpl * {@snippet lang=java : * JAVA_FLOAT.withByteAlignment(1); * } - * @apiNote Care should be taken when using unaligned value layouts as they may induce - * performance and portability issues. + * @apiNote Care should be taken when using unaligned value layouts as they may + * induce performance and portability issues. */ OfFloat JAVA_FLOAT_UNALIGNED = JAVA_FLOAT.withByteAlignment(1); @@ -533,8 +547,8 @@ sealed interface OfDouble extends ValueLayout permits ValueLayouts.OfDoubleImpl * {@snippet lang=java : * JAVA_DOUBLE.withByteAlignment(1); * } - * @apiNote Care should be taken when using unaligned value layouts as they may induce - * performance and portability issues. + * @apiNote Care should be taken when using unaligned value layouts as they may + * induce performance and portability issues. */ OfDouble JAVA_DOUBLE_UNALIGNED = JAVA_DOUBLE.withByteAlignment(1); diff --git a/src/java.base/share/classes/java/lang/foreign/package-info.java b/src/java.base/share/classes/java/lang/foreign/package-info.java index bf505284cef..b2a6a5f4474 100644 --- a/src/java.base/share/classes/java/lang/foreign/package-info.java +++ b/src/java.base/share/classes/java/lang/foreign/package-info.java @@ -29,18 +29,21 @@ *

    Foreign memory access

    * *

    - * The main abstraction introduced to support foreign memory access is {@link java.lang.foreign.MemorySegment}, which - * models a contiguous region of memory, residing either inside or outside the Java heap. Memory segments are - * typically allocated using an {@link java.lang.foreign.Arena}, which controls the lifetime of the regions of memory - * backing the segments it allocates. The contents of a memory segment can be described using a - * {@link java.lang.foreign.MemoryLayout memory layout}, which provides basic operations to query sizes, offsets, and - * alignment constraints. Memory layouts also provide an alternate, more abstract way, to + * The main abstraction introduced to support foreign memory access is + * {@link java.lang.foreign.MemorySegment}, that models a contiguous region of memory, + * residing either inside or outside the Java heap. Memory segments are typically + * allocated using an {@link java.lang.foreign.Arena}, which controls the lifetime of + * the regions of memory backing the segments it allocates. The contents of a + * memory segment can be described using a {@link java.lang.foreign.MemoryLayout memory layout}, + * which provides basic operations to query sizes, offsets, and alignment constraints. + * Memory layouts also provide an alternate, more abstract way, to * access memory segments using * {@linkplain java.lang.foreign.MemoryLayout#varHandle(java.lang.foreign.MemoryLayout.PathElement...) var handles}, * which can be computed using layout paths. - * - * For example, to allocate an off-heap region of memory big enough to hold 10 values of the primitive type {@code int}, - * and fill it with values ranging from {@code 0} to {@code 9}, we can use the following code: + *

    + * For example, to allocate an off-heap region of memory big enough to hold 10 values of + * the primitive type {@code int}, and fill it with values ranging from {@code 0} to + * {@code 9}, we can use the following code: * * {@snippet lang = java: * try (Arena arena = Arena.ofConfined()) { @@ -51,38 +54,47 @@ * } * } * - * This code creates a native memory segment, that is, a memory segment backed by - * off-heap memory; the size of the segment is 40 bytes, enough to store 10 values of the primitive type {@code int}. - * The native segment is allocated using a {@linkplain java.lang.foreign.Arena#ofConfined() confined arena}. - * As such, access to the native segment is restricted to the current thread (the thread that created the arena). - * Moreover, when the arena is closed, the native segment is invalidated, and its backing region of memory is - * deallocated. Note the use of the try-with-resources construct: this idiom ensures that the off-heap region - * of memory backing the native segment will be released at the end of the block, according to the semantics described + * This code creates a native memory segment, that is, a memory segment backed + * by off-heap memory; the size of the segment is 40 bytes, enough to store 10 values of + * the primitive type {@code int}. The native segment is allocated using a + * {@linkplain java.lang.foreign.Arena#ofConfined() confined arena}. As such, access to + * the native segment is restricted to the current thread (the thread that created the + * arena). Moreover, when the arena is closed, the native segment is invalidated, and + * its backing region of memory is deallocated. Note the use of the try-with-resources + * construct: this idiom ensures that the off-heap region of memory backing the native + * segment will be released at the end of the block, according to the semantics described * in Section {@jls 14.20.3} of The Java Language Specification. *

    - * Memory segments provide strong safety guarantees when it comes to memory access. First, when accessing a memory segment, - * the access coordinates are validated (upon access), to make sure that access does not occur at any address that resides - * outside the boundaries of the memory segment used by the access operation. We call this guarantee spatial safety; - * in other words, access to memory segments is bounds-checked, in the same way as array access is, as described in + * Memory segments provide strong safety guarantees when it comes to memory access. + * First, when accessing a memory segment, the access coordinates are validated + * (upon access), to make sure that access does not occur at any address that resides + * outside the boundaries of the memory segment used by the access operation. + * We call this guarantee spatial safety; in other words, access to + * memory segments is bounds-checked, in the same way as array access is, as described in * Section {@jls 15.10.4} of The Java Language Specification. *

    - * Additionally, to prevent a region of memory from being accessed after it has been deallocated - * (i.e. use-after-free), a segment is also validated (upon access) to make sure that the arena from which it - * has been obtained has not been closed. We call this guarantee temporal safety. + * Additionally, to prevent a region of memory from being accessed after it has + * been deallocated (i.e. use-after-free), a segment is also validated + * (upon access) to make sure that the arena from which it has been obtained has not + * been closed. We call this guarantee temporal safety. *

    - * Together, spatial and temporal safety ensure that each memory access operation either succeeds - and accesses a valid - * location within the region of memory backing the memory segment - or fails. + * Together, spatial and temporal safety ensure that each memory access operation either + * succeeds - and accesses a valid location within the region of memory backing the + * memory segment - or fails. * *

    Foreign function access

    - * The key abstractions introduced to support foreign function access are {@link java.lang.foreign.SymbolLookup}, - * {@link java.lang.foreign.FunctionDescriptor} and {@link java.lang.foreign.Linker}. The first is used to look up symbols - * inside libraries; the second is used to model the signature of foreign functions, while the third is used - * to link foreign functions as {@link java.lang.invoke.MethodHandle} instances, - * so that clients can perform foreign function calls directly in Java, without the need for intermediate layers of C/C++ - * code (as is the case with the Java Native Interface (JNI)). + * + * The key abstractions introduced to support foreign function access are + * {@link java.lang.foreign.SymbolLookup}, {@link java.lang.foreign.FunctionDescriptor} and + * {@link java.lang.foreign.Linker}. The first is used to look up symbols inside + * libraries; the second is used to model the signature of foreign functions, while the + * third is used to link foreign functions as {@link java.lang.invoke.MethodHandle} + * instances, so that clients can perform foreign function calls directly in Java, + * without the need for intermediate layers of C/C++ code (as is the case with the + * Java Native Interface (JNI)). *

    - * 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: + * For example, to compute the length of a string using the C standard library function + * {@code strlen} on a Linux/x64 platform, we can use the following code: * * {@snippet lang = java: * Linker linker = Linker.nativeLinker(); @@ -98,52 +110,65 @@ * } *} * - * Here, we obtain a {@linkplain java.lang.foreign.Linker#nativeLinker() native linker} and we use it - * to {@linkplain java.lang.foreign.SymbolLookup#find(java.lang.String) look up} the {@code strlen} function in the - * standard C library; a downcall method handle targeting said function is subsequently + * Here, we obtain a {@linkplain java.lang.foreign.Linker#nativeLinker() native linker} + * and we use it to {@linkplain java.lang.foreign.SymbolLookup#find(java.lang.String) look up} + * the {@code strlen} function in the standard C library; a downcall method handle + * targeting said function is subsequently * {@linkplain java.lang.foreign.Linker#downcallHandle(FunctionDescriptor, Linker.Option...) obtained}. - * To complete the linking successfully, we must provide a {@link java.lang.foreign.FunctionDescriptor} instance, - * describing the signature of the {@code strlen} function. - * From this information, the linker will uniquely determine the sequence of steps which will turn - * the method handle invocation (here performed using {@link java.lang.invoke.MethodHandle#invokeExact(java.lang.Object...)}) - * into a foreign function call, according to the rules specified by the ABI of the underlying platform. + * To complete the linking successfully, we must provide a + * {@link java.lang.foreign.FunctionDescriptor} instance, describing the signature of the + * {@code strlen} function. From this information, the linker will uniquely determine + * the sequence of steps which will turn the method handle invocation (here performed + * using {@link java.lang.invoke.MethodHandle#invokeExact(java.lang.Object...)}) + * into a foreign function call, according to the rules specified by the ABI of the + * underlying platform. + *

    * The {@link java.lang.foreign.Arena} class also provides many useful methods for * interacting with foreign code, such as - * {@linkplain java.lang.foreign.SegmentAllocator#allocateFrom(java.lang.String) converting} Java strings into - * zero-terminated, UTF-8 strings, as demonstrated in the above example. + * {@linkplain java.lang.foreign.SegmentAllocator#allocateFrom(java.lang.String) converting} + * Java strings into zero-terminated, UTF-8 strings, as demonstrated in the above example. * *

    Restricted methods

    - * Some methods in this package are considered restricted. Restricted methods are typically used to bind native - * foreign data and/or functions to first-class Java API elements which can then be used directly by clients. For instance - * the restricted method {@link java.lang.foreign.MemorySegment#reinterpret(long)} - * can be used to create a fresh segment with the same address and temporal bounds, - * but with the provided size. This can be useful to resize memory segments obtained when interacting with native functions. + * + * Some methods in this package are considered restricted. Restricted methods + * are typically used to bind native foreign data and/or functions to first-class + * Java API elements which can then be used directly by clients. For instance the + * restricted method {@link java.lang.foreign.MemorySegment#reinterpret(long)} can be + * used to create a fresh segment with the same address and temporal bounds, but with + * the provided size. This can be useful to resize memory segments obtained when + * interacting with native functions. *

    - * 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, incorrectly resizing a native - * memory segment using {@link java.lang.foreign.MemorySegment#reinterpret(long)} can lead to a JVM crash, or, worse, - * lead to silent memory corruption when attempting to access the resized 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. + * 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, incorrectly resizing a native memory segment using + * {@link java.lang.foreign.MemorySegment#reinterpret(long)} can lead to a JVM crash, or, + * worse, lead to silent memory corruption when attempting to access the resized 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. *

    - * Given the potential danger of restricted methods, the Java runtime issues a warning on the standard error stream - * every time a restricted method is invoked. Such warnings can be disabled by granting access to restricted methods - * to selected modules. This can be done either via implementation-specific command line options or programmatically, e.g. by calling - * {@link java.lang.ModuleLayer.Controller#enableNativeAccess(java.lang.Module)}. + * Given the potential danger of restricted methods, the Java runtime issues a warning on + * the standard error stream every time a restricted method is invoked. Such warnings can + * be disabled by granting access to restricted methods to selected modules. This can be + * done either via implementation-specific command line options or programmatically, e.g. + * by calling {@link java.lang.ModuleLayer.Controller#enableNativeAccess(java.lang.Module)}. *

    - * 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. + * For every class in this package, unless specified otherwise, any method arguments of + * reference type must not be {@code null}, and any null argument will elicit a + * {@code NullPointerException}. This fact is not individually documented for methods of + * this API. * - * @apiNote Usual memory model guarantees (see {@jls 17.4}) do not apply when accessing native memory segments as - * these segments are backed by off-heap regions of memory. + * @apiNote Usual memory model guarantees (see {@jls 17.4}) do not apply when accessing + * native memory segments as these segments are backed by off-heap regions of memory. * * @implNote - * In the reference implementation, access to restricted methods can be granted to specific modules using the command line option - * {@code --enable-native-access=M1,M2, ... Mn}, where {@code M1}, {@code M2}, {@code ... Mn} are module names - * (for the unnamed module, the special value {@code ALL-UNNAMED} can be used). If this option is specified, access to - * restricted methods are 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. + * In the reference implementation, access to restricted methods can be granted to + * specific modules using the command line option {@code --enable-native-access=M1,M2, ... Mn}, + * where {@code M1}, {@code M2}, {@code ... Mn} are module names (for the unnamed module, + * the special value {@code ALL-UNNAMED} can be used). If this option is specified, + * access to restricted methods are 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. * * @spec jni/index.html Java Native Interface Specification * diff --git a/src/java.base/share/classes/java/nio/channels/FileChannel.java b/src/java.base/share/classes/java/nio/channels/FileChannel.java index f785b2290cb..95151293430 100644 --- a/src/java.base/share/classes/java/nio/channels/FileChannel.java +++ b/src/java.base/share/classes/java/nio/channels/FileChannel.java @@ -1045,48 +1045,48 @@ public abstract MappedByteBuffer map(MapMode mode, long position, long size) * 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()}). + * 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. + * mapped segment is to start * * @param size * The size (in bytes) of the mapped memory backing the memory - * segment. + * segment * * @param arena - * The segment arena. + * The segment arena * - * @return A new mapped memory segment. + * @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}. + * {@code offset + size} overflows the range of {@code long} * * @throws IllegalStateException - * If {@code arena.isAlive() == false}. + * If {@code arena.isAlive() == false} * * @throws WrongThreadException - * If {@code arena} is a confined scoped arena, and this method is called from a - * thread {@code T}, other than the scoped arena's owner thread. + * If {@code arena} is a confined scoped arena, and this method is called + * from a thread {@code T}, other than the scoped arena's owner thread * * @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. + * 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. + * opened for both reading and writing * * @throws IOException - * If some other I/O error occurs. + * If some other I/O error occurs * * @throws UnsupportedOperationException - * If an unsupported map mode is specified. + * If an unsupported map mode is specified * * @since 22 */ From c6cd90f4aed8824048744e0e64c7f47f02ca08d1 Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Thu, 9 Nov 2023 15:58:54 +0000 Subject: [PATCH 6/9] 8319705: RISC-V: signumF/D intrinsics fails compiler/intrinsics/math/TestSignumIntrinsic.java Reviewed-by: fyang, vkempik --- .../jtreg/compiler/intrinsics/math/TestSignumIntrinsic.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/hotspot/jtreg/compiler/intrinsics/math/TestSignumIntrinsic.java b/test/hotspot/jtreg/compiler/intrinsics/math/TestSignumIntrinsic.java index 65d261bb8e2..a5546ba9e5c 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/math/TestSignumIntrinsic.java +++ b/test/hotspot/jtreg/compiler/intrinsics/math/TestSignumIntrinsic.java @@ -35,6 +35,10 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions * -XX:-UseSignumIntrinsic -XX:+UseCopySignIntrinsic * compiler.intrinsics.math.TestSignumIntrinsic + * @run main/othervm + * -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions + * -Xcomp -XX:+UseSignumIntrinsic + * compiler.intrinsics.math.TestSignumIntrinsic */ package compiler.intrinsics.math; From 4375a0a71adbef914b4cc27deac3abfb25d29867 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Thu, 9 Nov 2023 16:21:42 +0000 Subject: [PATCH 7/9] 8319574: Exec/process tests should be marked as flagless Reviewed-by: bpb, naoto, jpai --- test/jdk/java/lang/ProcessBuilder/Basic.java | 3 ++- test/jdk/java/lang/ProcessBuilder/InheritIOTest.java | 1 + test/jdk/java/lang/ProcessBuilder/JspawnhelperProtocol.java | 1 + .../jdk/java/lang/ProcessBuilder/ProcessStartLoggingTest.java | 1 + test/jdk/java/lang/ProcessBuilder/ReaderWriterTest.java | 1 + test/jdk/java/lang/ProcessBuilder/SkipTest.java | 3 ++- test/jdk/java/lang/ProcessHandle/OnExitTest.java | 3 ++- test/jdk/java/lang/ProcessHandle/TreeTest.java | 1 + test/jdk/java/lang/RuntimeTests/RuntimeExitLogTest.java | 1 + .../lang/RuntimeTests/exec/ArgWithSpaceAndFinalBackslash.java | 3 ++- test/jdk/java/lang/RuntimeTests/exec/Duped.java | 3 ++- test/jdk/java/lang/RuntimeTests/exec/ExecWithLotsOfArgs.java | 3 ++- test/jdk/java/lang/RuntimeTests/exec/ExitValue.java | 3 ++- test/jdk/java/lang/RuntimeTests/exec/SetCwd.java | 4 ++-- 14 files changed, 22 insertions(+), 9 deletions(-) diff --git a/test/jdk/java/lang/ProcessBuilder/Basic.java b/test/jdk/java/lang/ProcessBuilder/Basic.java index 532dde18fe4..382df89050c 100644 --- a/test/jdk/java/lang/ProcessBuilder/Basic.java +++ b/test/jdk/java/lang/ProcessBuilder/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, 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 @@ -34,6 +34,7 @@ * java.base/java.io:open * java.base/jdk.internal.misc * @requires !vm.musl + * @requires vm.flagless * @library /test/lib * @run main/othervm/native/timeout=300 -Djava.security.manager=allow Basic * @run main/othervm/native/timeout=300 -Djava.security.manager=allow -Djdk.lang.Process.launchMechanism=fork Basic diff --git a/test/jdk/java/lang/ProcessBuilder/InheritIOTest.java b/test/jdk/java/lang/ProcessBuilder/InheritIOTest.java index f1c1940f538..a372eeefbf8 100644 --- a/test/jdk/java/lang/ProcessBuilder/InheritIOTest.java +++ b/test/jdk/java/lang/ProcessBuilder/InheritIOTest.java @@ -25,6 +25,7 @@ * @test * @bug 8023130 8166026 * @summary Unit test for java.lang.ProcessBuilder inheritance of standard output and standard error streams + * @requires vm.flagless * @library /test/lib * @build jdk.test.lib.process.* * @run testng InheritIOTest diff --git a/test/jdk/java/lang/ProcessBuilder/JspawnhelperProtocol.java b/test/jdk/java/lang/ProcessBuilder/JspawnhelperProtocol.java index 00543b09947..1949571cca7 100644 --- a/test/jdk/java/lang/ProcessBuilder/JspawnhelperProtocol.java +++ b/test/jdk/java/lang/ProcessBuilder/JspawnhelperProtocol.java @@ -27,6 +27,7 @@ * @bug 8307990 * @requires (os.family == "linux") | (os.family == "aix") * @requires vm.debug + * @requires vm.flagless * @library /test/lib * @run main/othervm/timeout=300 JspawnhelperProtocol */ diff --git a/test/jdk/java/lang/ProcessBuilder/ProcessStartLoggingTest.java b/test/jdk/java/lang/ProcessBuilder/ProcessStartLoggingTest.java index e33ec0bc69a..e9b2fa6b264 100644 --- a/test/jdk/java/lang/ProcessBuilder/ProcessStartLoggingTest.java +++ b/test/jdk/java/lang/ProcessBuilder/ProcessStartLoggingTest.java @@ -40,6 +40,7 @@ /* * @test * @summary verify logging of ProcessBuilder.start() + * @requires vm.flagless * @run junit/othervm ProcessStartLoggingTest */ public class ProcessStartLoggingTest { diff --git a/test/jdk/java/lang/ProcessBuilder/ReaderWriterTest.java b/test/jdk/java/lang/ProcessBuilder/ReaderWriterTest.java index 3768b34ea53..a73451417bf 100644 --- a/test/jdk/java/lang/ProcessBuilder/ReaderWriterTest.java +++ b/test/jdk/java/lang/ProcessBuilder/ReaderWriterTest.java @@ -49,6 +49,7 @@ /* * @test + * @requires vm.flagless * @library /test/lib * @build jdk.test.lib.process.ProcessTools jdk.test.lib.hexdump.HexPrinter * @run testng ReaderWriterTest diff --git a/test/jdk/java/lang/ProcessBuilder/SkipTest.java b/test/jdk/java/lang/ProcessBuilder/SkipTest.java index 329e3a1affb..cad2adaa6fe 100644 --- a/test/jdk/java/lang/ProcessBuilder/SkipTest.java +++ b/test/jdk/java/lang/ProcessBuilder/SkipTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /* * @test * @bug 8155808 + * @requires vm.flagless * @run main SkipTest * @summary verify skip method of Process Input Stream */ diff --git a/test/jdk/java/lang/ProcessHandle/OnExitTest.java b/test/jdk/java/lang/ProcessHandle/OnExitTest.java index 98133e7bfbb..b75775b51a2 100644 --- a/test/jdk/java/lang/ProcessHandle/OnExitTest.java +++ b/test/jdk/java/lang/ProcessHandle/OnExitTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2023, 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 @@ -40,6 +40,7 @@ /* * @test + * @requires vm.flagless * @library /test/lib * @modules jdk.management * @build jdk.test.lib.Utils diff --git a/test/jdk/java/lang/ProcessHandle/TreeTest.java b/test/jdk/java/lang/ProcessHandle/TreeTest.java index 1fe1f10cb38..cec880f1fef 100644 --- a/test/jdk/java/lang/ProcessHandle/TreeTest.java +++ b/test/jdk/java/lang/ProcessHandle/TreeTest.java @@ -44,6 +44,7 @@ /* * @test + * @requires vm.flagless * @library /test/lib * @modules java.base/jdk.internal.misc * jdk.management diff --git a/test/jdk/java/lang/RuntimeTests/RuntimeExitLogTest.java b/test/jdk/java/lang/RuntimeTests/RuntimeExitLogTest.java index e552dcb7bef..da40cdbd742 100644 --- a/test/jdk/java/lang/RuntimeTests/RuntimeExitLogTest.java +++ b/test/jdk/java/lang/RuntimeTests/RuntimeExitLogTest.java @@ -41,6 +41,7 @@ /* * @test * @summary verify logging of call to System.exit or Runtime.exit. + * @requires vm.flagless * @run junit/othervm RuntimeExitLogTest */ diff --git a/test/jdk/java/lang/RuntimeTests/exec/ArgWithSpaceAndFinalBackslash.java b/test/jdk/java/lang/RuntimeTests/exec/ArgWithSpaceAndFinalBackslash.java index ed74576abbd..c5edf6c1212 100644 --- a/test/jdk/java/lang/RuntimeTests/exec/ArgWithSpaceAndFinalBackslash.java +++ b/test/jdk/java/lang/RuntimeTests/exec/ArgWithSpaceAndFinalBackslash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ * @bug 4794652 * @summary Ensure that a command argument that contains a space and a final * backslash is handled correctly + * @requires vm.flagless */ import java.io.*; diff --git a/test/jdk/java/lang/RuntimeTests/exec/Duped.java b/test/jdk/java/lang/RuntimeTests/exec/Duped.java index d86fbdae124..f2e29cf0e04 100644 --- a/test/jdk/java/lang/RuntimeTests/exec/Duped.java +++ b/test/jdk/java/lang/RuntimeTests/exec/Duped.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /* @test @bug 4180429 @summary Lossage in dup2 if System.in is closed. + @requires vm.flagless @run main/othervm Duped */ diff --git a/test/jdk/java/lang/RuntimeTests/exec/ExecWithLotsOfArgs.java b/test/jdk/java/lang/RuntimeTests/exec/ExecWithLotsOfArgs.java index 26267e0d6ab..454e468ce26 100644 --- a/test/jdk/java/lang/RuntimeTests/exec/ExecWithLotsOfArgs.java +++ b/test/jdk/java/lang/RuntimeTests/exec/ExecWithLotsOfArgs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ @bug 4033560 @summary 4033560 limited args of exec to 198 on Solaris. We check that we can actually exec more args than that. + @requires vm.flagless @author Anand Palaniswamy @run main/othervm ExecWithLotsOfArgs */ diff --git a/test/jdk/java/lang/RuntimeTests/exec/ExitValue.java b/test/jdk/java/lang/RuntimeTests/exec/ExitValue.java index 03f56240cd4..96b6ed9d5f9 100644 --- a/test/jdk/java/lang/RuntimeTests/exec/ExitValue.java +++ b/test/jdk/java/lang/RuntimeTests/exec/ExitValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ * @test * @bug 4680945 4873419 * @summary Check process exit code + * @requires vm.flagless * @author kladko, Martin Buchholz */ diff --git a/test/jdk/java/lang/RuntimeTests/exec/SetCwd.java b/test/jdk/java/lang/RuntimeTests/exec/SetCwd.java index a457b48b5e5..0749847a9d7 100644 --- a/test/jdk/java/lang/RuntimeTests/exec/SetCwd.java +++ b/test/jdk/java/lang/RuntimeTests/exec/SetCwd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ * @summary Basic functional test for * Runtime.exec(String[] command, String[] env, File path) and * Runtime.exec(String command, String[] env, File path). - * + * @requires vm.flagless * @library /test/lib * @run testng/othervm SetCwd */ From e8d78b4d7b6f64cd5f6a7774b31fd6020f5eb938 Mon Sep 17 00:00:00 2001 From: Xin Liu Date: Thu, 9 Nov 2023 17:52:08 +0000 Subject: [PATCH 8/9] 8319554: Select LogOutput* directly for stdout and stderr Reviewed-by: jsjolen, dholmes --- test/hotspot/gtest/logging/test_asynclog.cpp | 46 ++++++++++++-------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/test/hotspot/gtest/logging/test_asynclog.cpp b/test/hotspot/gtest/logging/test_asynclog.cpp index 216cc320d38..89a1d6fef8a 100644 --- a/test/hotspot/gtest/logging/test_asynclog.cpp +++ b/test/hotspot/gtest/logging/test_asynclog.cpp @@ -256,7 +256,10 @@ TEST_VM_F(AsyncLogTest, droppingMessage) { TEST_VM_F(AsyncLogTest, stdoutOutput) { testing::internal::CaptureStdout(); fprintf(stdout, "header"); - set_log_config("stdout", "logging=debug"); + + if (!set_log_config("stdout", "logging=debug")) { + return; + } test_asynclog_ls(); test_asynclog_drop_messages(); @@ -264,22 +267,27 @@ TEST_VM_F(AsyncLogTest, stdoutOutput) { AsyncLogWriter::flush(); fflush(nullptr); - if (write_to_file(testing::internal::GetCapturedStdout())) { - EXPECT_TRUE(file_contains_substring(TestLogFileName, "header")); - EXPECT_TRUE(file_contains_substring(TestLogFileName, "LogStreamWithAsyncLogImpl")); - EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream msg1-msg2-msg3")); - EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream newline")); + if (!write_to_file(testing::internal::GetCapturedStdout())) { + return; + } - if (AsyncLogWriter::instance() != nullptr) { - EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging")); - } + EXPECT_TRUE(file_contains_substring(TestLogFileName, "header")); + EXPECT_TRUE(file_contains_substring(TestLogFileName, "LogStreamWithAsyncLogImpl")); + EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream msg1-msg2-msg3")); + EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream newline")); + + if (AsyncLogWriter::instance() != nullptr) { + EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging")); } } TEST_VM_F(AsyncLogTest, stderrOutput) { testing::internal::CaptureStderr(); fprintf(stderr, "header"); - set_log_config("stderr", "logging=debug"); + + if (!set_log_config("stderr", "logging=debug")) { + return; + } test_asynclog_ls(); test_asynclog_drop_messages(); @@ -287,14 +295,16 @@ TEST_VM_F(AsyncLogTest, stderrOutput) { AsyncLogWriter::flush(); fflush(nullptr); - if (write_to_file(testing::internal::GetCapturedStderr())) { - EXPECT_TRUE(file_contains_substring(TestLogFileName, "header")); - EXPECT_TRUE(file_contains_substring(TestLogFileName, "LogStreamWithAsyncLogImpl")); - EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream msg1-msg2-msg3")); - EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream newline")); + if (!write_to_file(testing::internal::GetCapturedStderr())) { + return; + } - if (AsyncLogWriter::instance() != nullptr) { - EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging")); - } + EXPECT_TRUE(file_contains_substring(TestLogFileName, "header")); + EXPECT_TRUE(file_contains_substring(TestLogFileName, "LogStreamWithAsyncLogImpl")); + EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream msg1-msg2-msg3")); + EXPECT_TRUE(file_contains_substring(TestLogFileName, "logStream newline")); + + if (AsyncLogWriter::instance() != nullptr) { + EXPECT_TRUE(file_contains_substring(TestLogFileName, "messages dropped due to async logging")); } } From 782befddd3f7c5cd8f2f6b099e4a2a1129408b53 Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Thu, 9 Nov 2023 20:21:15 +0000 Subject: [PATCH 9/9] 8319670: Improve comments describing system properties for TLS server and client for max chain length Reviewed-by: mullan --- .../sun/security/ssl/SSLConfiguration.java | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java b/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java index 65f2099287f..fcf93704ef9 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java @@ -138,7 +138,10 @@ final class SSLConfiguration implements Cloneable { static { boolean globalPropSet = false; - // jdk.tls.maxCertificateChainLength property has no default + /* + * jdk.tls.maxCertificateChainLength system property works for both + * server and client modes. + */ Integer maxCertificateChainLength = GetIntegerAction.privilegedGetProperty( "jdk.tls.maxCertificateChainLength"); if (maxCertificateChainLength != null && maxCertificateChainLength >= 0) { @@ -146,20 +149,15 @@ final class SSLConfiguration implements Cloneable { } /* - * If either jdk.tls.server.maxInboundCertificateChainLength or - * jdk.tls.client.maxInboundCertificateChainLength is set, it will - * override jdk.tls.maxCertificateChainLength, regardless of whether - * jdk.tls.maxCertificateChainLength is set or not. - * If neither jdk.tls.server.maxInboundCertificateChainLength nor - * jdk.tls.client.maxInboundCertificateChainLength is set, the behavior - * depends on the setting of jdk.tls.maxCertificateChainLength. If - * jdk.tls.maxCertificateChainLength is set, it falls back to that - * value; otherwise, it defaults to 8 for - * jdk.tls.server.maxInboundCertificateChainLength - * and 10 for jdk.tls.client.maxInboundCertificateChainLength. - * Users can independently set either - * jdk.tls.server.maxInboundCertificateChainLength or - * jdk.tls.client.maxInboundCertificateChainLength. + * jdk.tls.server.maxInboundCertificateChainLength system property + * works in server mode. + * maxInboundClientCertChainLen is the maximum length of a client + * certificate chain accepted by a server. It is determined as follows: + * - If the jdk.tls.server.maxInboundCertificateChainLength system + * property is set and its value >= 0, it uses that value. + * - Otherwise, if the jdk.tls.maxCertificateChainLength system + * property is set and its value >= 0, it uses that value. + * - Otherwise it is set to a default value of 8. */ Integer inboundClientLen = GetIntegerAction.privilegedGetProperty( "jdk.tls.server.maxInboundCertificateChainLength"); @@ -172,6 +170,17 @@ final class SSLConfiguration implements Cloneable { maxInboundClientCertChainLen = inboundClientLen; } + /* + * jdk.tls.client.maxInboundCertificateChainLength system property + * works in client mode. + * maxInboundServerCertChainLen is the maximum length of a server + * certificate chain accepted by a client. It is determined as follows: + * - If the jdk.tls.client.maxInboundCertificateChainLength system + * property is set and its value >= 0, it uses that value. + * - Otherwise, if the jdk.tls.maxCertificateChainLength system + * property is set and its value >= 0, it uses that value. + * - Otherwise it is set to a default value of 10. + */ Integer inboundServerLen = GetIntegerAction.privilegedGetProperty( "jdk.tls.client.maxInboundCertificateChainLength");