8318598: FFM stylistic cleanups

Co-authored-by: Per Minborg <pminborg@openjdk.org>
Co-authored-by: Maurizio Cimadamore <mcimadamore@openjdk.org>
Reviewed-by: mcimadamore
This commit is contained in:
Jorn Vernee 2023-10-20 15:40:39 +00:00
parent b1228de623
commit 8065233e8b
34 changed files with 230 additions and 256 deletions

View File

@ -49,7 +49,6 @@ import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets; import jdk.internal.access.SharedSecrets;
import jdk.internal.access.foreign.UnmapperProxy; import jdk.internal.access.foreign.UnmapperProxy;
import jdk.internal.misc.ScopedMemoryAccess; import jdk.internal.misc.ScopedMemoryAccess;
import jdk.internal.misc.Unsafe;
import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection; import jdk.internal.reflect.Reflection;
import jdk.internal.util.ArraysSupport; import jdk.internal.util.ArraysSupport;
@ -560,23 +559,23 @@ public abstract sealed class AbstractMemorySegmentImpl
bufferScope = MemorySessionImpl.createHeap(bufferRef(bb)); bufferScope = MemorySessionImpl.createHeap(bufferRef(bb));
} }
if (base != null) { if (base != null) {
if (base instanceof byte[]) { return switch (base) {
return new HeapMemorySegmentImpl.OfByte(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); case byte[] __ ->
} else if (base instanceof short[]) { new HeapMemorySegmentImpl.OfByte(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
return new HeapMemorySegmentImpl.OfShort(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); case short[] __ ->
} else if (base instanceof char[]) { new HeapMemorySegmentImpl.OfShort(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
return new HeapMemorySegmentImpl.OfChar(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); case char[] __ ->
} else if (base instanceof int[]) { new HeapMemorySegmentImpl.OfChar(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
return new HeapMemorySegmentImpl.OfInt(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); case int[] __ ->
} else if (base instanceof float[]) { new HeapMemorySegmentImpl.OfInt(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
return new HeapMemorySegmentImpl.OfFloat(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); case float[] __ ->
} else if (base instanceof long[]) { new HeapMemorySegmentImpl.OfFloat(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
return new HeapMemorySegmentImpl.OfLong(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); case long[] __ ->
} else if (base instanceof double[]) { new HeapMemorySegmentImpl.OfLong(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
return new HeapMemorySegmentImpl.OfDouble(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); case double[] __ ->
} else { new HeapMemorySegmentImpl.OfDouble(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope);
throw new AssertionError("Cannot get here"); default -> throw new AssertionError("Cannot get here");
} };
} else if (unmapper == null) { } else if (unmapper == null) {
return new NativeMemorySegmentImpl(bbAddress + (pos << scaleFactor), size << scaleFactor, readOnly, bufferScope); return new NativeMemorySegmentImpl(bbAddress + (pos << scaleFactor), size << scaleFactor, readOnly, bufferScope);
} else { } else {
@ -596,26 +595,6 @@ public abstract sealed class AbstractMemorySegmentImpl
} }
} }
private static int getScaleFactor(Buffer buffer) {
if (buffer instanceof ByteBuffer) {
return 0;
} else if (buffer instanceof CharBuffer) {
return 1;
} else if (buffer instanceof ShortBuffer) {
return 1;
} else if (buffer instanceof IntBuffer) {
return 2;
} else if (buffer instanceof FloatBuffer) {
return 2;
} else if (buffer instanceof LongBuffer) {
return 3;
} else if (buffer instanceof DoubleBuffer) {
return 3;
} else {
throw new AssertionError("Cannot get here");
}
}
@ForceInline @ForceInline
public static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long srcOffset, public static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long srcOffset,
MemorySegment dstSegment, ValueLayout dstElementLayout, long dstOffset, MemorySegment dstSegment, ValueLayout dstElementLayout, long dstOffset,
@ -653,27 +632,25 @@ public abstract sealed class AbstractMemorySegmentImpl
Object dstArray, int dstIndex, Object dstArray, int dstIndex,
int elementCount) { int elementCount) {
long baseAndScale = getBaseAndScale(dstArray.getClass()); var dstInfo = Utils.BaseAndScale.of(dstArray);
if (dstArray.getClass().componentType() != srcLayout.carrier()) { if (dstArray.getClass().componentType() != srcLayout.carrier()) {
throw new IllegalArgumentException("Incompatible value layout: " + srcLayout); throw new IllegalArgumentException("Incompatible value layout: " + srcLayout);
} }
int dstBase = (int)baseAndScale;
long dstWidth = (int)(baseAndScale >> 32); // Use long arithmetics below
AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)srcSegment; AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)srcSegment;
Utils.checkElementAlignment(srcLayout, "Source layout alignment greater than its size"); Utils.checkElementAlignment(srcLayout, "Source layout alignment greater than its size");
if (!srcImpl.isAlignedForElement(srcOffset, srcLayout)) { if (!srcImpl.isAlignedForElement(srcOffset, srcLayout)) {
throw new IllegalArgumentException("Source segment incompatible with alignment constraints"); throw new IllegalArgumentException("Source segment incompatible with alignment constraints");
} }
srcImpl.checkAccess(srcOffset, elementCount * dstWidth, true); srcImpl.checkAccess(srcOffset, elementCount * dstInfo.scale(), true);
Objects.checkFromIndexSize(dstIndex, elementCount, Array.getLength(dstArray)); Objects.checkFromIndexSize(dstIndex, elementCount, Array.getLength(dstArray));
if (dstWidth == 1 || srcLayout.order() == ByteOrder.nativeOrder()) { if (dstInfo.scale() == 1 || srcLayout.order() == ByteOrder.nativeOrder()) {
ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(srcImpl.sessionImpl(), null, ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(srcImpl.sessionImpl(), null,
srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset, srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset,
dstArray, dstBase + (dstIndex * dstWidth), elementCount * dstWidth); dstArray, dstInfo.base() + (dstIndex * dstInfo.scale()), elementCount * dstInfo.scale());
} else { } else {
ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(srcImpl.sessionImpl(), null, ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(srcImpl.sessionImpl(), null,
srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset, srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset,
dstArray, dstBase + (dstIndex * dstWidth), elementCount * dstWidth, dstWidth); dstArray, dstInfo.base() + (dstIndex * dstInfo.scale()), elementCount * dstInfo.scale(), dstInfo.scale());
} }
} }
@ -682,27 +659,25 @@ public abstract sealed class AbstractMemorySegmentImpl
MemorySegment dstSegment, ValueLayout dstLayout, long dstOffset, MemorySegment dstSegment, ValueLayout dstLayout, long dstOffset,
int elementCount) { int elementCount) {
long baseAndScale = getBaseAndScale(srcArray.getClass()); var srcInfo = Utils.BaseAndScale.of(srcArray);
if (srcArray.getClass().componentType() != dstLayout.carrier()) { if (srcArray.getClass().componentType() != dstLayout.carrier()) {
throw new IllegalArgumentException("Incompatible value layout: " + dstLayout); throw new IllegalArgumentException("Incompatible value layout: " + dstLayout);
} }
int srcBase = (int)baseAndScale;
long srcWidth = (int)(baseAndScale >> 32); // Use long arithmetics below
Objects.checkFromIndexSize(srcIndex, elementCount, Array.getLength(srcArray)); Objects.checkFromIndexSize(srcIndex, elementCount, Array.getLength(srcArray));
AbstractMemorySegmentImpl destImpl = (AbstractMemorySegmentImpl)dstSegment; AbstractMemorySegmentImpl destImpl = (AbstractMemorySegmentImpl)dstSegment;
Utils.checkElementAlignment(dstLayout, "Destination layout alignment greater than its size"); Utils.checkElementAlignment(dstLayout, "Destination layout alignment greater than its size");
if (!destImpl.isAlignedForElement(dstOffset, dstLayout)) { if (!destImpl.isAlignedForElement(dstOffset, dstLayout)) {
throw new IllegalArgumentException("Destination segment incompatible with alignment constraints"); throw new IllegalArgumentException("Destination segment incompatible with alignment constraints");
} }
destImpl.checkAccess(dstOffset, elementCount * srcWidth, false); destImpl.checkAccess(dstOffset, elementCount * srcInfo.scale(), false);
if (srcWidth == 1 || dstLayout.order() == ByteOrder.nativeOrder()) { if (srcInfo.scale() == 1 || dstLayout.order() == ByteOrder.nativeOrder()) {
ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(null, destImpl.sessionImpl(), ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(null, destImpl.sessionImpl(),
srcArray, srcBase + (srcIndex * srcWidth), srcArray, srcInfo.base() + (srcIndex * srcInfo.scale()),
destImpl.unsafeGetBase(), destImpl.unsafeGetOffset() + dstOffset, elementCount * srcWidth); destImpl.unsafeGetBase(), destImpl.unsafeGetOffset() + dstOffset, elementCount * srcInfo.scale());
} else { } else {
ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(null, destImpl.sessionImpl(), ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(null, destImpl.sessionImpl(),
srcArray, srcBase + (srcIndex * srcWidth), srcArray, srcInfo.base() + (srcIndex * srcInfo.scale()),
destImpl.unsafeGetBase(), destImpl.unsafeGetOffset() + dstOffset, elementCount * srcWidth, srcWidth); destImpl.unsafeGetBase(), destImpl.unsafeGetOffset() + dstOffset, elementCount * srcInfo.scale(), srcInfo.scale());
} }
} }
@ -744,24 +719,16 @@ public abstract sealed class AbstractMemorySegmentImpl
return srcBytes != dstBytes ? bytes : -1; return srcBytes != dstBytes ? bytes : -1;
} }
private static long getBaseAndScale(Class<?> arrayType) { private static int getScaleFactor(Buffer buffer) {
if (arrayType.equals(byte[].class)) { return switch (buffer) {
return (long) Unsafe.ARRAY_BYTE_BASE_OFFSET | ((long)Unsafe.ARRAY_BYTE_INDEX_SCALE << 32); case ByteBuffer __ -> 0;
} else if (arrayType.equals(char[].class)) { case CharBuffer __ -> 1;
return (long) Unsafe.ARRAY_CHAR_BASE_OFFSET | ((long)Unsafe.ARRAY_CHAR_INDEX_SCALE << 32); case ShortBuffer __ -> 1;
} else if (arrayType.equals(short[].class)) { case IntBuffer __ -> 2;
return (long)Unsafe.ARRAY_SHORT_BASE_OFFSET | ((long)Unsafe.ARRAY_SHORT_INDEX_SCALE << 32); case FloatBuffer __ -> 2;
} else if (arrayType.equals(int[].class)) { case LongBuffer __ -> 3;
return (long)Unsafe.ARRAY_INT_BASE_OFFSET | ((long) Unsafe.ARRAY_INT_INDEX_SCALE << 32); case DoubleBuffer __ -> 3;
} else if (arrayType.equals(float[].class)) { };
return (long)Unsafe.ARRAY_FLOAT_BASE_OFFSET | ((long)Unsafe.ARRAY_FLOAT_INDEX_SCALE << 32);
} else if (arrayType.equals(long[].class)) {
return (long)Unsafe.ARRAY_LONG_BASE_OFFSET | ((long)Unsafe.ARRAY_LONG_INDEX_SCALE << 32);
} else if (arrayType.equals(double[].class)) {
return (long)Unsafe.ARRAY_DOUBLE_BASE_OFFSET | ((long)Unsafe.ARRAY_DOUBLE_INDEX_SCALE << 32);
} else {
throw new IllegalArgumentException("Not a supported array class: " + arrayType.getSimpleName());
}
} }
// accessors // accessors

