8308276: Change layout API to work with bytes, not bits

Reviewed-by: psandoz, pminborg
This commit is contained in:
Maurizio Cimadamore 2023-05-22 14:57:00 +00:00
parent 91aeb5de58
commit 5fc9b5787d
93 changed files with 527 additions and 721 deletions

View file

@ -38,7 +38,7 @@ import java.util.Optional;
/**
* A value layout used to model the address of some region of memory. The carrier associated with an address layout is
* {@code MemorySegment.class}. The size and alignment of an address layout are platform dependent
* (e.g. on a 64-bit platform, the size and alignment of an address layout are set to 64 bits).
* (e.g. on a 64-bit platform, the size and alignment of an address layout are set to 8 bytes).
* <p>
* An address layout may optionally feature a {@linkplain #targetLayout() target layout}. An address layout with
* target layout {@code T} can be used to model the address of a region of memory whose layout is {@code T}.
@ -74,7 +74,7 @@ public sealed interface AddressLayout extends ValueLayout permits ValueLayouts.O
* {@inheritDoc}
*/
@Override
AddressLayout withBitAlignment(long bitAlignment);
AddressLayout withByteAlignment(long byteAlignment);
/**
* {@inheritDoc}

View file

@ -68,9 +68,9 @@ public sealed interface GroupLayout extends MemoryLayout permits StructLayout, U
/**
* {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
* @throws IllegalArgumentException if {@code bitAlignment} is less than {@code M}, where {@code M} is the maximum alignment
* @throws IllegalArgumentException if {@code byteAlignment} is less than {@code M}, where {@code M} is the maximum alignment
* constraint in any of the member layouts associated with this group layout.
*/
@Override
GroupLayout withBitAlignment(long bitAlignment);
GroupLayout withByteAlignment(long byteAlignment);
}

View file

