8318324: Drop redundant default methods from FFM API

Reviewed-by: jvernee
This commit is contained in:
Maurizio Cimadamore 2023-10-19 09:51:02 +00:00
parent 1a098356dd
commit 15acf4b8d7
4 changed files with 407 additions and 277 deletions
src/java.base/share/classes

@ -26,14 +26,9 @@
package java.lang.foreign;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;
import jdk.internal.foreign.LayoutPath;
@ -44,7 +39,6 @@ import jdk.internal.foreign.layout.PaddingLayoutImpl;
import jdk.internal.foreign.layout.SequenceLayoutImpl;
import jdk.internal.foreign.layout.StructLayoutImpl;
import jdk.internal.foreign.layout.UnionLayoutImpl;
import jdk.internal.vm.annotation.ForceInline;
/**
* A memory layout describes the contents of a memory segment.
@ -404,35 +398,12 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* @throws IllegalArgumentException if {@code offset} or {@code index} is negative
* @throws ArithmeticException if either the addition or multiplication overflows
*/
@ForceInline
default long scale(long offset, long index) {
if (offset < 0) {
throw new IllegalArgumentException("Negative offset: " + offset);
}
if (index < 0) {
throw new IllegalArgumentException("Negative index: " + index);
}
return Math.addExact(offset, Math.multiplyExact(byteSize(), index));
}
long scale(long offset, long index);
/**
*{@return a method handle that can be used to invoke {@link #scale(long, long)} on this layout}
*/
default MethodHandle scaleHandle() {
class Holder {
static final MethodHandle MH_SCALE;
static {
try {
MH_SCALE = MethodHandles.lookup().findVirtual(MemoryLayout.class, "scale",
MethodType.methodType(long.class, long.class, long.class));
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
}
return Holder.MH_SCALE.bindTo(this);
}
MethodHandle scaleHandle();
/**
* Computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the
@ -444,10 +415,7 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* @throws IllegalArgumentException if the layout path contains one or more <a href=#open-path-elements>open path elements</a>.
* @throws IllegalArgumentException if the layout path contains one or more <a href=#deref-path-elements>dereference path elements</a>.
*/
default long byteOffset(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this), LayoutPath::offset,
EnumSet.of(PathKind.SEQUENCE_ELEMENT, PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements);
}
long byteOffset(PathElement... elements);
/**
* Creates a method handle that computes the offset, in bytes, of the layout selected
@ -482,10 +450,7 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout.
* @throws IllegalArgumentException if the layout path contains one or more <a href=#deref-path-elements>dereference path elements</a>.
*/
default MethodHandle byteOffsetHandle(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this), LayoutPath::offsetHandle,
EnumSet.of(PathKind.DEREF_ELEMENT), elements);
}
MethodHandle byteOffsetHandle(PathElement... elements);
/**
* Creates a var handle that accesses a memory segment at the offset selected by the given layout path,
@ -577,14 +542,7 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout.
* @throws IllegalArgumentException if the layout selected by the provided path is not a {@linkplain ValueLayout value layout}.
*/
default VarHandle varHandle(PathElement... elements) {
Objects.requireNonNull(elements);
if (this instanceof ValueLayout vl && elements.length == 0) {
return vl.varHandle(); // fast path
}
return computePathOp(LayoutPath.rootPath(this), LayoutPath::dereferenceHandle,
Set.of(), elements);
}
VarHandle varHandle(PathElement... elements);
/**
* Creates a method handle which, given a memory segment, returns a {@linkplain MemorySegment#asSlice(long,long) slice}
@ -623,10 +581,7 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* @throws IllegalArgumentException if the layout path is not <a href="#well-formedness">well-formed</a> for this layout.
* @throws IllegalArgumentException if the layout path contains one or more <a href=#deref-path-elements>dereference path elements</a>.
*/
default MethodHandle sliceHandle(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this), LayoutPath::sliceHandle,
Set.of(PathKind.DEREF_ELEMENT), elements);
}
MethodHandle sliceHandle(PathElement... elements);
/**
* Returns the layout selected from the provided path, where the initial layout in the path is this layout.
@ -638,23 +593,7 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* @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)}).
*/
default MemoryLayout select(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this), LayoutPath::layout,
EnumSet.of(PathKind.SEQUENCE_ELEMENT_INDEX, PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements);
}
private static <Z> Z computePathOp(LayoutPath path, Function<LayoutPath, Z> finalizer,
Set<PathKind> badKinds, PathElement... elements) {
Objects.requireNonNull(elements);
for (PathElement e : elements) {
LayoutPath.PathElementImpl pathElem = (LayoutPath.PathElementImpl)Objects.requireNonNull(e);
if (badKinds.contains(pathElem.kind())) {
throw new IllegalArgumentException(String.format("Invalid %s selection in layout path", pathElem.kind().description()));
}
path = pathElem.apply(path);
}
return finalizer.apply(path);
}
MemoryLayout select(PathElement... elements);
/**
* An element in a <a href="MemoryLayout.html#layout-paths"><em>layout path</em></a>. There

@ -573,10 +573,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* the alignment constraint specified by {@code layout}.
* @return a slice of this memory segment.
*/
default MemorySegment asSlice(long offset, MemoryLayout layout) {
Objects.requireNonNull(layout);
return asSlice(offset, layout.byteSize(), layout.byteAlignment());
}
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
@ -788,10 +785,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
* @return this segment.
*/
default MemorySegment copyFrom(MemorySegment src) {
MemorySegment.copy(src, 0, this, 0, src.byteSize());
return this;
}
MemorySegment copyFrom(MemorySegment src);
/**
* Finds and returns the offset, in bytes, of the first mismatch between
@ -820,10 +814,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code other.isAccessibleBy(T) == false}.
*/
default long mismatch(MemorySegment other) {
Objects.requireNonNull(other);
return MemorySegment.mismatch(this, 0, byteSize(), other, 0, other.byteSize());
}
long mismatch(MemorySegment other);
/**
* Determines whether the contents of this mapped segment is resident in physical
@ -1068,9 +1059,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code isAccessibleBy(T) == false}.
*/
default String getString(long offset) {
return getString(offset, sun.nio.cs.UTF_8.INSTANCE);
}
String getString(long offset);
/**
* Reads a null-terminated string from this segment at the given offset, using the provided charset.
@ -1099,10 +1088,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if {@code charset} is not a {@linkplain StandardCharsets standard charset}.
*/
default String getString(long offset, Charset charset) {
Objects.requireNonNull(charset);
return StringSupport.read(this, offset, 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
@ -1123,10 +1109,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws WrongThreadException if this method is called from a thread {@code T},
* such that {@code isAccessibleBy(T) == false}.
*/
default void setString(long offset, String str) {
Objects.requireNonNull(str);
setString(offset, str, sun.nio.cs.UTF_8.INSTANCE);
}
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
@ -1160,11 +1143,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* such that {@code isAccessibleBy(T) == false}.
* @throws IllegalArgumentException if {@code charset} is not a {@linkplain StandardCharsets standard charset}.
*/
default void setString(long offset, String str, Charset charset) {
Objects.requireNonNull(charset);
Objects.requireNonNull(str);
StringSupport.write(this, offset, charset, str);
}
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.
@ -1411,10 +1390,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default byte get(ValueLayout.OfByte layout, long offset) {
return (byte) layout.varHandle().get(this, offset);
}
byte get(ValueLayout.OfByte layout, long offset);
/**
* Writes a byte into this segment at the given offset, with the given layout.
@ -1431,10 +1407,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
default void set(ValueLayout.OfByte layout, long offset, byte value) {
layout.varHandle().set(this, offset, value);
}
void set(ValueLayout.OfByte layout, long offset, byte value);
/**
* Reads a boolean from this segment at the given offset, with the given layout.
@ -1450,10 +1423,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default boolean get(ValueLayout.OfBoolean layout, long offset) {
return (boolean) layout.varHandle().get(this, offset);
}
boolean get(ValueLayout.OfBoolean layout, long offset);
/**
* Writes a boolean into this segment at the given offset, with the given layout.
@ -1470,10 +1440,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
default void set(ValueLayout.OfBoolean layout, long offset, boolean value) {
layout.varHandle().set(this, offset, value);
}
void set(ValueLayout.OfBoolean layout, long offset, boolean value);
/**
* Reads a char from this segment at the given offset, with the given layout.
@ -1489,10 +1456,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default char get(ValueLayout.OfChar layout, long offset) {
return (char) layout.varHandle().get(this, offset);
}
char get(ValueLayout.OfChar layout, long offset);
/**
* Writes a char into this segment at the given offset, with the given layout.
@ -1509,10 +1473,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
default void set(ValueLayout.OfChar layout, long offset, char value) {
layout.varHandle().set(this, offset, value);
}
void set(ValueLayout.OfChar layout, long offset, char value);
/**
* Reads a short from this segment at the given offset, with the given layout.
@ -1528,10 +1489,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default short get(ValueLayout.OfShort layout, long offset) {
return (short) layout.varHandle().get(this, offset);
}
short get(ValueLayout.OfShort layout, long offset);
/**
* Writes a short into this segment at the given offset, with the given layout.
@ -1548,10 +1506,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
default void set(ValueLayout.OfShort layout, long offset, short value) {
layout.varHandle().set(this, offset, value);
}
void set(ValueLayout.OfShort layout, long offset, short value);
/**
* Reads an int from this segment at the given offset, with the given layout.
@ -1567,10 +1522,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default int get(ValueLayout.OfInt layout, long offset) {
return (int) layout.varHandle().get(this, offset);
}
int get(ValueLayout.OfInt layout, long offset);
/**
* Writes an int into this segment at the given offset, with the given layout.
@ -1587,10 +1539,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
default void set(ValueLayout.OfInt layout, long offset, int value) {
layout.varHandle().set(this, offset, value);
}
void set(ValueLayout.OfInt layout, long offset, int value);
/**
* Reads a float from this segment at the given offset, with the given layout.
@ -1606,10 +1555,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default float get(ValueLayout.OfFloat layout, long offset) {
return (float)layout.varHandle().get(this, offset);
}
float get(ValueLayout.OfFloat layout, long offset);
/**
* Writes a float into this segment at the given offset, with the given layout.
@ -1626,10 +1572,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
default void set(ValueLayout.OfFloat layout, long offset, float value) {
layout.varHandle().set(this, offset, value);
}
void set(ValueLayout.OfFloat layout, long offset, float value);
/**
* Reads a long from this segment at the given offset, with the given layout.
@ -1645,10 +1588,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default long get(ValueLayout.OfLong layout, long offset) {
return (long) layout.varHandle().get(this, offset);
}
long get(ValueLayout.OfLong layout, long offset);
/**
* Writes a long into this segment at the given offset, with the given layout.
@ -1665,10 +1605,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
default void set(ValueLayout.OfLong layout, long offset, long value) {
layout.varHandle().set(this, offset, value);
}
void set(ValueLayout.OfLong layout, long offset, long value);
/**
* Reads a double from this segment at the given offset, with the given layout.
@ -1684,10 +1621,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default double get(ValueLayout.OfDouble layout, long offset) {
return (double) layout.varHandle().get(this, offset);
}
double get(ValueLayout.OfDouble layout, long offset);
/**
* Writes a double into this segment at the given offset, with the given layout.
@ -1704,10 +1638,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
default void set(ValueLayout.OfDouble layout, long offset, double value) {
layout.varHandle().set(this, offset, value);
}
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
@ -1729,10 +1660,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in {@code T}.
* @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}.
*/
@ForceInline
default MemorySegment get(AddressLayout layout, long offset) {
return (MemorySegment) layout.varHandle().get(this, offset);
}
MemorySegment get(AddressLayout layout, long offset);
/**
* Writes an address into this segment at the given offset, with the given layout.
@ -1750,10 +1678,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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(AddressLayout layout, long offset, MemorySegment value) {
layout.varHandle().set(this, offset, value);
}
void set(AddressLayout layout, long offset, MemorySegment value);
/**
* Reads a byte from this segment at the given index, scaled by the given layout size.
@ -1772,12 +1697,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default byte getAtIndex(ValueLayout.OfByte layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
return (byte) layout.varHandle().get(this, index * layout.byteSize());
}
byte getAtIndex(ValueLayout.OfByte layout, long index);
/**
* Reads a boolean from this segment at the given index, scaled by the given layout size.
@ -1796,12 +1716,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default boolean getAtIndex(ValueLayout.OfBoolean layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
return (boolean) layout.varHandle().get(this, index * layout.byteSize());
}
boolean getAtIndex(ValueLayout.OfBoolean layout, long index);
/**
* Reads a char from this segment at the given index, scaled by the given layout size.
@ -1820,12 +1735,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default char getAtIndex(ValueLayout.OfChar layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
return (char) layout.varHandle().get(this, index * layout.byteSize());
}
char getAtIndex(ValueLayout.OfChar layout, long index);
/**
* Writes a char into this segment at the given index, scaled by the given layout size.
@ -1845,12 +1755,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
default void setAtIndex(ValueLayout.OfChar layout, long index, char value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
layout.varHandle().set(this, index * layout.byteSize(), value);
}
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.
@ -1869,12 +1774,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default short getAtIndex(ValueLayout.OfShort layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
return (short) layout.varHandle().get(this, index * layout.byteSize());
}
short getAtIndex(ValueLayout.OfShort layout, long index);
/**
* Writes a byte into this segment at the given index, scaled by the given layout size.
@ -1894,13 +1794,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
default void setAtIndex(ValueLayout.OfByte layout, long index, byte value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
layout.varHandle().set(this, index * layout.byteSize(), value);
}
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.
@ -1920,12 +1814,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
default void setAtIndex(ValueLayout.OfBoolean layout, long index, boolean value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
layout.varHandle().set(this, index * layout.byteSize(), value);
}
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.
@ -1945,12 +1834,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
default void setAtIndex(ValueLayout.OfShort layout, long index, short value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
layout.varHandle().set(this, index * layout.byteSize(), value);
}
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.
@ -1969,12 +1853,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default int getAtIndex(ValueLayout.OfInt layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
return (int) layout.varHandle().get(this, index * layout.byteSize());
}
int getAtIndex(ValueLayout.OfInt layout, long index);
/**
* Writes an int into this segment at the given index, scaled by the given layout size.
@ -1994,12 +1873,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
default void setAtIndex(ValueLayout.OfInt layout, long index, int value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
layout.varHandle().set(this, index * layout.byteSize(), value);
}
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.
@ -2018,12 +1892,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default float getAtIndex(ValueLayout.OfFloat layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
return (float) layout.varHandle().get(this, index * layout.byteSize());
}
float getAtIndex(ValueLayout.OfFloat layout, long index);
/**
* Writes a float into this segment at the given index, scaled by the given layout size.
@ -2043,12 +1912,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
default void setAtIndex(ValueLayout.OfFloat layout, long index, float value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
layout.varHandle().set(this, index * layout.byteSize(), value);
}
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.
@ -2067,12 +1931,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default long getAtIndex(ValueLayout.OfLong layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
return (long) layout.varHandle().get(this, index * layout.byteSize());
}
long getAtIndex(ValueLayout.OfLong layout, long index);
/**
* Writes a long into this segment at the given index, scaled by the given layout size.
@ -2092,12 +1951,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
default void setAtIndex(ValueLayout.OfLong layout, long index, long value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
layout.varHandle().set(this, index * layout.byteSize(), value);
}
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.
@ -2116,12 +1970,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default double getAtIndex(ValueLayout.OfDouble layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
return (double) layout.varHandle().get(this, index * layout.byteSize());
}
double getAtIndex(ValueLayout.OfDouble layout, long index);
/**
* Writes a double into this segment at the given index, scaled by the given layout size.
@ -2141,12 +1990,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
* @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}.
*/
@ForceInline
default void setAtIndex(ValueLayout.OfDouble layout, long index, double value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
layout.varHandle().set(this, index * layout.byteSize(), value);
}
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
@ -2171,12 +2015,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows.
* @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}.
*/
@ForceInline
default MemorySegment getAtIndex(AddressLayout layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
return (MemorySegment) layout.varHandle().get(this, index * layout.byteSize());
}
MemorySegment getAtIndex(AddressLayout layout, long index);
/**
* Writes an address into this segment at the given index, scaled by the given layout size.
@ -2197,12 +2036,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @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(AddressLayout layout, long index, MemorySegment value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
// note: we know size is a small value (as it comes from ValueLayout::byteSize())
layout.varHandle().set(this, index * layout.byteSize(), value);
}
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

@ -36,6 +36,7 @@ import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.LongBuffer;
import java.nio.ShortBuffer;
import java.nio.charset.Charset;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Consumer;
@ -122,6 +123,12 @@ public abstract sealed class AbstractMemorySegmentImpl
return asSliceNoCheck(offset, newSize);
}
@Override
public MemorySegment asSlice(long offset, MemoryLayout layout) {
Objects.requireNonNull(layout);
return asSlice(offset, layout.byteSize(), layout.byteAlignment());
}
@Override
@CallerSensitive
public final MemorySegment reinterpret(long newSize, Arena arena, Consumer<MemorySegment> cleanup) {
@ -272,6 +279,18 @@ public abstract sealed class AbstractMemorySegmentImpl
return Optional.empty();
}
@Override
public MemorySegment copyFrom(MemorySegment src) {
MemorySegment.copy(src, 0, this, 0, src.byteSize());
return this;
}
@Override
public long mismatch(MemorySegment other) {
Objects.requireNonNull(other);
return MemorySegment.mismatch(this, 0, byteSize(), other, 0, other.byteSize());
}
@Override
public void load() {
throw notAMappedSegment();
@ -732,4 +751,264 @@ public abstract sealed class AbstractMemorySegmentImpl
throw new IllegalArgumentException("Not a supported array class: " + arrayType.getSimpleName());
}
}
// accessors
@ForceInline
@Override
public byte get(ValueLayout.OfByte layout, long offset) {
return (byte) layout.varHandle().get(this, offset);
}
@ForceInline
@Override
public void set(ValueLayout.OfByte layout, long offset, byte value) {
layout.varHandle().set(this, offset, value);
}
@ForceInline
@Override
public boolean get(ValueLayout.OfBoolean layout, long offset) {
return (boolean) layout.varHandle().get(this, offset);
}
@ForceInline
@Override
public void set(ValueLayout.OfBoolean layout, long offset, boolean value) {
layout.varHandle().set(this, offset, value);
}
@ForceInline
@Override
public char get(ValueLayout.OfChar layout, long offset) {
return (char) layout.varHandle().get(this, offset);
}
@ForceInline
@Override
public void set(ValueLayout.OfChar layout, long offset, char value) {
layout.varHandle().set(this, offset, value);
}
@ForceInline
@Override
public short get(ValueLayout.OfShort layout, long offset) {
return (short) layout.varHandle().get(this, offset);
}
@ForceInline
@Override
public void set(ValueLayout.OfShort layout, long offset, short value) {
layout.varHandle().set(this, offset, value);
}
@ForceInline
@Override
public int get(ValueLayout.OfInt layout, long offset) {
return (int) layout.varHandle().get(this, offset);
}
@ForceInline
@Override
public void set(ValueLayout.OfInt layout, long offset, int value) {
layout.varHandle().set(this, offset, value);
}
@ForceInline
@Override
public float get(ValueLayout.OfFloat layout, long offset) {
return (float) layout.varHandle().get(this, offset);
}
@ForceInline
@Override
public void set(ValueLayout.OfFloat layout, long offset, float value) {
layout.varHandle().set(this, offset, value);
}
@ForceInline
@Override
public long get(ValueLayout.OfLong layout, long offset) {
return (long) layout.varHandle().get(this, offset);
}
@ForceInline
@Override
public void set(ValueLayout.OfLong layout, long offset, long value) {
layout.varHandle().set(this, offset, value);
}
@ForceInline
@Override
public double get(ValueLayout.OfDouble layout, long offset) {
return (double) layout.varHandle().get(this, offset);
}
@ForceInline
@Override
public void set(ValueLayout.OfDouble layout, long offset, double value) {
layout.varHandle().set(this, offset, value);
}
@ForceInline
@Override
public MemorySegment get(AddressLayout layout, long offset) {
return (MemorySegment) layout.varHandle().get(this, offset);
}
@ForceInline
@Override
public void set(AddressLayout layout, long offset, MemorySegment value) {
layout.varHandle().set(this, offset, value);
}
@ForceInline
@Override
public byte getAtIndex(ValueLayout.OfByte layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
return (byte) layout.varHandle().get(this, index * layout.byteSize());
}
@ForceInline
@Override
public boolean getAtIndex(ValueLayout.OfBoolean layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
return (boolean) layout.varHandle().get(this, index * layout.byteSize());
}
@ForceInline
@Override
public char getAtIndex(ValueLayout.OfChar layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
return (char) layout.varHandle().get(this, index * layout.byteSize());
}
@ForceInline
@Override
public void setAtIndex(ValueLayout.OfChar layout, long index, char value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
layout.varHandle().set(this, index * layout.byteSize(), value);
}
@ForceInline
@Override
public short getAtIndex(ValueLayout.OfShort layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
return (short) layout.varHandle().get(this, index * layout.byteSize());
}
@ForceInline
@Override
public void setAtIndex(ValueLayout.OfByte layout, long index, byte value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
layout.varHandle().set(this, index * layout.byteSize(), value);
}
@ForceInline
@Override
public void setAtIndex(ValueLayout.OfBoolean layout, long index, boolean value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
layout.varHandle().set(this, index * layout.byteSize(), value);
}
@ForceInline
@Override
public void setAtIndex(ValueLayout.OfShort layout, long index, short value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
layout.varHandle().set(this, index * layout.byteSize(), value);
}
@ForceInline
@Override
public int getAtIndex(ValueLayout.OfInt layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
return (int) layout.varHandle().get(this, index * layout.byteSize());
}
@ForceInline
@Override
public void setAtIndex(ValueLayout.OfInt layout, long index, int value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
layout.varHandle().set(this, index * layout.byteSize(), value);
}
@ForceInline
@Override
public float getAtIndex(ValueLayout.OfFloat layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
return (float) layout.varHandle().get(this, index * layout.byteSize());
}
@ForceInline
@Override
public void setAtIndex(ValueLayout.OfFloat layout, long index, float value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
layout.varHandle().set(this, index * layout.byteSize(), value);
}
@ForceInline
@Override
public long getAtIndex(ValueLayout.OfLong layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
return (long) layout.varHandle().get(this, index * layout.byteSize());
}
@ForceInline
@Override
public void setAtIndex(ValueLayout.OfLong layout, long index, long value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
layout.varHandle().set(this, index * layout.byteSize(), value);
}
@ForceInline
@Override
public double getAtIndex(ValueLayout.OfDouble layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
return (double) layout.varHandle().get(this, index * layout.byteSize());
}
@ForceInline
@Override
public void setAtIndex(ValueLayout.OfDouble layout, long index, double value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
layout.varHandle().set(this, index * layout.byteSize(), value);
}
@ForceInline
@Override
public MemorySegment getAtIndex(AddressLayout layout, long index) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
return (MemorySegment) layout.varHandle().get(this, index * layout.byteSize());
}
@ForceInline
@Override
public void setAtIndex(AddressLayout layout, long index, MemorySegment value) {
Utils.checkElementAlignment(layout, "Layout alignment greater than its size");
layout.varHandle().set(this, index * layout.byteSize(), value);
}
@Override
public String getString(long offset) {
return getString(offset, sun.nio.cs.UTF_8.INSTANCE);
}
@Override
public String getString(long offset, Charset charset) {
Objects.requireNonNull(charset);
return StringSupport.read(this, offset, charset);
}
@Override
public void setString(long offset, String str) {
Objects.requireNonNull(str);
setString(offset, str, sun.nio.cs.UTF_8.INSTANCE);
}
@Override
public void setString(long offset, String str, Charset charset) {
Objects.requireNonNull(charset);
Objects.requireNonNull(str);
StringSupport.write(this, offset, charset, str);
}
}

@ -25,16 +25,26 @@
*/
package jdk.internal.foreign.layout;
import jdk.internal.foreign.LayoutPath;
import jdk.internal.foreign.LayoutPath.PathElementImpl.PathKind;
import jdk.internal.foreign.Utils;
import java.lang.foreign.GroupLayout;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemoryLayout.PathElement;
import java.lang.foreign.SequenceLayout;
import java.lang.foreign.StructLayout;
import java.lang.foreign.UnionLayout;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle;
import java.util.EnumSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
public abstract sealed class AbstractLayout<L extends AbstractLayout<L> & MemoryLayout>
permits AbstractGroupLayout, PaddingLayoutImpl, SequenceLayoutImpl, ValueLayouts.AbstractValueLayout {
@ -140,4 +150,72 @@ public abstract sealed class AbstractLayout<L extends AbstractLayout<L> & Memory
return value;
}
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);
}
return Math.addExact(offset, Math.multiplyExact(byteSize(), index));
}
public MethodHandle scaleHandle() {
class Holder {
static final MethodHandle MH_SCALE;
static {
try {
MH_SCALE = MethodHandles.lookup().findVirtual(MemoryLayout.class, "scale",
MethodType.methodType(long.class, long.class, long.class));
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
}
return Holder.MH_SCALE.bindTo(this);
}
public long byteOffset(PathElement... elements) {
return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::offset,
EnumSet.of(PathKind.SEQUENCE_ELEMENT, PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements);
}
public MethodHandle byteOffsetHandle(PathElement... elements) {
return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::offsetHandle,
EnumSet.of(PathKind.DEREF_ELEMENT), elements);
}
public VarHandle varHandle(PathElement... elements) {
Objects.requireNonNull(elements);
if (this instanceof ValueLayout vl && elements.length == 0) {
return vl.varHandle(); // fast path
}
return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::dereferenceHandle,
Set.of(), elements);
}
public MethodHandle sliceHandle(PathElement... elements) {
return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::sliceHandle,
Set.of(PathKind.DEREF_ELEMENT), elements);
}
public MemoryLayout select(PathElement... elements) {
return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::layout,
EnumSet.of(PathKind.SEQUENCE_ELEMENT_INDEX, PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements);
}
private static <Z> Z computePathOp(LayoutPath path, Function<LayoutPath, Z> finalizer,
Set<PathKind> badKinds, PathElement... elements) {
Objects.requireNonNull(elements);
for (PathElement e : elements) {
LayoutPath.PathElementImpl pathElem = (LayoutPath.PathElementImpl)Objects.requireNonNull(e);
if (badKinds.contains(pathElem.kind())) {
throw new IllegalArgumentException(String.format("Invalid %s selection in layout path", pathElem.kind().description()));
}
path = pathElem.apply(path);
}
return finalizer.apply(path);
}
}