View File

@ -27,7 +27,6 @@ package jdk.internal.foreign;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle; import java.lang.invoke.VarHandle;
import java.lang.ref.Cleaner;
import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.ForceInline;

View File

@ -33,14 +33,13 @@ import java.util.Optional;
import jdk.internal.access.JavaNioAccess; import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets; import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.Unsafe;
import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.ForceInline;
/** /**
* Implementation for heap memory segments. A heap memory segment is composed by an offset and * Implementation for heap memory segments. A heap memory segment is composed by an offset and
* a base object (typically an array). To enhance performances, the access to the base object needs to feature * a base object (typically an array). To enhance performances, the access to the base object needs to feature
* sharp type information, as well as sharp null-check information. For this reason, many concrete subclasses * sharp type information, as well as sharp null-check information. For this reason, many concrete subclasses
* of {@link HeapMemorySegmentImpl} are defined (e.g. {@link OfFloat}, so that each subclass can override the * of {@link HeapMemorySegmentImpl} are defined (e.g. {@link OfFloat}), so that each subclass can override the
* {@link HeapMemorySegmentImpl#unsafeGetBase()} method so that it returns an array of the correct (sharp) type. Note that * {@link HeapMemorySegmentImpl#unsafeGetBase()} method so that it returns an array of the correct (sharp) type. Note that
* the field type storing the 'base' coordinate is just Object; similarly, all the constructor in the subclasses * the field type storing the 'base' coordinate is just Object; similarly, all the constructor in the subclasses
* accept an Object 'base' parameter instead of a sharper type (e.g. {@code byte[]}). This is deliberate, as * accept an Object 'base' parameter instead of a sharper type (e.g. {@code byte[]}). This is deliberate, as
@ -49,13 +48,15 @@ import jdk.internal.vm.annotation.ForceInline;
*/ */
abstract sealed class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl { abstract sealed class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
private static final Unsafe UNSAFE = Unsafe.getUnsafe(); // Constants defining the maximum alignment supported by various kinds of heap arrays.
private static final int BYTE_ARR_BASE = UNSAFE.arrayBaseOffset(byte[].class); // While for most arrays, the maximum alignment is constant (the size, in bytes, of the array elements),
// note that the alignment of a long[]/double[] depends on the platform: it's 4-byte on x86, but 8 bytes on x64
// (as specified by the JAVA_LONG layout constant).
private static final long MAX_ALIGN_1 = ValueLayout.JAVA_BYTE.byteAlignment(); private static final long MAX_ALIGN_BYTE_ARRAY = ValueLayout.JAVA_BYTE.byteAlignment();
private static final long MAX_ALIGN_2 = ValueLayout.JAVA_SHORT.byteAlignment(); private static final long MAX_ALIGN_SHORT_ARRAY = ValueLayout.JAVA_SHORT.byteAlignment();
private static final long MAX_ALIGN_4 = ValueLayout.JAVA_INT.byteAlignment(); private static final long MAX_ALIGN_INT_ARRAY = ValueLayout.JAVA_INT.byteAlignment();
private static final long MAX_ALIGN_8 = ValueLayout.JAVA_LONG.byteAlignment(); private static final long MAX_ALIGN_LONG_ARRAY = ValueLayout.JAVA_LONG.byteAlignment();
final long offset; final long offset;
final Object base; final Object base;
@ -88,7 +89,7 @@ abstract sealed class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
throw new UnsupportedOperationException("Not an address to an heap-allocated byte array"); throw new UnsupportedOperationException("Not an address to an heap-allocated byte array");
} }
JavaNioAccess nioAccess = SharedSecrets.getJavaNioAccess(); JavaNioAccess nioAccess = SharedSecrets.getJavaNioAccess();
return nioAccess.newHeapByteBuffer(baseByte, (int)offset - BYTE_ARR_BASE, (int) byteSize(), null); return nioAccess.newHeapByteBuffer(baseByte, (int)offset - Utils.BaseAndScale.BYTE.base(), (int) byteSize(), null);
} }
// factories // factories
@ -111,12 +112,12 @@ abstract sealed class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
@Override @Override
public long maxAlignMask() { public long maxAlignMask() {
return MAX_ALIGN_1; return MAX_ALIGN_BYTE_ARRAY;
} }
@Override @Override
public long address() { public long address() {
return offset - Unsafe.ARRAY_BYTE_BASE_OFFSET; return offset - Utils.BaseAndScale.BYTE.base();
} }
} }
@ -138,12 +139,12 @@ abstract sealed class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
@Override @Override
public long maxAlignMask() { public long maxAlignMask() {
return MAX_ALIGN_2; return MAX_ALIGN_SHORT_ARRAY;
} }
@Override @Override
public long address() { public long address() {
return offset - Unsafe.ARRAY_CHAR_BASE_OFFSET; return offset - Utils.BaseAndScale.CHAR.base();
} }
} }
@ -165,12 +166,12 @@ abstract sealed class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
@Override @Override
public long maxAlignMask() { public long maxAlignMask() {
return MAX_ALIGN_2; return MAX_ALIGN_SHORT_ARRAY;
} }
@Override @Override
public long address() { public long address() {
return offset - Unsafe.ARRAY_SHORT_BASE_OFFSET; return offset - Utils.BaseAndScale.SHORT.base();
} }
} }
@ -192,12 +193,12 @@ abstract sealed class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
@Override @Override
public long maxAlignMask() { public long maxAlignMask() {
return MAX_ALIGN_4; return MAX_ALIGN_INT_ARRAY;
} }
@Override @Override
public long address() { public long address() {
return offset - Unsafe.ARRAY_INT_BASE_OFFSET; return offset - Utils.BaseAndScale.INT.base();
} }
} }
@ -219,12 +220,12 @@ abstract sealed class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
@Override @Override
public long maxAlignMask() { public long maxAlignMask() {
return MAX_ALIGN_8; return MAX_ALIGN_LONG_ARRAY;
} }
@Override @Override
public long address() { public long address() {
return offset - Unsafe.ARRAY_LONG_BASE_OFFSET; return offset - Utils.BaseAndScale.LONG.base();
} }
} }
@ -246,12 +247,12 @@ abstract sealed class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
@Override @Override
public long maxAlignMask() { public long maxAlignMask() {
return MAX_ALIGN_4; return MAX_ALIGN_INT_ARRAY;
} }
@Override @Override
public long address() { public long address() {
return offset - Unsafe.ARRAY_FLOAT_BASE_OFFSET; return offset - Utils.BaseAndScale.FLOAT.base();
} }
} }
@ -273,12 +274,12 @@ abstract sealed class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl {
@Override @Override
public long maxAlignMask() { public long maxAlignMask() {
return MAX_ALIGN_8; return MAX_ALIGN_LONG_ARRAY;
} }
@Override @Override
public long address() { public long address() {
return offset - Unsafe.ARRAY_DOUBLE_BASE_OFFSET; return offset - Utils.BaseAndScale.DOUBLE.base();
} }
} }

