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 321d9b09bad..8a2b3b4df30 100644
--- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
+++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java
@@ -1016,7 +1016,7 @@ public sealed interface MemoryLayout
* @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}
*/
static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) {
- MemoryLayoutUtil.requireNonNegative(elementCount);
+ Utils.checkNonNegativeArgument(elementCount, "elementCount");
Objects.requireNonNull(elementLayout);
Utils.checkElementAlignment(elementLayout,
"Element layout size is not multiple of alignment");
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 da255b9912b..faf28b01bf0 100644
--- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java
+++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java
@@ -44,6 +44,7 @@ import java.util.stream.Stream;
import jdk.internal.foreign.AbstractMemorySegmentImpl;
import jdk.internal.foreign.MemorySessionImpl;
import jdk.internal.foreign.SegmentFactories;
+import jdk.internal.foreign.Utils;
import jdk.internal.javac.Restricted;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.vm.annotation.ForceInline;
@@ -1591,6 +1592,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
*/
byte get(ValueLayout.OfByte layout, long offset);
@@ -1609,6 +1611,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
@@ -1629,6 +1632,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
*/
boolean get(ValueLayout.OfBoolean layout, long offset);
@@ -1647,6 +1651,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
@@ -1667,6 +1672,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
*/
char get(ValueLayout.OfChar layout, long offset);
@@ -1685,6 +1691,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
@@ -1705,6 +1712,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
*/
short get(ValueLayout.OfShort layout, long offset);
@@ -1723,6 +1731,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
@@ -1743,6 +1752,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
*/
int get(ValueLayout.OfInt layout, long offset);
@@ -1761,6 +1771,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
@@ -1781,6 +1792,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
*/
float get(ValueLayout.OfFloat layout, long offset);
@@ -1799,6 +1811,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
@@ -1819,6 +1832,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
*/
long get(ValueLayout.OfLong layout, long offset);
@@ -1837,6 +1851,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
@@ -1857,6 +1872,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
*/
double get(ValueLayout.OfDouble layout, long offset);
@@ -1875,6 +1891,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in the provided layout
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
*/
@@ -1905,6 +1922,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* incompatible with the alignment constraint
* in {@code T}
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}
+ * or {@code offset < 0}
*/
MemorySegment get(AddressLayout layout, long offset);
@@ -1923,8 +1941,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* 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}
+ * or {@code offset < 0}
* @throws IllegalArgumentException if {@code value} is not a
* {@linkplain #isNative() native} segment
* @throws IllegalArgumentException if this segment is
@@ -1951,6 +1968,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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()}
+ * or {@code index < 0}
*/
byte getAtIndex(ValueLayout.OfByte layout, long index);
@@ -1973,6 +1991,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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()}
+ * or {@code index < 0}
*/
boolean getAtIndex(ValueLayout.OfBoolean layout, long index);
@@ -1995,6 +2014,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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()}
+ * or {@code index < 0}
*/
char getAtIndex(ValueLayout.OfChar layout, long index);
@@ -2017,7 +2037,8 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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}
+ * or {@code index < 0}
+ * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfChar layout, long index, char value);
@@ -2040,6 +2061,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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()}
+ * or {@code index < 0}
*/
short getAtIndex(ValueLayout.OfShort layout, long index);
@@ -2061,6 +2083,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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()}
+ * or {@code index < 0}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfByte layout, long index, byte value);
@@ -2084,6 +2107,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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()}
+ * or {@code index < 0}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfBoolean layout, long index, boolean value);
@@ -2107,6 +2131,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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()}
+ * or {@code index < 0}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfShort layout, long index, short value);
@@ -2130,6 +2155,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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()}
+ * or {@code index < 0}
*/
int getAtIndex(ValueLayout.OfInt layout, long index);
@@ -2152,6 +2178,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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()}
+ * or {@code index < 0}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfInt layout, long index, int value);
@@ -2175,6 +2202,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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()}
+ * or {@code index < 0}
*/
float getAtIndex(ValueLayout.OfFloat layout, long index);
@@ -2197,6 +2225,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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()}
+ * or {@code index < 0}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfFloat layout, long index, float value);
@@ -2220,6 +2249,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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()}
+ * or {@code index < 0}
*/
long getAtIndex(ValueLayout.OfLong layout, long index);
@@ -2242,6 +2272,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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()}
+ * or {@code index < 0}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfLong layout, long index, long value);
@@ -2265,6 +2296,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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()}
+ * or {@code index < 0}
*/
double getAtIndex(ValueLayout.OfDouble layout, long index);
@@ -2287,6 +2319,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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()}
+ * or {@code index < 0}
* @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only}
*/
void setAtIndex(ValueLayout.OfDouble layout, long index, double value);
@@ -2319,6 +2352,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* in {@code T}
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows
* @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()}
+ * or {@code index < 0}
*/
MemorySegment getAtIndex(AddressLayout layout, long index);
@@ -2341,7 +2375,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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}
+ * or {@code index < 0}
* @throws IllegalArgumentException if {@code value} is not a {@linkplain #isNative() native} segment
* @throws IllegalArgumentException if this segment is
* {@linkplain #isReadOnly() read-only}
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 6be9d949ea6..6c9cf51bee8 100644
--- a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java
+++ b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java
@@ -33,6 +33,7 @@ import jdk.internal.foreign.AbstractMemorySegmentImpl;
import jdk.internal.foreign.ArenaImpl;
import jdk.internal.foreign.SlicingAllocator;
import jdk.internal.foreign.StringSupport;
+import jdk.internal.foreign.Utils;
import jdk.internal.vm.annotation.ForceInline;
/**
@@ -390,9 +391,10 @@ public interface SegmentAllocator {
* 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
+ * @throws IllegalArgumentException if {@code elementCount * sourceElementLayout.byteSize()} overflows
+ * @throws IllegalArgumentException if {@code elementCount < 0}
* @throws IndexOutOfBoundsException if {@code sourceOffset > source.byteSize() - (elementCount * sourceElementLayout.byteSize())}
- * @throws IndexOutOfBoundsException if either {@code sourceOffset} or {@code elementCount} are {@code < 0}
+ * @throws IndexOutOfBoundsException if {@code sourceOffset < 0}
*/
@ForceInline
default MemorySegment allocateFrom(ValueLayout elementLayout,
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 305594952d4..0efe62c1e4f 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java
@@ -153,9 +153,7 @@ public abstract sealed class AbstractMemorySegmentImpl
public MemorySegment reinterpretInternal(Class> callerClass, long newSize, Scope scope, Consumer cleanup) {
Reflection.ensureNativeAccess(callerClass, MemorySegment.class, "reinterpret");
- if (newSize < 0) {
- throw new IllegalArgumentException("newSize < 0");
- }
+ Utils.checkNonNegativeArgument(newSize, "newSize");
if (!isNative()) throw new UnsupportedOperationException("Not a native segment");
Runnable action = cleanup != null ?
() -> cleanup.accept(SegmentFactories.makeNativeSegmentUnchecked(address(), newSize)) :
@@ -594,6 +592,7 @@ public abstract sealed class AbstractMemorySegmentImpl
MemorySegment dstSegment, ValueLayout dstElementLayout, long dstOffset,
long elementCount) {
+ Utils.checkNonNegativeIndex(elementCount, "elementCount");
AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)srcSegment;
AbstractMemorySegmentImpl dstImpl = (AbstractMemorySegmentImpl)dstSegment;
if (srcElementLayout.byteSize() != dstElementLayout.byteSize()) {
@@ -625,7 +624,7 @@ public abstract sealed class AbstractMemorySegmentImpl
public static void copy(MemorySegment srcSegment, ValueLayout srcLayout, long srcOffset,
Object dstArray, int dstIndex,
int elementCount) {
-
+ Utils.checkNonNegativeIndex(elementCount, "elementCount");
var dstInfo = Utils.BaseAndScale.of(dstArray);
if (dstArray.getClass().componentType() != srcLayout.carrier()) {
throw new IllegalArgumentException("Incompatible value layout: " + srcLayout);
@@ -652,7 +651,6 @@ public abstract sealed class AbstractMemorySegmentImpl
public static void copy(Object srcArray, int srcIndex,
MemorySegment dstSegment, ValueLayout dstLayout, long dstOffset,
int elementCount) {
-
var srcInfo = Utils.BaseAndScale.of(srcArray);
if (srcArray.getClass().componentType() != dstLayout.carrier()) {
throw new IllegalArgumentException("Incompatible value layout: " + dstLayout);
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 d0d5c866f6b..6a081e23eac 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/Utils.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/Utils.java
@@ -200,11 +200,8 @@ public final class Utils {
}
public static void checkAllocationSizeAndAlign(long byteSize, long byteAlignment) {
- // size should be >= 0
- if (byteSize < 0) {
- throw new IllegalArgumentException("Invalid allocation size : " + byteSize);
- }
-
+ // byteSize should be >= 0
+ Utils.checkNonNegativeArgument(byteSize, "allocation size");
checkAlign(byteAlignment);
}
@@ -216,6 +213,20 @@ public final class Utils {
}
}
+ @ForceInline
+ public static void checkNonNegativeArgument(long value, String name) {
+ if (value < 0) {
+ throw new IllegalArgumentException("The provided " + name + " is negative: " + value);
+ }
+ }
+
+ @ForceInline
+ public static void checkNonNegativeIndex(long value, String name) {
+ if (value < 0) {
+ throw new IndexOutOfBoundsException("The provided " + name + " is negative: " + value);
+ }
+ }
+
private static long computePadding(long offset, long align) {
boolean isAligned = offset == 0 || offset % align == 0;
if (isAligned) {
diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java b/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java
index e4d931127af..3c0cf3902bb 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java
@@ -151,13 +151,8 @@ public abstract sealed class AbstractLayout & Memory
}
public long scale(long offset, long index) {
- if (offset < 0) {
- throw new IllegalArgumentException("Negative offset: " + offset);
- }
- if (index < 0) {
- throw new IllegalArgumentException("Negative index: " + index);
- }
-
+ Utils.checkNonNegativeArgument(offset, "offset");
+ Utils.checkNonNegativeArgument(index, "index");
return Math.addExact(offset, Math.multiplyExact(byteSize(), index));
}
diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java b/src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java
index dce06141028..6b8e7738198 100644
--- a/src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java
+++ b/src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java
@@ -30,13 +30,6 @@ public final class MemoryLayoutUtil {
private MemoryLayoutUtil() {
}
- public static long requireNonNegative(long value) {
- if (value < 0) {
- throw new IllegalArgumentException("The provided value was negative: " + value);
- }
- return value;
- }
-
public static long requireByteSizeValid(long byteSize, boolean allowZero) {
if ((byteSize == 0 && !allowZero) || byteSize < 0) {
throw new IllegalArgumentException("Invalid byte size: " + byteSize);
diff --git a/test/jdk/java/foreign/TestLayouts.java b/test/jdk/java/foreign/TestLayouts.java
index f4048aaa68a..2aa398468cc 100644
--- a/test/jdk/java/foreign/TestLayouts.java
+++ b/test/jdk/java/foreign/TestLayouts.java
@@ -371,13 +371,13 @@ public class TestLayouts {
}
@Test(expectedExceptions=IllegalArgumentException.class,
- expectedExceptionsMessageRegExp=".*Negative offset.*")
+ expectedExceptionsMessageRegExp=".*offset is negative.*")
public void testScaleNegativeOffset() {
JAVA_INT.scale(-1, 0);
}
@Test(expectedExceptions=IllegalArgumentException.class,
- expectedExceptionsMessageRegExp=".*Negative index.*")
+ expectedExceptionsMessageRegExp=".*index is negative.*")
public void testScaleNegativeIndex() {
JAVA_INT.scale(0, -1);
}
diff --git a/test/jdk/java/foreign/TestMemoryAccessInstance.java b/test/jdk/java/foreign/TestMemoryAccessInstance.java
index d56f44388a4..b749c96ac54 100644
--- a/test/jdk/java/foreign/TestMemoryAccessInstance.java
+++ b/test/jdk/java/foreign/TestMemoryAccessInstance.java
@@ -164,6 +164,13 @@ public class TestMemoryAccessInstance {
}
}
+ @Test(dataProvider = "segmentAccessors")
+ public void negativeOffset(String testName, Accessor accessor) {
+ MemorySegment segment = MemorySegment.ofArray(new byte[100]);
+ assertThrows(IndexOutOfBoundsException.class, () -> accessor.get(segment, -ValueLayout.JAVA_LONG.byteSize()));
+ assertThrows(IndexOutOfBoundsException.class, () -> accessor.set(segment, -ValueLayout.JAVA_LONG.byteSize(), accessor.value));
+ }
+
static final ByteOrder NE = ByteOrder.nativeOrder();
@DataProvider(name = "segmentAccessors")
diff --git a/test/jdk/java/foreign/TestScopedOperations.java b/test/jdk/java/foreign/TestScopedOperations.java
index 70223c00c00..d680d234145 100644
--- a/test/jdk/java/foreign/TestScopedOperations.java
+++ b/test/jdk/java/foreign/TestScopedOperations.java
@@ -27,6 +27,7 @@
*/
import java.lang.foreign.Arena;
+import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout;
@@ -135,6 +136,8 @@ public class TestScopedOperations {
ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_FLOAT, new float[]{0}), "Arena::allocateFrom/float");
ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_LONG, new long[]{0}), "Arena::allocateFrom/long");
ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_DOUBLE, new double[]{0}), "Arena::allocateFrom/double");
+ var source = MemorySegment.ofArray(new byte[]{});
+ ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_INT, source, JAVA_BYTE, 0, 1), "Arena::allocateFrom/5arg");
};
@DataProvider(name = "scopedOperations")
diff --git a/test/jdk/java/foreign/TestSegmentAllocators.java b/test/jdk/java/foreign/TestSegmentAllocators.java
index 0e0c49320da..87418f39d90 100644
--- a/test/jdk/java/foreign/TestSegmentAllocators.java
+++ b/test/jdk/java/foreign/TestSegmentAllocators.java
@@ -44,6 +44,8 @@ import java.nio.LongBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;
import java.util.function.Function;
@@ -189,6 +191,81 @@ public class TestSegmentAllocators {
}
}
+ // Invariant checking tests for the SegmentAllocator method:
+ // MemorySegment allocateFrom(ValueLayout elementLayout,
+ // MemorySegment source,
+ // ValueLayout sourceElementLayout,
+ // long sourceOffset,
+ // long elementCount) {
+ @Test
+ public void testAllocatorAllocateFromArguments() {
+ try (Arena arena = Arena.ofConfined()) {
+ var sourceElements = 2;
+ var source = arena.allocate(ValueLayout.JAVA_LONG, sourceElements);
+ var elementLayout = ValueLayout.JAVA_INT;
+ var sourceElementLayout = ValueLayout.JAVA_INT;
+
+ // IllegalArgumentException if {@code elementLayout.byteSize() != sourceElementLayout.byteSize()}
+ assertThrows(IllegalArgumentException.class, () ->
+ arena.allocateFrom(elementLayout, source, ValueLayout.JAVA_BYTE, 0, 1)
+ );
+
+ // IllegalArgumentException if source segment/offset
+ // are incompatible with the alignment constraint
+ // in the source element layout
+ assertThrows(IllegalArgumentException.class, () ->
+ arena.allocateFrom(elementLayout, source.asSlice(1), sourceElementLayout, 0, 1)
+ );
+ assertThrows(IllegalArgumentException.class, () ->
+ arena.allocateFrom(elementLayout, source, sourceElementLayout, 1, 1)
+ );
+
+ // IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()}
+ assertThrows(IllegalArgumentException.class, () ->
+ arena.allocateFrom(elementLayout.withByteAlignment(elementLayout.byteAlignment() * 2), source, sourceElementLayout, 1, 1)
+ );
+
+ // IllegalStateException if the {@linkplain MemorySegment#scope() scope} associated
+ // with {@code source} is not {@linkplain MemorySegment.Scope#isAlive() alive}
+ // This is tested in TestScopedOperations
+
+ // WrongThreadException if this method is called from a thread {@code T},
+ // such that {@code source.isAccessibleBy(T) == false}
+ CompletableFuture future = CompletableFuture.supplyAsync(Arena::ofConfined);
+ try {
+ Arena otherThreadArena = future.get();
+ assertThrows(WrongThreadException.class, () ->
+ otherThreadArena.allocateFrom(elementLayout, source, sourceElementLayout, 0, 1)
+ );
+ } catch (ExecutionException | InterruptedException e) {
+ fail("Unable to create arena", e);
+ }
+
+ // IllegalArgumentException if {@code elementCount * sourceElementLayout.byteSize()} overflows
+ assertThrows(IllegalArgumentException.class, () ->
+ arena.allocateFrom(elementLayout, source, sourceElementLayout, 0, Long.MAX_VALUE)
+ );
+
+ // IndexOutOfBoundsException if {@code sourceOffset > source.byteSize() - (elementCount * sourceElementLayout.byteSize())}
+ assertThrows(IndexOutOfBoundsException.class, () ->
+ arena.allocateFrom(elementLayout, source, sourceElementLayout, source.byteSize() - (1 * sourceElementLayout.byteAlignment()) + elementLayout.byteSize(), 1)
+ );
+
+ // IndexOutOfBoundsException if {@code sourceOffset < 0}
+ assertThrows(IndexOutOfBoundsException.class, () ->
+ arena.allocateFrom(elementLayout, source, sourceElementLayout, -elementLayout.byteSize(), 1)
+ );
+
+ // IllegalArgumentException if {@code elementCount < 0}
+ assertThrows(IllegalArgumentException.class, () ->
+ arena.allocateFrom(elementLayout, source, sourceElementLayout, 0, -1)
+ );
+
+
+ }
+ }
+
+
@Test
public void testArrayAllocateDelegation() {
AtomicInteger calls = new AtomicInteger();
diff --git a/test/jdk/java/foreign/TestSegmentCopy.java b/test/jdk/java/foreign/TestSegmentCopy.java
index 414cd0a8451..88636bf5420 100644
--- a/test/jdk/java/foreign/TestSegmentCopy.java
+++ b/test/jdk/java/foreign/TestSegmentCopy.java
@@ -145,6 +145,66 @@ public class TestSegmentCopy {
MemorySegment.copy(segment, JAVA_BYTE.withByteAlignment(2), 0, segment, 0, 4);
}
+ @Test
+ public void testCopy5ArgWithNegativeValues() {
+ MemorySegment src = MemorySegment.ofArray(new byte[] {1, 2, 3, 4});
+ MemorySegment dst = MemorySegment.ofArray(new byte[] {1, 2, 3, 4});
+ assertThrows(IndexOutOfBoundsException.class, () ->
+ MemorySegment.copy(src, -1, dst, 0, 4)
+ );
+ assertThrows(IndexOutOfBoundsException.class, () ->
+ MemorySegment.copy(src, 0, dst, -1, 4)
+ );
+ assertThrows(IndexOutOfBoundsException.class, () ->
+ MemorySegment.copy(src, 0, dst, 0, -1)
+ );
+ }
+
+ @Test
+ public void testCopy7ArgWithNegativeValues() {
+ MemorySegment src = MemorySegment.ofArray(new byte[] {1, 2, 3, 4});
+ MemorySegment dst = MemorySegment.ofArray(new byte[] {1, 2, 3, 4});
+ assertThrows(IndexOutOfBoundsException.class, () ->
+ MemorySegment.copy(src, JAVA_BYTE, -1, dst, JAVA_BYTE, 0, 4)
+ );
+ assertThrows(IndexOutOfBoundsException.class, () ->
+ MemorySegment.copy(src, JAVA_BYTE, 0, dst, JAVA_BYTE, -1, 4)
+ );
+ assertThrows(IndexOutOfBoundsException.class, () ->
+ MemorySegment.copy(src, JAVA_BYTE, 0, dst, JAVA_BYTE, 0, -1)
+ );
+ }
+
+ @Test
+ public void testCopyFromArrayWithNegativeValues() {
+ MemorySegment src = MemorySegment.ofArray(new byte[] {1, 2, 3, 4});
+ byte[] dst = new byte[] {1, 2, 3, 4};
+ assertThrows(IndexOutOfBoundsException.class, () ->
+ MemorySegment.copy(src, JAVA_BYTE, -1, dst, 0, 4)
+ );
+ assertThrows(IndexOutOfBoundsException.class, () ->
+ MemorySegment.copy(src, JAVA_BYTE, 0, dst, -1, 4)
+ );
+ assertThrows(IndexOutOfBoundsException.class, () ->
+ MemorySegment.copy(src, JAVA_BYTE, 0, dst, 0, -1)
+ );
+ }
+
+ @Test
+ public void testCopyToArrayWithNegativeValues() {
+ byte[] src = new byte[] {1, 2, 3, 4};
+ MemorySegment dst = MemorySegment.ofArray(new byte[] {1, 2, 3, 4});
+ assertThrows(IndexOutOfBoundsException.class, () ->
+ MemorySegment.copy(src, -1, dst, JAVA_BYTE, 0, 4)
+ );
+ assertThrows(IndexOutOfBoundsException.class, () ->
+ MemorySegment.copy(src, 0, dst, JAVA_BYTE, -1, 4)
+ );
+ assertThrows(IndexOutOfBoundsException.class, () ->
+ MemorySegment.copy(src, 0, dst, JAVA_BYTE, 0, -1)
+ );
+ }
+
enum Type {
// Byte
BYTE(byte.class, JAVA_BYTE, i -> (byte)i),
diff --git a/test/jdk/java/foreign/TestSegments.java b/test/jdk/java/foreign/TestSegments.java
index 94b49eb7e59..44ecd12ba5e 100644
--- a/test/jdk/java/foreign/TestSegments.java
+++ b/test/jdk/java/foreign/TestSegments.java
@@ -43,6 +43,7 @@ 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 {
@@ -55,14 +56,13 @@ public class TestSegments {
@Test
public void testZeroLengthNativeSegment() {
try (Arena arena = Arena.ofConfined()) {
- Arena session = arena;
- var segment = session.allocate(0, 1);
+ var segment = arena.allocate(0, 1);
assertEquals(segment.byteSize(), 0);
MemoryLayout seq = MemoryLayout.sequenceLayout(0, JAVA_INT);
- segment = session.allocate(seq);
+ segment = arena.allocate(seq);
assertEquals(segment.byteSize(), 0);
assertEquals(segment.address() % seq.byteAlignment(), 0);
- segment = session.allocate(0, 4);
+ segment = arena.allocate(0, 4);
assertEquals(segment.byteSize(), 0);
assertEquals(segment.address() % 4, 0);
MemorySegment rawAddress = MemorySegment.ofAddress(segment.address());
@@ -133,8 +133,7 @@ public class TestSegments {
@Test
public void testEqualsOffHeap() {
try (Arena arena = Arena.ofConfined()) {
- Arena scope1 = arena;
- MemorySegment segment = scope1.allocate(100, 1);
+ MemorySegment segment = arena.allocate(100, 1);
assertEquals(segment, segment.asReadOnly());
assertEquals(segment, segment.asSlice(0, 100));
assertNotEquals(segment, segment.asSlice(10, 90));