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 aa1f1762aec..83a8b09f9d4 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -633,6 +633,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * asSlice(offset, newSize, 1); * } *

+ * If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, + * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. + *

* The returned memory segment shares a region of backing memory with this segment. * Hence, no memory will be allocated or freed by this method. * @@ -652,6 +655,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * 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. *

+ * If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, + * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. + *

* The returned memory segment shares a region of backing memory with this segment. * Hence, no memory will be allocated or freed by this method. * @@ -679,6 +685,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * asSlice(offset, layout.byteSize(), layout.byteAlignment()); * } *

+ * If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, + * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. + *

* The returned memory segment shares a region of backing memory with this segment. * Hence, no memory will be allocated or freed by this method. * @@ -705,6 +714,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * asSlice(offset, byteSize() - offset); * } *

+ * If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, + * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. + *

* The returned memory segment shares a region of backing memory with this segment. * Hence, no memory will be allocated or freed by this method. * @@ -721,6 +733,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * Returns a new memory segment that has the same address and scope as this segment, * but with the provided size. *

+ * If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, + * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. + *

* The returned memory segment shares a region of backing memory with this segment. * Hence, no memory will be allocated or freed by this method. * @@ -759,6 +774,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * scope, and is accessible from any thread. The size of the segment accepted by the * cleanup action is {@link #byteSize()}. *

+ * If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, + * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. + *

* The returned memory segment shares a region of backing memory with this segment. * Hence, no memory will be allocated or freed by this method. * @@ -807,6 +825,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * scope, and is accessible from any thread. The size of the segment accepted by the * cleanup action is {@code newSize}. *

+ * If this segment is {@linkplain MemorySegment#isReadOnly() read-only}, + * the returned segment is also {@linkplain MemorySegment#isReadOnly() read-only}. + *

* The returned memory segment shares a region of backing memory with this segment. * Hence, no memory will be allocated or freed by this method. * diff --git a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java index f9f6ac2022a..325dbe1093f 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -159,7 +159,7 @@ public abstract sealed class AbstractMemorySegmentImpl () -> cleanup.accept(SegmentFactories.makeNativeSegmentUnchecked(address(), newSize)) : null; return SegmentFactories.makeNativeSegmentUnchecked(address(), newSize, - (MemorySessionImpl)scope, action); + (MemorySessionImpl)scope, readOnly, action); } private AbstractMemorySegmentImpl asSliceNoCheck(long offset, long newSize) { diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java index 17f141b4e8c..133631e2aa4 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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 @@ -57,14 +57,18 @@ public class SegmentFactories { // associated with MemorySegment::ofAddress. @ForceInline - public static MemorySegment makeNativeSegmentUnchecked(long min, long byteSize, MemorySessionImpl sessionImpl, Runnable action) { + public static MemorySegment makeNativeSegmentUnchecked(long min, + long byteSize, + MemorySessionImpl sessionImpl, + boolean readOnly, + Runnable action) { ensureInitialized(); if (action == null) { sessionImpl.checkValidState(); } else { sessionImpl.addCloseAction(action); } - return new NativeMemorySegmentImpl(min, byteSize, false, sessionImpl); + return new NativeMemorySegmentImpl(min, byteSize, readOnly, sessionImpl); } @ForceInline diff --git a/test/jdk/java/foreign/TestSegments.java b/test/jdk/java/foreign/TestSegments.java index 44ecd12ba5e..b361abac3df 100644 --- a/test/jdk/java/foreign/TestSegments.java +++ b/test/jdk/java/foreign/TestSegments.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -43,7 +43,6 @@ import java.util.function.IntFunction; import java.util.function.Supplier; import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; import static org.testng.Assert.*; public class TestSegments { @@ -383,9 +382,14 @@ public class TestSegments { assertEquals(MemorySegment.ofAddress(42).reinterpret(100, Arena.ofAuto(), null).byteSize(), 100); // check scope and cleanup assertEquals(MemorySegment.ofAddress(42).reinterpret(100, arena, s -> counter.incrementAndGet()).scope(), arena.scope()); - assertEquals(MemorySegment.ofAddress(42).reinterpret(arena, s -> counter.incrementAndGet()).scope(), arena.scope()); + assertEquals(MemorySegment.ofAddress(42).reinterpret(arena, _ -> counter.incrementAndGet()).scope(), arena.scope()); + // check read-only state + assertFalse(MemorySegment.ofAddress(42).reinterpret(100).isReadOnly()); + assertTrue(MemorySegment.ofAddress(42).asReadOnly().reinterpret(100).isReadOnly()); + assertTrue(MemorySegment.ofAddress(42).asReadOnly().reinterpret(100, Arena.ofAuto(), null).isReadOnly()); + assertTrue(MemorySegment.ofAddress(42).asReadOnly().reinterpret(arena, _ -> counter.incrementAndGet()).isReadOnly()); } - assertEquals(counter.get(), 2); + assertEquals(counter.get(), 3); } @Test