View File

@ -26,8 +26,6 @@
package jdk.internal.foreign; package jdk.internal.foreign;
import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Stable;
import java.lang.foreign.AddressLayout; import java.lang.foreign.AddressLayout;
import java.lang.foreign.GroupLayout; import java.lang.foreign.GroupLayout;
import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemoryLayout;
@ -41,7 +39,6 @@ import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle; import java.lang.invoke.VarHandle;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
import java.util.stream.IntStream; import java.util.stream.IntStream;
@ -50,7 +47,7 @@ import java.util.stream.Stream;
import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.joining;
/** /**
* This class provide support for constructing layout paths; that is, starting from a root path (see {@link #rootPath(MemoryLayout)}, * This class provide support for constructing layout paths; that is, starting from a root path (see {@link #rootPath(MemoryLayout)}),
* a path can be constructed by selecting layout elements using the selector methods provided by this class * a path can be constructed by selecting layout elements using the selector methods provided by this class
* (see {@link #sequenceElement()}, {@link #sequenceElement(long)}, {@link #sequenceElement(long, long)}, {@link #groupElement(String)}). * (see {@link #sequenceElement()}, {@link #sequenceElement(long)}, {@link #sequenceElement(long, long)}, {@link #groupElement(String)}).
* Once a path has been fully constructed, clients can ask for the offset associated with the layout element selected * Once a path has been fully constructed, clients can ask for the offset associated with the layout element selected

View File

@ -83,7 +83,7 @@ public abstract sealed class MemorySessionImpl
} }
@ForceInline @ForceInline
public static final MemorySessionImpl toMemorySession(Arena arena) { public static MemorySessionImpl toMemorySession(Arena arena) {
return (MemorySessionImpl) arena.scope(); return (MemorySessionImpl) arena.scope();
} }
@ -99,10 +99,10 @@ public abstract sealed class MemorySessionImpl
} }
/** /**
* Add a cleanup action. If a failure occurred (because of a add vs. close race), call the cleanup action. * Add a cleanup action. If a failure occurred (because of an add vs. close race), call the cleanup action.
* This semantics is useful when allocating new memory segments, since we first do a malloc/mmap and _then_ * This semantics is useful when allocating new memory segments, since we first do a malloc/mmap and _then_
* we register the cleanup (free/munmap) against the session; so, if registration fails, we still have to * we register the cleanup (free/munmap) against the session; so, if registration fails, we still have to
* cleanup memory. From the perspective of the client, such a failure would manifest as a factory * clean up memory. From the perspective of the client, such a failure would manifest as a factory
* returning a segment that is already "closed" - which is always possible anyway (e.g. if the session * returning a segment that is already "closed" - which is always possible anyway (e.g. if the session
* is closed _after_ the cleanup for the segment is registered but _before_ the factory returns the * is closed _after_ the cleanup for the segment is registered but _before_ the factory returns the
* new segment to the client). For this reason, it's not worth adding extra complexity to the segment * new segment to the client). For this reason, it's not worth adding extra complexity to the segment
@ -201,7 +201,7 @@ public abstract sealed class MemorySessionImpl
/** /**
* Checks that this session is still alive (see {@link #isAlive()}). * Checks that this session is still alive (see {@link #isAlive()}).
* @throws IllegalStateException if this session is already closed or if this is * @throws IllegalStateException if this session is already closed or if this is
* a confined session and this method is called outside of the owner thread. * a confined session and this method is called outside the owner thread.
*/ */
public void checkValidState() { public void checkValidState() {
try { try {
@ -211,7 +211,7 @@ public abstract sealed class MemorySessionImpl
} }
} }
public static final void checkValidState(MemorySegment segment) { public static void checkValidState(MemorySegment segment) {
((AbstractMemorySegmentImpl)segment).sessionImpl().checkValidState(); ((AbstractMemorySegmentImpl)segment).sessionImpl().checkValidState();
} }
@ -227,7 +227,7 @@ public abstract sealed class MemorySessionImpl
/** /**
* Closes this session, executing any cleanup action (where provided). * Closes this session, executing any cleanup action (where provided).
* @throws IllegalStateException if this session is already closed or if this is * @throws IllegalStateException if this session is already closed or if this is
* a confined session and this method is called outside of the owner thread. * a confined session and this method is called outside the owner thread.
*/ */
public void close() { public void close() {
justClose(); justClose();

View File

@ -83,56 +83,56 @@ public class SegmentFactories {
public static MemorySegment fromArray(byte[] arr) { public static MemorySegment fromArray(byte[] arr) {
ensureInitialized(); ensureInitialized();
Objects.requireNonNull(arr); Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_BYTE_INDEX_SCALE; long byteSize = (long)arr.length * Utils.BaseAndScale.BYTE.scale();
return new OfByte(Unsafe.ARRAY_BYTE_BASE_OFFSET, arr, byteSize, false, return new OfByte(Utils.BaseAndScale.BYTE.base(), arr, byteSize, false,
MemorySessionImpl.createHeap(arr)); MemorySessionImpl.createHeap(arr));
} }
public static MemorySegment fromArray(short[] arr) { public static MemorySegment fromArray(short[] arr) {
ensureInitialized(); ensureInitialized();
Objects.requireNonNull(arr); Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_SHORT_INDEX_SCALE; long byteSize = (long)arr.length * Utils.BaseAndScale.SHORT.scale();
return new OfShort(Unsafe.ARRAY_SHORT_BASE_OFFSET, arr, byteSize, false, return new OfShort(Utils.BaseAndScale.SHORT.base(), arr, byteSize, false,
MemorySessionImpl.createHeap(arr)); MemorySessionImpl.createHeap(arr));
} }
public static MemorySegment fromArray(int[] arr) { public static MemorySegment fromArray(int[] arr) {
ensureInitialized(); ensureInitialized();
Objects.requireNonNull(arr); Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_INT_INDEX_SCALE; long byteSize = (long)arr.length * Utils.BaseAndScale.INT.scale();
return new OfInt(Unsafe.ARRAY_INT_BASE_OFFSET, arr, byteSize, false, return new OfInt(Utils.BaseAndScale.INT.base(), arr, byteSize, false,
MemorySessionImpl.createHeap(arr)); MemorySessionImpl.createHeap(arr));
} }
public static MemorySegment fromArray(char[] arr) { public static MemorySegment fromArray(char[] arr) {
ensureInitialized(); ensureInitialized();
Objects.requireNonNull(arr); Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_CHAR_INDEX_SCALE; long byteSize = (long)arr.length * Utils.BaseAndScale.CHAR.scale();
return new OfChar(Unsafe.ARRAY_CHAR_BASE_OFFSET, arr, byteSize, false, return new OfChar(Utils.BaseAndScale.CHAR.base(), arr, byteSize, false,
MemorySessionImpl.createHeap(arr)); MemorySessionImpl.createHeap(arr));
} }
public static MemorySegment fromArray(float[] arr) { public static MemorySegment fromArray(float[] arr) {
ensureInitialized(); ensureInitialized();
Objects.requireNonNull(arr); Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_FLOAT_INDEX_SCALE; long byteSize = (long)arr.length * Utils.BaseAndScale.FLOAT.scale();
return new OfFloat(Unsafe.ARRAY_FLOAT_BASE_OFFSET, arr, byteSize, false, return new OfFloat(Utils.BaseAndScale.FLOAT.base(), arr, byteSize, false,
MemorySessionImpl.createHeap(arr)); MemorySessionImpl.createHeap(arr));
} }
public static MemorySegment fromArray(double[] arr) { public static MemorySegment fromArray(double[] arr) {
ensureInitialized(); ensureInitialized();
Objects.requireNonNull(arr); Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_DOUBLE_INDEX_SCALE; long byteSize = (long)arr.length * Utils.BaseAndScale.DOUBLE.scale();
return new OfDouble(Unsafe.ARRAY_DOUBLE_BASE_OFFSET, arr, byteSize, false, return new OfDouble(Utils.BaseAndScale.DOUBLE.base(), arr, byteSize, false,
MemorySessionImpl.createHeap(arr)); MemorySessionImpl.createHeap(arr));
} }
public static MemorySegment fromArray(long[] arr) { public static MemorySegment fromArray(long[] arr) {
ensureInitialized(); ensureInitialized();
Objects.requireNonNull(arr); Objects.requireNonNull(arr);
long byteSize = (long)arr.length * Unsafe.ARRAY_LONG_INDEX_SCALE; long byteSize = (long)arr.length * Utils.BaseAndScale.LONG.scale();
return new OfLong(Unsafe.ARRAY_LONG_BASE_OFFSET, arr, byteSize, false, return new OfLong(Utils.BaseAndScale.LONG.base(), arr, byteSize, false,
MemorySessionImpl.createHeap(arr)); MemorySessionImpl.createHeap(arr));
} }

View File

@ -27,7 +27,6 @@ package jdk.internal.foreign;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle; import java.lang.invoke.VarHandle;
import java.lang.ref.Cleaner;
import jdk.internal.misc.ScopedMemoryAccess; import jdk.internal.misc.ScopedMemoryAccess;
import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.ForceInline;

View File

@ -39,7 +39,7 @@ import static java.lang.foreign.ValueLayout.*;
/** /**
* Miscellaneous functions to read and write strings, in various charsets. * Miscellaneous functions to read and write strings, in various charsets.
*/ */
public class StringSupport { public final class StringSupport {
static final JavaLangAccess JAVA_LANG_ACCESS = SharedSecrets.getJavaLangAccess(); static final JavaLangAccess JAVA_LANG_ACCESS = SharedSecrets.getJavaLangAccess();

View File

@ -75,7 +75,7 @@ public final class SystemLookup implements SymbolLookup {
private static SymbolLookup makeWindowsLookup() { private static SymbolLookup makeWindowsLookup() {
@SuppressWarnings("removal") @SuppressWarnings("removal")
String systemRoot = AccessController.doPrivileged(new PrivilegedAction<String>() { String systemRoot = AccessController.doPrivileged(new PrivilegedAction<>() {
@Override @Override
public String run() { public String run() {
return System.getenv("SystemRoot"); return System.getenv("SystemRoot");
@ -86,7 +86,7 @@ public final class SystemLookup implements SymbolLookup {
Path msvcrt = system32.resolve("msvcrt.dll"); Path msvcrt = system32.resolve("msvcrt.dll");
@SuppressWarnings("removal") @SuppressWarnings("removal")
boolean useUCRT = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { boolean useUCRT = AccessController.doPrivileged(new PrivilegedAction<>() {
@Override @Override
public Boolean run() { public Boolean run() {
return Files.exists(ucrtbase); return Files.exists(ucrtbase);

View File

@ -43,6 +43,7 @@ import java.util.function.Supplier;
import jdk.internal.access.SharedSecrets; import jdk.internal.access.SharedSecrets;
import jdk.internal.foreign.abi.SharedUtils; import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.misc.Unsafe;
import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.ForceInline;
import sun.invoke.util.Wrapper; import sun.invoke.util.Wrapper;
@ -276,4 +277,36 @@ public final class Utils {
return "0x" + Long.toHexString(value); return "0x" + Long.toHexString(value);
} }
public record BaseAndScale(int base, long scale) {
public static final BaseAndScale BYTE =
new BaseAndScale(Unsafe.ARRAY_BYTE_BASE_OFFSET, Unsafe.ARRAY_BYTE_INDEX_SCALE);
public static final BaseAndScale CHAR =
new BaseAndScale(Unsafe.ARRAY_CHAR_BASE_OFFSET, Unsafe.ARRAY_CHAR_INDEX_SCALE);
public static final BaseAndScale SHORT =
new BaseAndScale(Unsafe.ARRAY_SHORT_BASE_OFFSET, Unsafe.ARRAY_SHORT_INDEX_SCALE);
public static final BaseAndScale INT =
new BaseAndScale(Unsafe.ARRAY_INT_BASE_OFFSET, Unsafe.ARRAY_INT_INDEX_SCALE);
public static final BaseAndScale FLOAT =
new BaseAndScale(Unsafe.ARRAY_FLOAT_BASE_OFFSET, Unsafe.ARRAY_FLOAT_INDEX_SCALE);
public static final BaseAndScale LONG =
new BaseAndScale(Unsafe.ARRAY_LONG_BASE_OFFSET, Unsafe.ARRAY_LONG_INDEX_SCALE);
public static final BaseAndScale DOUBLE =
new BaseAndScale(Unsafe.ARRAY_DOUBLE_BASE_OFFSET, Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
public static BaseAndScale of(Object array) {
return switch (array) {
case byte[] __ -> BaseAndScale.BYTE;
case char[] __ -> BaseAndScale.CHAR;
case short[] __ -> BaseAndScale.SHORT;
case int[] __ -> BaseAndScale.INT;
case float[] __ -> BaseAndScale.FLOAT;
case long[] __ -> BaseAndScale.LONG;
case double[] __ -> BaseAndScale.DOUBLE;
default -> throw new IllegalArgumentException("Not a supported array class: " + array.getClass().getSimpleName());
};
}
}
} }

View File

@ -91,7 +91,7 @@ public abstract sealed class AbstractLinker implements Linker permits LinuxAArch
return downcallHandle0(function, options); return downcallHandle0(function, options);
} }
private final MethodHandle downcallHandle0(FunctionDescriptor function, Option... options) { private MethodHandle downcallHandle0(FunctionDescriptor function, Option... options) {
Objects.requireNonNull(function); Objects.requireNonNull(function);
Objects.requireNonNull(options); Objects.requireNonNull(options);
checkLayouts(function); checkLayouts(function);

View File

@ -32,7 +32,6 @@ import java.lang.foreign.*;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.nio.ByteOrder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Deque; import java.util.Deque;
import java.util.List; import java.util.List;
@ -57,7 +56,7 @@ import static java.lang.foreign.ValueLayout.JAVA_SHORT_UNALIGNED;
* the CONVERT_ADDRESS operator 'unboxes' a MemoryAddress to a long, but 'boxes' a long to a MemoryAddress. * the CONVERT_ADDRESS operator 'unboxes' a MemoryAddress to a long, but 'boxes' a long to a MemoryAddress.
* *
* Here are some examples of binding recipes derived from C declarations, and according to the Windows ABI (recipes are * Here are some examples of binding recipes derived from C declarations, and according to the Windows ABI (recipes are
* ABI-specific). Note that each argument has it's own recipe, which is indicated by '[number]:' (though, the only * ABI-specific). Note that each argument has its own recipe, which is indicated by '[number]:' (though, the only
* example that has multiple arguments is the one using varargs). * example that has multiple arguments is the one using varargs).
* *
* -------------------- * --------------------

View File

@ -33,7 +33,6 @@ import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import static java.lang.foreign.ValueLayout.JAVA_INT; import static java.lang.foreign.ValueLayout.JAVA_INT;
import static sun.security.action.GetPropertyAction.privilegedGetProperty;
public enum CapturableState { public enum CapturableState {
GET_LAST_ERROR ("GetLastError", JAVA_INT, 1 << 0, Utils.IS_WINDOWS), GET_LAST_ERROR ("GetLastError", JAVA_INT, 1 << 0, Utils.IS_WINDOWS),

View File

@ -178,7 +178,7 @@ public final class SharedUtils {
if (dropReturn) { // no handling for return value, need to drop it if (dropReturn) { // no handling for return value, need to drop it
target = dropReturn(target); target = dropReturn(target);
} else { } else {
// adjust return type so it matches the inferred type of the effective // adjust return type so that it matches the inferred type of the effective
// function descriptor // function descriptor
target = target.asType(target.type().changeReturnType(MemorySegment.class)); target = target.asType(target.type().changeReturnType(MemorySegment.class));
} }

View File

@ -29,7 +29,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function; import java.util.function.Function;
class SoftReferenceCache<K, V> { final class SoftReferenceCache<K, V> {
private final Map<K, Node> cache = new ConcurrentHashMap<>(); private final Map<K, Node> cache = new ConcurrentHashMap<>();
public V get(K key, Function<K, V> valueFactory) { public V get(K key, Function<K, V> valueFactory) {
@ -41,10 +41,7 @@ class SoftReferenceCache<K, V> {
private final class Node { private final class Node {
private volatile SoftReference<V> ref; private volatile SoftReference<V> ref;
public Node() { V get(K key, Function<K, V> valueFactory) {
}
public V get(K key, Function<K, V> valueFactory) {
V result; V result;
if (ref == null || (result = ref.get()) == null) { if (ref == null || (result = ref.get()) == null) {
synchronized (this) { // don't let threads race on the valueFactory::apply call synchronized (this) { // don't let threads race on the valueFactory::apply call

View File

@ -37,7 +37,6 @@ import jdk.internal.foreign.abi.CallingSequence;
import jdk.internal.foreign.abi.CallingSequenceBuilder; import jdk.internal.foreign.abi.CallingSequenceBuilder;
import jdk.internal.foreign.abi.DowncallLinker; import jdk.internal.foreign.abi.DowncallLinker;
import jdk.internal.foreign.abi.LinkerOptions; import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.UpcallLinker;
import jdk.internal.foreign.abi.SharedUtils; import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.abi.VMStorage;
import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64CallArranger; import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64CallArranger;
@ -246,8 +245,8 @@ public abstract class CallArranger {
| enough registers | some registers, but not enough | no registers | enough registers | some registers, but not enough | no registers
----------------+------------------+---------------------------------+------------------------- ----------------+------------------+---------------------------------+-------------------------
Linux | FW in regs | CW on the stack | CW on the stack Linux | FW in regs | CW on the stack | CW on the stack
MacOs, non-VA | FW in regs | FW on the stack | FW on the stack macOS, non-VA | FW in regs | FW on the stack | FW on the stack
MacOs, VA | FW in regs | CW on the stack | CW on the stack macOS, VA | FW in regs | CW on the stack | CW on the stack
Windows, non-VF | FW in regs | CW on the stack | CW on the stack Windows, non-VF | FW in regs | CW on the stack | CW on the stack
Windows, VF | FW in regs | CW split between regs and stack | CW on the stack Windows, VF | FW in regs | CW split between regs and stack | CW on the stack
(where FW = Field-wise copy, CW = Chunk-wise copy, VA is a variadic argument, and VF is a variadic function) (where FW = Field-wise copy, CW = Chunk-wise copy, VA is a variadic argument, and VF is a variadic function)
@ -257,7 +256,7 @@ public abstract class CallArranger {
| enough registers | some registers, but not enough | no registers | enough registers | some registers, but not enough | no registers
----------------+------------------+---------------------------------+------------------------- ----------------+------------------+---------------------------------+-------------------------
Linux | CW in regs | CW on the stack | CW on the stack Linux | CW in regs | CW on the stack | CW on the stack
MacOs | CW in regs | CW on the stack | CW on the stack macOS | CW in regs | CW on the stack | CW on the stack
Windows, non-VF | CW in regs | CW on the stack | CW on the stack Windows, non-VF | CW in regs | CW on the stack | CW on the stack
Windows, VF | CW in regs | CW split between regs and stack | CW on the stack Windows, VF | CW in regs | CW split between regs and stack | CW on the stack
*/ */

View File

@ -39,7 +39,7 @@ import java.nio.ByteOrder;
import java.util.Map; import java.util.Map;
/** /**
* ABI implementation for macOS on Apple silicon. Based on AAPCS with * ABI implementation for macOS on Apple Silicon. Based on AAPCS with
* changes to va_list and passing arguments on the stack. * changes to va_list and passing arguments on the stack.
*/ */
public final class MacOsAArch64Linker extends AbstractLinker { public final class MacOsAArch64Linker extends AbstractLinker {

View File

@ -52,7 +52,7 @@ public class WindowsAArch64CallArranger extends CallArranger {
// //
// Although the AAPCS64 says r0-7 and v0-7 are all valid return // Although the AAPCS64 says r0-7 and v0-7 are all valid return
// registers, it's not possible to generate a C function that uses // registers, it's not possible to generate a C function that uses
// r2-7 and v4-7 so they are omitted here. // r2-7 and v4-7 so, they are omitted here.
private static final ABIDescriptor WindowsAArch64AbiDescriptor = abiFor( private static final ABIDescriptor WindowsAArch64AbiDescriptor = abiFor(
new VMStorage[] { r0, r1, r2, r3, r4, r5, r6, r7, INDIRECT_RESULT}, new VMStorage[] { r0, r1, r2, r3, r4, r5, r6, r7, INDIRECT_RESULT},
new VMStorage[] { v0, v1, v2, v3, v4, v5, v6, v7 }, new VMStorage[] { v0, v1, v2, v3, v4, v5, v6, v7 },

View File

@ -47,13 +47,12 @@ public final class WindowsAArch64Linker extends AbstractLinker {
static final Map<String, MemoryLayout> CANONICAL_LAYOUTS = static final Map<String, MemoryLayout> CANONICAL_LAYOUTS =
SharedUtils.canonicalLayouts(ValueLayout.JAVA_INT, ValueLayout.JAVA_LONG, ValueLayout.JAVA_CHAR); SharedUtils.canonicalLayouts(ValueLayout.JAVA_INT, ValueLayout.JAVA_LONG, ValueLayout.JAVA_CHAR);
private static WindowsAArch64Linker instance;
public static WindowsAArch64Linker getInstance() { public static WindowsAArch64Linker getInstance() {
if (instance == null) { class Holder {
instance = new WindowsAArch64Linker(); private static final WindowsAArch64Linker INSTANCE = new WindowsAArch64Linker();
} }
return instance; return Holder.INSTANCE;
} }
@Override @Override

View File

@ -58,6 +58,7 @@ import static java.lang.foreign.ValueLayout.JAVA_SHORT;
* } ffi_type; * } ffi_type;
*/ */
class FFIType { class FFIType {
static final ValueLayout SIZE_T = layoutFor((int)ADDRESS.byteSize()); static final ValueLayout SIZE_T = layoutFor((int)ADDRESS.byteSize());
private static final ValueLayout UNSIGNED_SHORT = JAVA_SHORT; private static final ValueLayout UNSIGNED_SHORT = JAVA_SHORT;
private static final StructLayout LAYOUT = Utils.computePaddedStructLayout( private static final StructLayout LAYOUT = Utils.computePaddedStructLayout(

View File

@ -240,30 +240,25 @@ public final class FallbackLinker extends AbstractLinker {
private static void writeValue(Object arg, MemoryLayout layout, MemorySegment argSeg, private static void writeValue(Object arg, MemoryLayout layout, MemorySegment argSeg,
Consumer<MemorySegment> acquireCallback) { Consumer<MemorySegment> acquireCallback) {
if (layout instanceof ValueLayout.OfBoolean bl) { switch (layout) {
argSeg.set(bl, 0, (Boolean) arg); case ValueLayout.OfBoolean bl -> argSeg.set(bl, 0, (Boolean) arg);
} else if (layout instanceof ValueLayout.OfByte bl) { case ValueLayout.OfByte bl -> argSeg.set(bl, 0, (Byte) arg);
argSeg.set(bl, 0, (Byte) arg); case ValueLayout.OfShort sl -> argSeg.set(sl, 0, (Short) arg);
} else if (layout instanceof ValueLayout.OfShort sl) { case ValueLayout.OfChar cl -> argSeg.set(cl, 0, (Character) arg);
argSeg.set(sl, 0, (Short) arg); case ValueLayout.OfInt il -> argSeg.set(il, 0, (Integer) arg);
} else if (layout instanceof ValueLayout.OfChar cl) { case ValueLayout.OfLong ll -> argSeg.set(ll, 0, (Long) arg);
argSeg.set(cl, 0, (Character) arg); case ValueLayout.OfFloat fl -> argSeg.set(fl, 0, (Float) arg);
} else if (layout instanceof ValueLayout.OfInt il) { case ValueLayout.OfDouble dl -> argSeg.set(dl, 0, (Double) arg);
argSeg.set(il, 0, (Integer) arg); case AddressLayout al -> {
} else if (layout instanceof ValueLayout.OfLong ll) { MemorySegment addrArg = (MemorySegment) arg;
argSeg.set(ll, 0, (Long) arg); acquireCallback.accept(addrArg);
} else if (layout instanceof ValueLayout.OfFloat fl) { argSeg.set(al, 0, addrArg);
argSeg.set(fl, 0, (Float) arg); }
} else if (layout instanceof ValueLayout.OfDouble dl) { case GroupLayout __ ->
argSeg.set(dl, 0, (Double) arg); MemorySegment.copy((MemorySegment) arg, 0, argSeg, 0, argSeg.byteSize()); // by-value struct
} else if (layout instanceof AddressLayout al) { case null, default -> {
MemorySegment addrArg = (MemorySegment) arg; assert layout == null;
acquireCallback.accept(addrArg); }
argSeg.set(al, 0, addrArg);
} else if (layout instanceof GroupLayout) {
MemorySegment.copy((MemorySegment) arg, 0, argSeg, 0, argSeg.byteSize()); // by-value struct
} else {
assert layout == null;
} }
} }

View File

@ -52,13 +52,12 @@ public final class PPC64Architecture implements Architecture {
@Override @Override
public int typeSize(int cls) { public int typeSize(int cls) {
switch (cls) { return switch (cls) {
case StorageType.INTEGER: return INTEGER_REG_SIZE; case StorageType.INTEGER -> INTEGER_REG_SIZE;
case StorageType.FLOAT: return FLOAT_REG_SIZE; case StorageType.FLOAT -> FLOAT_REG_SIZE;
// STACK is deliberately omitted // STACK is deliberately omitted
} default -> throw new IllegalArgumentException("Invalid Storage Class: " + cls);
};
throw new IllegalArgumentException("Invalid Storage Class: " + cls);
} }
public interface StorageType { public interface StorageType {

View File

@ -32,7 +32,6 @@ import jdk.internal.foreign.abi.ABIDescriptor;
import jdk.internal.foreign.abi.Architecture; import jdk.internal.foreign.abi.Architecture;
import jdk.internal.foreign.abi.StubLocations; import jdk.internal.foreign.abi.StubLocations;
import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.abi.VMStorage;
import jdk.internal.foreign.abi.riscv64.linux.TypeClass;
public final class RISCV64Architecture implements Architecture { public final class RISCV64Architecture implements Architecture {
public static final Architecture INSTANCE = new RISCV64Architecture(); public static final Architecture INSTANCE = new RISCV64Architecture();

View File

@ -40,12 +40,10 @@ import jdk.internal.foreign.abi.CallingSequence;
import jdk.internal.foreign.abi.CallingSequenceBuilder; import jdk.internal.foreign.abi.CallingSequenceBuilder;
import jdk.internal.foreign.abi.DowncallLinker; import jdk.internal.foreign.abi.DowncallLinker;
import jdk.internal.foreign.abi.LinkerOptions; import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.UpcallLinker;
import jdk.internal.foreign.abi.SharedUtils; import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.abi.VMStorage;
import jdk.internal.foreign.Utils; import jdk.internal.foreign.Utils;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.util.List; import java.util.List;
@ -150,7 +148,7 @@ public class LinuxRISCV64CallArranger {
this.forArguments = forArguments; this.forArguments = forArguments;
} }
// Aggregates or scalars passed on the stack are aligned to the greater of // Aggregates or scalars passed on the stack are aligned to the greatest of
// the type alignment and XLEN bits, but never more than the stack alignment. // the type alignment and XLEN bits, but never more than the stack alignment.
void alignStack(long alignment) { void alignStack(long alignment) {
alignment = Utils.alignUp(Math.clamp(alignment, STACK_SLOT_SIZE, 16), STACK_SLOT_SIZE); alignment = Utils.alignUp(Math.clamp(alignment, STACK_SLOT_SIZE, 16), STACK_SLOT_SIZE);
@ -253,8 +251,8 @@ public class LinuxRISCV64CallArranger {
Map.entry(STRUCT_REGISTER_XF, STRUCT_REGISTER_X)); Map.entry(STRUCT_REGISTER_XF, STRUCT_REGISTER_X));
} }
static class UnboxBindingCalculator extends BindingCalculator { static final class UnboxBindingCalculator extends BindingCalculator {
boolean forArguments; final boolean forArguments;
UnboxBindingCalculator(boolean forArguments) { UnboxBindingCalculator(boolean forArguments) {
super(forArguments); super(forArguments);

View File

@ -78,7 +78,7 @@ public enum TypeClass {
* Struct will be flattened while classifying. That is, struct{struct{int, double}} will be treated * Struct will be flattened while classifying. That is, struct{struct{int, double}} will be treated
* same as struct{int, double} and struct{int[2]} will be treated same as struct{int, int}. * same as struct{int, double} and struct{int[2]} will be treated same as struct{int, int}.
* */ * */
private static record FieldCounter(long integerCnt, long floatCnt, long pointerCnt) { private record FieldCounter(long integerCnt, long floatCnt, long pointerCnt) {
static final FieldCounter EMPTY = new FieldCounter(0, 0, 0); static final FieldCounter EMPTY = new FieldCounter(0, 0, 0);
static final FieldCounter SINGLE_INTEGER = new FieldCounter(1, 0, 0); static final FieldCounter SINGLE_INTEGER = new FieldCounter(1, 0, 0);
static final FieldCounter SINGLE_FLOAT = new FieldCounter(0, 1, 0); static final FieldCounter SINGLE_FLOAT = new FieldCounter(0, 1, 0);
@ -128,39 +128,40 @@ public enum TypeClass {
} }
} }
public static record FlattenedFieldDesc(TypeClass typeClass, long offset, ValueLayout layout) { public record FlattenedFieldDesc(TypeClass typeClass, long offset, ValueLayout layout) { }
}
private static List<FlattenedFieldDesc> getFlattenedFieldsInner(long offset, MemoryLayout layout) { private static List<FlattenedFieldDesc> getFlattenedFieldsInner(long offset, MemoryLayout layout) {
if (layout instanceof ValueLayout valueLayout) { return switch (layout) {
TypeClass typeClass = classifyValueType(valueLayout); case ValueLayout valueLayout -> {
return List.of(switch (typeClass) { TypeClass typeClass = classifyValueType(valueLayout);
case INTEGER, FLOAT -> new FlattenedFieldDesc(typeClass, offset, valueLayout); yield List.of(switch (typeClass) {
default -> throw new IllegalStateException("Should not reach here."); case INTEGER, FLOAT -> new FlattenedFieldDesc(typeClass, offset, valueLayout);
}); default -> throw new IllegalStateException("Should not reach here.");
} else if (layout instanceof GroupLayout groupLayout) { });
List<FlattenedFieldDesc> fields = new ArrayList<>(); }
for (MemoryLayout memberLayout : groupLayout.memberLayouts()) { case GroupLayout groupLayout -> {
if (memberLayout instanceof PaddingLayout) { List<FlattenedFieldDesc> fields = new ArrayList<>();
for (MemoryLayout memberLayout : groupLayout.memberLayouts()) {
if (memberLayout instanceof PaddingLayout) {
offset += memberLayout.byteSize();
continue;
}
fields.addAll(getFlattenedFieldsInner(offset, memberLayout));
offset += memberLayout.byteSize(); offset += memberLayout.byteSize();
continue;
} }
fields.addAll(getFlattenedFieldsInner(offset, memberLayout)); yield fields;
offset += memberLayout.byteSize();
} }
return fields; case SequenceLayout sequenceLayout -> {
} else if (layout instanceof SequenceLayout sequenceLayout) { List<FlattenedFieldDesc> fields = new ArrayList<>();
List<FlattenedFieldDesc> fields = new ArrayList<>(); MemoryLayout elementLayout = sequenceLayout.elementLayout();
MemoryLayout elementLayout = sequenceLayout.elementLayout(); for (long i = 0; i < sequenceLayout.elementCount(); i++) {
for (long i = 0; i < sequenceLayout.elementCount(); i++) { fields.addAll(getFlattenedFieldsInner(offset, elementLayout));
fields.addAll(getFlattenedFieldsInner(offset, elementLayout)); offset += elementLayout.byteSize();
offset += elementLayout.byteSize(); }
yield fields;
} }
return fields; case null, default -> throw new IllegalStateException("Cannot get here: " + layout);
} else { };
throw new IllegalStateException("Cannot get here: " + layout);
}
} }
public static List<FlattenedFieldDesc> getFlattenedFields(GroupLayout layout) { public static List<FlattenedFieldDesc> getFlattenedFields(GroupLayout layout) {

View File

@ -52,15 +52,12 @@ public final class S390Architecture implements Architecture {
@Override @Override
public int typeSize(int cls) { public int typeSize(int cls) {
switch (cls) { return switch (cls) {
case StorageType.INTEGER: case StorageType.INTEGER -> INTEGER_REG_SIZE;
return INTEGER_REG_SIZE; case StorageType.FLOAT -> FLOAT_REG_SIZE;
case StorageType.FLOAT:
return FLOAT_REG_SIZE;
// STACK is deliberately omitted // STACK is deliberately omitted
} default -> throw new IllegalArgumentException("Invalid Storage Class: " + cls);
};
throw new IllegalArgumentException("Invalid Storage Class: " + cls);
} }
public interface StorageType { public interface StorageType {

View File

@ -37,19 +37,15 @@ import jdk.internal.foreign.abi.CallingSequence;
import jdk.internal.foreign.abi.CallingSequenceBuilder; import jdk.internal.foreign.abi.CallingSequenceBuilder;
import jdk.internal.foreign.abi.DowncallLinker; import jdk.internal.foreign.abi.DowncallLinker;
import jdk.internal.foreign.abi.LinkerOptions; import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.UpcallLinker;
import jdk.internal.foreign.abi.SharedUtils; import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.abi.VMStorage;
import jdk.internal.foreign.Utils; import jdk.internal.foreign.Utils;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import static jdk.internal.foreign.abi.s390.linux.TypeClass.*;
import static jdk.internal.foreign.abi.s390.S390Architecture.*; import static jdk.internal.foreign.abi.s390.S390Architecture.*;
import static jdk.internal.foreign.abi.s390.S390Architecture.Regs.*; import static jdk.internal.foreign.abi.s390.S390Architecture.Regs.*;

View File

@ -96,10 +96,7 @@ public enum TypeClass {
return false; return false;
TypeClass baseArgClass = classifyValueType((ValueLayout) baseType); TypeClass baseArgClass = classifyValueType((ValueLayout) baseType);
if (baseArgClass != FLOAT) return baseArgClass == FLOAT;
return false;
return true;
} }
private static TypeClass classifyStructType(MemoryLayout layout) { private static TypeClass classifyStructType(MemoryLayout layout) {

View File

@ -34,7 +34,6 @@ import jdk.internal.foreign.abi.CallingSequenceBuilder;
import jdk.internal.foreign.abi.DowncallLinker; import jdk.internal.foreign.abi.DowncallLinker;
import jdk.internal.foreign.abi.LinkerOptions; import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.SharedUtils; import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.UpcallLinker;
import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.abi.VMStorage;
import jdk.internal.foreign.abi.x64.X86_64Architecture; import jdk.internal.foreign.abi.x64.X86_64Architecture;
@ -208,7 +207,7 @@ public class CallArranger {
return typeClass.classes.stream().map(c -> stackAlloc()).toArray(VMStorage[]::new); return typeClass.classes.stream().map(c -> stackAlloc()).toArray(VMStorage[]::new);
} }
//ok, let's pass pass on registers //ok, let's pass on registers
VMStorage[] storage = new VMStorage[(int)(nIntegerReg + nVectorReg)]; VMStorage[] storage = new VMStorage[(int)(nIntegerReg + nVectorReg)];
for (int i = 0 ; i < typeClass.classes.size() ; i++) { for (int i = 0 ; i < typeClass.classes.size() ; i++) {
boolean sse = typeClass.classes.get(i) == ArgumentClassImpl.SSE; boolean sse = typeClass.classes.get(i) == ArgumentClassImpl.SSE;

View File

@ -208,35 +208,40 @@ class TypeClass {
return groups; return groups;
} }
private static void groupByEightBytes(MemoryLayout l, long offset, List<ArgumentClassImpl>[] groups) { private static void groupByEightBytes(MemoryLayout layout,
if (l instanceof GroupLayout group) { long offset,
for (MemoryLayout m : group.memberLayouts()) { List<ArgumentClassImpl>[] groups) {
groupByEightBytes(m, offset, groups); switch (layout) {
if (group instanceof StructLayout) { case GroupLayout group -> {
offset += m.byteSize(); for (MemoryLayout m : group.memberLayouts()) {
groupByEightBytes(m, offset, groups);
if (group instanceof StructLayout) {
offset += m.byteSize();
}
} }
} }
} else if (l instanceof PaddingLayout) { case PaddingLayout __ -> {
return;
} else if (l instanceof SequenceLayout seq) {
MemoryLayout elem = seq.elementLayout();
for (long i = 0 ; i < seq.elementCount() ; i++) {
groupByEightBytes(elem, offset, groups);
offset += elem.byteSize();
} }
} else if (l instanceof ValueLayout vl) { case SequenceLayout seq -> {
List<ArgumentClassImpl> layouts = groups[(int)offset / 8]; MemoryLayout elem = seq.elementLayout();
if (layouts == null) { for (long i = 0; i < seq.elementCount(); i++) {
layouts = new ArrayList<>(); groupByEightBytes(elem, offset, groups);
groups[(int)offset / 8] = layouts; offset += elem.byteSize();
}
} }
// if the aggregate contains unaligned fields, it has class MEMORY case ValueLayout vl -> {
ArgumentClassImpl argumentClass = (offset % vl.byteAlignment()) == 0 ? List<ArgumentClassImpl> layouts = groups[(int) offset / 8];
argumentClassFor(vl) : if (layouts == null) {
ArgumentClassImpl.MEMORY; layouts = new ArrayList<>();
layouts.add(argumentClass); groups[(int) offset / 8] = layouts;
} else { }
throw new IllegalStateException("Unexpected layout: " + l); // if the aggregate contains unaligned fields, it has class MEMORY
ArgumentClassImpl argumentClass = (offset % vl.byteAlignment()) == 0 ?
argumentClassFor(vl) :
ArgumentClassImpl.MEMORY;
layouts.add(argumentClass);
}
case null, default -> throw new IllegalStateException("Unexpected layout: " + layout);
} }
} }
} }

View File

@ -33,7 +33,6 @@ import jdk.internal.foreign.abi.CallingSequenceBuilder;
import jdk.internal.foreign.abi.DowncallLinker; import jdk.internal.foreign.abi.DowncallLinker;
import jdk.internal.foreign.abi.LinkerOptions; import jdk.internal.foreign.abi.LinkerOptions;
import jdk.internal.foreign.abi.SharedUtils; import jdk.internal.foreign.abi.SharedUtils;
import jdk.internal.foreign.abi.UpcallLinker;
import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.abi.VMStorage;
import jdk.internal.foreign.abi.x64.X86_64Architecture; import jdk.internal.foreign.abi.x64.X86_64Architecture;
@ -42,7 +41,6 @@ import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.GroupLayout; import java.lang.foreign.GroupLayout;
import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.util.List; import java.util.List;

View File

@ -38,7 +38,7 @@ enum TypeClass {
VARARG_FLOAT; VARARG_FLOAT;
private static TypeClass classifyValueType(ValueLayout type, boolean isVararg) { private static TypeClass classifyValueType(ValueLayout type, boolean isVararg) {
// No 128-bit integers in the Windows C ABI. There are __m128(i|d) intrinsic types but they act just // No 128-bit integers in the Windows C ABI. There are __m128(i|d) intrinsic types but, they act just
// like a struct when passing as an argument (passed by pointer). // like a struct when passing as an argument (passed by pointer).
// https://docs.microsoft.com/en-us/cpp/cpp/m128?view=vs-2019 // https://docs.microsoft.com/en-us/cpp/cpp/m128?view=vs-2019

View File

@ -40,7 +40,7 @@ import java.util.stream.Collectors;
* @implSpec * @implSpec
* This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>. * This class is immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*/ */
public sealed abstract class AbstractGroupLayout<L extends AbstractGroupLayout<L> & MemoryLayout> abstract sealed class AbstractGroupLayout<L extends AbstractGroupLayout<L> & MemoryLayout>
extends AbstractLayout<L> extends AbstractLayout<L>
permits StructLayoutImpl, UnionLayoutImpl { permits StructLayoutImpl, UnionLayoutImpl {

View File

@ -59,7 +59,7 @@ public final class ValueLayouts {
// Suppresses default constructor, ensuring non-instantiability. // Suppresses default constructor, ensuring non-instantiability.
private ValueLayouts() {} private ValueLayouts() {}
abstract sealed static class AbstractValueLayout<V extends AbstractValueLayout<V> & ValueLayout> extends AbstractLayout<V> { abstract static sealed class AbstractValueLayout<V extends AbstractValueLayout<V> & ValueLayout> extends AbstractLayout<V> {
static final int ADDRESS_SIZE_BYTES = Unsafe.ADDRESS_SIZE; static final int ADDRESS_SIZE_BYTES = Unsafe.ADDRESS_SIZE;