8256865: Foreign Memory Access and Linker API are missing NPE checks
Reviewed-by: jvernee, sundar, chegar
This commit is contained in:
parent
8cd2e0f694
commit
9aeadbb020
@ -62,6 +62,7 @@ abstract class AbstractLayout implements MemoryLayout {
|
||||
|
||||
@Override
|
||||
public AbstractLayout withName(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
return withAttribute(LAYOUT_NAME, name);
|
||||
}
|
||||
|
||||
@ -72,6 +73,7 @@ abstract class AbstractLayout implements MemoryLayout {
|
||||
|
||||
@Override
|
||||
public Optional<Constable> attribute(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
return Optional.ofNullable(attributes.get(name));
|
||||
}
|
||||
|
||||
@ -82,6 +84,7 @@ abstract class AbstractLayout implements MemoryLayout {
|
||||
|
||||
@Override
|
||||
public AbstractLayout withAttribute(String name, Constable value) {
|
||||
Objects.requireNonNull(name);
|
||||
Map<String, Constable> newAttributes = new HashMap<>(attributes);
|
||||
newAttributes.put(name, value);
|
||||
return dup(alignment, newAttributes);
|
||||
|
@ -36,6 +36,7 @@ import java.lang.invoke.MethodType;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static jdk.internal.foreign.PlatformLayouts.*;
|
||||
|
||||
@ -94,6 +95,9 @@ import static jdk.internal.foreign.PlatformLayouts.*;
|
||||
* {@link #asVarArg(MemoryLayout)} is used to create the memory layouts for each parameter corresponding to a variadic
|
||||
* argument in a specialized function descriptor.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*
|
||||
* @apiNote In the future, if the Java language permits, {@link CLinker}
|
||||
* may become a {@code sealed} interface, which would prohibit subclassing except by
|
||||
* explicitly permitted types.
|
||||
@ -186,14 +190,16 @@ public interface CLinker {
|
||||
MemoryLayout C_VA_LIST = pick(SysV.C_VA_LIST, Win64.C_VA_LIST, AArch64.C_VA_LIST);
|
||||
|
||||
/**
|
||||
* Returns a memory layout that is suitable to use the layout for variadic arguments.
|
||||
* Returns a memory layout that is suitable to use as the layout for variadic arguments in a specialized
|
||||
* function descriptor.
|
||||
* @param <T> the memory layout type
|
||||
* @param ml the layout the adapt
|
||||
* @param layout the layout the adapt
|
||||
* @return a potentially newly created layout with the right attributes
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T extends MemoryLayout> T asVarArg(T ml) {
|
||||
return (T) PlatformLayouts.asVarArg(ml);
|
||||
static <T extends MemoryLayout> T asVarArg(T layout) {
|
||||
Objects.requireNonNull(layout);
|
||||
return (T) PlatformLayouts.asVarArg(layout);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -207,7 +213,6 @@ public interface CLinker {
|
||||
*
|
||||
* @param str the Java string to be converted into a C string.
|
||||
* @return a new native memory segment containing the converted C string.
|
||||
* @throws NullPointerException if {@code str == null}.
|
||||
*/
|
||||
static MemorySegment toCString(String str) {
|
||||
Objects.requireNonNull(str);
|
||||
@ -226,7 +231,6 @@ public interface CLinker {
|
||||
* @param str the Java string to be converted into a C string.
|
||||
* @param charset The {@link java.nio.charset.Charset} to be used to compute the contents of the C string.
|
||||
* @return a new native memory segment containing the converted C string.
|
||||
* @throws NullPointerException if either {@code str == null} or {@code charset == null}.
|
||||
*/
|
||||
static MemorySegment toCString(String str, Charset charset) {
|
||||
Objects.requireNonNull(str);
|
||||
@ -246,7 +250,6 @@ public interface CLinker {
|
||||
* @param str the Java string to be converted into a C string.
|
||||
* @param scope the scope to be used for the native segment allocation.
|
||||
* @return a new native memory segment containing the converted C string.
|
||||
* @throws NullPointerException if either {@code str == null} or {@code scope == null}.
|
||||
*/
|
||||
static MemorySegment toCString(String str, NativeScope scope) {
|
||||
Objects.requireNonNull(str);
|
||||
@ -267,7 +270,6 @@ public interface CLinker {
|
||||
* @param charset The {@link java.nio.charset.Charset} to be used to compute the contents of the C string.
|
||||
* @param scope the scope to be used for the native segment allocation.
|
||||
* @return a new native memory segment containing the converted C string.
|
||||
* @throws NullPointerException if either {@code str == null}, {@code charset == null} or {@code scope == null}.
|
||||
*/
|
||||
static MemorySegment toCString(String str, Charset charset, NativeScope scope) {
|
||||
Objects.requireNonNull(str);
|
||||
@ -289,11 +291,11 @@ public interface CLinker {
|
||||
* restricted methods, and use safe and supported functionalities, where possible.
|
||||
* @param addr the address at which the string is stored.
|
||||
* @return a Java string with the contents of the null-terminated C string at given address.
|
||||
* @throws NullPointerException if {@code addr == null}
|
||||
* @throws IllegalArgumentException if the size of the native string is greater than the largest string supported by the platform.
|
||||
*/
|
||||
static String toJavaStringRestricted(MemoryAddress addr) {
|
||||
Utils.checkRestrictedAccess("CLinker.toJavaStringRestricted");
|
||||
Objects.requireNonNull(addr);
|
||||
return SharedUtils.toJavaStringInternal(NativeMemorySegmentImpl.EVERYTHING, addr.toRawLongValue(), Charset.defaultCharset());
|
||||
}
|
||||
|
||||
@ -311,7 +313,6 @@ public interface CLinker {
|
||||
* @param addr the address at which the string is stored.
|
||||
* @param charset The {@link java.nio.charset.Charset} to be used to compute the contents of the Java string.
|
||||
* @return a Java string with the contents of the null-terminated C string at given address.
|
||||
* @throws NullPointerException if {@code addr == null} or {@code charset == null}.
|
||||
* @throws IllegalArgumentException if the size of the native string is greater than the largest string supported by the platform.
|
||||
*/
|
||||
static String toJavaStringRestricted(MemoryAddress addr, Charset charset) {
|
||||
@ -330,7 +331,6 @@ public interface CLinker {
|
||||
* over the decoding process is required.
|
||||
* @param addr the address at which the string is stored.
|
||||
* @return a Java string with the contents of the null-terminated C string at given address.
|
||||
* @throws NullPointerException if {@code addr == null}
|
||||
* @throws IllegalArgumentException if the size of the native string is greater than the largest string supported by the platform.
|
||||
* @throws IllegalStateException if the size of the native string is greater than the size of the segment
|
||||
* associated with {@code addr}, or if {@code addr} is associated with a segment that is <em>not alive</em>.
|
||||
@ -350,7 +350,6 @@ public interface CLinker {
|
||||
* @param addr the address at which the string is stored.
|
||||
* @param charset The {@link java.nio.charset.Charset} to be used to compute the contents of the Java string.
|
||||
* @return a Java string with the contents of the null-terminated C string at given address.
|
||||
* @throws NullPointerException if {@code addr == null} or {@code charset == null}.
|
||||
* @throws IllegalArgumentException if the size of the native string is greater than the largest string supported by the platform.
|
||||
* @throws IllegalStateException if the size of the native string is greater than the size of the segment
|
||||
* associated with {@code addr}, or if {@code addr} is associated with a segment that is <em>not alive</em>.
|
||||
@ -408,7 +407,6 @@ public interface CLinker {
|
||||
* restricted methods, and use safe and supported functionalities, where possible.
|
||||
*
|
||||
* @param addr memory address of the native memory to be freed
|
||||
* @throws NullPointerException if {@code addr == null}.
|
||||
*/
|
||||
static void freeMemoryRestricted(MemoryAddress addr) {
|
||||
Utils.checkRestrictedAccess("CLinker.freeMemoryRestricted");
|
||||
@ -429,6 +427,9 @@ public interface CLinker {
|
||||
* As such, this interface only supports reading {@code int}, {@code double},
|
||||
* and any other type that fits into a {@code long}.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*
|
||||
* @apiNote In the future, if the Java language permits, {@link VaList}
|
||||
* may become a {@code sealed} interface, which would prohibit subclassing except by
|
||||
* explicitly permitted types.
|
||||
@ -597,6 +598,7 @@ public interface CLinker {
|
||||
*/
|
||||
static VaList ofAddressRestricted(MemoryAddress address) {
|
||||
Utils.checkRestrictedAccess("VaList.ofAddressRestricted");
|
||||
Objects.requireNonNull(address);
|
||||
return SharedUtils.newVaListOfAddress(address);
|
||||
}
|
||||
|
||||
@ -618,6 +620,7 @@ public interface CLinker {
|
||||
* @return a new {@code VaList} instance backed by a fresh C {@code va_list}.
|
||||
*/
|
||||
static VaList make(Consumer<Builder> actions) {
|
||||
Objects.requireNonNull(actions);
|
||||
return SharedUtils.newVaList(actions, MemorySegment::allocateNative);
|
||||
}
|
||||
|
||||
@ -639,6 +642,8 @@ public interface CLinker {
|
||||
* @return a new {@code VaList} instance backed by a fresh C {@code va_list}.
|
||||
*/
|
||||
static VaList make(Consumer<Builder> actions, NativeScope scope) {
|
||||
Objects.requireNonNull(actions);
|
||||
Objects.requireNonNull(scope);
|
||||
return SharedUtils.newVaList(actions, SharedUtils.Allocator.ofScope(scope));
|
||||
}
|
||||
|
||||
@ -656,6 +661,9 @@ public interface CLinker {
|
||||
/**
|
||||
* A builder interface used to construct a C {@code va_list}.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*
|
||||
* @apiNote In the future, if the Java language permits, {@link Builder}
|
||||
* may become a {@code sealed} interface, which would prohibit subclassing except by
|
||||
* explicitly permitted types.
|
||||
|
@ -42,6 +42,9 @@ import java.util.stream.Stream;
|
||||
/**
|
||||
* A function descriptor is made up of zero or more argument layouts and zero or one return layout. A function descriptor
|
||||
* is used to model the signature of foreign functions.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*/
|
||||
public final class FunctionDescriptor implements Constable {
|
||||
|
||||
@ -68,6 +71,7 @@ public final class FunctionDescriptor implements Constable {
|
||||
* @return the attribute with the given name (if it exists).
|
||||
*/
|
||||
public Optional<Constable> attribute(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
return Optional.ofNullable(attributes.get(name));
|
||||
}
|
||||
|
||||
@ -90,6 +94,7 @@ public final class FunctionDescriptor implements Constable {
|
||||
* @return a new function descriptor which features the same attributes as this descriptor, plus the newly specified attribute.
|
||||
*/
|
||||
public FunctionDescriptor withAttribute(String name, Constable value) {
|
||||
Objects.requireNonNull(name);
|
||||
Map<String, Constable> newAttributes = new HashMap<>(attributes);
|
||||
newAttributes.put(name, value);
|
||||
return new FunctionDescriptor(resLayout, newAttributes, argLayouts);
|
||||
@ -116,10 +121,10 @@ public final class FunctionDescriptor implements Constable {
|
||||
* @param resLayout the return layout.
|
||||
* @param argLayouts the argument layouts.
|
||||
* @return the new function descriptor.
|
||||
* @throws NullPointerException if any of the argument layouts, or the return layout is null.
|
||||
*/
|
||||
public static FunctionDescriptor of(MemoryLayout resLayout, MemoryLayout... argLayouts) {
|
||||
Objects.requireNonNull(resLayout);
|
||||
Objects.requireNonNull(argLayouts);
|
||||
Arrays.stream(argLayouts).forEach(Objects::requireNonNull);
|
||||
return new FunctionDescriptor(resLayout, Map.of(), argLayouts);
|
||||
}
|
||||
@ -128,9 +133,9 @@ public final class FunctionDescriptor implements Constable {
|
||||
* Create a function descriptor with given argument layouts and no return layout.
|
||||
* @param argLayouts the argument layouts.
|
||||
* @return the new function descriptor.
|
||||
* @throws NullPointerException if any of the argument layouts is null.
|
||||
*/
|
||||
public static FunctionDescriptor ofVoid(MemoryLayout... argLayouts) {
|
||||
Objects.requireNonNull(argLayouts);
|
||||
Arrays.stream(argLayouts).forEach(Objects::requireNonNull);
|
||||
return new FunctionDescriptor(null, Map.of(), argLayouts);
|
||||
}
|
||||
@ -140,9 +145,9 @@ public final class FunctionDescriptor implements Constable {
|
||||
* of this function descriptor.
|
||||
* @param addedLayouts the argument layouts to append.
|
||||
* @return the new function descriptor.
|
||||
* @throws NullPointerException if any of the new argument layouts is null.
|
||||
*/
|
||||
public FunctionDescriptor withAppendedArgumentLayouts(MemoryLayout... addedLayouts) {
|
||||
Objects.requireNonNull(addedLayouts);
|
||||
Arrays.stream(addedLayouts).forEach(Objects::requireNonNull);
|
||||
MemoryLayout[] newLayouts = Arrays.copyOf(argLayouts, argLayouts.length + addedLayouts.length);
|
||||
System.arraycopy(addedLayouts, 0, newLayouts, argLayouts.length, addedLayouts.length);
|
||||
@ -153,7 +158,6 @@ public final class FunctionDescriptor implements Constable {
|
||||
* Create a new function descriptor with the given memory layout as the new return layout.
|
||||
* @param newReturn the new return layout.
|
||||
* @return the new function descriptor.
|
||||
* @throws NullPointerException if the new return layout is null.
|
||||
*/
|
||||
public FunctionDescriptor withReturnLayout(MemoryLayout newReturn) {
|
||||
Objects.requireNonNull(newReturn);
|
||||
|
@ -52,6 +52,9 @@ import java.util.stream.Collectors;
|
||||
* {@code GroupLayout} may have unpredictable results and should be avoided.
|
||||
* The {@code equals} method should be used for comparisons.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*/
|
||||
|
@ -56,6 +56,9 @@ MemorySegment errnoSegment = errno.address().asRestrictedSegment(4, errno);
|
||||
* <p>
|
||||
* To allow for a library to be unloaded, a client will have to discard any strong references it
|
||||
* maintains, directly, or indirectly to a lookup object associated with given library.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*/
|
||||
public interface LibraryLookup {
|
||||
|
||||
|
@ -28,6 +28,7 @@ package jdk.incubator.foreign;
|
||||
import jdk.internal.foreign.MappedMemorySegmentImpl;
|
||||
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This class provides capabilities to manipulate mapped memory segments, such as {@link #force(MemorySegment)},
|
||||
@ -42,6 +43,9 @@ import java.nio.MappedByteBuffer;
|
||||
* with the desired parameters; the returned address can be easily wrapped into a memory segment, using
|
||||
* {@link MemoryAddress#ofLong(long)} and {@link MemoryAddress#asSegmentRestricted(long, Runnable, Object)}.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*
|
||||
* @implNote
|
||||
* The behavior of some the methods in this class (see {@link #load(MemorySegment)}, {@link #unload(MemorySegment)} and
|
||||
* {@link #isLoaded(MemorySegment)}) is highly platform-dependent; as a result, calling these methods might
|
||||
@ -151,6 +155,7 @@ public final class MappedMemorySegments {
|
||||
}
|
||||
|
||||
static MappedMemorySegmentImpl toMappedSegment(MemorySegment segment) {
|
||||
Objects.requireNonNull(segment);
|
||||
if (segment instanceof MappedMemorySegmentImpl) {
|
||||
return (MappedMemorySegmentImpl)segment;
|
||||
} else {
|
||||
|
@ -30,6 +30,7 @@ import jdk.internal.vm.annotation.ForceInline;
|
||||
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This class defines ready-made static accessors which can be used to dereference memory segments in many ways.
|
||||
@ -49,6 +50,9 @@ import java.nio.ByteOrder;
|
||||
* <p>
|
||||
* In cases where native byte order is preferred, overloads are provided (see {@link #getIntAtOffset(MemorySegment, long)})
|
||||
* so that clients can omit the byte order parameter.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*/
|
||||
public final class MemoryAccess {
|
||||
|
||||
@ -92,6 +96,7 @@ public final class MemoryAccess {
|
||||
* @return a byte value read from {@code segment}.
|
||||
*/
|
||||
public static byte getByteAtOffset(MemorySegment segment, long offset) {
|
||||
Objects.requireNonNull(segment);
|
||||
return (byte)byte_handle.get(segment, offset);
|
||||
}
|
||||
|
||||
@ -103,6 +108,7 @@ public final class MemoryAccess {
|
||||
* @param value the byte value to be written.
|
||||
*/
|
||||
public static void setByteAtOffset(MemorySegment segment, long offset, byte value) {
|
||||
Objects.requireNonNull(segment);
|
||||
byte_handle.set(segment, offset, value);
|
||||
}
|
||||
|
||||
@ -299,6 +305,7 @@ public final class MemoryAccess {
|
||||
* @return a memory address read from {@code segment}.
|
||||
*/
|
||||
public static MemoryAddress getAddressAtOffset(MemorySegment segment, long offset) {
|
||||
Objects.requireNonNull(segment);
|
||||
return (MemoryAddress)address_handle.get(segment, offset);
|
||||
}
|
||||
|
||||
@ -315,6 +322,8 @@ public final class MemoryAccess {
|
||||
* @param value the memory address to be written (expressed as an {@link Addressable} instance).
|
||||
*/
|
||||
public static void setAddressAtOffset(MemorySegment segment, long offset, Addressable value) {
|
||||
Objects.requireNonNull(segment);
|
||||
Objects.requireNonNull(value);
|
||||
address_handle.set(segment, offset, value.address());
|
||||
}
|
||||
|
||||
@ -332,6 +341,8 @@ public final class MemoryAccess {
|
||||
* @return a char value read from {@code segment}.
|
||||
*/
|
||||
public static char getCharAtOffset(MemorySegment segment, long offset, ByteOrder order) {
|
||||
Objects.requireNonNull(segment);
|
||||
Objects.requireNonNull(order);
|
||||
return (char)((order == ByteOrder.BIG_ENDIAN) ? char_BE_handle : char_LE_handle).get(segment, offset);
|
||||
}
|
||||
|
||||
@ -349,6 +360,8 @@ public final class MemoryAccess {
|
||||
* @param value the char value to be written.
|
||||
*/
|
||||
public static void setCharAtOffset(MemorySegment segment, long offset, ByteOrder order, char value) {
|
||||
Objects.requireNonNull(segment);
|
||||
Objects.requireNonNull(order);
|
||||
((order == ByteOrder.BIG_ENDIAN) ? char_BE_handle : char_LE_handle).set(segment, offset, value);
|
||||
}
|
||||
|
||||
@ -366,6 +379,8 @@ public final class MemoryAccess {
|
||||
* @return a short value read from {@code segment}.
|
||||
*/
|
||||
public static short getShortAtOffset(MemorySegment segment, long offset, ByteOrder order) {
|
||||
Objects.requireNonNull(segment);
|
||||
Objects.requireNonNull(order);
|
||||
return (short)((order == ByteOrder.BIG_ENDIAN) ? short_BE_handle : short_LE_handle).get(segment, offset);
|
||||
}
|
||||
|
||||
@ -383,6 +398,8 @@ public final class MemoryAccess {
|
||||
* @param value the short value to be written.
|
||||
*/
|
||||
public static void setShortAtOffset(MemorySegment segment, long offset, ByteOrder order, short value) {
|
||||
Objects.requireNonNull(segment);
|
||||
Objects.requireNonNull(order);
|
||||
((order == ByteOrder.BIG_ENDIAN) ? short_BE_handle : short_LE_handle).set(segment, offset, value);
|
||||
}
|
||||
|
||||
@ -400,6 +417,8 @@ public final class MemoryAccess {
|
||||
* @return an int value read from {@code segment}.
|
||||
*/
|
||||
public static int getIntAtOffset(MemorySegment segment, long offset, ByteOrder order) {
|
||||
Objects.requireNonNull(segment);
|
||||
Objects.requireNonNull(order);
|
||||
return (int)((order == ByteOrder.BIG_ENDIAN) ? int_BE_handle : int_LE_handle).get(segment, offset);
|
||||
}
|
||||
|
||||
@ -417,6 +436,8 @@ public final class MemoryAccess {
|
||||
* @param value the int value to be written.
|
||||
*/
|
||||
public static void setIntAtOffset(MemorySegment segment, long offset, ByteOrder order, int value) {
|
||||
Objects.requireNonNull(segment);
|
||||
Objects.requireNonNull(order);
|
||||
((order == ByteOrder.BIG_ENDIAN) ? int_BE_handle : int_LE_handle).set(segment, offset, value);
|
||||
}
|
||||
|
||||
@ -434,6 +455,8 @@ public final class MemoryAccess {
|
||||
* @return a float value read from {@code segment}.
|
||||
*/
|
||||
public static float getFloatAtOffset(MemorySegment segment, long offset, ByteOrder order) {
|
||||
Objects.requireNonNull(segment);
|
||||
Objects.requireNonNull(order);
|
||||
return (float)((order == ByteOrder.BIG_ENDIAN) ? float_BE_handle : float_LE_handle).get(segment, offset);
|
||||
}
|
||||
|
||||
@ -451,6 +474,8 @@ public final class MemoryAccess {
|
||||
* @param value the float value to be written.
|
||||
*/
|
||||
public static void setFloatAtOffset(MemorySegment segment, long offset, ByteOrder order, float value) {
|
||||
Objects.requireNonNull(segment);
|
||||
Objects.requireNonNull(order);
|
||||
((order == ByteOrder.BIG_ENDIAN) ? float_BE_handle : float_LE_handle).set(segment, offset, value);
|
||||
}
|
||||
|
||||
@ -468,6 +493,8 @@ public final class MemoryAccess {
|
||||
* @return a long value read from {@code segment}.
|
||||
*/
|
||||
public static long getLongAtOffset(MemorySegment segment, long offset, ByteOrder order) {
|
||||
Objects.requireNonNull(segment);
|
||||
Objects.requireNonNull(order);
|
||||
return (long)((order == ByteOrder.BIG_ENDIAN) ? long_BE_handle : long_LE_handle).get(segment, offset);
|
||||
}
|
||||
|
||||
@ -485,6 +512,8 @@ public final class MemoryAccess {
|
||||
* @param value the long value to be written.
|
||||
*/
|
||||
public static void setLongAtOffset(MemorySegment segment, long offset, ByteOrder order, long value) {
|
||||
Objects.requireNonNull(segment);
|
||||
Objects.requireNonNull(order);
|
||||
((order == ByteOrder.BIG_ENDIAN) ? long_BE_handle : long_LE_handle).set(segment, offset, value);
|
||||
}
|
||||
|
||||
@ -502,6 +531,8 @@ public final class MemoryAccess {
|
||||
* @return a double value read from {@code segment}.
|
||||
*/
|
||||
public static double getDoubleAtOffset(MemorySegment segment, long offset, ByteOrder order) {
|
||||
Objects.requireNonNull(segment);
|
||||
Objects.requireNonNull(order);
|
||||
return (double)((order == ByteOrder.BIG_ENDIAN) ? double_BE_handle : double_LE_handle).get(segment, offset);
|
||||
}
|
||||
|
||||
@ -519,6 +550,8 @@ public final class MemoryAccess {
|
||||
* @param value the double value to be written.
|
||||
*/
|
||||
public static void setDoubleAtOffset(MemorySegment segment, long offset, ByteOrder order, double value) {
|
||||
Objects.requireNonNull(segment);
|
||||
Objects.requireNonNull(order);
|
||||
((order == ByteOrder.BIG_ENDIAN) ? double_BE_handle : double_LE_handle).set(segment, offset, value);
|
||||
}
|
||||
|
||||
@ -1092,6 +1125,21 @@ public final class MemoryAccess {
|
||||
return getDoubleAtOffset(segment, scale(segment, index, 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a double at given segment and element index, with byte order set to {@link ByteOrder#nativeOrder()}.
|
||||
* <p>
|
||||
* This is equivalent to the following code:
|
||||
* <blockquote><pre>{@code
|
||||
setDoubleAtOffset(segment, 8 * index, value);
|
||||
* }</pre></blockquote>
|
||||
* @param segment the segment to be dereferenced.
|
||||
* @param index element index (relative to {@code segment}). The final address of this read operation can be expressed as {@code segment.address().addOffset(index * 8)}.
|
||||
* @param value the double value to be written.
|
||||
*/
|
||||
public static void setDoubleAtIndex(MemorySegment segment, long index, double value) {
|
||||
setDoubleAtOffset(segment, scale(segment, index, 8), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a memory address from given segment and element index, with byte order set to {@link ByteOrder#nativeOrder()}.
|
||||
* <p>
|
||||
@ -1122,21 +1170,6 @@ public final class MemoryAccess {
|
||||
setAddressAtOffset(segment, scale(segment, index, (int)MemoryLayouts.ADDRESS.byteSize()), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a double at given segment and element index, with byte order set to {@link ByteOrder#nativeOrder()}.
|
||||
* <p>
|
||||
* This is equivalent to the following code:
|
||||
* <blockquote><pre>{@code
|
||||
setDoubleAtOffset(segment, 8 * index, value);
|
||||
* }</pre></blockquote>
|
||||
* @param segment the segment to be dereferenced.
|
||||
* @param index element index (relative to {@code segment}). The final address of this read operation can be expressed as {@code segment.address().addOffset(index * 8)}.
|
||||
* @param value the double value to be written.
|
||||
*/
|
||||
public static void setDoubleAtIndex(MemorySegment segment, long index, double value) {
|
||||
setDoubleAtOffset(segment, scale(segment, index, 8), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a char from given segment and element index, with given byte order.
|
||||
* <p>
|
||||
|
@ -46,6 +46,9 @@ import java.lang.ref.Cleaner;
|
||||
* <p>
|
||||
* Non-platform classes should not implement {@linkplain MemoryAddress} directly.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*
|
||||
* @apiNote In the future, if the Java language permits, {@link MemoryAddress}
|
||||
* may become a {@code sealed} interface, which would prohibit subclassing except by
|
||||
* explicitly permitted types.
|
||||
|
@ -62,6 +62,9 @@ VarHandle handle = MemoryHandles.varHandle(int.class, ByteOrder.BIG_ENDIAN); //(
|
||||
handle = MemoryHandles.insertCoordinates(handle, 1, 4); //(MemorySegment) -> int
|
||||
* }</pre></blockquote>
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*
|
||||
* <h2><a id="memaccess-mode"></a>Alignment and access modes</h2>
|
||||
*
|
||||
* A memory access var handle is associated with an access size {@code S} and an alignment constraint {@code B}
|
||||
@ -170,7 +173,8 @@ public final class MemoryHandles {
|
||||
* @throws IllegalArgumentException when an illegal carrier type is used
|
||||
*/
|
||||
public static VarHandle varHandle(Class<?> carrier, ByteOrder byteOrder) {
|
||||
checkCarrier(carrier);
|
||||
Objects.requireNonNull(carrier);
|
||||
Objects.requireNonNull(byteOrder);
|
||||
return varHandle(carrier,
|
||||
carrierSize(carrier),
|
||||
byteOrder);
|
||||
@ -196,6 +200,8 @@ public final class MemoryHandles {
|
||||
* @throws IllegalArgumentException if an illegal carrier type is used, or if {@code alignmentBytes} is not a power of two.
|
||||
*/
|
||||
public static VarHandle varHandle(Class<?> carrier, long alignmentBytes, ByteOrder byteOrder) {
|
||||
Objects.requireNonNull(carrier);
|
||||
Objects.requireNonNull(byteOrder);
|
||||
checkCarrier(carrier);
|
||||
|
||||
if (alignmentBytes <= 0
|
||||
@ -220,6 +226,7 @@ public final class MemoryHandles {
|
||||
* {@code float}, or {@code double}, or is not a primitive type.
|
||||
*/
|
||||
public static VarHandle asAddressVarHandle(VarHandle target) {
|
||||
Objects.requireNonNull(target);
|
||||
Class<?> carrier = target.varType();
|
||||
if (!carrier.isPrimitive() || carrier == boolean.class ||
|
||||
carrier == float.class || carrier == double.class) {
|
||||
@ -279,9 +286,7 @@ public final class MemoryHandles {
|
||||
* is not one of {@code byte}, {@code short}, or {@code int}; if {@code
|
||||
* adaptedType} is not one of {@code int}, or {@code long}; if the bitwidth
|
||||
* of the {@code adaptedType} is not greater than that of the {@code target}
|
||||
* carrier type
|
||||
* @throws NullPointerException if either of {@code target} or {@code
|
||||
* adaptedType} is null
|
||||
* carrier type.
|
||||
*
|
||||
* @jls 5.1.3 Narrowing Primitive Conversion
|
||||
*/
|
||||
@ -331,7 +336,6 @@ public final class MemoryHandles {
|
||||
* @param filterToTarget a filter to convert some type {@code S} into the type of {@code target}
|
||||
* @param filterFromTarget a filter to convert the type of {@code target} to some type {@code S}
|
||||
* @return an adapter var handle which accepts a new type, performing the provided boxing/unboxing conversions.
|
||||
* @throws NullPointerException if either {@code target}, {@code filterToTarget} or {@code filterFromTarget} are {@code == null}.
|
||||
* @throws IllegalArgumentException if {@code filterFromTarget} and {@code filterToTarget} are not well-formed, that is, they have types
|
||||
* other than {@code (A... , S) -> T} and {@code (A... , T) -> S}, respectively, where {@code T} is the type of the target var handle,
|
||||
* or if either {@code filterFromTarget} or {@code filterToTarget} throws any checked exceptions.
|
||||
@ -360,7 +364,6 @@ public final class MemoryHandles {
|
||||
* @param filters the unary functions which are used to transform coordinates starting at position {@code pos}
|
||||
* @return an adapter var handle which accepts new coordinate types, applying the provided transformation
|
||||
* to the new coordinate values.
|
||||
* @throws NullPointerException if either {@code target}, {@code filters} are {@code == null}.
|
||||
* @throws IllegalArgumentException if the handles in {@code filters} are not well-formed, that is, they have types
|
||||
* other than {@code S1 -> T1, S2 -> T2, ... Sn -> Tn} where {@code T1, T2 ... Tn} are the coordinate types starting
|
||||
* at position {@code pos} of the target var handle, if {@code pos} is not between 0 and the target var handle coordinate arity, inclusive,
|
||||
@ -390,7 +393,6 @@ public final class MemoryHandles {
|
||||
* @param values the series of bound coordinates to insert
|
||||
* @return an adapter var handle which inserts an additional coordinates,
|
||||
* before calling the target var handle
|
||||
* @throws NullPointerException if either {@code target}, {@code values} are {@code == null}.
|
||||
* @throws IllegalArgumentException if {@code pos} is not between 0 and the target var handle coordinate arity, inclusive,
|
||||
* or if more values are provided than the actual number of coordinate types available starting at {@code pos}.
|
||||
* @throws ClassCastException if the bound coordinates in {@code values} are not well-formed, that is, they have types
|
||||
@ -432,7 +434,6 @@ public final class MemoryHandles {
|
||||
* @param reorder an index array which controls the reordering
|
||||
* @return an adapter var handle which re-arranges the incoming coordinate values,
|
||||
* before calling the target var handle
|
||||
* @throws NullPointerException if either {@code target}, {@code newCoordinates} or {@code reorder} are {@code == null}.
|
||||
* @throws IllegalArgumentException if the index array length is not equal to
|
||||
* the number of coordinates of the target var handle, or if any index array element is not a valid index for
|
||||
* a coordinate of {@code newCoordinates}, or if two corresponding coordinate types in
|
||||
@ -471,7 +472,6 @@ public final class MemoryHandles {
|
||||
* @param filter the filter method handle
|
||||
* @return an adapter var handle which filters the incoming coordinate values,
|
||||
* before calling the target var handle
|
||||
* @throws NullPointerException if either {@code target}, {@code filter} are {@code == null}.
|
||||
* @throws IllegalArgumentException if the return type of {@code filter}
|
||||
* is void, or it is not the same as the {@code pos} coordinate of the target var handle,
|
||||
* if {@code pos} is not between 0 and the target var handle coordinate arity, inclusive,
|
||||
@ -499,7 +499,6 @@ public final class MemoryHandles {
|
||||
* @param valueTypes the type(s) of the coordinate(s) to drop
|
||||
* @return an adapter var handle which drops some dummy coordinates,
|
||||
* before calling the target var handle
|
||||
* @throws NullPointerException if either {@code target}, {@code valueTypes} are {@code == null}.
|
||||
* @throws IllegalArgumentException if {@code pos} is not between 0 and the target var handle coordinate arity, inclusive.
|
||||
*/
|
||||
public static VarHandle dropCoordinates(VarHandle target, int pos, Class<?>... valueTypes) {
|
||||
|
@ -41,6 +41,7 @@ import java.util.OptionalLong;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
@ -82,6 +83,9 @@ SequenceLayout taggedValues = MemoryLayout.ofSequence(5,
|
||||
* <p>
|
||||
* Non-platform classes should not implement {@linkplain MemoryLayout} directly.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*
|
||||
* <h2><a id = "layout-align">Size, alignment and byte order</a></h2>
|
||||
*
|
||||
* All layouts have a size; layout size for value and padding layouts is always explicitly denoted; this means that a layout description
|
||||
@ -403,6 +407,7 @@ public interface MemoryLayout extends Constable {
|
||||
* or if the selected value layout has a size that that does not match that of the specified carrier type.
|
||||
*/
|
||||
default VarHandle varHandle(Class<?> carrier, PathElement... elements) {
|
||||
Objects.requireNonNull(carrier);
|
||||
return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), path -> path.dereferenceHandle(carrier),
|
||||
Set.of(), elements);
|
||||
}
|
||||
@ -434,14 +439,16 @@ public interface MemoryLayout extends Constable {
|
||||
* (see {@link PathElement#sequenceElement(long)} and {@link PathElement#sequenceElement(long, long)}).
|
||||
*/
|
||||
default MemoryLayout map(UnaryOperator<MemoryLayout> op, PathElement... elements) {
|
||||
Objects.requireNonNull(op);
|
||||
return computePathOp(LayoutPath.rootPath(this, l -> 0L), path -> path.map(op),
|
||||
EnumSet.of(PathKind.SEQUENCE_ELEMENT_INDEX, PathKind.SEQUENCE_RANGE), elements);
|
||||
}
|
||||
|
||||
private static <Z> Z computePathOp(LayoutPath path, Function<LayoutPath, Z> finalizer,
|
||||
Set<LayoutPath.PathElementImpl.PathKind> badKinds, PathElement... elements) {
|
||||
Objects.requireNonNull(elements);
|
||||
for (PathElement e : elements) {
|
||||
LayoutPath.PathElementImpl pathElem = (LayoutPath.PathElementImpl)e;
|
||||
LayoutPath.PathElementImpl pathElem = (LayoutPath.PathElementImpl)Objects.requireNonNull(e);
|
||||
if (badKinds.contains(pathElem.kind())) {
|
||||
throw new IllegalArgumentException(String.format("Invalid %s selection in layout path", pathElem.kind().description()));
|
||||
}
|
||||
@ -467,6 +474,9 @@ public interface MemoryLayout extends Constable {
|
||||
* <p>
|
||||
* Non-platform classes should not implement {@linkplain PathElement} directly.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*
|
||||
* @apiNote In the future, if the Java language permits, {@link PathElement}
|
||||
* may become a {@code sealed} interface, which would prohibit subclassing except by
|
||||
* explicitly permitted types.
|
||||
@ -486,7 +496,6 @@ public interface MemoryLayout extends Constable {
|
||||
*
|
||||
* @param name the name of the group element to be selected.
|
||||
* @return a path element which selects the group element with given name.
|
||||
* @throws NullPointerException if the specified group element name is {@code null}.
|
||||
*/
|
||||
static PathElement groupElement(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
@ -607,6 +616,7 @@ E * (S + I * F)
|
||||
* @throws IllegalArgumentException if {@code size <= 0}.
|
||||
*/
|
||||
static ValueLayout ofValueBits(long size, ByteOrder order) {
|
||||
Objects.requireNonNull(order);
|
||||
AbstractLayout.checkSize(size);
|
||||
return new ValueLayout(order, size);
|
||||
}
|
||||
@ -622,7 +632,7 @@ E * (S + I * F)
|
||||
static SequenceLayout ofSequence(long elementCount, MemoryLayout elementLayout) {
|
||||
AbstractLayout.checkSize(elementCount, true);
|
||||
OptionalLong size = OptionalLong.of(elementCount);
|
||||
return new SequenceLayout(size, elementLayout);
|
||||
return new SequenceLayout(size, Objects.requireNonNull(elementLayout));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -632,7 +642,7 @@ E * (S + I * F)
|
||||
* @return the new sequence layout with given element layout.
|
||||
*/
|
||||
static SequenceLayout ofSequence(MemoryLayout elementLayout) {
|
||||
return new SequenceLayout(OptionalLong.empty(), elementLayout);
|
||||
return new SequenceLayout(OptionalLong.empty(), Objects.requireNonNull(elementLayout));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -642,7 +652,11 @@ E * (S + I * F)
|
||||
* @return a new <em>struct</em> group layout with given member layouts.
|
||||
*/
|
||||
static GroupLayout ofStruct(MemoryLayout... elements) {
|
||||
return new GroupLayout(GroupLayout.Kind.STRUCT, List.of(elements));
|
||||
Objects.requireNonNull(elements);
|
||||
return new GroupLayout(GroupLayout.Kind.STRUCT,
|
||||
Stream.of(elements)
|
||||
.map(Objects::requireNonNull)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -652,7 +666,11 @@ E * (S + I * F)
|
||||
* @return a new <em>union</em> group layout with given member layouts.
|
||||
*/
|
||||
static GroupLayout ofUnion(MemoryLayout... elements) {
|
||||
return new GroupLayout(GroupLayout.Kind.UNION, List.of(elements));
|
||||
Objects.requireNonNull(elements);
|
||||
return new GroupLayout(GroupLayout.Kind.UNION,
|
||||
Stream.of(elements)
|
||||
.map(Objects::requireNonNull)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,6 +56,9 @@ import java.util.Spliterator;
|
||||
* <p>
|
||||
* Non-platform classes should not implement {@linkplain MemorySegment} directly.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*
|
||||
* <h2>Constructing memory segments</h2>
|
||||
*
|
||||
* There are multiple ways to obtain a memory segment. First, memory segments backed by off-heap memory can
|
||||
@ -323,7 +326,6 @@ public interface MemorySegment extends Addressable, AutoCloseable {
|
||||
* @param newBase The new segment base address.
|
||||
* @param newSize The new segment size, specified in bytes.
|
||||
* @return a new memory segment view with updated base/limit addresses.
|
||||
* @throws NullPointerException if {@code newBase == null}.
|
||||
* @throws IndexOutOfBoundsException if {@code offset < 0}, {@code offset > byteSize()}, {@code newSize < 0}, or {@code newSize > byteSize() - offset}
|
||||
*/
|
||||
default MemorySegment asSlice(MemoryAddress newBase, long newSize) {
|
||||
@ -367,7 +369,6 @@ public interface MemorySegment extends Addressable, AutoCloseable {
|
||||
*
|
||||
* @param newBase The new segment base offset (relative to the current segment base address), specified in bytes.
|
||||
* @return a new memory segment view with updated base/limit addresses.
|
||||
* @throws NullPointerException if {@code newBase == null}.
|
||||
* @throws IndexOutOfBoundsException if {@code address.segmentOffset(this) < 0}, or {@code address.segmentOffset(this) > byteSize()}.
|
||||
*/
|
||||
default MemorySegment asSlice(MemoryAddress newBase) {
|
||||
@ -431,7 +432,6 @@ public interface MemorySegment extends Addressable, AutoCloseable {
|
||||
* @throws IllegalStateException if this segment is not <em>alive</em>, or if access occurs from a thread other than the
|
||||
* thread owning this segment.
|
||||
* @throws UnsupportedOperationException if this segment does not support the {@link #HANDOFF} access mode.
|
||||
* @throws NullPointerException if {@code thread == null}
|
||||
*/
|
||||
MemorySegment handoff(Thread thread);
|
||||
|
||||
@ -459,7 +459,6 @@ public interface MemorySegment extends Addressable, AutoCloseable {
|
||||
* @throws IllegalStateException if this segment is not <em>alive</em>, or if access occurs from a thread other than the
|
||||
* thread owning this segment.
|
||||
* @throws UnsupportedOperationException if this segment does not support the {@link #HANDOFF} access mode.
|
||||
* @throws NullPointerException if {@code nativeScope == null}.
|
||||
*/
|
||||
MemorySegment handoff(NativeScope nativeScope);
|
||||
|
||||
@ -823,6 +822,7 @@ for (long l = 0; l < segment.byteSize(); l++) {
|
||||
* @throws IllegalArgumentException if the specified layout has illegal size or alignment constraint.
|
||||
*/
|
||||
static MemorySegment allocateNative(MemoryLayout layout) {
|
||||
Objects.requireNonNull(layout);
|
||||
return allocateNative(layout.byteSize(), layout.byteAlignment());
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ import jdk.internal.foreign.Utils;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.lang.reflect.Array;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Objects;
|
||||
import java.util.OptionalLong;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
@ -54,6 +55,9 @@ import java.util.stream.Stream;
|
||||
* created to share the same life-cycle as a given native scope - which in turns enables a client to group all memory
|
||||
* allocation and usage under a single <em>try-with-resources block</em>.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*
|
||||
* @apiNote In the future, if the Java language permits, {@link NativeScope}
|
||||
* may become a {@code sealed} interface, which would prohibit subclassing except by
|
||||
* explicitly permitted types.
|
||||
@ -90,6 +94,7 @@ public interface NativeScope extends AutoCloseable {
|
||||
* @throws IllegalArgumentException if {@code layout.byteSize()} does not conform to the size of a byte value.
|
||||
*/
|
||||
default MemorySegment allocate(ValueLayout layout, byte value) {
|
||||
Objects.requireNonNull(layout);
|
||||
VarHandle handle = layout.varHandle(byte.class);
|
||||
MemorySegment addr = allocate(layout);
|
||||
handle.set(addr, value);
|
||||
@ -108,6 +113,7 @@ public interface NativeScope extends AutoCloseable {
|
||||
* @throws IllegalArgumentException if {@code layout.byteSize()} does not conform to the size of a char value.
|
||||
*/
|
||||
default MemorySegment allocate(ValueLayout layout, char value) {
|
||||
Objects.requireNonNull(layout);
|
||||
VarHandle handle = layout.varHandle(char.class);
|
||||
MemorySegment addr = allocate(layout);
|
||||
handle.set(addr, value);
|
||||
@ -126,6 +132,7 @@ public interface NativeScope extends AutoCloseable {
|
||||
* @throws IllegalArgumentException if {@code layout.byteSize()} does not conform to the size of a short value.
|
||||
*/
|
||||
default MemorySegment allocate(ValueLayout layout, short value) {
|
||||
Objects.requireNonNull(layout);
|
||||
VarHandle handle = layout.varHandle(short.class);
|
||||
MemorySegment addr = allocate(layout);
|
||||
handle.set(addr, value);
|
||||
@ -144,6 +151,7 @@ public interface NativeScope extends AutoCloseable {
|
||||
* @throws IllegalArgumentException if {@code layout.byteSize()} does not conform to the size of a int value.
|
||||
*/
|
||||
default MemorySegment allocate(ValueLayout layout, int value) {
|
||||
Objects.requireNonNull(layout);
|
||||
VarHandle handle = layout.varHandle(int.class);
|
||||
MemorySegment addr = allocate(layout);
|
||||
handle.set(addr, value);
|
||||
@ -162,6 +170,7 @@ public interface NativeScope extends AutoCloseable {
|
||||
* @throws IllegalArgumentException if {@code layout.byteSize()} does not conform to the size of a float value.
|
||||
*/
|
||||
default MemorySegment allocate(ValueLayout layout, float value) {
|
||||
Objects.requireNonNull(layout);
|
||||
VarHandle handle = layout.varHandle(float.class);
|
||||
MemorySegment addr = allocate(layout);
|
||||
handle.set(addr, value);
|
||||
@ -180,6 +189,7 @@ public interface NativeScope extends AutoCloseable {
|
||||
* @throws IllegalArgumentException if {@code layout.byteSize()} does not conform to the size of a long value.
|
||||
*/
|
||||
default MemorySegment allocate(ValueLayout layout, long value) {
|
||||
Objects.requireNonNull(layout);
|
||||
VarHandle handle = layout.varHandle(long.class);
|
||||
MemorySegment addr = allocate(layout);
|
||||
handle.set(addr, value);
|
||||
@ -198,6 +208,7 @@ public interface NativeScope extends AutoCloseable {
|
||||
* @throws IllegalArgumentException if {@code layout.byteSize()} does not conform to the size of a double value.
|
||||
*/
|
||||
default MemorySegment allocate(ValueLayout layout, double value) {
|
||||
Objects.requireNonNull(layout);
|
||||
VarHandle handle = layout.varHandle(double.class);
|
||||
MemorySegment addr = allocate(layout);
|
||||
handle.set(addr, value);
|
||||
@ -218,6 +229,8 @@ public interface NativeScope extends AutoCloseable {
|
||||
* @throws IllegalArgumentException if {@code layout.byteSize() != MemoryLayouts.ADDRESS.byteSize()}.
|
||||
*/
|
||||
default MemorySegment allocate(ValueLayout layout, Addressable value) {
|
||||
Objects.requireNonNull(value);
|
||||
Objects.requireNonNull(layout);
|
||||
if (MemoryLayouts.ADDRESS.byteSize() != layout.byteSize()) {
|
||||
throw new IllegalArgumentException("Layout size mismatch - " + layout.byteSize() + " != " + MemoryLayouts.ADDRESS.byteSize());
|
||||
}
|
||||
@ -346,6 +359,9 @@ public interface NativeScope extends AutoCloseable {
|
||||
* @throws IllegalArgumentException if {@code layout.byteSize() != MemoryLayouts.ADDRESS.byteSize()}.
|
||||
*/
|
||||
default MemorySegment allocateArray(ValueLayout elementLayout, Addressable[] array) {
|
||||
Objects.requireNonNull(elementLayout);
|
||||
Objects.requireNonNull(array);
|
||||
Stream.of(array).forEach(Objects::requireNonNull);
|
||||
if (MemoryLayouts.ADDRESS.byteSize() != elementLayout.byteSize()) {
|
||||
throw new IllegalArgumentException("Layout size mismatch - " + elementLayout.byteSize() + " != " + MemoryLayouts.ADDRESS.byteSize());
|
||||
}
|
||||
@ -362,6 +378,8 @@ public interface NativeScope extends AutoCloseable {
|
||||
|
||||
private <Z> MemorySegment copyArrayWithSwapIfNeeded(Z array, ValueLayout elementLayout,
|
||||
Function<Z, MemorySegment> heapSegmentFactory) {
|
||||
Objects.requireNonNull(array);
|
||||
Objects.requireNonNull(elementLayout);
|
||||
Utils.checkPrimitiveCarrierCompat(array.getClass().componentType(), elementLayout);
|
||||
MemorySegment addr = allocate(MemoryLayout.ofSequence(Array.getLength(array), elementLayout));
|
||||
if (elementLayout.byteSize() == 1 || (elementLayout.order() == ByteOrder.nativeOrder())) {
|
||||
@ -381,6 +399,7 @@ public interface NativeScope extends AutoCloseable {
|
||||
* bounded allocation scope, and {@code byteSize().getAsLong() - allocatedBytes() < layout.byteSize()}.
|
||||
*/
|
||||
default MemorySegment allocate(MemoryLayout layout) {
|
||||
Objects.requireNonNull(layout);
|
||||
return allocate(layout.byteSize(), layout.byteAlignment());
|
||||
}
|
||||
|
||||
@ -399,6 +418,7 @@ public interface NativeScope extends AutoCloseable {
|
||||
* bounded allocation scope, and {@code byteSize().getAsLong() - allocatedBytes() < (elementLayout.byteSize() * count)}.
|
||||
*/
|
||||
default MemorySegment allocateArray(MemoryLayout elementLayout, long count) {
|
||||
Objects.requireNonNull(elementLayout);
|
||||
return allocate(MemoryLayout.ofSequence(count, elementLayout));
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,9 @@ import java.util.OptionalLong;
|
||||
* {@code PaddingLayout} may have unpredictable results and should be avoided.
|
||||
* The {@code equals} method should be used for comparisons.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*/
|
||||
|
@ -60,6 +60,9 @@ MemoryLayout.ofStruct(
|
||||
* {@code SequenceLayout} may have unpredictable results and should be avoided.
|
||||
* The {@code equals} method should be used for comparisons.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*/
|
||||
@ -137,7 +140,6 @@ public final class SequenceLayout extends AbstractLayout {
|
||||
* @param elementCounts an array of element counts, of which at most one can be {@code -1}.
|
||||
* @return a new sequence layout where element layouts in the flattened projection of this
|
||||
* sequence layout (see {@link #flatten()}) are re-arranged into one or more nested sequence layouts.
|
||||
* @throws NullPointerException if {@code elementCounts == null}.
|
||||
* @throws UnsupportedOperationException if this sequence layout does not have an element count.
|
||||
* @throws IllegalArgumentException if two or more element counts are set to {@code -1}, or if one
|
||||
* or more element count is {@code <= 0} (but other than {@code -1}) or, if, after any required inference,
|
||||
|
@ -45,6 +45,9 @@ import java.util.OptionalLong;
|
||||
* {@code ValueLayout} may have unpredictable results and should be avoided.
|
||||
* The {@code equals} method should be used for comparisons.
|
||||
*
|
||||
* <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
|
||||
* elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
|
||||
*
|
||||
* @implSpec
|
||||
* This class is immutable and thread-safe.
|
||||
*/
|
||||
@ -77,7 +80,7 @@ public final class ValueLayout extends AbstractLayout implements MemoryLayout {
|
||||
* @return a new value layout with given byte order.
|
||||
*/
|
||||
public ValueLayout withOrder(ByteOrder order) {
|
||||
return new ValueLayout(order, bitSize(), alignment, attributes);
|
||||
return new ValueLayout(Objects.requireNonNull(order), bitSize(), alignment, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,6 +109,7 @@ public abstract class AbstractMemorySegmentImpl implements MemorySegment, Memory
|
||||
|
||||
@Override
|
||||
public Spliterator<MemorySegment> spliterator(SequenceLayout sequenceLayout) {
|
||||
Objects.requireNonNull(sequenceLayout);
|
||||
checkValidState();
|
||||
if (sequenceLayout.byteSize() != byteSize()) {
|
||||
throw new IllegalArgumentException();
|
||||
@ -125,7 +126,7 @@ public abstract class AbstractMemorySegmentImpl implements MemorySegment, Memory
|
||||
}
|
||||
|
||||
public void copyFrom(MemorySegment src) {
|
||||
AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl)src;
|
||||
AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl)Objects.requireNonNull(src);
|
||||
long size = that.byteSize();
|
||||
checkAccess(0, size, false);
|
||||
that.checkAccess(0, size, true);
|
||||
@ -146,7 +147,7 @@ public abstract class AbstractMemorySegmentImpl implements MemorySegment, Memory
|
||||
|
||||
@Override
|
||||
public long mismatch(MemorySegment other) {
|
||||
AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl)other;
|
||||
AbstractMemorySegmentImpl that = (AbstractMemorySegmentImpl)Objects.requireNonNull(other);
|
||||
final long thisSize = this.byteSize();
|
||||
final long thatSize = that.byteSize();
|
||||
final long length = Math.min(thisSize, thatSize);
|
||||
@ -591,6 +592,7 @@ public abstract class AbstractMemorySegmentImpl implements MemorySegment, Memory
|
||||
}
|
||||
|
||||
public static AbstractMemorySegmentImpl ofBuffer(ByteBuffer bb) {
|
||||
Objects.requireNonNull(bb);
|
||||
long bbAddress = nioAccess.getBufferAddress(bb);
|
||||
Object base = nioAccess.getBufferBase(bb);
|
||||
UnmapperProxy unmapper = nioAccess.unmapper(bb);
|
||||
|
@ -97,6 +97,7 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
}
|
||||
|
||||
public static MemorySegment fromArray(byte[] arr) {
|
||||
Objects.requireNonNull(arr);
|
||||
int byteSize = arr.length * Unsafe.ARRAY_BYTE_INDEX_SCALE;
|
||||
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
|
||||
return new OfByte(Unsafe.ARRAY_BYTE_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
|
||||
@ -120,6 +121,7 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
}
|
||||
|
||||
public static MemorySegment fromArray(char[] arr) {
|
||||
Objects.requireNonNull(arr);
|
||||
int byteSize = arr.length * Unsafe.ARRAY_CHAR_INDEX_SCALE;
|
||||
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
|
||||
return new OfChar(Unsafe.ARRAY_CHAR_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
|
||||
@ -143,6 +145,7 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
}
|
||||
|
||||
public static MemorySegment fromArray(short[] arr) {
|
||||
Objects.requireNonNull(arr);
|
||||
int byteSize = arr.length * Unsafe.ARRAY_SHORT_INDEX_SCALE;
|
||||
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
|
||||
return new OfShort(Unsafe.ARRAY_SHORT_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
|
||||
@ -166,6 +169,7 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
}
|
||||
|
||||
public static MemorySegment fromArray(int[] arr) {
|
||||
Objects.requireNonNull(arr);
|
||||
int byteSize = arr.length * Unsafe.ARRAY_INT_INDEX_SCALE;
|
||||
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
|
||||
return new OfInt(Unsafe.ARRAY_INT_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
|
||||
@ -189,6 +193,7 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
}
|
||||
|
||||
public static MemorySegment fromArray(long[] arr) {
|
||||
Objects.requireNonNull(arr);
|
||||
int byteSize = arr.length * Unsafe.ARRAY_LONG_INDEX_SCALE;
|
||||
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
|
||||
return new OfLong(Unsafe.ARRAY_LONG_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
|
||||
@ -212,6 +217,7 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
}
|
||||
|
||||
public static MemorySegment fromArray(float[] arr) {
|
||||
Objects.requireNonNull(arr);
|
||||
int byteSize = arr.length * Unsafe.ARRAY_FLOAT_INDEX_SCALE;
|
||||
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
|
||||
return new OfFloat(Unsafe.ARRAY_FLOAT_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
|
||||
@ -235,6 +241,7 @@ public abstract class HeapMemorySegmentImpl<H> extends AbstractMemorySegmentImpl
|
||||
}
|
||||
|
||||
public static MemorySegment fromArray(double[] arr) {
|
||||
Objects.requireNonNull(arr);
|
||||
int byteSize = arr.length * Unsafe.ARRAY_DOUBLE_INDEX_SCALE;
|
||||
MemoryScope scope = MemoryScope.createConfined(null, MemoryScope.DUMMY_CLEANUP_ACTION, null);
|
||||
return new OfDouble(Unsafe.ARRAY_DOUBLE_BASE_OFFSET, arr, byteSize, defaultAccessModes(byteSize), scope);
|
||||
|
@ -38,6 +38,7 @@ import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Supplier;
|
||||
@ -117,6 +118,7 @@ public final class LibrariesHelper {
|
||||
@Override
|
||||
public Optional<Symbol> lookup(String name) {
|
||||
try {
|
||||
Objects.requireNonNull(name);
|
||||
MemoryAddress addr = MemoryAddress.ofLong(library.lookup(name));
|
||||
return Optional.of(new Symbol() { // inner class - retains a link to enclosing lookup
|
||||
@Override
|
||||
|
@ -37,6 +37,7 @@ import java.nio.channels.FileChannel;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@ -109,6 +110,8 @@ public class MappedMemorySegmentImpl extends NativeMemorySegmentImpl {
|
||||
// factories
|
||||
|
||||
public static MemorySegment makeMappedSegment(Path path, long bytesOffset, long bytesSize, FileChannel.MapMode mapMode) throws IOException {
|
||||
Objects.requireNonNull(path);
|
||||
Objects.requireNonNull(mapMode);
|
||||
if (bytesSize < 0) throw new IllegalArgumentException("Requested bytes size must be >= 0.");
|
||||
if (bytesOffset < 0) throw new IllegalArgumentException("Requested bytes offset must be >= 0.");
|
||||
try (FileChannelImpl channelImpl = (FileChannelImpl)FileChannel.open(path, openOptions(mapMode))) {
|
||||
|
@ -37,6 +37,7 @@ import jdk.internal.foreign.abi.UpcallStubs;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static jdk.internal.foreign.PlatformLayouts.*;
|
||||
@ -74,6 +75,9 @@ public class AArch64Linker implements CLinker {
|
||||
|
||||
@Override
|
||||
public MethodHandle downcallHandle(Addressable symbol, MethodType type, FunctionDescriptor function) {
|
||||
Objects.requireNonNull(symbol);
|
||||
Objects.requireNonNull(type);
|
||||
Objects.requireNonNull(function);
|
||||
MethodType llMt = SharedUtils.convertVaListCarriers(type, AArch64VaList.CARRIER);
|
||||
MethodHandle handle = CallArranger.arrangeDowncall(symbol, llMt, function);
|
||||
handle = SharedUtils.unboxVaLists(type, handle, MH_unboxVaList);
|
||||
@ -82,6 +86,8 @@ public class AArch64Linker implements CLinker {
|
||||
|
||||
@Override
|
||||
public MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function) {
|
||||
Objects.requireNonNull(target);
|
||||
Objects.requireNonNull(function);
|
||||
target = SharedUtils.boxVaLists(target, MH_boxVaList);
|
||||
return UpcallStubs.upcallAddress(CallArranger.arrangeUpcall(target, target.type(), function));
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ import java.lang.ref.Cleaner;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static jdk.internal.foreign.PlatformLayouts.AArch64;
|
||||
import static jdk.incubator.foreign.CLinker.VaList;
|
||||
@ -239,6 +240,7 @@ public class AArch64VaList implements VaList {
|
||||
|
||||
@Override
|
||||
public MemorySegment vargAsSegment(MemoryLayout layout, NativeScope scope) {
|
||||
Objects.requireNonNull(scope);
|
||||
return (MemorySegment) read(MemorySegment.class, layout, SharedUtils.Allocator.ofScope(scope));
|
||||
}
|
||||
|
||||
@ -247,6 +249,7 @@ public class AArch64VaList implements VaList {
|
||||
}
|
||||
|
||||
private Object read(Class<?> carrier, MemoryLayout layout, SharedUtils.Allocator allocator) {
|
||||
Objects.requireNonNull(layout);
|
||||
checkCompatibleType(carrier, layout, AArch64Linker.ADDRESS_SIZE);
|
||||
|
||||
TypeClass typeClass = TypeClass.classifyLayout(layout);
|
||||
@ -336,7 +339,9 @@ public class AArch64VaList implements VaList {
|
||||
|
||||
@Override
|
||||
public void skip(MemoryLayout... layouts) {
|
||||
Objects.requireNonNull(layouts);
|
||||
for (MemoryLayout layout : layouts) {
|
||||
Objects.requireNonNull(layout);
|
||||
TypeClass typeClass = TypeClass.classifyLayout(layout);
|
||||
if (isRegOverflow(currentGPOffset(), currentFPOffset(), typeClass, layout)) {
|
||||
preAlignStack(layout);
|
||||
@ -377,6 +382,7 @@ public class AArch64VaList implements VaList {
|
||||
|
||||
@Override
|
||||
public VaList copy(NativeScope scope) {
|
||||
Objects.requireNonNull(scope);
|
||||
return copy(SharedUtils.Allocator.ofScope(scope));
|
||||
}
|
||||
|
||||
@ -458,6 +464,8 @@ public class AArch64VaList implements VaList {
|
||||
}
|
||||
|
||||
private Builder arg(Class<?> carrier, MemoryLayout layout, Object value) {
|
||||
Objects.requireNonNull(layout);
|
||||
Objects.requireNonNull(value);
|
||||
checkCompatibleType(carrier, layout, AArch64Linker.ADDRESS_SIZE);
|
||||
|
||||
TypeClass typeClass = TypeClass.classifyLayout(layout);
|
||||
|
@ -36,6 +36,7 @@ import java.lang.ref.Cleaner;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static jdk.internal.foreign.PlatformLayouts.SysV;
|
||||
import static jdk.incubator.foreign.CLinker.VaList;
|
||||
@ -216,6 +217,7 @@ public class SysVVaList implements VaList {
|
||||
|
||||
@Override
|
||||
public MemorySegment vargAsSegment(MemoryLayout layout, NativeScope scope) {
|
||||
Objects.requireNonNull(scope);
|
||||
return (MemorySegment) read(MemorySegment.class, layout, SharedUtils.Allocator.ofScope(scope));
|
||||
}
|
||||
|
||||
@ -224,6 +226,7 @@ public class SysVVaList implements VaList {
|
||||
}
|
||||
|
||||
private Object read(Class<?> carrier, MemoryLayout layout, SharedUtils.Allocator allocator) {
|
||||
Objects.requireNonNull(layout);
|
||||
checkCompatibleType(carrier, layout, SysVx64Linker.ADDRESS_SIZE);
|
||||
TypeClass typeClass = TypeClass.classifyLayout(layout);
|
||||
if (isRegOverflow(currentGPOffset(), currentFPOffset(), typeClass)
|
||||
@ -288,7 +291,9 @@ public class SysVVaList implements VaList {
|
||||
|
||||
@Override
|
||||
public void skip(MemoryLayout... layouts) {
|
||||
Objects.requireNonNull(layouts);
|
||||
for (MemoryLayout layout : layouts) {
|
||||
Objects.requireNonNull(layout);
|
||||
TypeClass typeClass = TypeClass.classifyLayout(layout);
|
||||
if (isRegOverflow(currentGPOffset(), currentFPOffset(), typeClass)) {
|
||||
preAlignStack(layout);
|
||||
@ -326,6 +331,7 @@ public class SysVVaList implements VaList {
|
||||
|
||||
@Override
|
||||
public VaList copy(NativeScope scope) {
|
||||
Objects.requireNonNull(scope);
|
||||
return copy(SharedUtils.Allocator.ofScope(scope));
|
||||
}
|
||||
|
||||
@ -393,6 +399,8 @@ public class SysVVaList implements VaList {
|
||||
}
|
||||
|
||||
private Builder arg(Class<?> carrier, MemoryLayout layout, Object value) {
|
||||
Objects.requireNonNull(layout);
|
||||
Objects.requireNonNull(value);
|
||||
checkCompatibleType(carrier, layout, SysVx64Linker.ADDRESS_SIZE);
|
||||
TypeClass typeClass = TypeClass.classifyLayout(layout);
|
||||
if (isRegOverflow(currentGPOffset, currentFPOffset, typeClass)
|
||||
|
@ -36,6 +36,7 @@ import jdk.internal.foreign.abi.UpcallStubs;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@ -85,6 +86,9 @@ public class SysVx64Linker implements CLinker {
|
||||
|
||||
@Override
|
||||
public MethodHandle downcallHandle(Addressable symbol, MethodType type, FunctionDescriptor function) {
|
||||
Objects.requireNonNull(symbol);
|
||||
Objects.requireNonNull(type);
|
||||
Objects.requireNonNull(function);
|
||||
MethodType llMt = SharedUtils.convertVaListCarriers(type, SysVVaList.CARRIER);
|
||||
MethodHandle handle = CallArranger.arrangeDowncall(symbol, llMt, function);
|
||||
handle = SharedUtils.unboxVaLists(type, handle, MH_unboxVaList);
|
||||
@ -93,6 +97,8 @@ public class SysVx64Linker implements CLinker {
|
||||
|
||||
@Override
|
||||
public MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function) {
|
||||
Objects.requireNonNull(target);
|
||||
Objects.requireNonNull(function);
|
||||
target = SharedUtils.boxVaLists(target, MH_boxVaList);
|
||||
return UpcallStubs.upcallAddress(CallArranger.arrangeUpcall(target, target.type(), function));
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ import jdk.internal.foreign.abi.SharedUtils.SimpleVaArg;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static jdk.internal.foreign.PlatformLayouts.Win64.C_POINTER;
|
||||
|
||||
@ -100,6 +102,7 @@ class WinVaList implements VaList {
|
||||
|
||||
@Override
|
||||
public MemorySegment vargAsSegment(MemoryLayout layout, NativeScope scope) {
|
||||
Objects.requireNonNull(scope);
|
||||
return (MemorySegment) read(MemorySegment.class, layout, SharedUtils.Allocator.ofScope(scope));
|
||||
}
|
||||
|
||||
@ -108,6 +111,7 @@ class WinVaList implements VaList {
|
||||
}
|
||||
|
||||
private Object read(Class<?> carrier, MemoryLayout layout, SharedUtils.Allocator allocator) {
|
||||
Objects.requireNonNull(layout);
|
||||
SharedUtils.checkCompatibleType(carrier, layout, Windowsx64Linker.ADDRESS_SIZE);
|
||||
Object res;
|
||||
if (carrier == MemorySegment.class) {
|
||||
@ -139,6 +143,8 @@ class WinVaList implements VaList {
|
||||
|
||||
@Override
|
||||
public void skip(MemoryLayout... layouts) {
|
||||
Objects.requireNonNull(layouts);
|
||||
Stream.of(layouts).forEach(Objects::requireNonNull);
|
||||
segment = segment.asSlice(layouts.length * VA_SLOT_SIZE_BYTES);
|
||||
}
|
||||
|
||||
@ -167,6 +173,7 @@ class WinVaList implements VaList {
|
||||
|
||||
@Override
|
||||
public VaList copy(NativeScope scope) {
|
||||
Objects.requireNonNull(scope);
|
||||
MemorySegment liveness = handoffIfNeeded(MemoryAddress.NULL.asSegmentRestricted(1),
|
||||
segment.ownerThread());
|
||||
liveness = liveness.handoff(scope);
|
||||
@ -195,6 +202,8 @@ class WinVaList implements VaList {
|
||||
}
|
||||
|
||||
private Builder arg(Class<?> carrier, MemoryLayout layout, Object value) {
|
||||
Objects.requireNonNull(layout);
|
||||
Objects.requireNonNull(value);
|
||||
SharedUtils.checkCompatibleType(carrier, layout, Windowsx64Linker.ADDRESS_SIZE);
|
||||
args.add(new SimpleVaArg(carrier, layout, value));
|
||||
return this;
|
||||
|
@ -36,6 +36,7 @@ import jdk.internal.foreign.abi.UpcallStubs;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static jdk.internal.foreign.PlatformLayouts.*;
|
||||
@ -86,6 +87,9 @@ public class Windowsx64Linker implements CLinker {
|
||||
|
||||
@Override
|
||||
public MethodHandle downcallHandle(Addressable symbol, MethodType type, FunctionDescriptor function) {
|
||||
Objects.requireNonNull(symbol);
|
||||
Objects.requireNonNull(type);
|
||||
Objects.requireNonNull(function);
|
||||
MethodType llMt = SharedUtils.convertVaListCarriers(type, WinVaList.CARRIER);
|
||||
MethodHandle handle = CallArranger.arrangeDowncall(symbol, llMt, function);
|
||||
handle = SharedUtils.unboxVaLists(type, handle, MH_unboxVaList);
|
||||
@ -94,6 +98,8 @@ public class Windowsx64Linker implements CLinker {
|
||||
|
||||
@Override
|
||||
public MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function) {
|
||||
Objects.requireNonNull(target);
|
||||
Objects.requireNonNull(function);
|
||||
target = SharedUtils.boxVaLists(target, MH_boxVaList);
|
||||
return UpcallStubs.upcallAddress(CallArranger.arrangeUpcall(target, target.type(), function));
|
||||
}
|
||||
|
@ -152,21 +152,6 @@ public class TestAdaptVarHandles {
|
||||
assertEquals(value, "42");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testBadFilterNullTarget() {
|
||||
MemoryHandles.filterValue(null, S2I, I2S);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testBadFilterNullUnbox() {
|
||||
MemoryHandles.filterValue(intHandle, null, I2S);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testBadFilterNullBox() {
|
||||
MemoryHandles.filterValue(intHandle, S2I, null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testBadFilterCarrier() {
|
||||
MemoryHandles.filterValue(floatHandle, S2I, I2S);
|
||||
@ -234,16 +219,6 @@ public class TestAdaptVarHandles {
|
||||
assertEquals(value, 42);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testBadFilterCoordinatesNullTarget() {
|
||||
MemoryHandles.filterCoordinates(null, 0, S2I);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testBadFilterCoordinatesNullFilters() {
|
||||
MemoryHandles.filterCoordinates(intHandle, 0, null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testBadFilterCoordinatesNegativePos() {
|
||||
MemoryHandles.filterCoordinates(intHandle, -1, SUM_OFFSETS);
|
||||
@ -287,16 +262,6 @@ public class TestAdaptVarHandles {
|
||||
assertEquals(value, 42);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testBadInsertCoordinatesNullTarget() {
|
||||
MemoryHandles.insertCoordinates(null, 0, 42);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testBadInsertCoordinatesNullValues() {
|
||||
MemoryHandles.insertCoordinates(intHandle, 0, null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testBadInsertCoordinatesNegativePos() {
|
||||
MemoryHandles.insertCoordinates(intHandle, -1, 42);
|
||||
@ -336,21 +301,6 @@ public class TestAdaptVarHandles {
|
||||
assertEquals(value, 42);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testBadPermuteCoordinatesNullTarget() {
|
||||
MemoryHandles.permuteCoordinates(null, List.of());
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testBadPermuteCoordinatesNullCoordinates() {
|
||||
MemoryHandles.permuteCoordinates(intHandle, null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testBadPermuteCoordinatesNullReorder() {
|
||||
MemoryHandles.permuteCoordinates(intHandle, List.of(int.class), null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testBadPermuteCoordinatesTooManyCoordinates() {
|
||||
MemoryHandles.permuteCoordinates(intHandle, List.of(int.class, int.class), new int[2]);
|
||||
@ -389,16 +339,6 @@ public class TestAdaptVarHandles {
|
||||
assertEquals(value, 42);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testBadCollectCoordinatesNullTarget() {
|
||||
MemoryHandles.collectCoordinates(null, 0, SUM_OFFSETS);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testBadCollectCoordinatesNullFilters() {
|
||||
MemoryHandles.collectCoordinates(intHandle, 0, null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testBadCollectCoordinatesNegativePos() {
|
||||
MemoryHandles.collectCoordinates(intHandle, -1, SUM_OFFSETS);
|
||||
@ -452,16 +392,6 @@ public class TestAdaptVarHandles {
|
||||
MemoryHandles.dropCoordinates(intHandle, 2);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testBadDropCoordinatesNullValueTypes() {
|
||||
MemoryHandles.dropCoordinates(intHandle, 1, null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testBadDropCoordinatesNullTarget() {
|
||||
MemoryHandles.dropCoordinates(null, 1);
|
||||
}
|
||||
|
||||
//helper methods
|
||||
|
||||
static int stringToInt(String s) {
|
||||
|
@ -119,27 +119,4 @@ public class TestFunctionDescriptor {
|
||||
assertFalse(returnLayoutOp.isPresent());
|
||||
assertEquals(fd.attributes().collect(Collectors.toList()), List.of(DUMMY_ATTR));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testNullArgumentLayout() {
|
||||
FunctionDescriptor.ofVoid(C_INT, null, C_LONG_LONG);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testNullReturnLayout() {
|
||||
FunctionDescriptor.of(null, C_INT, C_LONG_LONG);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testNullArgumentLayoutsAppend() {
|
||||
FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT, C_LONG_LONG);
|
||||
fd.withAppendedArgumentLayouts(C_DOUBLE, null); // should throw
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testNullReturnLayoutChange() {
|
||||
FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT, C_LONG_LONG);
|
||||
fd.withReturnLayout(null); // should throw
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -79,5 +79,4 @@ public class TestLayoutAttributes {
|
||||
assertTrue(attribs.contains("MyAttribute"));
|
||||
assertTrue(attribs.contains(MemoryLayout.LAYOUT_NAME));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -89,23 +89,6 @@ public class TestLayoutPaths {
|
||||
g.byteOffset(PathElement.groupElement("foo"));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testNullGroupElementName() {
|
||||
PathElement.groupElement(null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testBitNullGroupElementName() {
|
||||
GroupLayout g = MemoryLayout.ofStruct(MemoryLayouts.JAVA_INT);
|
||||
g.bitOffset(PathElement.groupElement(null));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testByteNullGroupElementName() {
|
||||
GroupLayout g = MemoryLayout.ofStruct(MemoryLayouts.JAVA_INT);
|
||||
g.byteOffset(PathElement.groupElement(null));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testBitOutOfBoundsSeqIndex() {
|
||||
SequenceLayout seq = MemoryLayout.ofSequence(5, MemoryLayouts.JAVA_INT);
|
||||
|
364
test/jdk/java/foreign/TestMemoryAccessStatics.java
Normal file
364
test/jdk/java/foreign/TestMemoryAccessStatics.java
Normal file
@ -0,0 +1,364 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @run testng TestMemoryAccessStatics
|
||||
*/
|
||||
|
||||
import jdk.incubator.foreign.MemoryAccess;
|
||||
import jdk.incubator.foreign.MemoryAddress;
|
||||
import jdk.incubator.foreign.MemoryLayouts;
|
||||
import jdk.incubator.foreign.MemorySegment;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
import org.testng.annotations.*;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class TestMemoryAccessStatics {
|
||||
|
||||
static class Accessor<X> {
|
||||
|
||||
interface SegmentGetter<X> {
|
||||
X get(MemorySegment segment);
|
||||
}
|
||||
|
||||
interface SegmentSetter<X> {
|
||||
void set(MemorySegment segment, X o);
|
||||
}
|
||||
|
||||
interface BufferGetter<X> {
|
||||
X get(ByteBuffer segment);
|
||||
}
|
||||
|
||||
interface BufferSetter<X> {
|
||||
void set(ByteBuffer buffer, X o);
|
||||
}
|
||||
|
||||
final X value;
|
||||
final SegmentGetter<X> segmentGetter;
|
||||
final SegmentSetter<X> segmentSetter;
|
||||
final BufferGetter<X> bufferGetter;
|
||||
final BufferSetter<X> bufferSetter;
|
||||
|
||||
Accessor(X value,
|
||||
SegmentGetter<X> segmentGetter, SegmentSetter<X> segmentSetter,
|
||||
BufferGetter<X> bufferGetter, BufferSetter<X> bufferSetter) {
|
||||
this.value = value;
|
||||
this.segmentGetter = segmentGetter;
|
||||
this.segmentSetter = segmentSetter;
|
||||
this.bufferGetter = bufferGetter;
|
||||
this.bufferSetter = bufferSetter;
|
||||
}
|
||||
|
||||
void test() {
|
||||
MemorySegment segment = MemorySegment.ofArray(new byte[32]);
|
||||
ByteBuffer buffer = segment.asByteBuffer();
|
||||
segmentSetter.set(segment, value);
|
||||
assertEquals(bufferGetter.get(buffer), value);
|
||||
bufferSetter.set(buffer, value);
|
||||
assertEquals(value, segmentGetter.get(segment));
|
||||
}
|
||||
|
||||
<Z> Accessor<Z> of(Z value,
|
||||
SegmentGetter<Z> segmentGetter, SegmentSetter<Z> segmentSetter,
|
||||
BufferGetter<Z> bufferGetter, BufferSetter<Z> bufferSetter) {
|
||||
return new Accessor<>(value, segmentGetter, segmentSetter, bufferGetter, bufferSetter);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(dataProvider = "accessors")
|
||||
public void testMemoryAccess(String testName, Accessor<?> accessor) {
|
||||
accessor.test();
|
||||
}
|
||||
|
||||
static final ByteOrder BE = ByteOrder.BIG_ENDIAN;
|
||||
static final ByteOrder LE = ByteOrder.LITTLE_ENDIAN;
|
||||
static final ByteOrder NE = ByteOrder.nativeOrder();
|
||||
|
||||
@DataProvider(name = "accessors")
|
||||
static Object[][] accessors() {
|
||||
return new Object[][]{
|
||||
|
||||
{"byte", new Accessor<>((byte) 42,
|
||||
MemoryAccess::getByte, MemoryAccess::setByte,
|
||||
(bb) -> bb.get(0), (bb, v) -> bb.put(0, v))
|
||||
},
|
||||
{"char", new Accessor<>((char) 42,
|
||||
MemoryAccess::getChar, MemoryAccess::setChar,
|
||||
(bb) -> bb.order(NE).getChar(0), (bb, v) -> bb.order(NE).putChar(0, v))
|
||||
},
|
||||
{"char/LE", new Accessor<>((char) 42,
|
||||
s -> MemoryAccess.getChar(s, LE), (s, x) -> MemoryAccess.setChar(s, LE, x),
|
||||
(bb) -> bb.order(LE).getChar(0), (bb, v) -> bb.order(LE).putChar(0, v))
|
||||
},
|
||||
{"char/BE", new Accessor<>((char) 42,
|
||||
s -> MemoryAccess.getChar(s, BE), (s, x) -> MemoryAccess.setChar(s, BE, x),
|
||||
(bb) -> bb.order(BE).getChar(0), (bb, v) -> bb.order(BE).putChar(0, v))
|
||||
},
|
||||
{"short", new Accessor<>((short) 42,
|
||||
MemoryAccess::getShort, MemoryAccess::setShort,
|
||||
(bb) -> bb.order(NE).getShort(0), (bb, v) -> bb.order(NE).putShort(0, v))
|
||||
},
|
||||
{"short/LE", new Accessor<>((short) 42,
|
||||
s -> MemoryAccess.getShort(s, LE), (s, x) -> MemoryAccess.setShort(s, LE, x),
|
||||
(bb) -> bb.order(LE).getShort(0), (bb, v) -> bb.order(LE).putShort(0, v))
|
||||
},
|
||||
{"short/BE", new Accessor<>((short) 42,
|
||||
s -> MemoryAccess.getShort(s, BE), (s, x) -> MemoryAccess.setShort(s, BE, x),
|
||||
(bb) -> bb.order(BE).getShort(0), (bb, v) -> bb.order(BE).putShort(0, v))
|
||||
},
|
||||
{"int", new Accessor<>(42,
|
||||
MemoryAccess::getInt, MemoryAccess::setInt,
|
||||
(bb) -> bb.order(NE).getInt(0), (bb, v) -> bb.order(NE).putInt(0, v))
|
||||
},
|
||||
{"int/LE", new Accessor<>(42,
|
||||
s -> MemoryAccess.getInt(s, LE), (s, x) -> MemoryAccess.setInt(s, LE, x),
|
||||
(bb) -> bb.order(LE).getInt(0), (bb, v) -> bb.order(LE).putInt(0, v))
|
||||
},
|
||||
{"int/BE", new Accessor<>(42,
|
||||
s -> MemoryAccess.getInt(s, BE), (s, x) -> MemoryAccess.setInt(s, BE, x),
|
||||
(bb) -> bb.order(BE).getInt(0), (bb, v) -> bb.order(BE).putInt(0, v))
|
||||
},
|
||||
// float, no offset
|
||||
{"float", new Accessor<>(42f,
|
||||
MemoryAccess::getFloat, MemoryAccess::setFloat,
|
||||
(bb) -> bb.order(NE).getFloat(0), (bb, v) -> bb.order(NE).putFloat(0, v))
|
||||
},
|
||||
{"float/LE", new Accessor<>(42f,
|
||||
s -> MemoryAccess.getFloat(s, LE), (s, x) -> MemoryAccess.setFloat(s, LE, x),
|
||||
(bb) -> bb.order(LE).getFloat(0), (bb, v) -> bb.order(LE).putFloat(0, v))
|
||||
},
|
||||
{"float/BE", new Accessor<>(42f,
|
||||
s -> MemoryAccess.getFloat(s, BE), (s, x) -> MemoryAccess.setFloat(s, BE, x),
|
||||
(bb) -> bb.order(BE).getFloat(0), (bb, v) -> bb.order(BE).putFloat(0, v))
|
||||
},
|
||||
// double, no offset
|
||||
{"double", new Accessor<>(42d,
|
||||
MemoryAccess::getDouble, MemoryAccess::setDouble,
|
||||
(bb) -> bb.order(NE).getDouble(0), (bb, v) -> bb.order(NE).putDouble(0, v))
|
||||
},
|
||||
{"double/LE", new Accessor<>(42d,
|
||||
s -> MemoryAccess.getDouble(s, LE), (s, x) -> MemoryAccess.setDouble(s, LE, x),
|
||||
(bb) -> bb.order(LE).getDouble(0), (bb, v) -> bb.order(LE).putDouble(0, v))
|
||||
},
|
||||
{"double/BE", new Accessor<>(42d,
|
||||
s -> MemoryAccess.getDouble(s, BE), (s, x) -> MemoryAccess.setDouble(s, BE, x),
|
||||
(bb) -> bb.order(BE).getDouble(0), (bb, v) -> bb.order(BE).putDouble(0, v))
|
||||
},
|
||||
|
||||
|
||||
// byte, offset
|
||||
{"byte/offset", new Accessor<>((byte) 42,
|
||||
s -> MemoryAccess.getByteAtOffset(s, 4), (s, x) -> MemoryAccess.setByteAtOffset(s, 4, x),
|
||||
(bb) -> bb.get(4), (bb, v) -> bb.put(4, v))
|
||||
},
|
||||
// char, offset
|
||||
{"char/offset", new Accessor<>((char) 42,
|
||||
s -> MemoryAccess.getCharAtOffset(s, 4), (s, x) -> MemoryAccess.setCharAtOffset(s, 4, x),
|
||||
(bb) -> bb.order(NE).getChar(4), (bb, v) -> bb.order(NE).putChar(4, v))
|
||||
},
|
||||
{"char/offset/LE", new Accessor<>((char) 42,
|
||||
s -> MemoryAccess.getCharAtOffset(s, 4, LE), (s, x) -> MemoryAccess.setCharAtOffset(s, 4, LE, x),
|
||||
(bb) -> bb.order(LE).getChar(4), (bb, v) -> bb.order(LE).putChar(4, v))
|
||||
},
|
||||
{"char/offset/BE", new Accessor<>((char) 42,
|
||||
s -> MemoryAccess.getCharAtOffset(s, 4, BE), (s, x) -> MemoryAccess.setCharAtOffset(s, 4, BE, x),
|
||||
(bb) -> bb.order(BE).getChar(4), (bb, v) -> bb.order(BE).putChar(4, v))
|
||||
},
|
||||
// short, offset
|
||||
{"short/offset", new Accessor<>((short) 42,
|
||||
s -> MemoryAccess.getShortAtOffset(s, 4), (s, x) -> MemoryAccess.setShortAtOffset(s, 4, x),
|
||||
(bb) -> bb.order(NE).getShort(4), (bb, v) -> bb.order(NE).putShort(4, v))
|
||||
},
|
||||
{"short/offset/LE", new Accessor<>((short) 42,
|
||||
s -> MemoryAccess.getShortAtOffset(s, 4, LE), (s, x) -> MemoryAccess.setShortAtOffset(s, 4, LE, x),
|
||||
(bb) -> bb.order(LE).getShort(4), (bb, v) -> bb.order(LE).putShort(4, v))
|
||||
},
|
||||
{"short/offset/BE", new Accessor<>((short) 42,
|
||||
s -> MemoryAccess.getShortAtOffset(s, 4, BE), (s, x) -> MemoryAccess.setShortAtOffset(s, 4, BE, x),
|
||||
(bb) -> bb.order(BE).getShort(4), (bb, v) -> bb.order(BE).putShort(4, v))
|
||||
},
|
||||
// int, offset
|
||||
{"int/offset", new Accessor<>(42,
|
||||
s -> MemoryAccess.getIntAtOffset(s, 4), (s, x) -> MemoryAccess.setIntAtOffset(s, 4, x),
|
||||
(bb) -> bb.order(NE).getInt(4), (bb, v) -> bb.order(NE).putInt(4, v))
|
||||
},
|
||||
{"int/offset/LE", new Accessor<>(42,
|
||||
s -> MemoryAccess.getIntAtOffset(s, 4, LE), (s, x) -> MemoryAccess.setIntAtOffset(s, 4, LE, x),
|
||||
(bb) -> bb.order(LE).getInt(4), (bb, v) -> bb.order(LE).putInt(4, v))
|
||||
},
|
||||
{"int/offset/BE", new Accessor<>(42,
|
||||
s -> MemoryAccess.getIntAtOffset(s, 4, BE), (s, x) -> MemoryAccess.setIntAtOffset(s, 4, BE, x),
|
||||
(bb) -> bb.order(BE).getInt(4), (bb, v) -> bb.order(BE).putInt(4, v))
|
||||
},
|
||||
// float, offset
|
||||
{"float/offset", new Accessor<>(42f,
|
||||
s -> MemoryAccess.getFloatAtOffset(s, 4), (s, x) -> MemoryAccess.setFloatAtOffset(s, 4, x),
|
||||
(bb) -> bb.order(NE).getFloat(4), (bb, v) -> bb.order(NE).putFloat(4, v))
|
||||
},
|
||||
{"float/offset/LE", new Accessor<>(42f,
|
||||
s -> MemoryAccess.getFloatAtOffset(s, 4, LE), (s, x) -> MemoryAccess.setFloatAtOffset(s, 4, LE, x),
|
||||
(bb) -> bb.order(LE).getFloat(4), (bb, v) -> bb.order(LE).putFloat(4, v))
|
||||
},
|
||||
{"float/offset/BE", new Accessor<>(42f,
|
||||
s -> MemoryAccess.getFloatAtOffset(s, 4, BE), (s, x) -> MemoryAccess.setFloatAtOffset(s, 4, BE, x),
|
||||
(bb) -> bb.order(BE).getFloat(4), (bb, v) -> bb.order(BE).putFloat(4, v))
|
||||
},
|
||||
// double, offset
|
||||
{"double/offset", new Accessor<>(42d,
|
||||
s -> MemoryAccess.getDoubleAtOffset(s, 4), (s, x) -> MemoryAccess.setDoubleAtOffset(s, 4, x),
|
||||
(bb) -> bb.order(NE).getDouble(4), (bb, v) -> bb.order(NE).putDouble(4, v))
|
||||
},
|
||||
{"double/offset/LE", new Accessor<>(42d,
|
||||
s -> MemoryAccess.getDoubleAtOffset(s, 4, LE), (s, x) -> MemoryAccess.setDoubleAtOffset(s, 4, LE, x),
|
||||
(bb) -> bb.order(LE).getDouble(4), (bb, v) -> bb.order(LE).putDouble(4, v))
|
||||
},
|
||||
{"double/offset/BE", new Accessor<>(42d,
|
||||
s -> MemoryAccess.getDoubleAtOffset(s, 4, BE), (s, x) -> MemoryAccess.setDoubleAtOffset(s, 4, BE, x),
|
||||
(bb) -> bb.order(BE).getDouble(4), (bb, v) -> bb.order(BE).putDouble(4, v))
|
||||
},
|
||||
|
||||
|
||||
// char, index
|
||||
{"char/index", new Accessor<>((char) 42,
|
||||
s -> MemoryAccess.getCharAtIndex(s, 2), (s, x) -> MemoryAccess.setCharAtIndex(s, 2, x),
|
||||
(bb) -> bb.order(NE).asCharBuffer().get(2), (bb, v) -> bb.order(NE).asCharBuffer().put(2, v))
|
||||
},
|
||||
{"char/index/LE", new Accessor<>((char) 42,
|
||||
s -> MemoryAccess.getCharAtIndex(s, 2, LE), (s, x) -> MemoryAccess.setCharAtIndex(s, 2, LE, x),
|
||||
(bb) -> bb.order(LE).asCharBuffer().get(2), (bb, v) -> bb.order(LE).asCharBuffer().put(2, v))
|
||||
},
|
||||
{"char/index/BE", new Accessor<>((char) 42,
|
||||
s -> MemoryAccess.getCharAtIndex(s, 2, BE), (s, x) -> MemoryAccess.setCharAtIndex(s, 2, BE, x),
|
||||
(bb) -> bb.order(BE).asCharBuffer().get(2), (bb, v) -> bb.order(BE).asCharBuffer().put(2, v))
|
||||
},
|
||||
// short, index
|
||||
{"short/index", new Accessor<>((short) 42,
|
||||
s -> MemoryAccess.getShortAtIndex(s, 2), (s, x) -> MemoryAccess.setShortAtIndex(s, 2, x),
|
||||
(bb) -> bb.order(NE).asShortBuffer().get(2), (bb, v) -> bb.order(NE).asShortBuffer().put(2, v))
|
||||
},
|
||||
{"short/index/LE", new Accessor<>((short) 42,
|
||||
s -> MemoryAccess.getShortAtIndex(s, 2, LE), (s, x) -> MemoryAccess.setShortAtIndex(s, 2, LE, x),
|
||||
(bb) -> bb.order(LE).asShortBuffer().get(2), (bb, v) -> bb.order(LE).asShortBuffer().put(2, v))
|
||||
},
|
||||
{"short/index/BE", new Accessor<>((short) 42,
|
||||
s -> MemoryAccess.getShortAtIndex(s, 2, BE), (s, x) -> MemoryAccess.setShortAtIndex(s, 2, BE, x),
|
||||
(bb) -> bb.order(BE).asShortBuffer().get(2), (bb, v) -> bb.order(BE).asShortBuffer().put(2, v))
|
||||
},
|
||||
{"int/index", new Accessor<>(42,
|
||||
s -> MemoryAccess.getIntAtIndex(s, 2), (s, x) -> MemoryAccess.setIntAtIndex(s, 2, x),
|
||||
(bb) -> bb.order(NE).asIntBuffer().get(2), (bb, v) -> bb.order(NE).asIntBuffer().put(2, v))
|
||||
},
|
||||
{"int/index/LE", new Accessor<>(42,
|
||||
s -> MemoryAccess.getIntAtIndex(s, 2, LE), (s, x) -> MemoryAccess.setIntAtIndex(s, 2, LE, x),
|
||||
(bb) -> bb.order(LE).asIntBuffer().get(2), (bb, v) -> bb.order(LE).asIntBuffer().put(2, v))
|
||||
},
|
||||
{"int/index/BE", new Accessor<>(42,
|
||||
s -> MemoryAccess.getIntAtIndex(s, 2, BE), (s, x) -> MemoryAccess.setIntAtIndex(s, 2, BE, x),
|
||||
(bb) -> bb.order(BE).asIntBuffer().get(2), (bb, v) -> bb.order(BE).asIntBuffer().put(2, v))
|
||||
},
|
||||
{"float/index", new Accessor<>(42f,
|
||||
s -> MemoryAccess.getFloatAtIndex(s, 2), (s, x) -> MemoryAccess.setFloatAtIndex(s, 2, x),
|
||||
(bb) -> bb.order(NE).asFloatBuffer().get(2), (bb, v) -> bb.order(NE).asFloatBuffer().put(2, v))
|
||||
},
|
||||
{"float/index/LE", new Accessor<>(42f,
|
||||
s -> MemoryAccess.getFloatAtIndex(s, 2, LE), (s, x) -> MemoryAccess.setFloatAtIndex(s, 2, LE, x),
|
||||
(bb) -> bb.order(LE).asFloatBuffer().get(2), (bb, v) -> bb.order(LE).asFloatBuffer().put(2, v))
|
||||
},
|
||||
{"float/index/BE", new Accessor<>(42f,
|
||||
s -> MemoryAccess.getFloatAtIndex(s, 2, BE), (s, x) -> MemoryAccess.setFloatAtIndex(s, 2, BE, x),
|
||||
(bb) -> bb.order(BE).asFloatBuffer().get(2), (bb, v) -> bb.order(BE).asFloatBuffer().put(2, v))
|
||||
},
|
||||
{"double/index", new Accessor<>(42d,
|
||||
s -> MemoryAccess.getDoubleAtIndex(s, 2), (s, x) -> MemoryAccess.setDoubleAtIndex(s, 2, x),
|
||||
(bb) -> bb.order(NE).asDoubleBuffer().get(2), (bb, v) -> bb.order(NE).asDoubleBuffer().put(2, v))
|
||||
},
|
||||
{"double/index/LE", new Accessor<>(42d,
|
||||
s -> MemoryAccess.getDoubleAtIndex(s, 2, LE), (s, x) -> MemoryAccess.setDoubleAtIndex(s, 2, LE, x),
|
||||
(bb) -> bb.order(LE).asDoubleBuffer().get(2), (bb, v) -> bb.order(LE).asDoubleBuffer().put(2, v))
|
||||
},
|
||||
{"double/index/BE", new Accessor<>(42d,
|
||||
s -> MemoryAccess.getDoubleAtIndex(s, 2, BE), (s, x) -> MemoryAccess.setDoubleAtIndex(s, 2, BE, x),
|
||||
(bb) -> bb.order(BE).asDoubleBuffer().get(2), (bb, v) -> bb.order(BE).asDoubleBuffer().put(2, v))
|
||||
},
|
||||
|
||||
{ "address", new Accessor<>(MemoryAddress.ofLong(42),
|
||||
MemoryAccess::getAddress, MemoryAccess::setAddress,
|
||||
(bb) -> {
|
||||
ByteBuffer nb = bb.order(NE);
|
||||
long addr = MemoryLayouts.ADDRESS.byteSize() == 8 ?
|
||||
nb.getLong(0) : nb.getInt(0);
|
||||
return MemoryAddress.ofLong(addr);
|
||||
},
|
||||
(bb, v) -> {
|
||||
ByteBuffer nb = bb.order(NE);
|
||||
if (MemoryLayouts.ADDRESS.byteSize() == 8) {
|
||||
nb.putLong(0, v.toRawLongValue());
|
||||
} else {
|
||||
nb.putInt(0, (int)v.toRawLongValue());
|
||||
}
|
||||
})
|
||||
},
|
||||
{ "address/offset", new Accessor<>(MemoryAddress.ofLong(42),
|
||||
s -> MemoryAccess.getAddressAtOffset(s, 4), (s, x) -> MemoryAccess.setAddressAtOffset(s, 4, x),
|
||||
(bb) -> {
|
||||
ByteBuffer nb = bb.order(NE);
|
||||
long addr = MemoryLayouts.ADDRESS.byteSize() == 8 ?
|
||||
nb.getLong(4) : nb.getInt(4);
|
||||
return MemoryAddress.ofLong(addr);
|
||||
},
|
||||
(bb, v) -> {
|
||||
ByteBuffer nb = bb.order(NE);
|
||||
if (MemoryLayouts.ADDRESS.byteSize() == 8) {
|
||||
nb.putLong(4, v.toRawLongValue());
|
||||
} else {
|
||||
nb.putInt(4, (int)v.toRawLongValue());
|
||||
}
|
||||
})
|
||||
},
|
||||
{ "address/index", new Accessor<>(MemoryAddress.ofLong(42),
|
||||
s -> MemoryAccess.getAddressAtIndex(s, 2), (s, x) -> MemoryAccess.setAddressAtIndex(s, 2, x),
|
||||
(bb) -> {
|
||||
ByteBuffer nb = bb.order(NE);
|
||||
long addr = MemoryLayouts.ADDRESS.byteSize() == 8 ?
|
||||
nb.asLongBuffer().get(2) : nb.asIntBuffer().get(2);
|
||||
return MemoryAddress.ofLong(addr);
|
||||
},
|
||||
(bb, v) -> {
|
||||
ByteBuffer nb = bb.order(NE);
|
||||
if (MemoryLayouts.ADDRESS.byteSize() == 8) {
|
||||
nb.asLongBuffer().put(2, v.toRawLongValue());
|
||||
} else {
|
||||
nb.asIntBuffer().put(2, (int)v.toRawLongValue());
|
||||
}
|
||||
})
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
@ -169,12 +169,6 @@ public class TestMismatch {
|
||||
assertThrows(UOE, () -> s1WithoutRead.mismatch(s2WithoutRead));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testNull() {
|
||||
var segment = MemorySegment.ofArray(new byte[4]);
|
||||
segment.mismatch(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThreadAccess() throws Exception {
|
||||
var segment = MemorySegment.ofArray(new byte[4]);
|
||||
|
@ -27,17 +27,15 @@
|
||||
* @run testng/othervm TestNativeScope
|
||||
*/
|
||||
|
||||
import jdk.incubator.foreign.MemorySegment;
|
||||
import jdk.incubator.foreign.NativeScope;
|
||||
import jdk.incubator.foreign.MemoryHandles;
|
||||
import jdk.incubator.foreign.MemoryLayouts;
|
||||
import jdk.incubator.foreign.MemoryLayout;
|
||||
import jdk.incubator.foreign.MemoryAddress;
|
||||
import jdk.incubator.foreign.*;
|
||||
|
||||
import jdk.incubator.foreign.ValueLayout;
|
||||
import org.testng.annotations.*;
|
||||
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.DoubleBuffer;
|
||||
@ -46,9 +44,11 @@ import java.nio.IntBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.LongStream;
|
||||
|
||||
@ -166,11 +166,6 @@ public class TestNativeScope {
|
||||
s1.handoff(scope1).handoff(scope2);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testNullClaim() {
|
||||
MemorySegment.ofArray(new byte[5]).handoff((NativeScope)null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testNotAliveClaim() {
|
||||
MemorySegment segment = MemorySegment.ofArray(new byte[1]);
|
||||
|
257
test/jdk/java/foreign/TestNulls.java
Normal file
257
test/jdk/java/foreign/TestNulls.java
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @modules java.base/jdk.internal.ref
|
||||
* jdk.incubator.foreign
|
||||
* @run testng/othervm -Dforeign.restricted=permit TestNulls
|
||||
*/
|
||||
|
||||
import jdk.incubator.foreign.*;
|
||||
import jdk.internal.ref.CleanerFactory;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.NoInjection;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.lang.constant.Constable;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.lang.ref.Cleaner;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
import static org.testng.Assert.fail;
|
||||
|
||||
/**
|
||||
* This test makes sure that public API classes (listed in {@link TestNulls#CLASSES}) throws NPEs whenever
|
||||
* nulls are provided. The test looks at all the public methods in all the listed classes, and injects
|
||||
* values automatically. If an API takes a reference, the test will try to inject nulls. For APIs taking
|
||||
* either reference arrays, or collections, the framework will also generate additional <em>replacements</em>
|
||||
* (e.g. other than just replacing the array, or collection with null), such as an array or collection
|
||||
* with null elements. The test can be customized by adding/removing classes to the {@link #CLASSES} array,
|
||||
* by adding/removing default mappings for standard carrier types (see {@link #DEFAULT_VALUES} or by
|
||||
* adding/removing custom replacements (see {@link #REPLACEMENT_VALUES}).
|
||||
*/
|
||||
public class TestNulls {
|
||||
|
||||
static final Class<?>[] CLASSES = new Class<?>[] {
|
||||
MemorySegment.class,
|
||||
MemoryAddress.class,
|
||||
MemoryLayout.class,
|
||||
MemoryLayout.PathElement.class,
|
||||
SequenceLayout.class,
|
||||
ValueLayout.class,
|
||||
GroupLayout.class,
|
||||
Addressable.class,
|
||||
MemoryAccess.class,
|
||||
MappedMemorySegments.class,
|
||||
MemoryLayouts.class,
|
||||
MemoryHandles.class,
|
||||
NativeScope.class,
|
||||
CLinker.class,
|
||||
CLinker.VaList.class,
|
||||
CLinker.VaList.Builder.class,
|
||||
FunctionDescriptor.class,
|
||||
LibraryLookup.class
|
||||
};
|
||||
|
||||
static final Set<String> EXCLUDE_LIST = Set.of(
|
||||
"jdk.incubator.foreign.MemoryLayout/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0",
|
||||
"jdk.incubator.foreign.MemoryAddress/asSegmentRestricted(long,java.lang.Runnable,java.lang.Object)/1/0",
|
||||
"jdk.incubator.foreign.MemoryAddress/asSegmentRestricted(long,java.lang.Runnable,java.lang.Object)/2/0",
|
||||
"jdk.incubator.foreign.SequenceLayout/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0",
|
||||
"jdk.incubator.foreign.ValueLayout/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0",
|
||||
"jdk.incubator.foreign.GroupLayout/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0",
|
||||
"jdk.incubator.foreign.MemoryHandles/insertCoordinates(java.lang.invoke.VarHandle,int,java.lang.Object[])/2/1",
|
||||
"jdk.incubator.foreign.FunctionDescriptor/withAttribute(java.lang.String,java.lang.constant.Constable)/1/0"
|
||||
);
|
||||
|
||||
static final Set<String> OBJECT_METHODS = Stream.of(Object.class.getMethods())
|
||||
.map(Method::getName)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
static final Map<Class<?>, Object> DEFAULT_VALUES = new HashMap<>();
|
||||
|
||||
static <Z> void addDefaultMapping(Class<Z> carrier, Z value) {
|
||||
DEFAULT_VALUES.put(carrier, value);
|
||||
}
|
||||
|
||||
static {
|
||||
addDefaultMapping(char.class, (char)0);
|
||||
addDefaultMapping(byte.class, (byte)0);
|
||||
addDefaultMapping(short.class, (short)0);
|
||||
addDefaultMapping(int.class, 0);
|
||||
addDefaultMapping(float.class, 0f);
|
||||
addDefaultMapping(long.class, 0L);
|
||||
addDefaultMapping(double.class, 0d);
|
||||
addDefaultMapping(ByteOrder.class, ByteOrder.nativeOrder());
|
||||
addDefaultMapping(Thread.class, Thread.currentThread());
|
||||
addDefaultMapping(Cleaner.class, CleanerFactory.cleaner());
|
||||
addDefaultMapping(ByteBuffer.class, ByteBuffer.wrap(new byte[10]));
|
||||
addDefaultMapping(Path.class, Path.of("nonExistent"));
|
||||
addDefaultMapping(FileChannel.MapMode.class, FileChannel.MapMode.PRIVATE);
|
||||
addDefaultMapping(UnaryOperator.class, UnaryOperator.identity());
|
||||
addDefaultMapping(String.class, "Hello!");
|
||||
addDefaultMapping(Constable.class, "Hello!");
|
||||
addDefaultMapping(Class.class, String.class);
|
||||
addDefaultMapping(Runnable.class, () -> {});
|
||||
addDefaultMapping(Object.class, new Object());
|
||||
addDefaultMapping(VarHandle.class, MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder()));
|
||||
addDefaultMapping(MethodHandle.class, MethodHandles.identity(int.class));
|
||||
addDefaultMapping(List.class, List.of());
|
||||
addDefaultMapping(Charset.class, Charset.defaultCharset());
|
||||
addDefaultMapping(Consumer.class, x -> {});
|
||||
addDefaultMapping(MethodType.class, MethodType.methodType(void.class));
|
||||
addDefaultMapping(MemoryAddress.class, MemoryAddress.NULL);
|
||||
addDefaultMapping(Addressable.class, MemoryAddress.NULL);
|
||||
addDefaultMapping(MemoryLayout.class, MemoryLayouts.JAVA_INT);
|
||||
addDefaultMapping(ValueLayout.class, MemoryLayouts.JAVA_INT);
|
||||
addDefaultMapping(GroupLayout.class, MemoryLayout.ofStruct(MemoryLayouts.JAVA_INT));
|
||||
addDefaultMapping(SequenceLayout.class, MemoryLayout.ofSequence(MemoryLayouts.JAVA_INT));
|
||||
addDefaultMapping(MemorySegment.class, MemorySegment.ofArray(new byte[10]));
|
||||
addDefaultMapping(NativeScope.class, NativeScope.boundedScope(10));
|
||||
addDefaultMapping(FunctionDescriptor.class, FunctionDescriptor.ofVoid());
|
||||
addDefaultMapping(CLinker.class, CLinker.getInstance());
|
||||
addDefaultMapping(CLinker.VaList.class, VaListHelper.vaList);
|
||||
addDefaultMapping(CLinker.VaList.Builder.class, VaListHelper.vaListBuilder);
|
||||
addDefaultMapping(LibraryLookup.class, LibraryLookup.ofDefault());
|
||||
}
|
||||
|
||||
static class VaListHelper {
|
||||
static final CLinker.VaList vaList;
|
||||
static final CLinker.VaList.Builder vaListBuilder;
|
||||
|
||||
static {
|
||||
AtomicReference<CLinker.VaList.Builder> builderRef = new AtomicReference<>();
|
||||
vaList = CLinker.VaList.make(b -> {
|
||||
builderRef.set(b);
|
||||
b.vargFromLong(CLinker.C_LONG_LONG, 42L);
|
||||
});
|
||||
vaListBuilder = builderRef.get();
|
||||
}
|
||||
}
|
||||
|
||||
static final Map<Class<?>, Object[]> REPLACEMENT_VALUES = new HashMap<>();
|
||||
|
||||
@SafeVarargs
|
||||
static <Z> void addReplacements(Class<Z> carrier, Z... value) {
|
||||
REPLACEMENT_VALUES.put(carrier, value);
|
||||
}
|
||||
|
||||
static {
|
||||
addReplacements(Collection.class, null, Stream.of(new Object[] { null }).collect(Collectors.toList()));
|
||||
addReplacements(List.class, null, Stream.of(new Object[] { null }).collect(Collectors.toList()));
|
||||
addReplacements(Set.class, null, Stream.of(new Object[] { null }).collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "cases")
|
||||
public void testNulls(String testName, @NoInjection Method meth, Object receiver, Object[] args) {
|
||||
try {
|
||||
meth.invoke(receiver, args);
|
||||
fail("Method invocation completed normally");
|
||||
} catch (InvocationTargetException ex) {
|
||||
Class<?> cause = ex.getCause().getClass();
|
||||
assertEquals(cause, NullPointerException.class, "got " + cause.getName() + " - expected NullPointerException");
|
||||
} catch (Throwable ex) {
|
||||
fail("Unexpected exception: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
@DataProvider(name = "cases")
|
||||
static Iterator<Object[]> cases() {
|
||||
List<Object[]> cases = new ArrayList<>();
|
||||
for (Class<?> clazz : CLASSES) {
|
||||
for (Method m : clazz.getMethods()) {
|
||||
if (OBJECT_METHODS.contains(m.getName())) continue;
|
||||
boolean isStatic = (m.getModifiers() & Modifier.STATIC) != 0;
|
||||
List<Integer> refIndices = new ArrayList<>();
|
||||
for (int i = 0; i < m.getParameterCount(); i++) {
|
||||
Class<?> param = m.getParameterTypes()[i];
|
||||
if (!param.isPrimitive()) {
|
||||
refIndices.add(i);
|
||||
}
|
||||
}
|
||||
for (int i : refIndices) {
|
||||
Object[] replacements = replacements(m.getParameterTypes()[i]);
|
||||
for (int r = 0 ; r < replacements.length ; r++) {
|
||||
String testName = clazz.getName() + "/" + shortSig(m) + "/" + i + "/" + r;
|
||||
if (EXCLUDE_LIST.contains(testName)) continue;
|
||||
Object[] args = new Object[m.getParameterCount()];
|
||||
for (int j = 0; j < args.length; j++) {
|
||||
args[j] = defaultValue(m.getParameterTypes()[j]);
|
||||
}
|
||||
args[i] = replacements[r];
|
||||
Object receiver = isStatic ? null : defaultValue(clazz);
|
||||
cases.add(new Object[]{testName, m, receiver, args});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cases.iterator();
|
||||
};
|
||||
|
||||
static String shortSig(Method m) {
|
||||
StringJoiner sj = new StringJoiner(",", m.getName() + "(", ")");
|
||||
for (Class<?> parameterType : m.getParameterTypes()) {
|
||||
sj.add(parameterType.getTypeName());
|
||||
}
|
||||
return sj.toString();
|
||||
}
|
||||
|
||||
static Object defaultValue(Class<?> carrier) {
|
||||
if (carrier.isArray()) {
|
||||
return Array.newInstance(carrier.componentType(), 0);
|
||||
}
|
||||
Object value = DEFAULT_VALUES.get(carrier);
|
||||
if (value == null) {
|
||||
throw new UnsupportedOperationException(carrier.getName());
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static Object[] replacements(Class<?> carrier) {
|
||||
if (carrier.isArray() && !carrier.getComponentType().isPrimitive()) {
|
||||
Object arr = Array.newInstance(carrier.componentType(), 1);
|
||||
Array.set(arr, 0, null);
|
||||
return new Object[] { null, arr };
|
||||
}
|
||||
return REPLACEMENT_VALUES.getOrDefault(carrier, new Object[] { null });
|
||||
}
|
||||
}
|
@ -52,12 +52,6 @@ public class TestReshape {
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testNullReshape() {
|
||||
SequenceLayout seq = MemoryLayout.ofSequence(4, MemoryLayouts.JAVA_INT);
|
||||
seq.reshape(null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testInvalidReshape() {
|
||||
SequenceLayout seq = MemoryLayout.ofSequence(4, MemoryLayouts.JAVA_INT);
|
||||
|
@ -26,18 +26,23 @@
|
||||
* @run testng/othervm -XX:MaxDirectMemorySize=1M TestSegments
|
||||
*/
|
||||
|
||||
import jdk.incubator.foreign.MappedMemorySegments;
|
||||
import jdk.incubator.foreign.MemoryLayout;
|
||||
import jdk.incubator.foreign.MemoryLayouts;
|
||||
import jdk.incubator.foreign.MemorySegment;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
@ -46,6 +46,9 @@ import java.lang.invoke.MethodHandleProxies;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
@ -61,9 +64,7 @@ import static jdk.incubator.foreign.CLinker.C_VA_LIST;
|
||||
import static jdk.incubator.foreign.MemoryLayout.PathElement.groupElement;
|
||||
import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT;
|
||||
import static jdk.internal.foreign.PlatformLayouts.*;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class VaListTest {
|
||||
|
||||
@ -803,5 +804,4 @@ public class VaListTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user