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 ece3e4e22c1..db656ada136 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java @@ -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 open path elements. * @throws IllegalArgumentException if the layout path contains one or more dereference path elements. */ - 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 well-formed for this layout. * @throws IllegalArgumentException if the layout path contains one or more dereference path elements. */ - 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 well-formed 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 well-formed for this layout. * @throws IllegalArgumentException if the layout path contains one or more dereference path elements. */ - 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 computePathOp(LayoutPath path, Function finalizer, - Set 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 layout path. There 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 2bfdb4ec56e..5565eaf2461 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -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 { * incompatible with the alignment constraint 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 { * incompatible with the alignment constraint 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 { * incompatible with the alignment constraint 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 { * incompatible with the alignment constraint 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 { * incompatible with the alignment constraint 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 { * incompatible with the alignment constraint 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 { * incompatible with the alignment constraint 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 { * incompatible with the alignment constraint 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 { * incompatible with the alignment constraint 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 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 63132f7f89c..8b674a90c33 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -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 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); + } } 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 eb67ad5e3af..42baaa69270 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 @@ -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 & MemoryLayout> permits AbstractGroupLayout, PaddingLayoutImpl, SequenceLayoutImpl, ValueLayouts.AbstractValueLayout { @@ -140,4 +150,72 @@ public abstract sealed class AbstractLayout & 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 computePathOp(LayoutPath path, Function finalizer, + Set 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); + } }