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 a1da55b8c0e..11633df2ce7 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -1734,6 +1734,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds of the * memory segment. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. + * @throws UnsupportedOperationException if {@code value} is not a {@linkplain #isNative() native} segment. */ @ForceInline default void set(ValueLayout.OfAddress layout, long offset, MemorySegment value) { @@ -2079,6 +2080,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * @throws IndexOutOfBoundsException when the access operation falls outside the spatial bounds of the * memory segment. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. + * @throws UnsupportedOperationException if {@code value} is not a {@linkplain #isNative() native} segment. */ @ForceInline default void setAtIndex(ValueLayout.OfAddress layout, long index, MemorySegment value) { diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index a63f53d3ca1..4c901afefb1 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -7931,8 +7931,11 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum")); * {@code get} and {@code set} access modes will result in an {@code IllegalStateException}. If access is partially aligned, * atomic access is only guaranteed with respect to the largest power of two that divides the GCD of {@code A} and {@code S}. *

- * Finally, in all other cases, we say that a memory access operation is misaligned; in such cases an + * In all other cases, we say that a memory access operation is misaligned; in such cases an * {@code IllegalStateException} is thrown, irrespective of the access mode being used. + *

+ * Finally, if {@code T} is {@code MemorySegment} all write access modes throw {@link IllegalArgumentException} + * unless the value to be written is a {@linkplain MemorySegment#isNative() native} memory segment. * * @param layout the value layout for which a memory access handle is to be obtained. * @return the new memory segment view var handle. diff --git a/src/java.base/share/classes/jdk/internal/foreign/Utils.java b/src/java.base/share/classes/jdk/internal/foreign/Utils.java index f00c49bb442..facde705729 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/Utils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/Utils.java @@ -38,6 +38,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; import jdk.internal.access.SharedSecrets; +import jdk.internal.foreign.abi.SharedUtils; import jdk.internal.vm.annotation.ForceInline; import static java.lang.foreign.ValueLayout.JAVA_BYTE; @@ -62,8 +63,8 @@ public final class Utils { MethodType.methodType(boolean.class, byte.class)); BOOL_TO_BYTE = lookup.findStatic(Utils.class, "booleanToByte", MethodType.methodType(byte.class, boolean.class)); - ADDRESS_TO_LONG = lookup.findVirtual(MemorySegment.class, "address", - MethodType.methodType(long.class)); + ADDRESS_TO_LONG = lookup.findStatic(SharedUtils.class, "unboxSegment", + MethodType.methodType(long.class, MemorySegment.class)); LONG_TO_ADDRESS_SAFE = lookup.findStatic(Utils.class, "longToAddressSafe", MethodType.methodType(MemorySegment.class, long.class)); LONG_TO_ADDRESS_UNSAFE = lookup.findStatic(Utils.class, "longToAddressUnsafe", diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java b/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java index 77e4e05659d..fb25a18a92d 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java @@ -259,7 +259,7 @@ public final class SharedUtils { } } - static long unboxSegment(MemorySegment segment) { + public static long unboxSegment(MemorySegment segment) { if (!segment.isNative()) { throw new IllegalArgumentException("Heap segment not allowed: " + segment); } diff --git a/test/jdk/java/foreign/TestMemoryAccessInstance.java b/test/jdk/java/foreign/TestMemoryAccessInstance.java index d2a8ba14f9c..e80c170ca65 100644 --- a/test/jdk/java/foreign/TestMemoryAccessInstance.java +++ b/test/jdk/java/foreign/TestMemoryAccessInstance.java @@ -29,6 +29,7 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; +import java.lang.foreign.SegmentScope; import java.lang.foreign.ValueLayout; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -132,6 +133,22 @@ public class TestMemoryAccessInstance { } } + @Test(expectedExceptions = IllegalArgumentException.class, + expectedExceptionsMessageRegExp = ".*Heap segment not allowed.*") + public void badHeapSegmentSet() { + MemorySegment targetSegment = MemorySegment.allocateNative(ValueLayout.ADDRESS.byteSize(), SegmentScope.auto()); + MemorySegment segment = MemorySegment.ofArray(new byte[]{ 0, 1, 2 }); + targetSegment.set(ValueLayout.ADDRESS, 0, segment); // should throw + } + + @Test(expectedExceptions = IllegalArgumentException.class, + expectedExceptionsMessageRegExp = ".*Heap segment not allowed.*") + public void badHeapSegmentSetAtIndex() { + MemorySegment targetSegment = MemorySegment.allocateNative(ValueLayout.ADDRESS.byteSize(), SegmentScope.auto()); + MemorySegment segment = MemorySegment.ofArray(new byte[]{ 0, 1, 2 }); + targetSegment.setAtIndex(ValueLayout.ADDRESS, 0, segment); // should throw + } + static final ByteOrder NE = ByteOrder.nativeOrder(); @DataProvider(name = "segmentAccessors")