@ -75,7 +75,7 @@ import jdk.internal.javac.PreviewFeature;
* SequenceLayout taggedValues = MemoryLayout.sequenceLayout(5,
* MemoryLayout.structLayout(
* ValueLayout.JAVA_BYTE.withName("kind"),
* MemoryLayout.paddingLayout(24),
* MemoryLayout.paddingLayout(3),
* ValueLayout.JAVA_INT.withName("value")
* )
* ).withName("TaggedValues");
@ -84,7 +84,7 @@ import jdk.internal.javac.PreviewFeature;
* <h2 id="layout-align">Size, alignment and byte order</h2>
*
* All layouts have a size; layout size for value and padding layouts is always explicitly denoted; this means that a layout description
* always has the same size in bits, regardless of the platform in which it is used. For derived layouts, the size is computed
* always has the same size in bytes, regardless of the platform in which it is used. For derived layouts, the size is computed
* as follows:
* <ul>
* <li>for a sequence layout <em>S</em> whose element layout is <em>E</em> and size is <em>L</em>,
@ -104,7 +104,7 @@ import jdk.internal.javac.PreviewFeature;
* <li>for a group layout <em>G</em> with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose alignments are
* <em>A1</em>, <em>A2</em>, ... <em>An</em>, respectively, the natural alignment of <em>G</em> is <em>max(A1, A2 ... An)</em></li>
* </ul>
* A layout's natural alignment can be overridden if needed (see {@link MemoryLayout#withBitAlignment(long)}), which can be useful to describe
* A layout's natural alignment can be overridden if needed (see {@link MemoryLayout#withByteAlignment(long)}), which can be useful to describe
* hyper-aligned layouts.
* <p>
* All value layouts have an <em>explicit</em> byte order (see {@link java.nio.ByteOrder}) which is set when the layout is created.
@ -115,17 +115,17 @@ import jdk.internal.javac.PreviewFeature;
* at a layout nested within the root layout - this is the layout <em>selected</em> by the layout path.
* Layout paths are typically expressed as a sequence of one or more {@link PathElement} instances.
* <p>
* Layout paths are for example useful in order to obtain {@linkplain MemoryLayout#bitOffset(PathElement...) offsets} of
* Layout paths are for example useful in order to obtain {@linkplain MemoryLayout#byteOffset(PathElement...) offsets} of
* arbitrarily nested layouts inside another layout, to quickly obtain a {@linkplain #varHandle(PathElement...) memory access handle}
* corresponding to the selected layout, or to {@linkplain #select(PathElement...) select} an arbitrarily nested layout inside
* another layout.
* <p>
* Such <em>layout paths</em> can be constructed programmatically using the methods in this class.
* For instance, given the {@code taggedValues} layout instance constructed as above, we can obtain the offset,
* in bits, of the member layout named <code>value</code> in the <em>first</em> sequence element, as follows:
* in bytes, of the member layout named <code>value</code> in the <em>first</em> sequence element, as follows:
* {@snippet lang=java :
* long valueOffset = taggedValues.bitOffset(PathElement.sequenceElement(0),
* PathElement.groupElement("value")); // yields 32
* long valueOffset = taggedValues.byteOffset(PathElement.sequenceElement(0),
* PathElement.groupElement("value")); // yields 4
* }
*
* Similarly, we can select the member layout named {@code value}, as follows:
@ -151,7 +151,7 @@ import jdk.internal.javac.PreviewFeature;
* access coordinate.
*
* <p>A layout path with free dimensions can also be used to create an offset-computing method handle, using the
* {@link #bitOffset(PathElement...)} or {@link #byteOffsetHandle(PathElement...)} method. Again, free dimensions are
* {@link #byteOffset(PathElement...)} or {@link #byteOffsetHandle(PathElement...)} method. Again, free dimensions are
* translated into {@code long} parameters of the created method handle. The method handle can be used to compute the
* offsets of elements of a sequence at different indices, by supplying these indices when invoking the method handle.
* For instance:
@ -172,14 +172,8 @@ import jdk.internal.javac.PreviewFeature;
@PreviewFeature(feature=PreviewFeature.Feature.FOREIGN)
public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, PaddingLayout, ValueLayout {
/**
* {@return the layout size, in bits}
*/
long bitSize();
/**
* {@return the layout size, in bytes}
* @throws UnsupportedOperationException if {@code bitSize()} is not a multiple of 8.
*/
long byteSize();
@ -210,24 +204,6 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
*/
MemoryLayout withoutName();
/**
* Returns the alignment constraint associated with this layout, expressed in bits. Layout alignment defines a power
* of two {@code A} which is the bit-wise alignment of the layout. If {@code A <= 8} then {@code A/8} is the number of
* bytes that must be aligned for any pointer that correctly points to this layout. Thus:
*
* <ul>
* <li>{@code A=8} means unaligned (in the usual sense), which is common in packets.</li>
* <li>{@code A=64} means word aligned (on LP64), {@code A=32} int aligned, {@code A=16} short aligned, etc.</li>
* <li>{@code A=512} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).</li>
* </ul>
*
* If no explicit alignment constraint was set on this layout (see {@link #withBitAlignment(long)}),
* then this method returns the <a href="#layout-align">natural alignment</a> constraint (in bits) associated with this layout.
*
* @return the layout alignment constraint, in bits.
*/
long bitAlignment();
/**
* Returns the alignment constraint associated with this layout, expressed in bytes. Layout alignment defines a power
* of two {@code A} which is the byte-wise alignment of the layout, where {@code A} is the number of bytes that must be aligned
@ -239,76 +215,24 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* <li>{@code A=64} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).</li>
* </ul>
*
* If no explicit alignment constraint was set on this layout (see {@link #withBitAlignment(long)}),
* If no explicit alignment constraint was set on this layout (see {@link #withByteAlignment(long)}),
* then this method returns the <a href="#layout-align">natural alignment</a> constraint (in bytes) associated with this layout.
*
* @return the layout alignment constraint, in bytes.
* @throws UnsupportedOperationException if {@code bitAlignment()} is not a multiple of 8.
*/
long byteAlignment();
/**
* Returns a memory layout of the same type with the same size and name as this layout,
* but with the specified alignment constraint (in bits).
* but with the specified alignment constraint (in bytes).
*
* @param bitAlignment the layout alignment constraint, expressed in bits.
* @param byteAlignment the layout alignment constraint, expressed in bytes.
* @return a memory layout with the given alignment constraint.
* @throws IllegalArgumentException if {@code bitAlignment} is not a power of two, or if it's less than 8.
* @throws IllegalArgumentException if {@code byteAlignment} is not a power of two, or if it's less than 1.
*/
MemoryLayout withBitAlignment(long bitAlignment);
MemoryLayout withByteAlignment(long byteAlignment);
/**
* Computes the offset, in bits, of the layout selected by the given layout path, where the path is considered rooted in this
* layout.
*
* @param elements the layout path elements.
* @return The offset, in bits, of the layout selected by the layout path in {@code elements}.
* @throws IllegalArgumentException if the layout path does not select any layout nested in this layout, or if the
* layout path contains one or more path elements that select multiple sequence element indices
* (see {@link PathElement#sequenceElement()} and {@link PathElement#sequenceElement(long, long)}).
* @throws IllegalArgumentException if the layout path contains one or more dereference path elements
* (see {@link PathElement#dereferenceElement()}).
* @throws NullPointerException if either {@code elements == null}, or if any of the elements
* in {@code elements} is {@code null}.
*/
default long bitOffset(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this), LayoutPath::offset,
EnumSet.of(PathKind.SEQUENCE_ELEMENT, PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements);
}
/**
* Creates a method handle that can be used to compute the offset, in bits, of the layout selected
* by the given layout path, where the path is considered rooted in this layout.
*
* <p>The returned method handle has a return type of {@code long}, and features as many {@code long}
* parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
* where the order of the parameters corresponds to the order of the path elements.
* The returned method handle can be used to compute a layout offset similar to {@link #bitOffset(PathElement...)},
* but where some sequence indices are specified only when invoking the method handle.
*
* <p>The final offset returned by the method handle is computed as follows:
*
* <blockquote><pre>{@code
* offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
* }</pre></blockquote>
*
* where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
* arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
* and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
* the layout path.
*
* @param elements the layout path elements.
* @return a method handle that can be used to compute the bit offset of the layout element
* specified by the given layout path elements, when supplied with the missing sequence element indices.
* @throws IllegalArgumentException if the layout path contains one or more path elements that select
* multiple sequence element indices (see {@link PathElement#sequenceElement(long, long)}).
* @throws IllegalArgumentException if the layout path contains one or more dereference path elements
* (see {@link PathElement#dereferenceElement()}).
*/
default MethodHandle bitOffsetHandle(PathElement... elements) {
return computePathOp(LayoutPath.rootPath(this), LayoutPath::offsetHandle,
EnumSet.of(PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements);
}
/**
* Computes the offset, in bytes, of the layout selected by the given layout path, where the path is considered rooted in this
@ -321,12 +245,12 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* (see {@link PathElement#sequenceElement()} and {@link PathElement#sequenceElement(long, long)}).
* @throws IllegalArgumentException if the layout path contains one or more dereference path elements
* (see {@link PathElement#dereferenceElement()}).
* @throws UnsupportedOperationException if {@code bitOffset(elements)} is not a multiple of 8.
* @throws NullPointerException if either {@code elements == null}, or if any of the elements
* in {@code elements} is {@code null}.
*/
default long byteOffset(PathElement... elements) {
return Utils.bitsToBytes(bitOffset(elements));
return computePathOp(LayoutPath.rootPath(this), LayoutPath::offset,
EnumSet.of(PathKind.SEQUENCE_ELEMENT, PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements);
}
/**
@ -342,8 +266,7 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* <p>The final offset returned by the method handle is computed as follows:
*
* <blockquote><pre>{@code
* bitOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
* offset = bitOffset / 8
* byteOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
* }</pre></blockquote>
*
* where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
@ -351,9 +274,6 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
* the layout path.
*
* <p>The method handle will throw an {@link UnsupportedOperationException} if the computed
* offset in bits is not a multiple of 8.
*
* @param elements the layout path elements.
* @return a method handle that can be used to compute the byte offset of the layout element
* specified by the given layout path elements, when supplied with the missing sequence element indices.
@ -363,9 +283,8 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* (see {@link PathElement#dereferenceElement()}).
*/
default MethodHandle byteOffsetHandle(PathElement... elements) {
MethodHandle mh = bitOffsetHandle(elements);
mh = MethodHandles.filterReturnValue(mh, Utils.BITS_TO_BYTES);
return mh;
return computePathOp(LayoutPath.rootPath(this), LayoutPath::offsetHandle,
EnumSet.of(PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements);
}
/**
@ -448,8 +367,7 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* <p>The offset of the returned segment is computed as follows:
*
* <blockquote><pre>{@code
* bitOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
* offset = bitOffset / 8
* byteOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
* }</pre></blockquote>
*
* where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
@ -465,12 +383,8 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* where {@code segment} is the segment to be sliced, and where {@code layout} is the layout selected by the given
* layout path, as per {@link MemoryLayout#select(PathElement...)}.
*
* <p>The method handle will throw an {@link UnsupportedOperationException} if the computed
* offset in bits is not a multiple of 8.
*
* @param elements the layout path elements.
* @return a method handle which can be used to create a slice of the selected layout element, given a segment.
* @throws UnsupportedOperationException if the size of the selected layout in bits is not a multiple of 8.
* @throws IllegalArgumentException if the layout path contains one or more dereference path elements
* (see {@link PathElement#dereferenceElement()}).
*/
@ -687,14 +601,14 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
String toString();
/**
* Creates a padding layout with the given bitSize and a bit-alignment of eight.
* Creates a padding layout with the given byte size and a byte-alignment of one.
*
* @param bitSize the padding size in bits.
* @param byteSize the padding size (expressed in bytes).
* @return the new selector layout.
* @throws IllegalArgumentException if {@code bitSize <= 0} or {@code bitSize % 8 != 0}
* @throws IllegalArgumentException if {@code byteSize <= 0}.
*/
static PaddingLayout paddingLayout(long bitSize) {
return PaddingLayoutImpl.of(MemoryLayoutUtil.requireBitSizeValid(bitSize, false));
static PaddingLayout paddingLayout(long byteSize) {
return PaddingLayoutImpl.of(MemoryLayoutUtil.requireByteSizeValid(byteSize, false));
}
/**
@ -704,7 +618,7 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* @param elementLayout the sequence element layout.
* @return the new sequence layout with the given element layout and size.
* @throws IllegalArgumentException if {@code elementCount } is negative.
* @throws IllegalArgumentException if {@code elementLayout.bitSize() % elementLayout.bitAlignment() != 0}.
* @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}.
*/
static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) {
MemoryLayoutUtil.requireNonNegative(elementCount);
@ -720,16 +634,16 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
*
* This is equivalent to the following code:
* {@snippet lang = java:
* sequenceLayout(Long.MAX_VALUE / elementLayout.bitSize(), elementLayout);
* sequenceLayout(Long.MAX_VALUE / elementLayout.byteSize(), elementLayout);
* }
*
* @param elementLayout the sequence element layout.
* @return a new sequence layout with the given element layout and maximum element count.
* @throws IllegalArgumentException if {@code elementLayout.bitSize() % elementLayout.bitAlignment() != 0}.
* @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}.
*/
static SequenceLayout sequenceLayout(MemoryLayout elementLayout) {
Objects.requireNonNull(elementLayout);
return sequenceLayout(Long.MAX_VALUE / elementLayout.bitSize(), elementLayout);
return sequenceLayout(Long.MAX_VALUE / elementLayout.byteSize(), elementLayout);
}
/**
@ -737,7 +651,7 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
*
* @param elements The member layouts of the struct layout.
* @return a struct layout with the given member layouts.
* @throws IllegalArgumentException if the sum of the {@linkplain #bitSize() bit sizes} of the member layouts
* @throws IllegalArgumentException if the sum of the {@linkplain #byteSize() byte sizes} of the member layouts
* overflows.
* @throws IllegalArgumentException if a member layout in {@code elements} occurs at an offset (relative to the start
* of the struct layout) which is not compatible with its alignment constraint.
@ -752,14 +666,14 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin
* To avoid the exception, clients can either insert additional padding layout elements:
*
* {@snippet lang = java:
* structLayout(JAVA_SHORT, MemoryLayout.ofPadding(16), JAVA_INT)
* structLayout(JAVA_SHORT, MemoryLayout.ofPadding(2), JAVA_INT)
* }
*
* Or, alternatively, they can use a member layout which features a smaller alignment constraint. This will result
* in a <em>packed</em> struct layout:
*
* {@snippet lang = java:
* structLayout(JAVA_SHORT, JAVA_INT.withBitAlignment(16))
* structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2))
* }
*/
static StructLayout structLayout(MemoryLayout... elements) {

View file

@ -379,7 +379,7 @@ import jdk.internal.vm.annotation.ForceInline;
* to read a pointer from some memory segment. This can be done via the
* {@linkplain MemorySegment#get(AddressLayout, long)} access method. This method accepts an
* {@linkplain AddressLayout address layout} (e.g. {@link ValueLayout#ADDRESS}), the layout of the pointer
* to be read. For instance on a 64-bit platform, the size of an address layout is 64 bits. The access operation
* to be read. For instance on a 64-bit platform, the size of an address layout is 8 bytes. The access operation
* also accepts an offset, expressed in bytes, which indicates the position (relative to the start of the memory segment)
* at which the pointer is stored. The access operation returns a zero-length native memory segment, backed by a region
* of memory whose starting address is the 64-bit value read at the specified offset.
@ -470,7 +470,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @return the element spliterator for this segment
* @throws IllegalArgumentException if {@code elementLayout.byteSize() == 0}.
* @throws IllegalArgumentException if {@code byteSize() % elementLayout.byteSize() != 0}.
* @throws IllegalArgumentException if {@code elementLayout.bitSize() % elementLayout.bitAlignment() != 0}.
* @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}.
* @throws IllegalArgumentException if this segment is <a href="MemorySegment.html#segment-alignment">incompatible
* with the alignment constraint</a> in the provided layout.
*/
@ -487,7 +487,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl {
* @return a sequential {@code Stream} over disjoint slices in this segment.
* @throws IllegalArgumentException if {@code elementLayout.byteSize() == 0}.
* @throws IllegalArgumentException if {@code byteSize() % elementLayout.byteSize() != 0}.
* @throws IllegalArgumentException if {@code elementLayout.bitSize() % elementLayout.bitAlignment() != 0}.
* @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0}.
* @throws IllegalArgumentException if this segment is <a href="MemorySegment.html#segment-alignment">incompatible
* with the alignment constraint</a> in the provided layout.
*/

View file

@ -56,6 +56,5 @@ public sealed interface PaddingLayout extends MemoryLayout permits PaddingLayout
* {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
*/
@Override
PaddingLayout withBitAlignment(long bitAlignment);
PaddingLayout withByteAlignment(long byteAlignment);
}

View file

@ -143,7 +143,7 @@ public sealed interface SequenceLayout extends MemoryLayout permits SequenceLayo
/**
* {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
* @throws IllegalArgumentException if {@code bitAlignment < elementLayout().bitAlignment()}.
* @throws IllegalArgumentException if {@code byteAlignment < elementLayout().byteAlignment()}.
*/
SequenceLayout withBitAlignment(long bitAlignment);
SequenceLayout withByteAlignment(long byteAlignment);
}

View file

@ -56,5 +56,5 @@ public sealed interface StructLayout extends GroupLayout permits StructLayoutImp
* @throws IllegalArgumentException {@inheritDoc}
*/
@Override
StructLayout withBitAlignment(long bitAlignment);
StructLayout withByteAlignment(long byteAlignment);
}

View file

@ -56,5 +56,5 @@ public sealed interface UnionLayout extends GroupLayout permits UnionLayoutImpl
* @throws IllegalArgumentException {@inheritDoc}
*/
@Override
UnionLayout withBitAlignment(long bitAlignment);
UnionLayout withByteAlignment(long byteAlignment);
}

View file

@ -37,7 +37,7 @@ import jdk.internal.javac.PreviewFeature;
* <em>integral</em> values (either signed or unsigned), <em>floating-point</em> values and
* <em>address</em> values.
* <p>
* Each value layout has a size, an alignment (in bits),
* Each value layout has a size, an alignment (both expressed in bytes),
* a {@linkplain ByteOrder byte order}, and a <em>carrier</em>, that is, the Java type that should be used when
* {@linkplain MemorySegment#get(OfInt, long) accessing} a region of memory using the value layout.
* <p>
@ -129,7 +129,7 @@ public sealed interface ValueLayout extends MemoryLayout permits
* featuring {@code shape.length + 1}
* {@code long} coordinates.
* @throws IllegalArgumentException if {@code shape[i] < 0}, for at least one index {@code i}.
* @throws UnsupportedOperationException if {@code bitAlignment() > bitSize()}.
* @throws UnsupportedOperationException if {@code byteAlignment() > byteSize()}.
* @see MethodHandles#memorySegmentViewVarHandle
* @see MemoryLayout#varHandle(PathElement...)
* @see SequenceLayout
@ -152,7 +152,7 @@ public sealed interface ValueLayout extends MemoryLayout permits
* @throws IllegalArgumentException {@inheritDoc}
*/
@Override
ValueLayout withBitAlignment(long bitAlignment);
ValueLayout withByteAlignment(long byteAlignment);
/**
* A value layout whose carrier is {@code boolean.class}.
@ -180,7 +180,7 @@ public sealed interface ValueLayout extends MemoryLayout permits
* @throws IllegalArgumentException {@inheritDoc}
*/
@Override
OfBoolean withBitAlignment(long bitAlignment);
OfBoolean withByteAlignment(long byteAlignment);
/**
* {@inheritDoc}
@ -216,7 +216,7 @@ public sealed interface ValueLayout extends MemoryLayout permits
* @throws IllegalArgumentException {@inheritDoc}
*/
@Override
OfByte withBitAlignment(long bitAlignment);
OfByte withByteAlignment(long byteAlignment);
/**
* {@inheritDoc}
@ -253,7 +253,7 @@ public sealed interface ValueLayout extends MemoryLayout permits
* @throws IllegalArgumentException {@inheritDoc}
*/
@Override
OfChar withBitAlignment(long bitAlignment);
OfChar withByteAlignment(long byteAlignment);
/**
* {@inheritDoc}
@ -290,7 +290,7 @@ public sealed interface ValueLayout extends MemoryLayout permits
* @throws IllegalArgumentException {@inheritDoc}
*/
@Override
OfShort withBitAlignment(long bitAlignment);
OfShort withByteAlignment(long byteAlignment);
/**
* {@inheritDoc}
@ -327,7 +327,7 @@ public sealed interface ValueLayout extends MemoryLayout permits
* @throws IllegalArgumentException {@inheritDoc}
*/
@Override
OfInt withBitAlignment(long bitAlignment);
OfInt withByteAlignment(long byteAlignment);
/**
* {@inheritDoc}
@ -363,7 +363,7 @@ public sealed interface ValueLayout extends MemoryLayout permits
* {@inheritDoc}
*/
@Override
OfFloat withBitAlignment(long bitAlignment);
OfFloat withByteAlignment(long byteAlignment);
/**
* {@inheritDoc}
@ -400,7 +400,7 @@ public sealed interface ValueLayout extends MemoryLayout permits
* @throws IllegalArgumentException {@inheritDoc}
*/
@Override
OfLong withBitAlignment(long bitAlignment);
OfLong withByteAlignment(long byteAlignment);
/**
* {@inheritDoc}
@ -437,7 +437,7 @@ public sealed interface ValueLayout extends MemoryLayout permits
* @throws IllegalArgumentException {@inheritDoc}
*/
@Override
OfDouble withBitAlignment(long bitAlignment);
OfDouble withByteAlignment(long byteAlignment);
/**
* {@inheritDoc}
@ -449,56 +449,56 @@ public sealed interface ValueLayout extends MemoryLayout permits
/**
* A value layout constant whose size is the same as that of a machine address ({@code size_t}),
* bit alignment set to {@code sizeof(size_t) * 8}, byte order set to {@link ByteOrder#nativeOrder()}.
* byte alignment set to {@code sizeof(size_t)}, byte order set to {@link ByteOrder#nativeOrder()}.
*/
AddressLayout ADDRESS = ValueLayouts.OfAddressImpl.of(ByteOrder.nativeOrder());
/**
* A value layout constant whose size is the same as that of a Java {@code byte},
* bit alignment set to 8, and byte order set to {@link ByteOrder#nativeOrder()}.
* byte alignment set to 1, and byte order set to {@link ByteOrder#nativeOrder()}.
*/
OfByte JAVA_BYTE = ValueLayouts.OfByteImpl.of(ByteOrder.nativeOrder());
/**
* A value layout constant whose size is the same as that of a Java {@code boolean},
* bit alignment set to 8, and byte order set to {@link ByteOrder#nativeOrder()}.
* byte alignment set to 1, and byte order set to {@link ByteOrder#nativeOrder()}.
*/
OfBoolean JAVA_BOOLEAN = ValueLayouts.OfBooleanImpl.of(ByteOrder.nativeOrder());
/**
* A value layout constant whose size is the same as that of a Java {@code char},
* bit alignment set to 16, and byte order set to {@link ByteOrder#nativeOrder()}.
* byte alignment set to 2, and byte order set to {@link ByteOrder#nativeOrder()}.
*/
OfChar JAVA_CHAR = ValueLayouts.OfCharImpl.of(ByteOrder.nativeOrder());
/**
* A value layout constant whose size is the same as that of a Java {@code short},
* bit alignment set to 16, and byte order set to {@link ByteOrder#nativeOrder()}.
* byte alignment set to 2, and byte order set to {@link ByteOrder#nativeOrder()}.
*/
OfShort JAVA_SHORT = ValueLayouts.OfShortImpl.of(ByteOrder.nativeOrder());
/**
* A value layout constant whose size is the same as that of a Java {@code int},
* bit alignment set to 32, and byte order set to {@link ByteOrder#nativeOrder()}.
* byte alignment set to 4, and byte order set to {@link ByteOrder#nativeOrder()}.
*/
OfInt JAVA_INT = ValueLayouts.OfIntImpl.of(ByteOrder.nativeOrder());
/**
* A value layout constant whose size is the same as that of a Java {@code long},
* (platform-dependent) bit alignment set to {@code ADDRESS.bitSize()},
* (platform-dependent) byte alignment set to {@code ADDRESS.byteSize()},
* and byte order set to {@link ByteOrder#nativeOrder()}.
*/
OfLong JAVA_LONG = ValueLayouts.OfLongImpl.of(ByteOrder.nativeOrder());
/**
* A value layout constant whose size is the same as that of a Java {@code float},
* bit alignment set to 32, and byte order set to {@link ByteOrder#nativeOrder()}.
* byte alignment set to 4, and byte order set to {@link ByteOrder#nativeOrder()}.
*/
OfFloat JAVA_FLOAT = ValueLayouts.OfFloatImpl.of(ByteOrder.nativeOrder());
/**
* A value layout constant whose size is the same as that of a Java {@code double},
* (platform-dependent) bit alignment set to {@code ADDRESS.bitSize()},
* (platform-dependent) byte alignment set to {@code ADDRESS.byteSize()},
* and byte order set to {@link ByteOrder#nativeOrder()}.
*/
OfDouble JAVA_DOUBLE = ValueLayouts.OfDoubleImpl.of(ByteOrder.nativeOrder());
@ -508,83 +508,83 @@ public sealed interface ValueLayout extends MemoryLayout permits
* and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* ADDRESS.withBitAlignment(8);
* ADDRESS.withByteAlignment(1);
* }
* @apiNote Care should be taken when using unaligned value layouts as they may induce
* performance and portability issues.
*/
AddressLayout ADDRESS_UNALIGNED = ADDRESS.withBitAlignment(8);
AddressLayout ADDRESS_UNALIGNED = ADDRESS.withByteAlignment(1);
/**
* An unaligned value layout constant whose size is the same as that of a Java {@code char}
* and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* JAVA_CHAR.withBitAlignment(8);
* JAVA_CHAR.withByteAlignment(1);
* }
* @apiNote Care should be taken when using unaligned value layouts as they may induce
* performance and portability issues.
*/
OfChar JAVA_CHAR_UNALIGNED = JAVA_CHAR.withBitAlignment(8);
OfChar JAVA_CHAR_UNALIGNED = JAVA_CHAR.withByteAlignment(1);
/**
* An unaligned value layout constant whose size is the same as that of a Java {@code short}
* and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* JAVA_SHORT.withBitAlignment(8);
* JAVA_SHORT.withByteAlignment(1);
* }
* @apiNote Care should be taken when using unaligned value layouts as they may induce
* performance and portability issues.
*/
OfShort JAVA_SHORT_UNALIGNED = JAVA_SHORT.withBitAlignment(8);
OfShort JAVA_SHORT_UNALIGNED = JAVA_SHORT.withByteAlignment(1);
/**
* An unaligned value layout constant whose size is the same as that of a Java {@code int}
* and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* JAVA_INT.withBitAlignment(8);
* JAVA_INT.withByteAlignment(1);
* }
* @apiNote Care should be taken when using unaligned value layouts as they may induce
* performance and portability issues.
*/
OfInt JAVA_INT_UNALIGNED = JAVA_INT.withBitAlignment(8);
OfInt JAVA_INT_UNALIGNED = JAVA_INT.withByteAlignment(1);
/**
* An unaligned value layout constant whose size is the same as that of a Java {@code long}
* and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* JAVA_LONG.withBitAlignment(8);
* JAVA_LONG.withByteAlignment(1);
* }
* @apiNote Care should be taken when using unaligned value layouts as they may induce
* performance and portability issues.
*/
OfLong JAVA_LONG_UNALIGNED = JAVA_LONG.withBitAlignment(8);
OfLong JAVA_LONG_UNALIGNED = JAVA_LONG.withByteAlignment(1);
/**
* An unaligned value layout constant whose size is the same as that of a Java {@code float}
* and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* JAVA_FLOAT.withBitAlignment(8);
* JAVA_FLOAT.withByteAlignment(1);
* }
* @apiNote Care should be taken when using unaligned value layouts as they may induce
* performance and portability issues.
*/
OfFloat JAVA_FLOAT_UNALIGNED = JAVA_FLOAT.withBitAlignment(8);
OfFloat JAVA_FLOAT_UNALIGNED = JAVA_FLOAT.withByteAlignment(1);
/**
* An unaligned value layout constant whose size is the same as that of a Java {@code double}
* and byte order set to {@link ByteOrder#nativeOrder()}.
* Equivalent to the following code:
* {@snippet lang=java :
* JAVA_DOUBLE.withBitAlignment(8);
* JAVA_DOUBLE.withByteAlignment(1);
* }
* @apiNote Care should be taken when using unaligned value layouts as they may induce
* performance and portability issues.
*/
OfDouble JAVA_DOUBLE_UNALIGNED = JAVA_DOUBLE.withBitAlignment(8);
OfDouble JAVA_DOUBLE_UNALIGNED = JAVA_DOUBLE.withByteAlignment(1);
}

View file

@ -7964,7 +7964,7 @@ assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
* <p>As an example, consider the memory layout expressed by a {@link GroupLayout} instance constructed as follows:
* {@snippet lang="java" :
* GroupLayout seq = java.lang.foreign.MemoryLayout.structLayout(
* MemoryLayout.paddingLayout(32),
* MemoryLayout.paddingLayout(4),
* ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value")
* );
* }

View file

@ -54,10 +54,10 @@ public enum CABI {
if (ForeignLinkerSupport.isSupported()) {
// figure out the ABI based on the platform
String arch = StaticProperty.osArch();
long addressSize = ADDRESS.bitSize();
long addressSize = ADDRESS.byteSize();
// might be running in a 32-bit VM on a 64-bit platform.
// addressSize will be correctly 32
if ((arch.equals("amd64") || arch.equals("x86_64")) && addressSize == 64) {
if ((arch.equals("amd64") || arch.equals("x86_64")) && addressSize == 8) {
if (OperatingSystem.isWindows()) {
return WIN_64;
} else {

View file

@ -97,7 +97,7 @@ public class LayoutPath {
check(SequenceLayout.class, "attempting to select a sequence element from a non-sequence layout");
SequenceLayout seq = (SequenceLayout)layout;
MemoryLayout elem = seq.elementLayout();
return LayoutPath.nestedPath(elem, offset, addStride(elem.bitSize()), addBound(seq.elementCount()), derefAdapters, this);
return LayoutPath.nestedPath(elem, offset, addStride(elem.byteSize()), addBound(seq.elementCount()), derefAdapters, this);
}
public LayoutPath sequenceElement(long start, long step) {
@ -105,7 +105,7 @@ public class LayoutPath {
SequenceLayout seq = (SequenceLayout)layout;
checkSequenceBounds(seq, start);
MemoryLayout elem = seq.elementLayout();
long elemSize = elem.bitSize();
long elemSize = elem.byteSize();
long nelems = step > 0 ?
seq.elementCount() - start :
start + 1;
@ -118,7 +118,7 @@ public class LayoutPath {
check(SequenceLayout.class, "attempting to select a sequence element from a non-sequence layout");
SequenceLayout seq = (SequenceLayout)layout;
checkSequenceBounds(seq, index);
long elemSize = seq.elementLayout().bitSize();
long elemSize = seq.elementLayout().byteSize();
long elemOffset = elemSize * index;
return LayoutPath.nestedPath(seq.elementLayout(), offset + elemOffset, strides, bounds, derefAdapters,this);
}
@ -135,7 +135,7 @@ public class LayoutPath {
elem = l;
break;
} else if (g instanceof StructLayout) {
offset += l.bitSize();
offset += l.byteSize();
}
}
if (elem == null) {
@ -156,7 +156,7 @@ public class LayoutPath {
}
elem = g.memberLayouts().get(i);
if (g instanceof StructLayout && i < index) {
offset += elem.bitSize();
offset += elem.byteSize();
}
}
return LayoutPath.nestedPath(elem, this.offset + offset, strides, bounds, derefAdapters, this);
@ -196,14 +196,14 @@ public class LayoutPath {
VarHandle handle = Utils.makeSegmentViewVarHandle(valueLayout);
for (int i = strides.length - 1; i >= 0; i--) {
MethodHandle collector = MethodHandles.insertArguments(MH_ADD_SCALED_OFFSET, 2,
Utils.bitsToBytes(strides[i]),
strides[i],
bounds[i]);
// (J, ...) -> J to (J, J, ...) -> J
// i.e. new coord is prefixed. Last coord will correspond to innermost layout
handle = MethodHandles.collectCoordinates(handle, 1, collector);
}
handle = MethodHandles.insertCoordinates(handle, 1,
Utils.bitsToBytes(offset));
offset);
if (adapt) {
for (int i = derefAdapters.length; i > 0; i--) {
@ -232,8 +232,7 @@ public class LayoutPath {
}
public MethodHandle sliceHandle() {
MethodHandle offsetHandle = offsetHandle(); // bit offset
offsetHandle = MethodHandles.filterReturnValue(offsetHandle, Utils.BITS_TO_BYTES); // byte offset
MethodHandle offsetHandle = offsetHandle(); // byte offset
MethodHandle sliceHandle = MH_SLICE; // (MS, long, long) -> MS
sliceHandle = MethodHandles.insertArguments(sliceHandle, 2, layout.byteSize()); // (MS, long) -> MS

View file

@ -43,8 +43,8 @@ public sealed class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl pe
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
// The maximum alignment supported by malloc - typically 16 on
// 64-bit platforms and 8 on 32-bit platforms.
// The maximum alignment supported by malloc - typically 16 bytes on
// 64-bit platforms and 8 bytes on 32-bit platforms.
private static final long MAX_MALLOC_ALIGN = Unsafe.ADDRESS_SIZE == 4 ? 8 : 16;
private static final boolean SKIP_ZERO_MEMORY = GetBooleanAction.privilegedGetProperty("jdk.internal.foreign.skipZeroMemory");

View file

@ -63,7 +63,6 @@ public final class Utils {
private static final MethodHandle BOOL_TO_BYTE;
private static final MethodHandle ADDRESS_TO_LONG;
private static final MethodHandle LONG_TO_ADDRESS;
public static final MethodHandle BITS_TO_BYTES;
static {
try {
@ -76,8 +75,6 @@ public final class Utils {
MethodType.methodType(long.class, MemorySegment.class));
LONG_TO_ADDRESS = lookup.findStatic(Utils.class, "longToAddress",
MethodType.methodType(MemorySegment.class, long.class, long.class, long.class));
BITS_TO_BYTES = lookup.findStatic(Utils.class, "bitsToBytes",
MethodType.methodType(long.class, long.class));
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
@ -92,11 +89,6 @@ public final class Utils {
return ms.asSlice(alignUp(offset, alignment) - offset);
}
public static long bitsToBytes(long bits) {
assert Utils.isAligned(bits, 8);
return bits / Byte.SIZE;
}
public static VarHandle makeSegmentViewVarHandle(ValueLayout layout) {
final class VarHandleCache {
private static final Map<ValueLayout, VarHandle> HANDLE_MAP = new ConcurrentHashMap<>();
@ -177,7 +169,7 @@ public final class Utils {
public static void checkElementAlignment(ValueLayout layout, String msg) {
// Fast-path: if both size and alignment are powers of two, we can just
// check if one is greater than the other.
assert isPowerOfTwo(layout.bitSize());
assert isPowerOfTwo(layout.byteSize());
if (layout.byteAlignment() > layout.byteSize()) {
throw new IllegalArgumentException(msg);
}
@ -236,14 +228,14 @@ public final class Utils {
List<MemoryLayout> layouts = new ArrayList<>();
long align = 0;
for (MemoryLayout l : elements) {
long padding = computePadding(offset, l.bitAlignment());
long padding = computePadding(offset, l.byteAlignment());
if (padding != 0) {
layouts.add(MemoryLayout.paddingLayout(padding));
offset += padding;
}
layouts.add(l);
align = Math.max(align, l.bitAlignment());
offset += l.bitSize();
align = Math.max(align, l.byteAlignment());
offset += l.byteSize();
}
long padding = computePadding(offset, align);
if (padding != 0) {

View file

@ -160,7 +160,7 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
checkMemberOffset(sl, member, lastUnpaddedOffset, offset);
checkLayoutRecursive(member);
offset += member.bitSize();
offset += member.byteSize();
if (!(member instanceof PaddingLayout)) {
lastUnpaddedOffset = offset;
}
@ -171,7 +171,7 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
for (MemoryLayout member : ul.memberLayouts()) {
checkLayoutRecursive(member);
if (!(member instanceof PaddingLayout)) {
maxUnpaddedLayout = Long.max(maxUnpaddedLayout, member.bitSize());
maxUnpaddedLayout = Long.max(maxUnpaddedLayout, member.byteSize());
}
}
checkGroupSize(ul, maxUnpaddedLayout);
@ -182,10 +182,10 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
// check for trailing padding
private static void checkGroupSize(GroupLayout gl, long maxUnpaddedOffset) {
long expectedSize = Utils.alignUp(maxUnpaddedOffset, gl.bitAlignment());
if (gl.bitSize() != expectedSize) {
long expectedSize = Utils.alignUp(maxUnpaddedOffset, gl.byteAlignment());
if (gl.byteSize() != expectedSize) {
throw new IllegalArgumentException("Layout '" + gl + "' has unexpected size: "
+ gl.bitSize() + " != " + expectedSize);
+ gl.byteSize() + " != " + expectedSize);
}
}
@ -193,7 +193,7 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
// the previous layout
private static void checkMemberOffset(StructLayout parent, MemoryLayout memberLayout,
long lastUnpaddedOffset, long offset) {
long expectedOffset = Utils.alignUp(lastUnpaddedOffset, memberLayout.bitAlignment());
long expectedOffset = Utils.alignUp(lastUnpaddedOffset, memberLayout.byteAlignment());
if (expectedOffset != offset) {
throw new IllegalArgumentException("Member layout '" + memberLayout + "', of '" + parent + "'" +
" found at unexpected offset: " + offset + " != " + expectedOffset);
@ -202,7 +202,7 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
private static void checkHasNaturalAlignment(MemoryLayout layout) {
if (!((AbstractLayout<?>) layout).hasNaturalAlignment()) {
throw new IllegalArgumentException("Layout bit alignment must be natural alignment: " + layout);
throw new IllegalArgumentException("Layout alignment must be natural alignment: " + layout);
}
}

View file

@ -79,7 +79,6 @@ public final class SharedUtils {
public static final MethodHandle MH_CHECK_SYMBOL;
public static final AddressLayout C_POINTER = ADDRESS
.withBitAlignment(64)
.withTargetLayout(MemoryLayout.sequenceLayout(JAVA_BYTE));
public static final Arena DUMMY_ARENA = new Arena() {

View file

@ -58,7 +58,7 @@ public enum TypeClass {
}
static boolean isRegisterAggregate(MemoryLayout type) {
return type.bitSize() <= MAX_AGGREGATE_REGS_SIZE * 64;
return type.byteSize() <= MAX_AGGREGATE_REGS_SIZE * 8;
}
static List<MemoryLayout> scalarLayouts(GroupLayout gl) {
@ -106,8 +106,8 @@ public enum TypeClass {
return false;
TypeClass argClass = classifyValueType((ValueLayout) elem);
if (elem.bitSize() != baseType.bitSize() ||
elem.bitAlignment() != baseType.bitAlignment() ||
if (elem.byteSize() != baseType.byteSize() ||
elem.byteAlignment() != baseType.byteAlignment() ||
baseArgClass != argClass) {
return false;
}

View file

@ -58,9 +58,9 @@ import static java.lang.foreign.ValueLayout.JAVA_SHORT;
* } ffi_type;
*/
class FFIType {
private static final ValueLayout SIZE_T = switch ((int) ADDRESS.bitSize()) {
case 64 -> JAVA_LONG;
case 32 -> JAVA_INT;
private static final ValueLayout SIZE_T = switch ((int) ADDRESS.byteSize()) {
case 8 -> JAVA_LONG;
case 4 -> JAVA_INT;
default -> throw new IllegalStateException("Address size not supported: " + ADDRESS.byteSize());
};
private static final ValueLayout UNSIGNED_SHORT = JAVA_SHORT;

View file

@ -181,7 +181,7 @@ public enum TypeClass {
}
private static boolean isRegisterAggregate(MemoryLayout type) {
return type.bitSize() <= MAX_AGGREGATE_REGS_SIZE * 64;
return type.byteSize() <= MAX_AGGREGATE_REGS_SIZE * 8;
}
private static TypeClass classifyStructType(GroupLayout layout) {

View file

@ -29,7 +29,6 @@ import java.lang.foreign.MemoryLayout;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.LongBinaryOperator;
import java.util.stream.Collectors;
/**
@ -49,13 +48,13 @@ public sealed abstract class AbstractGroupLayout<L extends AbstractGroupLayout<L
private final Kind kind;
private final List<MemoryLayout> elements;
final long minBitAlignment;
final long minByteAlignment;
AbstractGroupLayout(Kind kind, List<MemoryLayout> elements, long bitSize, long bitAlignment, long minBitAlignment, Optional<String> name) {
super(bitSize, bitAlignment, name); // Subclassing creates toctou problems here
AbstractGroupLayout(Kind kind, List<MemoryLayout> elements, long byteSize, long byteAlignment, long minByteAlignment, Optional<String> name) {
super(byteSize, byteAlignment, name); // Subclassing creates toctou problems here
this.kind = kind;
this.elements = List.copyOf(elements);
this.minBitAlignment = minBitAlignment;
this.minByteAlignment = minByteAlignment;
}
/**
@ -82,11 +81,11 @@ public sealed abstract class AbstractGroupLayout<L extends AbstractGroupLayout<L
}
@Override
public L withBitAlignment(long bitAlignment) {
if (bitAlignment < minBitAlignment) {
public L withByteAlignment(long byteAlignment) {
if (byteAlignment < minByteAlignment) {
throw new IllegalArgumentException("Invalid alignment constraint");
}
return super.withBitAlignment(bitAlignment);
return super.withByteAlignment(byteAlignment);
}
/**
@ -111,7 +110,7 @@ public sealed abstract class AbstractGroupLayout<L extends AbstractGroupLayout<L
@Override
public final boolean hasNaturalAlignment() {
return bitAlignment() == minBitAlignment;
return byteAlignment() == minByteAlignment;
}
/**

View file

@ -43,30 +43,26 @@ public abstract sealed class AbstractLayout<L extends AbstractLayout<L> & Memory
private final long byteAlignment;
private final Optional<String> name;
AbstractLayout(long bitSize, long bitAlignment, Optional<String> name) {
this.byteSize = MemoryLayoutUtil.requireBitSizeValid(bitSize, true) / 8;
this.byteAlignment = requirePowerOfTwoAndGreaterOrEqualToEight(bitAlignment) / 8;
AbstractLayout(long byteSize, long byteAlignment, Optional<String> name) {
this.byteSize = MemoryLayoutUtil.requireByteSizeValid(byteSize, true);
this.byteAlignment = requirePowerOfTwoAndGreaterOrEqualToOne(byteAlignment);
this.name = Objects.requireNonNull(name);
}
public final L withName(String name) {
return dup(bitAlignment(), Optional.of(name));
return dup(byteAlignment(), Optional.of(name));
}
public final L withoutName() {
return dup(bitAlignment(), Optional.empty());
return dup(byteAlignment(), Optional.empty());
}
public final Optional<String> name() {
return name;
}
public L withBitAlignment(long bitAlignment) {
return dup(bitAlignment, name);
}
public final long bitAlignment() {
return byteAlignment * 8;
public L withByteAlignment(long byteAlignment) {
return dup(byteAlignment, name);
}
public final long byteAlignment() {
@ -77,10 +73,6 @@ public abstract sealed class AbstractLayout<L extends AbstractLayout<L> & Memory
return byteSize;
}
public final long bitSize() {
return byteSize * 8;
}
public boolean hasNaturalAlignment() {
return byteSize == byteAlignment;
}
@ -127,21 +119,21 @@ public abstract sealed class AbstractLayout<L extends AbstractLayout<L> & Memory
@Override
public abstract String toString();
abstract L dup(long bitAlignment, Optional<String> name);
abstract L dup(long byteAlignment, Optional<String> name);
String decorateLayoutString(String s) {
if (name().isPresent()) {
s = String.format("%s(%s)", s, name().get());
}
if (!hasNaturalAlignment()) {
s = bitAlignment() + "%" + s;
s = byteAlignment() + "%" + s;
}
return s;
}
private static long requirePowerOfTwoAndGreaterOrEqualToEight(long value) {
private static long requirePowerOfTwoAndGreaterOrEqualToOne(long value) {
if (!Utils.isPowerOfTwo(value) || // value must be a power of two
value < 8) { // value must be greater or equal to 8
value < 1) { // value must be greater or equal to 1
throw new IllegalArgumentException("Invalid alignment: " + value);
}
return value;

View file

@ -37,11 +37,11 @@ public final class MemoryLayoutUtil {
return value;
}
public static long requireBitSizeValid(long bitSize, boolean allowZero) {
if ((bitSize == 0 && !allowZero) || bitSize < 0 || bitSize % 8 != 0) {
throw new IllegalArgumentException("Invalid bitSize: " + bitSize);
public static long requireByteSizeValid(long byteSize, boolean allowZero) {
if ((byteSize == 0 && !allowZero) || byteSize < 0) {
throw new IllegalArgumentException("Invalid byte size: " + byteSize);
}
return bitSize;
return byteSize;
}
}

View file

@ -31,17 +31,17 @@ import java.util.Optional;
public final class PaddingLayoutImpl extends AbstractLayout<PaddingLayoutImpl> implements PaddingLayout {
private PaddingLayoutImpl(long bitSize) {
this(bitSize, 8, Optional.empty());
private PaddingLayoutImpl(long byteSize) {
this(byteSize, 1, Optional.empty());
}
private PaddingLayoutImpl(long bitSize, long bitAlignment, Optional<String> name) {
super(bitSize, bitAlignment, name);
private PaddingLayoutImpl(long byteSize, long byteAlignment, Optional<String> name) {
super(byteSize, byteAlignment, name);
}
@Override
public String toString() {
return decorateLayoutString("x" + bitSize());
return decorateLayoutString("x" + byteSize());
}
@Override
@ -49,17 +49,17 @@ public final class PaddingLayoutImpl extends AbstractLayout<PaddingLayoutImpl> i
return this == other ||
other instanceof PaddingLayoutImpl otherPadding &&
super.equals(other) &&
bitSize() == otherPadding.bitSize();
byteSize() == otherPadding.byteSize();
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), bitSize());
return Objects.hash(super.hashCode(), byteSize());
}
@Override
PaddingLayoutImpl dup(long bitAlignment, Optional<String> name) {
return new PaddingLayoutImpl(bitSize(), bitAlignment, name);
PaddingLayoutImpl dup(long byteAlignment, Optional<String> name) {
return new PaddingLayoutImpl(byteSize(), byteAlignment, name);
}
@Override
@ -67,8 +67,8 @@ public final class PaddingLayoutImpl extends AbstractLayout<PaddingLayoutImpl> i
return true;
}
public static PaddingLayout of(long bitSize) {
return new PaddingLayoutImpl(bitSize);
public static PaddingLayout of(long byteSize) {
return new PaddingLayoutImpl(byteSize);
}
}

View file

@ -36,11 +36,11 @@ public final class SequenceLayoutImpl extends AbstractLayout<SequenceLayoutImpl>
private final MemoryLayout elementLayout;
private SequenceLayoutImpl(long elemCount, MemoryLayout elementLayout) {
this(elemCount, elementLayout, elementLayout.bitAlignment(), Optional.empty());
this(elemCount, elementLayout, elementLayout.byteAlignment(), Optional.empty());
}
private SequenceLayoutImpl(long elemCount, MemoryLayout elementLayout, long bitAlignment, Optional<String> name) {
super(Math.multiplyExact(elemCount, elementLayout.bitSize()), bitAlignment, name);
private SequenceLayoutImpl(long elemCount, MemoryLayout elementLayout, long byteAlignment, Optional<String> name) {
super(Math.multiplyExact(elemCount, elementLayout.byteSize()), byteAlignment, name);
this.elemCount = elemCount;
this.elementLayout = elementLayout;
}
@ -68,7 +68,7 @@ public final class SequenceLayoutImpl extends AbstractLayout<SequenceLayoutImpl>
* @throws IllegalArgumentException if {@code elementCount < 0}.
*/
public SequenceLayout withElementCount(long elementCount) {
return new SequenceLayoutImpl(elementCount, elementLayout, bitAlignment(), name());
return new SequenceLayoutImpl(elementCount, elementLayout, byteAlignment(), name());
}
/**
@ -176,7 +176,7 @@ public final class SequenceLayoutImpl extends AbstractLayout<SequenceLayoutImpl>
@Override
public String toString() {
boolean max = (Long.MAX_VALUE / elementLayout.bitSize()) == elemCount;
boolean max = (Long.MAX_VALUE / elementLayout.byteSize()) == elemCount;
return decorateLayoutString(String.format("[%s:%s]",
max ? "*" : elemCount, elementLayout));
}
@ -196,21 +196,21 @@ public final class SequenceLayoutImpl extends AbstractLayout<SequenceLayoutImpl>
}
@Override
SequenceLayoutImpl dup(long bitAlignment, Optional<String> name) {
return new SequenceLayoutImpl(elementCount(), elementLayout, bitAlignment, name);
SequenceLayoutImpl dup(long byteAlignment, Optional<String> name) {
return new SequenceLayoutImpl(elementCount(), elementLayout, byteAlignment, name);
}
@Override
public SequenceLayoutImpl withBitAlignment(long bitAlignment) {
if (bitAlignment < elementLayout.bitAlignment()) {
public SequenceLayoutImpl withByteAlignment(long byteAlignment) {
if (byteAlignment < elementLayout.byteAlignment()) {
throw new IllegalArgumentException("Invalid alignment constraint");
}
return super.withBitAlignment(bitAlignment);
return super.withByteAlignment(byteAlignment);
}
@Override
public boolean hasNaturalAlignment() {
return bitAlignment() == elementLayout.bitAlignment();
return byteAlignment() == elementLayout.byteAlignment();
}
public static SequenceLayout of(long elementCount, MemoryLayout elementLayout) {

View file

@ -32,24 +32,24 @@ import java.util.Optional;
public final class StructLayoutImpl extends AbstractGroupLayout<StructLayoutImpl> implements StructLayout {
private StructLayoutImpl(List<MemoryLayout> elements, long bitSize, long bitAlignment, long minBitAlignment, Optional<String> name) {
super(Kind.STRUCT, elements, bitSize, bitAlignment, minBitAlignment, name);
private StructLayoutImpl(List<MemoryLayout> elements, long byteSize, long byteAlignment, long minByteAlignment, Optional<String> name) {
super(Kind.STRUCT, elements, byteSize, byteAlignment, minByteAlignment, name);
}
@Override
StructLayoutImpl dup(long bitAlignment, Optional<String> name) {
return new StructLayoutImpl(memberLayouts(), bitSize(), bitAlignment, minBitAlignment, name);
StructLayoutImpl dup(long byteAlignment, Optional<String> name) {
return new StructLayoutImpl(memberLayouts(), byteSize(), byteAlignment, minByteAlignment, name);
}
public static StructLayout of(List<MemoryLayout> elements) {
long size = 0;
long align = 8;
long align = 1;
for (MemoryLayout elem : elements) {
if (size % elem.bitAlignment() != 0) {
if (size % elem.byteAlignment() != 0) {
throw new IllegalArgumentException("Invalid alignment constraint for member layout: " + elem);
}
size = Math.addExact(size, elem.bitSize());
align = Math.max(align, elem.bitAlignment());
size = Math.addExact(size, elem.byteSize());
align = Math.max(align, elem.byteAlignment());
}
return new StructLayoutImpl(elements, size, align, align, Optional.empty());
}

View file

@ -32,21 +32,21 @@ import java.util.Optional;
public final class UnionLayoutImpl extends AbstractGroupLayout<UnionLayoutImpl> implements UnionLayout {
private UnionLayoutImpl(List<MemoryLayout> elements, long bitSize, long bitAlignment, long minBitAlignment, Optional<String> name) {
super(Kind.UNION, elements, bitSize, bitAlignment, minBitAlignment, name);
private UnionLayoutImpl(List<MemoryLayout> elements, long byteSize, long byteAlignment, long minByteAlignment, Optional<String> name) {
super(Kind.UNION, elements, byteSize, byteAlignment, minByteAlignment, name);
}
@Override
UnionLayoutImpl dup(long bitAlignment, Optional<String> name) {
return new UnionLayoutImpl(memberLayouts(), bitSize(), bitAlignment, minBitAlignment, name);
UnionLayoutImpl dup(long byteAlignment, Optional<String> name) {
return new UnionLayoutImpl(memberLayouts(), byteSize(), byteAlignment, minByteAlignment, name);
}
public static UnionLayout of(List<MemoryLayout> elements) {
long size = 0;
long align = 8;
long align = 1;
for (MemoryLayout elem : elements) {
size = Math.max(size, elem.bitSize());
align = Math.max(align, elem.bitAlignment());
size = Math.max(size, elem.byteSize());
align = Math.max(align, elem.byteAlignment());
}
return new UnionLayoutImpl(elements, size, align, align, Optional.empty());
}

View file

@ -46,7 +46,7 @@ import java.util.Optional;
/**
* A value layout. A value layout is used to model the memory layout associated with values of basic data types, such as <em>integral</em> types
* (either signed or unsigned) and <em>floating-point</em> types. Each value layout has a size, an alignment (in bits),
* (either signed or unsigned) and <em>floating-point</em> types. Each value layout has a size, an alignment (expressed in bytes),
* a {@linkplain ByteOrder byte order}, and a <em>carrier</em>, that is, the Java type that should be used when
* {@linkplain MemorySegment#get(ValueLayout.OfInt, long) accessing} a memory region using the value layout.
* <p>
@ -64,18 +64,18 @@ public final class ValueLayouts {
abstract sealed static class AbstractValueLayout<V extends AbstractValueLayout<V> & ValueLayout> extends AbstractLayout<V> {
static final int ADDRESS_SIZE_BITS = Unsafe.ADDRESS_SIZE * 8;
static final int ADDRESS_SIZE_BYTES = Unsafe.ADDRESS_SIZE;
private final Class<?> carrier;
private final ByteOrder order;
@Stable
private VarHandle handle;
AbstractValueLayout(Class<?> carrier, ByteOrder order, long bitSize, long bitAlignment, Optional<String> name) {
super(bitSize, bitAlignment, name);
AbstractValueLayout(Class<?> carrier, ByteOrder order, long byteSize, long byteAlignment, Optional<String> name) {
super(byteSize, byteAlignment, name);
this.carrier = carrier;
this.order = order;
assertCarrierSize(carrier, bitSize);
assertCarrierSize(carrier, byteSize);
}
/**
@ -94,7 +94,7 @@ public final class ValueLayouts {
*/
public final V withOrder(ByteOrder order) {
Objects.requireNonNull(order);
return dup(order, bitAlignment(), name());
return dup(order, byteAlignment(), name());
}
@Override
@ -103,7 +103,7 @@ public final class ValueLayouts {
if (order == ByteOrder.LITTLE_ENDIAN) {
descriptor = Character.toLowerCase(descriptor);
}
return decorateLayoutString(String.format("%s%d", descriptor, bitSize()));
return decorateLayoutString(String.format("%s%d", descriptor, byteSize()));
}
@Override
@ -143,20 +143,21 @@ public final class ValueLayouts {
}
@Override
final V dup(long bitAlignment, Optional<String> name) {
return dup(order(), bitAlignment, name);
final V dup(long byteAlignment, Optional<String> name) {
return dup(order(), byteAlignment, name);
}
abstract V dup(ByteOrder order, long bitAlignment, Optional<String> name);
abstract V dup(ByteOrder order, long byteAlignment, Optional<String> name);
static void assertCarrierSize(Class<?> carrier, long bitSize) {
static void assertCarrierSize(Class<?> carrier, long byteSize) {
assert isValidCarrier(carrier);
assert carrier != MemorySegment.class
// MemorySegment bitSize must always equal ADDRESS_SIZE_BITS
|| bitSize == ADDRESS_SIZE_BITS;
// MemorySegment byteSize must always equal ADDRESS_SIZE_BYTES
|| byteSize == ADDRESS_SIZE_BYTES;
assert !carrier.isPrimitive() ||
// Primitive class bitSize must always correspond
bitSize == (carrier == boolean.class ? 8 : Wrapper.forPrimitiveType(carrier).bitWidth());
// Primitive class byteSize must always correspond
byteSize == (carrier == boolean.class ? 1 :
Utils.byteWidthOfPrimitive(carrier));
}
static boolean isValidCarrier(Class<?> carrier) {
@ -189,129 +190,129 @@ public final class ValueLayouts {
public static final class OfBooleanImpl extends AbstractValueLayout<OfBooleanImpl> implements ValueLayout.OfBoolean {
private OfBooleanImpl(ByteOrder order, long bitAlignment, Optional<String> name) {
super(boolean.class, order, Byte.SIZE, bitAlignment, name);
private OfBooleanImpl(ByteOrder order, long byteAlignment, Optional<String> name) {
super(boolean.class, order, Byte.BYTES, byteAlignment, name);
}
@Override
OfBooleanImpl dup(ByteOrder order, long bitAlignment, Optional<String> name) {
return new OfBooleanImpl(order, bitAlignment, name);
OfBooleanImpl dup(ByteOrder order, long byteAlignment, Optional<String> name) {
return new OfBooleanImpl(order, byteAlignment, name);
}
public static OfBoolean of(ByteOrder order) {
return new OfBooleanImpl(order, Byte.SIZE, Optional.empty());
return new OfBooleanImpl(order, Byte.BYTES, Optional.empty());
}
}
public static final class OfByteImpl extends AbstractValueLayout<OfByteImpl> implements ValueLayout.OfByte {
private OfByteImpl(ByteOrder order, long bitAlignment, Optional<String> name) {
super(byte.class, order, Byte.SIZE, bitAlignment, name);
private OfByteImpl(ByteOrder order, long byteAlignment, Optional<String> name) {
super(byte.class, order, Byte.BYTES, byteAlignment, name);
}
@Override
OfByteImpl dup(ByteOrder order, long bitAlignment, Optional<String> name) {
return new OfByteImpl(order, bitAlignment, name);
OfByteImpl dup(ByteOrder order, long byteAlignment, Optional<String> name) {
return new OfByteImpl(order, byteAlignment, name);
}
public static OfByte of(ByteOrder order) {
return new OfByteImpl(order, Byte.SIZE, Optional.empty());
return new OfByteImpl(order, Byte.BYTES, Optional.empty());
}
}
public static final class OfCharImpl extends AbstractValueLayout<OfCharImpl> implements ValueLayout.OfChar {
private OfCharImpl(ByteOrder order, long bitAlignment, Optional<String> name) {
super(char.class, order, Character.SIZE, bitAlignment, name);
private OfCharImpl(ByteOrder order, long byteAlignment, Optional<String> name) {
super(char.class, order, Character.BYTES, byteAlignment, name);
}
@Override
OfCharImpl dup(ByteOrder order, long bitAlignment, Optional<String> name) {
return new OfCharImpl(order, bitAlignment, name);
OfCharImpl dup(ByteOrder order, long byteAlignment, Optional<String> name) {
return new OfCharImpl(order, byteAlignment, name);
}
public static OfChar of(ByteOrder order) {
return new OfCharImpl(order, Character.SIZE, Optional.empty());
return new OfCharImpl(order, Character.BYTES, Optional.empty());
}
}
public static final class OfShortImpl extends AbstractValueLayout<OfShortImpl> implements ValueLayout.OfShort {
private OfShortImpl(ByteOrder order, long bitAlignment, Optional<String> name) {
super(short.class, order, Short.SIZE, bitAlignment, name);
private OfShortImpl(ByteOrder order, long byteAlignment, Optional<String> name) {
super(short.class, order, Short.BYTES, byteAlignment, name);
}
@Override
OfShortImpl dup(ByteOrder order, long bitAlignment, Optional<String> name) {
return new OfShortImpl(order, bitAlignment, name);
OfShortImpl dup(ByteOrder order, long byteAlignment, Optional<String> name) {
return new OfShortImpl(order, byteAlignment, name);
}
public static OfShort of(ByteOrder order) {
return new OfShortImpl(order, Short.SIZE, Optional.empty());
return new OfShortImpl(order, Short.BYTES, Optional.empty());
}
}
public static final class OfIntImpl extends AbstractValueLayout<OfIntImpl> implements ValueLayout.OfInt {
private OfIntImpl(ByteOrder order, long bitAlignment, Optional<String> name) {
super(int.class, order, Integer.SIZE, bitAlignment, name);
private OfIntImpl(ByteOrder order, long byteAlignment, Optional<String> name) {
super(int.class, order, Integer.BYTES, byteAlignment, name);
}
@Override
OfIntImpl dup(ByteOrder order, long bitAlignment, Optional<String> name) {
return new OfIntImpl(order, bitAlignment, name);
OfIntImpl dup(ByteOrder order, long byteAlignment, Optional<String> name) {
return new OfIntImpl(order, byteAlignment, name);
}
public static OfInt of(ByteOrder order) {
return new OfIntImpl(order, Integer.SIZE, Optional.empty());
return new OfIntImpl(order, Integer.BYTES, Optional.empty());
}
}
public static final class OfFloatImpl extends AbstractValueLayout<OfFloatImpl> implements ValueLayout.OfFloat {
private OfFloatImpl(ByteOrder order, long bitAlignment, Optional<String> name) {
super(float.class, order, Float.SIZE, bitAlignment, name);
private OfFloatImpl(ByteOrder order, long byteAlignment, Optional<String> name) {
super(float.class, order, Float.BYTES, byteAlignment, name);
}
@Override
OfFloatImpl dup(ByteOrder order, long bitAlignment, Optional<String> name) {
return new OfFloatImpl(order, bitAlignment, name);
OfFloatImpl dup(ByteOrder order, long byteAlignment, Optional<String> name) {
return new OfFloatImpl(order, byteAlignment, name);
}
public static OfFloat of(ByteOrder order) {
return new OfFloatImpl(order, Float.SIZE, Optional.empty());
return new OfFloatImpl(order, Float.BYTES, Optional.empty());
}
}
public static final class OfLongImpl extends AbstractValueLayout<OfLongImpl> implements ValueLayout.OfLong {
private OfLongImpl(ByteOrder order, long bitAlignment, Optional<String> name) {
super(long.class, order, Long.SIZE, bitAlignment, name);
private OfLongImpl(ByteOrder order, long byteAlignment, Optional<String> name) {
super(long.class, order, Long.BYTES, byteAlignment, name);
}
@Override
OfLongImpl dup(ByteOrder order, long bitAlignment, Optional<String> name) {
return new OfLongImpl(order, bitAlignment, name);
OfLongImpl dup(ByteOrder order, long byteAlignment, Optional<String> name) {
return new OfLongImpl(order, byteAlignment, name);
}
public static OfLong of(ByteOrder order) {
return new OfLongImpl(order, ADDRESS_SIZE_BITS, Optional.empty());
return new OfLongImpl(order, ADDRESS_SIZE_BYTES, Optional.empty());
}
}
public static final class OfDoubleImpl extends AbstractValueLayout<OfDoubleImpl> implements ValueLayout.OfDouble {
private OfDoubleImpl(ByteOrder order, long bitAlignment, Optional<String> name) {
super(double.class, order, Double.SIZE, bitAlignment, name);
private OfDoubleImpl(ByteOrder order, long byteAlignment, Optional<String> name) {
super(double.class, order, Double.BYTES, byteAlignment, name);
}
@Override
OfDoubleImpl dup(ByteOrder order, long bitAlignment, Optional<String> name) {
return new OfDoubleImpl(order, bitAlignment, name);
OfDoubleImpl dup(ByteOrder order, long byteAlignment, Optional<String> name) {
return new OfDoubleImpl(order, byteAlignment, name);
}
public static OfDouble of(ByteOrder order) {
return new OfDoubleImpl(order, ADDRESS_SIZE_BITS, Optional.empty());
return new OfDoubleImpl(order, ADDRESS_SIZE_BYTES, Optional.empty());
}
}
@ -320,14 +321,14 @@ public final class ValueLayouts {
private final MemoryLayout targetLayout;
private OfAddressImpl(ByteOrder order, long bitSize, long bitAlignment, MemoryLayout targetLayout, Optional<String> name) {
super(MemorySegment.class, order, bitSize, bitAlignment, name);
private OfAddressImpl(ByteOrder order, long byteSize, long byteAlignment, MemoryLayout targetLayout, Optional<String> name) {
super(MemorySegment.class, order, byteSize, byteAlignment, name);
this.targetLayout = targetLayout;
}
@Override
OfAddressImpl dup(ByteOrder order, long bitAlignment, Optional<String> name) {
return new OfAddressImpl(order, bitSize(), bitAlignment,targetLayout, name);
OfAddressImpl dup(ByteOrder order, long byteAlignment, Optional<String> name) {
return new OfAddressImpl(order, byteSize(), byteAlignment,targetLayout, name);
}
@Override
@ -346,12 +347,12 @@ public final class ValueLayouts {
public AddressLayout withTargetLayout(MemoryLayout layout) {
Reflection.ensureNativeAccess(Reflection.getCallerClass(), AddressLayout.class, "withTargetLayout");
Objects.requireNonNull(layout);
return new OfAddressImpl(order(), bitSize(), bitAlignment(), layout, name());
return new OfAddressImpl(order(), byteSize(), byteAlignment(), layout, name());
}
@Override
public AddressLayout withoutTargetLayout() {
return new OfAddressImpl(order(), bitSize(), bitAlignment(), null, name());
return new OfAddressImpl(order(), byteSize(), byteAlignment(), null, name());
}
@Override
@ -360,7 +361,7 @@ public final class ValueLayouts {
}
public static AddressLayout of(ByteOrder order) {
return new OfAddressImpl(order, ADDRESS_SIZE_BITS, ADDRESS_SIZE_BITS, null, Optional.empty());
return new OfAddressImpl(order, ADDRESS_SIZE_BYTES, ADDRESS_SIZE_BYTES, null, Optional.empty());
}
@Override
@ -369,7 +370,7 @@ public final class ValueLayouts {
if (order() == ByteOrder.LITTLE_ENDIAN) {
descriptor = Character.toLowerCase(descriptor);
}
String str = decorateLayoutString(String.format("%s%d", descriptor, bitSize()));
String str = decorateLayoutString(String.format("%s%d", descriptor, byteSize()));
if (targetLayout != null) {
str += ":" + targetLayout;
}