diff --git a/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/InternalDowncallHandler.java b/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/InternalDowncallHandler.java
index 2b85c9ae2dc..722592dd13e 100644
--- a/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/InternalDowncallHandler.java
+++ b/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/InternalDowncallHandler.java
@@ -62,6 +62,9 @@
import java.lang.foreign.SegmentScope;
/*[ENDIF] JAVA_SPEC_VERSION >= 20 */
import java.lang.foreign.ValueLayout;
+/*[IF JAVA_SPEC_VERSION >= 20]*/
+import static java.lang.foreign.ValueLayout.*;
+/*[ENDIF] JAVA_SPEC_VERSION >= 20 */
import java.lang.foreign.VaList;
/*[IF JAVA_SPEC_VERSION >= 20]*/
import jdk.internal.foreign.Utils;
@@ -103,13 +106,6 @@ public class InternalDowncallHandler {
/*[IF JAVA_SPEC_VERSION == 16]*/
private Addressable functionAddr;
/*[ENDIF] JAVA_SPEC_VERSION == 16 */
- /*[IF JAVA_SPEC_VERSION >= 18]*/
- /*[IF JAVA_SPEC_VERSION <= 19]*/
- private static final Class> addrClass = Addressable.class;
- /*[ENDIF] JAVA_SPEC_VERSION <= 19 */
- /*[ELSE] JAVA_SPEC_VERSION >= 18 */
- private static final Class> addrClass = MemoryAddress.class;
- /*[ENDIF] JAVA_SPEC_VERSION >= 18 */
private long cifNativeThunkAddr;
private long argTypesAddr;
private MemoryLayout[] argLayoutArray;
@@ -145,9 +141,11 @@ public class InternalDowncallHandler {
private static final MethodHandle intToLongArgFilter;
private static final MethodHandle floatToLongArgFilter;
private static final MethodHandle doubleToLongArgFilter;
- /*[IF JAVA_SPEC_VERSION <= 19]*/
+ /*[IF JAVA_SPEC_VERSION >= 20]*/
+ private MethodHandle memSegmtOfPtrToLongArgFilter;
+ /*[ELSE] JAVA_SPEC_VERSION >= 20 */
private MethodHandle memAddrToLongArgFilter;
- /*[ENDIF] JAVA_SPEC_VERSION <= 19 */
+ /*[ENDIF] JAVA_SPEC_VERSION >= 20 */
private MethodHandle memSegmtToLongArgFilter;
/* Return value filters that convert the Long object to the primitive types/MemoryAddress/MemorySegment. */
@@ -292,13 +290,20 @@ private void validateMemScope(ResourceScope memScope) throws IllegalStateExcepti
}
/*[ENDIF] JAVA_SPEC_VERSION >= 17 */
- /*[IF JAVA_SPEC_VERSION <= 19]*/
+ /*[IF JAVA_SPEC_VERSION >= 20]*/
+ /* Intended for memSegmtOfPtrToLongArgFilter that converts the memory segment
+ * of the passed-in pointer argument to long.
+ */
+ private final long memSegmtOfPtrToLongArg(MemorySegment argValue) throws IllegalStateException {
+ addMemArgScope(argValue.scope());
+ return UpcallMHMetaData.getNativeArgRetSegmentOfPtr(argValue);
+ }
+ /*[ELSEIF JAVA_SPEC_VERSION >= 18] */
/* Intended for memAddrToLongArgFilter that converts the memory address to long.
* Note: the passed-in argument can be an instance of MemoryAddress, MemorySegment
* or VaList which extends Addressable in OpenJDK since Java 18 featured with
* JEP419 (Second Incubator).
*/
- /*[IF JAVA_SPEC_VERSION >= 18]*/
private final long memAddrToLongArg(Addressable argValue) throws IllegalStateException {
/* Only check MemorySegment and VaList given MemoryAddress.scope() doesn't exist in JDK17. */
if (argValue instanceof MemorySegment value) {
@@ -319,19 +324,33 @@ else if (argValue instanceof NativeSymbol value) {
addMemArgScope(value.scope());
}
/*[ENDIF] JAVA_SPEC_VERSION == 18 */
- return argValue.address().toRawLongValue();
+
+ /* Instead of assigning nativeAddr with argValue.address().toRawLongValue() by fefault,
+ * (which triggers the exception in the case of the on-heap segment in JDK19), the
+ * argument is validated at first in the case of MemorySegment/MemoryAddress.
+ */
+ long nativeAddr = 0;
+ if (argValue instanceof MemorySegment value) {
+ nativeAddr = UpcallMHMetaData.getNativeArgRetSegmentOfPtr(value);
+ } else if (argValue instanceof MemoryAddress value) {
+ nativeAddr = UpcallMHMetaData.getNativeArgRetAddrOfPtr(value);
+ } else {
+ nativeAddr = argValue.address().toRawLongValue();
+ }
+ return nativeAddr;
}
/*[ELSEIF JAVA_SPEC_VERSION == 17]*/
+ /* Intended for memAddrToLongArgFilter that converts the memory address to long. */
private final long memAddrToLongArg(MemoryAddress argValue) throws IllegalStateException {
addMemArgScope(argValue.scope());
- return argValue.address().toRawLongValue();
+ return UpcallMHMetaData.getNativeArgRetAddrOfPtr(argValue);
}
/*[ELSE] JAVA_SPEC_VERSION == 17 */
+ /* Intended for memAddrToLongArgFilter that converts the memory address to long. */
private static final long memAddrToLongArg(MemoryAddress argValue) {
return argValue.address().toRawLongValue();
}
- /*[ENDIF] JAVA_SPEC_VERSION >= 18 */
- /*[ENDIF] JAVA_SPEC_VERSION <= 19 */
+ /*[ENDIF] JAVA_SPEC_VERSION >= 20 */
/* Intended for memSegmtToLongArgFilter that converts the memory segment to long. */
private final long memSegmtToLongArg(MemorySegment argValue) throws IllegalStateException {
@@ -340,12 +359,7 @@ private final long memSegmtToLongArg(MemorySegment argValue) throws IllegalState
/*[ELSE] JAVA_SPEC_VERSION == 19 */
addMemArgScope(argValue.scope());
/*[ENDIF] JAVA_SPEC_VERSION == 19 */
-
- /*[IF JAVA_SPEC_VERSION >= 20]*/
- return argValue.address();
- /*[ELSE] JAVA_SPEC_VERSION >= 20 */
- return argValue.address().toRawLongValue();
- /*[ENDIF] JAVA_SPEC_VERSION >= 20 */
+ return UpcallMHMetaData.getNativeArgRetSegment(argValue);
}
/* Intended for longObjToVoidRetFilter that converts the Long object to void. */
@@ -500,9 +514,13 @@ public InternalDowncallHandler(Addressable downcallAddr, MethodType functionMeth
try {
/*[IF JAVA_SPEC_VERSION >= 20]*/
longObjToMemSegmtRetFilter = lookup.bind(this, "longObjToMemSegmtRet", methodType(MemorySegment.class, Object.class)); //$NON-NLS-1$
- /*[ELSE] JAVA_SPEC_VERSION >= 20 */
- memAddrToLongArgFilter = lookup.bind(this, "memAddrToLongArg", methodType(long.class, addrClass)); //$NON-NLS-1$
+ memSegmtOfPtrToLongArgFilter = lookup.bind(this, "memSegmtOfPtrToLongArg", methodType(long.class, MemorySegment.class)); //$NON-NLS-1$
+ /*[ELSEIF JAVA_SPEC_VERSION >= 18]*/
+ memAddrToLongArgFilter = lookup.bind(this, "memAddrToLongArg", methodType(long.class, Addressable.class)); //$NON-NLS-1$
+ /*[ELSE] JAVA_SPEC_VERSION >= 18 */
+ memAddrToLongArgFilter = lookup.bind(this, "memAddrToLongArg", methodType(long.class, MemoryAddress.class)); //$NON-NLS-1$
/*[ENDIF] JAVA_SPEC_VERSION >= 20 */
+
memSegmtToLongArgFilter = lookup.bind(this, "memSegmtToLongArg", methodType(long.class, MemorySegment.class)); //$NON-NLS-1$
} catch (ReflectiveOperationException e) {
throw new InternalError(e);
@@ -635,7 +653,7 @@ private MethodHandle permuteMH(MethodHandle targetHandle, MethodType nativeMetho
/* Convert the argument values to long via filterArguments() prior to the native call. */
MethodHandle[] argFilters = new MethodHandle[nativeArgCount];
for (int argIndex = 0; argIndex < nativeArgCount; argIndex++) {
- argFilters[argIndex] = getArgumentFilter(argTypeClasses[argIndex]);
+ argFilters[argIndex] = getArgumentFilter(argTypeClasses[argIndex], argLayoutArray[argIndex]);
}
resultHandle = filterArguments(resultHandle, argPosition, argFilters);
@@ -655,7 +673,7 @@ private MethodHandle permuteMH(MethodHandle targetHandle, MethodType nativeMetho
}
/* Obtain the filter that converts the passed-in argument to long against its type. */
- private MethodHandle getArgumentFilter(Class> argTypeClass) {
+ private MethodHandle getArgumentFilter(Class> argTypeClass, MemoryLayout argLayout) {
/* Set the filter to null in the case of long by default as there is no conversion for long. */
MethodHandle filterMH = null;
@@ -684,7 +702,15 @@ private MethodHandle getArgumentFilter(Class> argTypeClass) {
} else
/*[ENDIF] JAVA_SPEC_VERSION <= 19 */
if (argTypeClass == MemorySegment.class) {
- filterMH = memSegmtToLongArgFilter;
+ /*[IF JAVA_SPEC_VERSION >= 20]*/
+ /* The address layout for pointer might come with different representations of ADDRESS. */
+ if (argLayout instanceof OfAddress) {
+ filterMH = memSegmtOfPtrToLongArgFilter;
+ } else
+ /*[ENDIF] JAVA_SPEC_VERSION >= 20 */
+ {
+ filterMH = memSegmtToLongArgFilter;
+ }
}
return filterMH;
diff --git a/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/UpcallMHMetaData.java b/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/UpcallMHMetaData.java
index 5134af34323..0a25cc71a2c 100644
--- a/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/UpcallMHMetaData.java
+++ b/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/UpcallMHMetaData.java
@@ -27,11 +27,18 @@
/*[IF JAVA_SPEC_VERSION >= 20]*/
import java.lang.foreign.Arena;
+import java.lang.foreign.MemorySegment;
import java.lang.foreign.SegmentScope;
import jdk.internal.foreign.MemorySessionImpl;
/*[ELSEIF JAVA_SPEC_VERSION == 19]*/
+import java.lang.foreign.Addressable;
+import java.lang.foreign.MemoryAddress;
+import java.lang.foreign.MemorySegment;
import java.lang.foreign.MemorySession;
/*[ELSE] JAVA_SPEC_VERSION == 19 */
+import jdk.incubator.foreign.Addressable;
+import jdk.incubator.foreign.MemoryAddress;
+import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.ResourceScope;
/*[ENDIF] JAVA_SPEC_VERSION >= 20 */
@@ -54,7 +61,7 @@ final class UpcallMHMetaData {
* by MethodHandleResolver.upcallLinkCallerMethod().
*/
private Object[] invokeCache;
- /* The argument array stores the memory specific argument(struct/pointer) object
+ /* The argument array stores the memory specific argument (struct/pointer) object
* being allocated in native for upcall to stop GC from updating the previously
* allocated argument reference when allocating the next argument.
*/
@@ -68,14 +75,14 @@ final class UpcallMHMetaData {
private ResourceScope scope;
/*[ENDIF] JAVA_SPEC_VERSION >= 20 */
- private static synchronized native void resolveUpcallDataFields();
+ private static synchronized native void resolveUpcallDataInfo();
static {
- /* Resolve the fields (offset in the JCL constant pool of VM) specific to the metadata plus the fields
- * of MemoryAddressImpl and NativeMemorySegmentImpl given the generated macros from vmconstantpool.xml
- * depend on their offsets to access the corresponding fields in the process of the upcall.
+ /* Resolve the methods/fields (offset in the JCL constant pool of VM) related to the metadata
+ * given the generated macros from vmconstantpool.xml depend on their offsets to access the
+ * corresponding methods/fields in the process of the upcall.
*/
- resolveUpcallDataFields();
+ resolveUpcallDataInfo();
}
/*[IF JAVA_SPEC_VERSION >= 20]*/
@@ -101,4 +108,82 @@ final class UpcallMHMetaData {
this.scope = ((scope != null) && (scope.ownerThread() != null)) ? scope : ResourceScope.newSharedScope();
/*[ENDIF] JAVA_SPEC_VERSION >= 20 */
}
+
+ /* Determine whether the memory segment of the passed-in/returned pointer is allocated
+ * in the native memory or not and return its native address if valid.
+ *
+ * Note:
+ * The method is shared in java (downcall) and in native (upcall) via the calling-in from the dispatcher.
+ */
+ static long getNativeArgRetSegmentOfPtr(MemorySegment argRetSegmentOfPtr) {
+ if (!argRetSegmentOfPtr.isNative()) {
+ throw new IllegalArgumentException("Heap segment not allowed: " + argRetSegmentOfPtr);
+ }
+
+ /*[IF JAVA_SPEC_VERSION >= 20]*/
+ return argRetSegmentOfPtr.address();
+ /*[ELSE] JAVA_SPEC_VERSION >= 20 */
+ return argRetSegmentOfPtr.address().toRawLongValue();
+ /*[ENDIF] JAVA_SPEC_VERSION >= 20 */
+ }
+
+ /*[IF JAVA_SPEC_VERSION <= 19]*/
+ /* Determine whether the memory address of the passed-in/returned pointer is allocated
+ * in the native memory or not and return its native address if valid.
+ *
+ * Note:
+ * The method is shared in java (downcall) and in native (upcall) via the calling-in from the dispatcher.
+ */
+ static long getNativeArgRetAddrOfPtr(MemoryAddress argRetAddrOfPtr) {
+ /*[IF JAVA_SPEC_VERSION > 17]*/
+ /* Validate the native address as MemoryAddress.isNative() is removed in JDK18/19. */
+ if (argRetAddrOfPtr.toRawLongValue() == 0)
+ /*[ELSE] JAVA_SPEC_VERSION > 17 */
+ if (!argRetAddrOfPtr.isNative())
+ /*[ENDIF] JAVA_SPEC_VERSION > 17 */
+ {
+ throw new IllegalArgumentException("A heap address is not allowed: " + argRetAddrOfPtr);
+ }
+
+ return argRetAddrOfPtr.toRawLongValue();
+ }
+ /*[ENDIF] JAVA_SPEC_VERSION <= 19 */
+
+ /* Determine whether the passed-in/returned segment is allocated in the native memory or not
+ * and return its native address if valid; otherwise, return the address of an newly allocated
+ * native segment with all values copied from the heap segment.
+ *
+ * Note:
+ * The method is shared in java (downcall) and in native (upcall) via the calling-in from the dispatcher.
+ */
+ static long getNativeArgRetSegment(MemorySegment argRetSegment) {
+ /*[IF JAVA_SPEC_VERSION >= 20]*/
+ /* MemorySegment.NULL is introduced since JDK20+. */
+ if (argRetSegment == MemorySegment.NULL) {
+ throw new NullPointerException("A NULL memory segment is not allowed for struct.");
+ }
+ /*[ENDIF] JAVA_SPEC_VERSION >= 20 */
+ MemorySegment nativeSegment = argRetSegment;
+
+ /* Copy all values in the heap segment to a newly allocated native segment
+ * given a heap segment with a zero address can't be accessed in native.
+ */
+ if (!argRetSegment.isNative()) {
+ /*[IF JAVA_SPEC_VERSION >= 20]*/
+ SegmentScope scope = SegmentScope.global();
+ /*[ELSEIF JAVA_SPEC_VERSION == 19]*/
+ MemorySession scope = MemorySession.global();
+ /*[ELSE] JAVA_SPEC_VERSION == 19 */
+ ResourceScope scope = ResourceScope.globalScope();
+ /*[ENDIF] JAVA_SPEC_VERSION >= 20 */
+ nativeSegment = MemorySegment.allocateNative(argRetSegment.byteSize(), scope);
+ nativeSegment.copyFrom(argRetSegment);
+ }
+
+ /*[IF JAVA_SPEC_VERSION >= 20]*/
+ return nativeSegment.address();
+ /*[ELSE] JAVA_SPEC_VERSION >= 20 */
+ return nativeSegment.address().toRawLongValue();
+ /*[ENDIF] JAVA_SPEC_VERSION >= 20 */
+ }
}
diff --git a/runtime/oti/vmconstantpool.xml b/runtime/oti/vmconstantpool.xml
index 6fc61ea5c15..a042da92770 100644
--- a/runtime/oti/vmconstantpool.xml
+++ b/runtime/oti/vmconstantpool.xml
@@ -481,6 +481,11 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-excepti
+
+
+
+
+
diff --git a/runtime/tests/clinkerffi/CMakeLists.txt b/runtime/tests/clinkerffi/CMakeLists.txt
index 0e13a80cc83..5fc0fda47a0 100644
--- a/runtime/tests/clinkerffi/CMakeLists.txt
+++ b/runtime/tests/clinkerffi/CMakeLists.txt
@@ -164,6 +164,7 @@ omr_add_exports(clinkerffitests
add2DoubleStructs_returnStruct
add2DoubleStructs_returnStructPointer
add3DoubleStructs_returnStruct
+ validateNullAddrArgument
add2BoolsWithOrByUpcallMH
addBoolAndBoolFromPointerWithOrByUpcallMH
addBoolAndBoolFromNativePtrWithOrByUpcallMH
@@ -341,6 +342,7 @@ omr_add_exports(clinkerffitests
addDoubleAndIntDoubleLongFromStructByUpcallMH
return254BytesFromStructByUpcallMH
return4KBytesFromStructByUpcallMH
+ validateReturnNullAddrByUpcallMH
addIntsFromVaList
addLongsFromVaList
addDoublesFromVaList
diff --git a/runtime/tests/clinkerffi/downcall.c b/runtime/tests/clinkerffi/downcall.c
index 3aee647b14f..b18606de239 100644
--- a/runtime/tests/clinkerffi/downcall.c
+++ b/runtime/tests/clinkerffi/downcall.c
@@ -1990,3 +1990,20 @@ add3DoubleStructs_returnStruct(stru_Double_Double_Double arg1, stru_Double_Doubl
doubleStruct.elem3 = arg1.elem3 + arg2.elem3;
return doubleStruct;
}
+
+/**
+ * Validate that a null pointer of struct is successfully passed
+ * from java to native in downcall.
+ *
+ * @param arg1 an integer
+ * @param arg2 a pointer to struct with two integers
+ * @return the value of arg1
+ *
+ * Note:
+ * arg2 is a null pointer passed from java to native.
+ */
+int
+validateNullAddrArgument(int arg1, stru_Int_Int *arg2)
+{
+ return arg1;
+}
diff --git a/runtime/tests/clinkerffi/module.xml b/runtime/tests/clinkerffi/module.xml
index d3d35d82473..ddfa45466e3 100644
--- a/runtime/tests/clinkerffi/module.xml
+++ b/runtime/tests/clinkerffi/module.xml
@@ -155,6 +155,7 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-excepti
+
@@ -332,6 +333,7 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-excepti
+
diff --git a/runtime/tests/clinkerffi/upcall.c b/runtime/tests/clinkerffi/upcall.c
index 8ad23fc7d95..007d630c126 100644
--- a/runtime/tests/clinkerffi/upcall.c
+++ b/runtime/tests/clinkerffi/upcall.c
@@ -2847,3 +2847,22 @@ return4KBytesFromStructByUpcallMH(stru_4K_Bytes (*upcallMH)())
{
return (*upcallMH)();
}
+
+/**
+ * Validate that a null pointer is successfully returned
+ * from the upcall method to native.
+ *
+ * @param arg1 a pointer to the 1st struct with two ints
+ * @param arg2 the 2nd struct with two ints
+ * @param upcallMH the function pointer to the upcall method
+ * @return a pointer to struct with two ints (arg1)
+ *
+ * Note:
+ * A null pointer is returned from upcallMH().
+ */
+stru_Int_Int *
+validateReturnNullAddrByUpcallMH(stru_Int_Int *arg1, stru_Int_Int arg2, stru_Int_Int * (*upcallMH)(stru_Int_Int *, stru_Int_Int))
+{
+ (*upcallMH)(arg1, arg2);
+ return arg1;
+}
diff --git a/runtime/vm/OutOfLineINL.hpp b/runtime/vm/OutOfLineINL.hpp
index d8ef6e3d204..db78344b685 100644
--- a/runtime/vm/OutOfLineINL.hpp
+++ b/runtime/vm/OutOfLineINL.hpp
@@ -47,7 +47,7 @@ J9OutOfLineINLMethod OutOfLineINL_java_lang_invoke_NativeMethodHandle_freeJ9Nati
J9OutOfLineINLMethod OutOfLineINL_openj9_internal_foreign_abi_InternalDowncallHandler_resolveRequiredFields;
J9OutOfLineINLMethod OutOfLineINL_openj9_internal_foreign_abi_InternalDowncallHandler_initCifNativeThunkData;
J9OutOfLineINLMethod OutOfLineINL_openj9_internal_foreign_abi_InternalUpcallHandler_allocateUpcallStub;
-J9OutOfLineINLMethod OutOfLineINL_openj9_internal_foreign_abi_UpcallMHMetaData_resolveUpcallDataFields;
+J9OutOfLineINLMethod OutOfLineINL_openj9_internal_foreign_abi_UpcallMHMetaData_resolveUpcallDataInfo;
#endif /* JAVA_SPEC_VERSION >= 16 */
}
diff --git a/runtime/vm/OutOfLineINL_openj9_internal_foreign_abi_UpCallMHMetaData.cpp b/runtime/vm/OutOfLineINL_openj9_internal_foreign_abi_UpCallMHMetaData.cpp
index 6994f717f98..2d6a1744c20 100644
--- a/runtime/vm/OutOfLineINL_openj9_internal_foreign_abi_UpCallMHMetaData.cpp
+++ b/runtime/vm/OutOfLineINL_openj9_internal_foreign_abi_UpCallMHMetaData.cpp
@@ -31,21 +31,29 @@
extern "C" {
#if JAVA_SPEC_VERSION >= 16
-/* openj9.internal.foreign.abi.UpcallMHMetaData: private static synchronized native void resolveUpcallDataFields(); */
+/* openj9.internal.foreign.abi.UpcallMHMetaData: private static synchronized native void resolveUpcallDataInfo(); */
VM_BytecodeAction
-OutOfLineINL_openj9_internal_foreign_abi_UpcallMHMetaData_resolveUpcallDataFields(J9VMThread *currentThread, J9Method *method)
+OutOfLineINL_openj9_internal_foreign_abi_UpcallMHMetaData_resolveUpcallDataInfo(J9VMThread *currentThread, J9Method *method)
{
VM_BytecodeAction rc = EXECUTE_BYTECODE;
J9JavaVM *vm = currentThread->javaVM;
J9ConstantPool *jclConstantPool = (J9ConstantPool *)vm->jclConstantPool;
+ J9ROMClass * jclROMClass = jclConstantPool->ramClass->romClass;
+ U_32 * cpShapeDescription = J9ROMCLASS_CPSHAPEDESCRIPTION(jclROMClass);
#if JAVA_SPEC_VERSION >= 20
- const int cpEntryNum = 8;
+ const int cpEntryNum = 10;
#elif JAVA_SPEC_VERSION >= 18 /* JAVA_SPEC_VERSION >= 20 */
- const int cpEntryNum = 9;
+ const int cpEntryNum = 11;
#else /* JAVA_SPEC_VERSION >= 18 */
- const int cpEntryNum = 10;
+ const int cpEntryNum = 12;
#endif /* JAVA_SPEC_VERSION >= 20 */
U_16 cpIndex[cpEntryNum] = {
+#if JAVA_SPEC_VERSION >= 20
+ J9VMCONSTANTPOOL_OPENJ9INTERNALFOREIGNABIUPCALLMHMETADATA_GETNATIVEARGRETSEGMENTOFPTR,
+#else /* JAVA_SPEC_VERSION >= 20 */
+ J9VMCONSTANTPOOL_OPENJ9INTERNALFOREIGNABIUPCALLMHMETADATA_GETNATIVEARGRETADDROFPTR,
+#endif /* JAVA_SPEC_VERSION >= 20 */
+ J9VMCONSTANTPOOL_OPENJ9INTERNALFOREIGNABIUPCALLMHMETADATA_GETNATIVEARGRETSEGMENT,
J9VMCONSTANTPOOL_OPENJ9INTERNALFOREIGNABIUPCALLMHMETADATA_CALLEEMH,
J9VMCONSTANTPOOL_OPENJ9INTERNALFOREIGNABIUPCALLMHMETADATA_CALLEETYPE,
J9VMCONSTANTPOOL_OPENJ9INTERNALFOREIGNABIUPCALLMHMETADATA_INVOKECACHE,
@@ -72,18 +80,28 @@ OutOfLineINL_openj9_internal_foreign_abi_UpcallMHMetaData_resolveUpcallDataField
VM_OutOfLineINL_Helpers::buildInternalNativeStackFrame(currentThread, method);
for (int i = 0; i < cpEntryNum; i++) {
- J9RAMFieldRef *cpFieldRef = ((J9RAMFieldRef*)jclConstantPool) + cpIndex[i];
- UDATA const flags = cpFieldRef->flags;
- UDATA const valueOffset = cpFieldRef->valueOffset;
+ UDATA offset = cpIndex[i];
+ UDATA cpType = J9_CP_TYPE(cpShapeDescription, offset);
+ UDATA resolveFlags = J9_RESOLVE_FLAG_NO_THROW_ON_FAIL | J9_RESOLVE_FLAG_JCL_CONSTANT_POOL;
- if (!VM_VMHelpers::instanceFieldRefIsResolved(flags, valueOffset)) {
- resolveInstanceFieldRef(currentThread, NULL, jclConstantPool, cpIndex[i], J9_RESOLVE_FLAG_NO_THROW_ON_FAIL | J9_RESOLVE_FLAG_JCL_CONSTANT_POOL, NULL);
- if (VM_VMHelpers::exceptionPending(currentThread)) {
- rc = GOTO_THROW_CURRENT_EXCEPTION;
- goto done;
+ if (J9CPTYPE_STATIC_METHOD == cpType) {
+ resolveStaticMethodRef(currentThread, jclConstantPool, offset, resolveFlags);
+ } else if (J9CPTYPE_FIELD == cpType) {
+ J9RAMFieldRef *cpFieldRef = ((J9RAMFieldRef*)jclConstantPool) + offset;
+ UDATA const flags = cpFieldRef->flags;
+ UDATA const valueOffset = cpFieldRef->valueOffset;
+
+ if (!VM_VMHelpers::instanceFieldRefIsResolved(flags, valueOffset)) {
+ resolveInstanceFieldRef(currentThread, NULL, jclConstantPool, offset, resolveFlags, NULL);
}
}
+
+ if (VM_VMHelpers::exceptionPending(currentThread)) {
+ rc = GOTO_THROW_CURRENT_EXCEPTION;
+ goto done;
+ }
}
+
VM_OutOfLineINL_Helpers::restoreInternalNativeStackFrame(currentThread);
done:
diff --git a/runtime/vm/UpcallVMHelpers.cpp b/runtime/vm/UpcallVMHelpers.cpp
index 88a25c4d80d..1fd15591e88 100644
--- a/runtime/vm/UpcallVMHelpers.cpp
+++ b/runtime/vm/UpcallVMHelpers.cpp
@@ -44,12 +44,12 @@ static U_64 JNICALL native2InterpJavaUpcallImpl(J9UpcallMetaData *data, void *ar
static J9VMThread * getCurrentThread(J9UpcallMetaData *data, bool *isCurThrdAllocated);
static void convertUpcallReturnValue(J9UpcallMetaData *data, U_8 returnType, U_64 *returnStorage);
static bool storeMemArgObjectsToJavaArray(J9UpcallMetaData *data, void *argsListPointer, J9VMThread *currentThread);
-static j9object_t createMemSegmentObject(J9UpcallMetaData *data, I_64 offset, U_32 sigTypeSize);
-static I_64 getNativeAddrFromMemSegmentObject(J9UpcallMetaData *data, j9object_t memSegmtObject);
+static j9object_t createMemSegmentObject(J9UpcallMetaData *data, I_64 offset, I_64 sigTypeSize);
#if JAVA_SPEC_VERSION <= 19
static j9object_t createMemAddressObject(J9UpcallMetaData *data, I_64 offset);
-static I_64 getNativeAddrFromMemAddressObject(J9UpcallMetaData *data, j9object_t memAddrObject);
#endif /* JAVA_SPEC_VERSION <= 19 */
+static bool validateNonNullRetMemObject(J9UpcallMetaData *data, j9object_t retMemObject);
+static U_64 performCallInForRetMemObject(J9UpcallMetaData *data, j9object_t memObject, UDATA callInMethod);
/**
* @brief Call into the interpreter via native2InterpJavaUpcallImpl to invoke the upcall
@@ -231,7 +231,7 @@ getInternalTypeFromSignature(J9JavaVM *vm, J9Class *typeClass, U_8 sigType)
*
* Note:
* The argument normalization is only intended for the type less then 4 bytes
- * in java, which include boolean(1 byte), byte, char(2 bytes), short.
+ * in java, which include boolean (1 byte), byte, char (2 bytes), short.
*/
static U_32
getNormalizedArgValue(U_8 argType, I_32 argValue)
@@ -351,8 +351,8 @@ native2InterpJavaUpcallImpl(J9UpcallMetaData *data, void *argsListPointer)
*/
I_64 argValue = *(I_64*)getArgPointer(nativeSig, argsListPointer, argIndex);
#if !defined(J9VM_ENV_LITTLE_ENDIAN)
- /* Right shift the 64-bit float argument by 4 bytes(32 bits) given the actual value
- * is placed on the higher 4 bytes on the Big-Endian(BE) platforms.
+ /* Right shift the 64-bit float argument by 4 bytes (32 bits) given the actual value
+ * is placed on the higher 4 bytes on the Big-Endian (BE) platforms.
*/
if (J9_FFI_UPCALL_SIG_TYPE_FLOAT == argSigType) {
argValue = argValue >> J9_FFI_UPCALL_SIG_TYPE_32_BIT;
@@ -489,11 +489,14 @@ getCurrentThread(J9UpcallMetaData *data, bool *isCurThrdAllocated)
}
/**
- * @brief Converts the type of the return value to the return type intended for JEP389/419 upcall.
+ * @brief Converts the type of the return value to the return type intended for upcall.
*
* @param data a pointer to J9UpcallMetaData
* @param returnType the type for the return value
* @param returnStorage a pointer to the return value
+ *
+ * Note:
+ * The VMAccess is required for the caller to do the exception check on struct/pointer.
*/
static void
convertUpcallReturnValue(J9UpcallMetaData *data, U_8 returnType, U_64 *returnStorage)
@@ -507,28 +510,43 @@ convertUpcallReturnValue(J9UpcallMetaData *data, U_8 returnType, U_64 *returnSto
case J9NtcFloat:
{
#if !defined(J9VM_ENV_LITTLE_ENDIAN)
- /* Right shift the returned value from the upcall method by 4 bytes(32 bits) for the signature type
+ /* Right shift the returned value from the upcall method by 4 bytes (32 bits) for the signature type
* less than or equal to 4 bytes in size given the actual value is placed on the higher 4 bytes
- * on the Big-Endian(BE) platforms.
+ * on the Big-Endian (BE) platforms.
*/
*returnStorage = *returnStorage >> J9_FFI_UPCALL_SIG_TYPE_32_BIT;
#endif /* !defined(J9VM_ENV_LITTLE_ENDIAN) */
break;
}
-#if JAVA_SPEC_VERSION <= 19
case J9NtcPointer:
{
- j9object_t memAddrObject = (j9object_t)*returnStorage;
- *returnStorage = (U_64)getNativeAddrFromMemAddressObject(data, memAddrObject);
+ j9object_t retMemObject = (j9object_t)*returnStorage;
+ if (validateNonNullRetMemObject(data, retMemObject)) {
+ /* Get the native address from the returned MemorySegment(JDK20+)/MemoryAddress(JDK17/19) object
+ * by performing a call-in so as to capture the exception for the heap address.
+ */
+#if JAVA_SPEC_VERSION >= 20
+ *returnStorage = performCallInForRetMemObject(data, retMemObject,
+ (UDATA)J9VMOPENJ9INTERNALFOREIGNABIUPCALLMHMETADATA_GETNATIVEARGRETSEGMENTOFPTR_METHOD(data->vm));
+#else /* JAVA_SPEC_VERSION >= 20 */
+ *returnStorage = performCallInForRetMemObject(data, retMemObject,
+ (UDATA)J9VMOPENJ9INTERNALFOREIGNABIUPCALLMHMETADATA_GETNATIVEARGRETADDROFPTR_METHOD(data->vm));
+#endif /* JAVA_SPEC_VERSION >= 20 */
+ }
break;
}
-#else /* JAVA_SPEC_VERSION <= 19 */
- case J9NtcPointer: /* Fall through */
-#endif /* JAVA_SPEC_VERSION <= 19 */
case J9NtcStruct:
{
j9object_t memSegmtObject = (j9object_t)*returnStorage;
- *returnStorage = (U_64)getNativeAddrFromMemSegmentObject(data, memSegmtObject);
+ if (validateNonNullRetMemObject(data, memSegmtObject)) {
+ /* Get the native address from the returned MemorySegment object for struct by performing a call-in.
+ * Note:
+ * A heap segment must be converted to a native segment in java to guarantee that all values
+ * of the segment are safely accessed in native.
+ */
+ *returnStorage = performCallInForRetMemObject(data, memSegmtObject,
+ (UDATA)J9VMOPENJ9INTERNALFOREIGNABIUPCALLMHMETADATA_GETNATIVEARGRETSEGMENT_METHOD(data->vm));
+ }
break;
}
default: /* J9NtcVoid */
@@ -568,7 +586,7 @@ storeMemArgObjectsToJavaArray(J9UpcallMetaData *data, void *argsListPointer, J9V
/* A pointer argument is wrapped as an unbounded memory segment in upcall
* to pass the access check on the boundary as specified in JDK20+.
*/
- memArgObject = createMemSegmentObject(data, offset, (U_32)LONG_MAX);
+ memArgObject = createMemSegmentObject(data, offset, LONG_MAX);
#else /* JAVA_SPEC_VERSION => 20 */
memArgObject = createMemAddressObject(data, offset);
#endif /* JAVA_SPEC_VERSION => 20 */
@@ -587,7 +605,7 @@ storeMemArgObjectsToJavaArray(J9UpcallMetaData *data, void *argsListPointer, J9V
}
/* Store the struct/pointer object (or null in the case of the primitive types) in the
- * java array so as to avoid being updated by GC(which is triggered by J9AllocateObject
+ * java array so as to avoid being updated by GC (which is triggered by J9AllocateObject
* in createMemAddressObject/createMemSegmentObject) when allocating memory for the next
* struct/pointer of the argument list.
*/
@@ -620,7 +638,7 @@ createMemAddressObject(J9UpcallMetaData *data, I_64 offset)
j9object_t memAddrObject = NULL;
/* To wrap up an object of the MemoryAddress's subclass as an argument on the java stack,
- * this object is directly allocated on the heap with the passed-in native address(offset)
+ * this object is directly allocated on the heap with the passed-in native address (offset)
* set to this object.
*/
memAddrObject = objectAllocate.inlineAllocateObject(currentThread, memAddrClass, true, false);
@@ -649,15 +667,15 @@ createMemAddressObject(J9UpcallMetaData *data, I_64 offset)
/**
* @brief Generate an object of the MemorySegment's subclass on the heap with the specified
- * native address to the requested struct or the unbounded pointer(JDK20+).
+ * native address to the requested struct or the unbounded pointer (JDK20+).
*
* @param data a pointer to J9UpcallMetaData
- * @param offset the native address to the requested struct or the unbounded pointer(JDK20+)
- * @param sigTypeSize the byte size of the requested struct or the unbounded pointer(JDK20+)
+ * @param offset the native address to the requested struct or the unbounded pointer (JDK20+)
+ * @param sigTypeSize the byte size of the requested struct or the unbounded pointer (JDK20+)
* @return a MemorySegment object
*/
static j9object_t
-createMemSegmentObject(J9UpcallMetaData *data, I_64 offset, U_32 sigTypeSize)
+createMemSegmentObject(J9UpcallMetaData *data, I_64 offset, I_64 sigTypeSize)
{
J9JavaVM *vm = data->vm;
J9VMThread *downCallThread = data->downCallThread;
@@ -668,7 +686,7 @@ createMemSegmentObject(J9UpcallMetaData *data, I_64 offset, U_32 sigTypeSize)
J9Class *memSegmtClass = J9VMJDKINTERNALFOREIGNNATIVEMEMORYSEGMENTIMPL(vm);
/* To wrap up an object of the MemorySegment's subclass as an argument on the java stack,
- * this object is directly allocated on the heap with the passed-in native address(offset)
+ * this object is directly allocated on the heap with the passed-in native address (offset)
* set to this object.
*/
memSegmtObject = objectAllocate.inlineAllocateObject(currentThread, memSegmtClass, true, false);
@@ -700,58 +718,78 @@ createMemSegmentObject(J9UpcallMetaData *data, I_64 offset, U_32 sigTypeSize)
return memSegmtObject;
}
-#if JAVA_SPEC_VERSION <= 19
/**
- * @brief Get the native address to the requested value from a MemoryAddress object.
+ * @brief Validate whether the returned memory object is null or not.
*
* @param data a pointer to J9UpcallMetaData
- * @param memAddrObject the specified MemoryAddress object
- * @return the native address to the value in the memory
- *
- * Note:
- * There are two cases for the calculation of the native memory address (offset) as follows:
- * 1) if the offset is generated via createMemAddressObject() in native and passed over into java,
- * then the offset is the requested native address value;
- * 2) MemorySegment.address() is invoked upon return in java, which means:
- * Java 17: address = segment.min() as specified in MemoryAddressImpl (offset is set to zero)
- * Java 18: address = offset which is indirectly set by segment.min() via NativeMemorySegmentImpl.address()
+ * @param retMemObject the returned memory object
+ * @return true in the case of the non-null object; otherwise, return false
*/
-static I_64
-getNativeAddrFromMemAddressObject(J9UpcallMetaData *data, j9object_t memAddrObject)
+static bool
+validateNonNullRetMemObject(J9UpcallMetaData *data, j9object_t retMemObject)
{
- J9VMThread *currentThread = currentVMThread(data->vm);
- I_64 offset = J9VMJDKINTERNALFOREIGNMEMORYADDRESSIMPL_OFFSET(currentThread, memAddrObject);
- I_64 nativePtrValue = offset;
-#if JAVA_SPEC_VERSION <= 17
- j9object_t segmtObject = J9VMJDKINTERNALFOREIGNMEMORYADDRESSIMPL_SEGMENT(currentThread, memAddrObject);
- /* The offset is set to zero in AbstractMemorySegmentImpl.address() in OpenJDK. */
- if (NULL != segmtObject) {
- nativePtrValue = J9VMJDKINTERNALFOREIGNNATIVEMEMORYSEGMENTIMPL_MIN(currentThread, segmtObject);
+ J9JavaVM *vm = data->vm;
+ J9VMThread *downCallThread = data->downCallThread;
+ J9VMThread *currentThread = currentVMThread(vm);
+ const J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
+ bool result = true;
+
+ /* Set NullPointerException to throw out upon return in the case of the null value.
+ *
+ * Note:
+ * For the returned memory object, the case of a NULL value rarely happens in that
+ * programmers should realize that only native segments with the non-zero address
+ * are allowed to return directly during the upcall; otherwise, JVM should handle
+ * these unexpected cases correctly.
+ */
+ if (NULL == retMemObject) {
+ vmFuncs->setCurrentExceptionUTF(currentThread, J9VMCONSTANTPOOL_JAVALANGNULLPOINTEREXCEPTION, NULL);
+ if (downCallThread != currentThread) {
+ downCallThread->currentException = currentThread->currentException;
+ currentThread->currentException = NULL;
+ }
+ result = false;
}
-#endif /* JAVA_SPEC_VERSION <= 17 */
- Assert_VM_true(0 != nativePtrValue);
- return nativePtrValue;
+ return result;
}
-#endif /* JAVA_SPEC_VERSION <= 19 */
/**
- * @brief Get the native address to the requested struct from a MemorySegment object.
+ * @brief Perform a call-in to invoke a method of the upcall metadata
+ * so as to handle the returned memory object.
*
* @param data a pointer to J9UpcallMetaData
- * @param memSegmtObject the specified MemorySegment object
- * @return the native address to the requested struct
+ * @param retMemObject the returned memory object
+ * @param callInMethod the converted code intended for the call-in method
+ * @return the native address to the returned struct or pointer (JDK20+)
*/
-static I_64
-getNativeAddrFromMemSegmentObject(J9UpcallMetaData *data, j9object_t memSegmtObject)
+static U_64
+performCallInForRetMemObject(J9UpcallMetaData *data, j9object_t retMemObject, UDATA callInMethod)
{
+ J9VMThread *downCallThread = data->downCallThread;
J9VMThread *currentThread = currentVMThread(data->vm);
- I_64 nativePtrValue = J9VMJDKINTERNALFOREIGNNATIVEMEMORYSEGMENTIMPL_MIN(currentThread, memSegmtObject);
+ J9VMEntryLocalStorage newELS = {0};
+ U_64 nativePtrValue = 0;
+
+ if (buildCallInStackFrameHelper(currentThread, &newELS, false)) {
+ *(j9object_t*)--(currentThread->sp) = retMemObject;
+ currentThread->returnValue = J9_BCLOOP_RUN_METHOD;
+ currentThread->returnValue2 = callInMethod;
+ c_cInterpreter(currentThread);
+ restoreCallInFrameHelper(currentThread);
+ }
+
+ if (VM_VMHelpers::exceptionPending(currentThread)) {
+ if (downCallThread != currentThread) {
+ downCallThread->currentException = currentThread->currentException;
+ currentThread->currentException = NULL;
+ }
+ } else {
+ nativePtrValue = (U_64)currentThread->returnValue;
+ }
- Assert_VM_true(0 != nativePtrValue);
return nativePtrValue;
}
-
#endif /* JAVA_SPEC_VERSION >= 16 */
} /* extern "C" */
diff --git a/runtime/vm/bindnatv.cpp b/runtime/vm/bindnatv.cpp
index 4b66c022818..4a39e47044b 100644
--- a/runtime/vm/bindnatv.cpp
+++ b/runtime/vm/bindnatv.cpp
@@ -330,7 +330,7 @@ static J9OutOfLineINLMapping outOfLineINLmappings[] = {
{ "Java_openj9_internal_foreign_abi_InternalDowncallHandler_resolveRequiredFields__", OutOfLineINL_openj9_internal_foreign_abi_InternalDowncallHandler_resolveRequiredFields },
{ "Java_openj9_internal_foreign_abi_InternalDowncallHandler_initCifNativeThunkData___3Ljava_lang_String_2Ljava_lang_String_2ZI", OutOfLineINL_openj9_internal_foreign_abi_InternalDowncallHandler_initCifNativeThunkData },
{ "Java_openj9_internal_foreign_abi_InternalUpcallHandler_allocateUpcallStub__Lopenj9_internal_foreign_abi_UpcallMHMetaData_2_3Ljava_lang_String_2", OutOfLineINL_openj9_internal_foreign_abi_InternalUpcallHandler_allocateUpcallStub },
- { "Java_openj9_internal_foreign_abi_UpcallMHMetaData_resolveUpcallDataFields__", OutOfLineINL_openj9_internal_foreign_abi_UpcallMHMetaData_resolveUpcallDataFields },
+ { "Java_openj9_internal_foreign_abi_UpcallMHMetaData_resolveUpcallDataInfo__", OutOfLineINL_openj9_internal_foreign_abi_UpcallMHMetaData_resolveUpcallDataInfo },
#endif /* JAVA_SPEC_VERSION >= 16 */
};
diff --git a/test/functional/Java17andUp/src_170/org/openj9/test/jep389/downcall/InvalidDownCallTests.java b/test/functional/Java17andUp/src_170/org/openj9/test/jep389/downcall/InvalidDownCallTests.java
index 01e7807982f..f8047c3c67b 100644
--- a/test/functional/Java17andUp/src_170/org/openj9/test/jep389/downcall/InvalidDownCallTests.java
+++ b/test/functional/Java17andUp/src_170/org/openj9/test/jep389/downcall/InvalidDownCallTests.java
@@ -25,17 +25,24 @@
import org.testng.Assert;
import org.testng.AssertJUnit;
import static org.testng.Assert.fail;
+
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
+import java.lang.invoke.VarHandle;
+import java.lang.invoke.WrongMethodTypeException;
import jdk.incubator.foreign.Addressable;
import jdk.incubator.foreign.CLinker;
import static jdk.incubator.foreign.CLinker.*;
import jdk.incubator.foreign.FunctionDescriptor;
+import jdk.incubator.foreign.GroupLayout;
import jdk.incubator.foreign.MemoryAddress;
import jdk.incubator.foreign.MemoryLayout;
import jdk.incubator.foreign.MemoryLayouts;
+import jdk.incubator.foreign.MemoryLayout.PathElement;
+import jdk.incubator.foreign.MemorySegment;
import jdk.incubator.foreign.ResourceScope;
+import jdk.incubator.foreign.SegmentAllocator;
import jdk.incubator.foreign.SymbolLookup;
import jdk.incubator.foreign.ValueLayout;
@@ -392,4 +399,93 @@ public void test_unsupportedStringType() throws Throwable {
fail("Failed to throw out IllegalArgumentException in the case of the unsupported String type");
}
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullValueForPtrArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(C_INT.withName("elem1"), C_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(int.class, PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(int.class, PathElement.groupElement("elem2"));
+
+ MethodType mt = MethodType.methodType(int.class, int.class, MemoryAddress.class);
+ FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_INT, C_POINTER);
+ Addressable functionSymbol = nativeLibLookup.lookup("addIntAndIntsFromStructPointer").get();
+ MethodHandle mh = clinker.downcallHandle(functionSymbol, mt, fd);
+
+ int result = (int)mh.invoke(19202122, null);
+ fail("Failed to throw out NullPointerException in the case of the null value");
+ }
+
+ @Test(expectedExceptions = WrongMethodTypeException.class)
+ public void test_nullValueForStructArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(C_INT.withName("elem1"), C_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(int.class, PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(int.class, PathElement.groupElement("elem2"));
+
+ MethodType mt = MethodType.methodType(MemorySegment.class, MemorySegment.class, MemorySegment.class);
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout);
+ Addressable functionSymbol = nativeLibLookup.lookup("add2IntStructs_returnStruct").get();
+ MethodHandle mh = clinker.downcallHandle(functionSymbol, mt, fd);
+
+ try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+ SegmentAllocator allocator = SegmentAllocator.ofScope(scope);
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invokeExact(allocator, structSegmt1, null);
+ fail("Failed to throw out WrongMethodTypeException in the case of the null value");
+ }
+ }
+
+ public void test_nullSegmentForPtrArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(C_INT.withName("elem1"), C_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(int.class, PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(int.class, PathElement.groupElement("elem2"));
+
+ MethodType mt = MethodType.methodType(int.class, int.class, MemoryAddress.class);
+ FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_INT, C_POINTER);
+ Addressable functionSymbol = nativeLibLookup.lookup("validateNullAddrArgument").get();
+ MethodHandle mh = clinker.downcallHandle(functionSymbol, mt, fd);
+
+ int result = (int)mh.invoke(19202122, MemoryAddress.NULL);
+ Assert.assertEquals(result, 19202122);
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "A heap address is not allowed.*")
+ public void test_heapSegmentForPtrArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(C_INT.withName("elem1"), C_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(int.class, PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(int.class, PathElement.groupElement("elem2"));
+
+ MethodType mt = MethodType.methodType(int.class, int.class, MemoryAddress.class);
+ FunctionDescriptor fd = FunctionDescriptor.of(C_INT, C_INT, C_POINTER);
+ Addressable functionSymbol = nativeLibLookup.lookup("addIntAndIntsFromStructPointer").get();
+ MethodHandle mh = clinker.downcallHandle(functionSymbol, mt, fd);
+
+ MemorySegment structSegmt = MemorySegment.ofArray(new int[]{11121314, 15161718});
+ int result = (int)mh.invoke(19202122, structSegmt.address());
+ fail("Failed to throw out IllegalArgumentException in the case of the heap address");
+ }
+
+ public void test_heapSegmentForStructArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(C_INT.withName("elem1"), C_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(int.class, PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(int.class, PathElement.groupElement("elem2"));
+
+ MethodType mt = MethodType.methodType(MemorySegment.class, MemorySegment.class, MemorySegment.class);
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout);
+ Addressable functionSymbol = nativeLibLookup.lookup("add2IntStructs_returnStruct").get();
+ MethodHandle mh = clinker.downcallHandle(functionSymbol, mt, fd);
+
+ try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+ SegmentAllocator allocator = SegmentAllocator.ofScope(scope);
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = MemorySegment.ofArray(new int[]{99001122, 33445566});
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invokeExact(allocator, structSegmt1, structSegmt2);
+ Assert.assertEquals(intHandle1.get(resultSegmt), 110224466);
+ Assert.assertEquals(intHandle2.get(resultSegmt), 89113354);
+ }
+ }
}
diff --git a/test/functional/Java17andUp/src_170/org/openj9/test/jep389/upcall/InvalidUpCallTests.java b/test/functional/Java17andUp/src_170/org/openj9/test/jep389/upcall/InvalidUpCallTests.java
index b3796a2d1b1..64e5427eae8 100644
--- a/test/functional/Java17andUp/src_170/org/openj9/test/jep389/upcall/InvalidUpCallTests.java
+++ b/test/functional/Java17andUp/src_170/org/openj9/test/jep389/upcall/InvalidUpCallTests.java
@@ -115,4 +115,140 @@ public void test_nestedUpcall_throwExceptionFromUpcallMethod() throws Throwable
fail("Failed to throw out IllegalArgumentException from the nested upcall");
}
}
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullValueForReturnPtr() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(C_INT.withName("elem1"), C_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(int.class, PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(int.class, PathElement.groupElement("elem2"));
+
+ MethodType mt = MethodType.methodType(MemoryAddress.class, MemoryAddress.class, MemorySegment.class, MemoryAddress.class);
+ FunctionDescriptor fd = FunctionDescriptor.of(C_POINTER, C_POINTER, structLayout, C_POINTER);
+ Addressable functionSymbol = nativeLibLookup.lookup("add2IntStructs_returnStructPointerByUpcallMH").get();
+ MethodHandle mh = clinker.downcallHandle(functionSymbol, mt, fd);
+
+ try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+ MemoryAddress upcallFuncAddr = clinker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStructPointer_nullValue,
+ FunctionDescriptor.of(C_POINTER, C_POINTER, structLayout), scope);
+ SegmentAllocator allocator = SegmentAllocator.ofScope(scope);
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemoryAddress resultAddr = (MemoryAddress)mh.invokeExact(structSegmt1.address(), structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out NullPointerException in the case of the null value upon return");
+ }
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullValueForReturnStruct() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(C_INT.withName("elem1"), C_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(int.class, PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(int.class, PathElement.groupElement("elem2"));
+
+ MethodType mt = MethodType.methodType(MemorySegment.class, MemorySegment.class, MemorySegment.class, MemoryAddress.class);
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout, C_POINTER);
+ Addressable functionSymbol = nativeLibLookup.lookup("add2IntStructs_returnStructByUpcallMH").get();
+
+ try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+ MemoryAddress upcallFuncAddr = clinker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStruct_nullValue,
+ FunctionDescriptor.of(structLayout, structLayout, structLayout), scope);
+ SegmentAllocator allocator = SegmentAllocator.ofScope(scope);
+ MethodHandle mh = clinker.downcallHandle(functionSymbol, allocator, mt, fd);
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invokeExact(structSegmt1, structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out NullPointerException in the case of the null value upon return");
+ }
+ }
+
+ public void test_nullAddrForReturnPtr() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(C_INT.withName("elem1"), C_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(int.class, PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(int.class, PathElement.groupElement("elem2"));
+
+ MethodType mt = MethodType.methodType(MemoryAddress.class, MemoryAddress.class, MemorySegment.class, MemoryAddress.class);
+ FunctionDescriptor fd = FunctionDescriptor.of(C_POINTER, C_POINTER, structLayout, C_POINTER);
+ Addressable functionSymbol = nativeLibLookup.lookup("validateReturnNullAddrByUpcallMH").get();
+ MethodHandle mh = clinker.downcallHandle(functionSymbol, mt, fd);
+
+ try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+ MemoryAddress upcallFuncAddr = clinker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStructPointer_nullAddr,
+ FunctionDescriptor.of(C_POINTER, C_POINTER, structLayout), scope);
+ SegmentAllocator allocator = SegmentAllocator.ofScope(scope);
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemoryAddress resultAddr = (MemoryAddress)mh.invokeExact(structSegmt1.address(), structSegmt2, upcallFuncAddr);
+ MemorySegment resultSegmt = resultAddr.asSegment(structLayout.byteSize(), scope);
+ Assert.assertEquals(intHandle1.get(resultSegmt), 11223344);
+ Assert.assertEquals(intHandle2.get(resultSegmt), 55667788);
+ }
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "A heap address is not allowed.*")
+ public void test_heapSegmentForReturnPtr() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(C_INT.withName("elem1"), C_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(int.class, PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(int.class, PathElement.groupElement("elem2"));
+
+ MethodType mt = MethodType.methodType(MemoryAddress.class, MemoryAddress.class, MemorySegment.class, MemoryAddress.class);
+ FunctionDescriptor fd = FunctionDescriptor.of(C_POINTER, C_POINTER, structLayout, C_POINTER);
+ Addressable functionSymbol = nativeLibLookup.lookup("add2IntStructs_returnStructPointerByUpcallMH").get();
+ MethodHandle mh = clinker.downcallHandle(functionSymbol, mt, fd);
+
+ try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+ MemoryAddress upcallFuncAddr = clinker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStructPointer_heapSegmt,
+ FunctionDescriptor.of(C_POINTER, C_POINTER, structLayout), scope);
+ SegmentAllocator allocator = SegmentAllocator.ofScope(scope);
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemoryAddress resultAddr = (MemoryAddress)mh.invokeExact(structSegmt1.address(), structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out IllegalArgumentException in the case of the heap address upon return");
+ }
+ }
+
+ public void test_heapSegmentForReturnStruct() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(C_INT.withName("elem1"), C_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(int.class, PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(int.class, PathElement.groupElement("elem2"));
+
+ MethodType mt = MethodType.methodType(MemorySegment.class, MemorySegment.class, MemorySegment.class, MemoryAddress.class);
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout, C_POINTER);
+ Addressable functionSymbol = nativeLibLookup.lookup("add2IntStructs_returnStructByUpcallMH").get();
+
+ try (ResourceScope scope = ResourceScope.newConfinedScope()) {
+ MemoryAddress upcallFuncAddr = clinker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStruct_heapSegmt,
+ FunctionDescriptor.of(structLayout, structLayout, structLayout), scope);
+ SegmentAllocator allocator = SegmentAllocator.ofScope(scope);
+ MethodHandle mh = clinker.downcallHandle(functionSymbol, allocator, mt, fd);
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invokeExact(structSegmt1, structSegmt2, upcallFuncAddr);
+ Assert.assertEquals(intHandle1.get(resultSegmt), 110224466);
+ Assert.assertEquals(intHandle2.get(resultSegmt), 89113354);
+ }
+ }
}
diff --git a/test/functional/Java17andUp/src_170/org/openj9/test/jep389/upcall/UpcallMethodHandles.java b/test/functional/Java17andUp/src_170/org/openj9/test/jep389/upcall/UpcallMethodHandles.java
index e05727f996c..3edb3d4c9f2 100644
--- a/test/functional/Java17andUp/src_170/org/openj9/test/jep389/upcall/UpcallMethodHandles.java
+++ b/test/functional/Java17andUp/src_170/org/openj9/test/jep389/upcall/UpcallMethodHandles.java
@@ -191,7 +191,12 @@ public class UpcallMethodHandles {
public static final MethodHandle MH_add2IntStructs_returnStruct;
public static final MethodHandle MH_add2IntStructs_returnStruct_throwException;
public static final MethodHandle MH_add2IntStructs_returnStruct_nestedUpcall;
+ public static final MethodHandle MH_add2IntStructs_returnStruct_nullValue;
+ public static final MethodHandle MH_add2IntStructs_returnStruct_heapSegmt;
public static final MethodHandle MH_add2IntStructs_returnStructPointer;
+ public static final MethodHandle MH_add2IntStructs_returnStructPointer_nullValue;
+ public static final MethodHandle MH_add2IntStructs_returnStructPointer_nullAddr;
+ public static final MethodHandle MH_add2IntStructs_returnStructPointer_heapSegmt;
public static final MethodHandle MH_add3IntStructs_returnStruct;
public static final MethodHandle MH_addLongAndLongsFromStruct;
@@ -395,7 +400,12 @@ public class UpcallMethodHandles {
MH_add2IntStructs_returnStruct = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_add2IntStructs_returnStruct_throwException = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_throwException", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_add2IntStructs_returnStruct_nestedUpcall = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_nestedUpcall", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStruct_nullValue = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_nullValue", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStruct_heapSegmt = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_heapSegmt", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_add2IntStructs_returnStructPointer = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStructPointer", MT_MemAddr_MemAddr_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStructPointer_nullValue = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStructPointer_nullValue", MT_MemAddr_MemAddr_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStructPointer_nullAddr = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStructPointer_nullAddr", MT_MemAddr_MemAddr_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStructPointer_heapSegmt = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStructPointer_heapSegmt", MT_MemAddr_MemAddr_MemSegmt); //$NON-NLS-1$
MH_add3IntStructs_returnStruct = lookup.findStatic(UpcallMethodHandles.class, "add3IntStructs_returnStruct", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_addLongAndLongsFromStruct = lookup.findStatic(UpcallMethodHandles.class, "addLongAndLongsFromStruct", MT_Long_Long_MemSegmt); //$NON-NLS-1$
@@ -1620,6 +1630,20 @@ public static MemorySegment add2IntStructs_returnStruct_nestedUpcall(MemorySegme
return resultSegmt;
}
+ public static MemorySegment add2IntStructs_returnStruct_nullValue(MemorySegment arg1, MemorySegment arg2) {
+ return null;
+ }
+
+ public static MemorySegment add2IntStructs_returnStruct_heapSegmt(MemorySegment arg1, MemorySegment arg2) {
+ GroupLayout structLayout = MemoryLayout.structLayout(C_INT.withName("elem1"), C_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(int.class, PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(int.class, PathElement.groupElement("elem2"));
+
+ int intStruct_Elem1 = (int)intHandle1.get(arg1) + (int)intHandle1.get(arg2);
+ int intStruct_Elem2 = (int)intHandle2.get(arg1) + (int)intHandle2.get(arg2);
+ return MemorySegment.ofArray(new int[]{intStruct_Elem1, intStruct_Elem2});
+ }
+
public static MemoryAddress add2IntStructs_returnStructPointer(MemoryAddress arg1Addr, MemorySegment arg2) {
GroupLayout structLayout = MemoryLayout.structLayout(C_INT.withName("elem1"), C_INT.withName("elem2"));
VarHandle intHandle1 = structLayout.varHandle(int.class, PathElement.groupElement("elem1"));
@@ -1633,6 +1657,26 @@ public static MemoryAddress add2IntStructs_returnStructPointer(MemoryAddress arg
return arg1Addr;
}
+ public static MemoryAddress add2IntStructs_returnStructPointer_nullValue(MemoryAddress arg1Addr, MemorySegment arg2) {
+ return null;
+ }
+
+ public static MemoryAddress add2IntStructs_returnStructPointer_nullAddr(MemoryAddress arg1Addr, MemorySegment arg2) {
+ return MemoryAddress.NULL;
+ }
+
+ public static MemoryAddress add2IntStructs_returnStructPointer_heapSegmt(MemoryAddress arg1Addr, MemorySegment arg2) {
+ GroupLayout structLayout = MemoryLayout.structLayout(C_INT.withName("elem1"), C_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(int.class, PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(int.class, PathElement.groupElement("elem2"));
+
+ MemorySegment arg1 = arg1Addr.asSegment(structLayout.byteSize(), arg1Addr.scope());
+ int intSum_Elem1 = (int)intHandle1.get(arg1) + (int)intHandle1.get(arg2);
+ int intSum_Elem2 = (int)intHandle2.get(arg1) + (int)intHandle2.get(arg2);
+ MemorySegment resultSegmt = MemorySegment.ofArray(new int[]{intSum_Elem1, intSum_Elem2});
+ return resultSegmt.address();
+ }
+
public static MemorySegment add3IntStructs_returnStruct(MemorySegment arg1, MemorySegment arg2) {
GroupLayout structLayout = MemoryLayout.structLayout(C_INT.withName("elem1"), C_INT.withName("elem2"), C_INT.withName("elem3"));
VarHandle intHandle1 = structLayout.varHandle(int.class, PathElement.groupElement("elem1"));
diff --git a/test/functional/Java19andUp/src/org/openj9/test/jep424/downcall/InvalidDownCallTests.java b/test/functional/Java19andUp/src/org/openj9/test/jep424/downcall/InvalidDownCallTests.java
index 1c38846a29b..c42ae30f035 100644
--- a/test/functional/Java19andUp/src/org/openj9/test/jep424/downcall/InvalidDownCallTests.java
+++ b/test/functional/Java19andUp/src/org/openj9/test/jep424/downcall/InvalidDownCallTests.java
@@ -27,10 +27,18 @@
import static org.testng.Assert.fail;
import java.lang.invoke.MethodHandle;
+import java.lang.invoke.VarHandle;
+import java.lang.invoke.WrongMethodTypeException;
+
import java.lang.foreign.Addressable;
import java.lang.foreign.Linker;
import java.lang.foreign.FunctionDescriptor;
+import java.lang.foreign.GroupLayout;
+import java.lang.foreign.MemoryAddress;
import java.lang.foreign.MemoryLayout;
+import java.lang.foreign.MemorySegment;
+import java.lang.foreign.MemorySession;
+import java.lang.foreign.SegmentAllocator;
import java.lang.foreign.SymbolLookup;
import static java.lang.foreign.ValueLayout.*;
@@ -73,4 +81,108 @@ public void test_invalidMemoryLayoutForReturnType() throws Throwable {
MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
fail("Failed to throw out IllegalArgumentException in the case of the invalid MemoryLayout");
}
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullValueForPtrArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS);
+ Addressable functionSymbol = nativeLibLookup.lookup("addIntAndIntsFromStructPointer").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ int result = (int)mh.invoke(19202122, null);
+ fail("Failed to throw out NullPointerException in the case of the null value");
+ }
+
+ @Test(expectedExceptions = WrongMethodTypeException.class)
+ public void test_nullValueForStructArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout);
+ Addressable functionSymbol = nativeLibLookup.lookup("add2IntStructs_returnStruct").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (MemorySession session = MemorySession.openConfined()) {
+ SegmentAllocator allocator = SegmentAllocator.newNativeArena(session);
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invokeExact(allocator, structSegmt1, null);
+ fail("Failed to throw out WrongMethodTypeException in the case of the null value");
+ }
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullSegmentForPtrArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS);
+ Addressable functionSymbol = nativeLibLookup.lookup("addIntAndIntsFromStructPointer").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ int result = (int)mh.invoke(19202122, MemoryAddress.NULL);
+ fail("Failed to throw out NullPointerException in the case of the null address");
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Heap segment not allowed.*")
+ public void test_heapSegmentForPtrArgument_1() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS);
+ Addressable functionSymbol = nativeLibLookup.lookup("addIntAndIntsFromStructPointer").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ MemorySegment structSegmt = MemorySegment.ofArray(new int[]{11121314, 15161718});
+ int result = (int)mh.invoke(19202122, structSegmt);
+ fail("Failed to throw out IllegalArgumentException in the case of the heap segment");
+ }
+
+ /* An UnsupportedOperationException is thrown out by MemorySegment.address() in the case of
+ * the on-heap segment in JDK19.
+ */
+ @Test(expectedExceptions = UnsupportedOperationException.class, expectedExceptionsMessageRegExp = "Cannot obtain address of on-heap segment.*")
+ public void test_heapSegmentForPtrArgument_2() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS);
+ Addressable functionSymbol = nativeLibLookup.lookup("addIntAndIntsFromStructPointer").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ MemorySegment structSegmt = MemorySegment.ofArray(new int[]{11121314, 15161718});
+ int result = (int)mh.invokeExact(19202122, structSegmt.address());
+ fail("Failed to throw out UnsupportedOperationException in the case of the heap address");
+ }
+
+ public void test_heapSegmentForStructArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout);
+ Addressable functionSymbol = nativeLibLookup.lookup("add2IntStructs_returnStruct").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (MemorySession session = MemorySession.openConfined()) {
+ SegmentAllocator allocator = SegmentAllocator.newNativeArena(session);
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = MemorySegment.ofArray(new int[]{99001122, 33445566});
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invokeExact(allocator, structSegmt1, structSegmt2);
+ Assert.assertEquals(intHandle1.get(resultSegmt), 110224466);
+ Assert.assertEquals(intHandle2.get(resultSegmt), 89113354);
+ }
+ }
}
diff --git a/test/functional/Java19andUp/src/org/openj9/test/jep424/upcall/InvalidUpCallTests.java b/test/functional/Java19andUp/src/org/openj9/test/jep424/upcall/InvalidUpCallTests.java
index 5a53b7215e1..54dc142f61d 100644
--- a/test/functional/Java19andUp/src/org/openj9/test/jep424/upcall/InvalidUpCallTests.java
+++ b/test/functional/Java19andUp/src/org/openj9/test/jep424/upcall/InvalidUpCallTests.java
@@ -108,4 +108,141 @@ public void test_nestedUpcall_throwExceptionFromUpcallMethod() throws Throwable
fail("Failed to throw out IllegalArgumentException from the nested upcall");
}
}
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullValueForReturnPtr() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout, ADDRESS);
+ Addressable functionSymbol = nativeLibLookup.lookup("add2IntStructs_returnStructPointerByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (MemorySession session = MemorySession.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStructPointer_nullValue,
+ FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout), session);
+ SegmentAllocator allocator = SegmentAllocator.newNativeArena(session);
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultAddr = (MemorySegment)mh.invoke(structSegmt1, structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out NullPointerException in the case of the null value upon return");
+ }
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullValueForReturnStruct() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout, ADDRESS);
+ Addressable functionSymbol = nativeLibLookup.lookup("add2IntStructs_returnStructByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (MemorySession session = MemorySession.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStruct_nullValue,
+ FunctionDescriptor.of(structLayout, structLayout, structLayout), session);
+ SegmentAllocator allocator = SegmentAllocator.newNativeArena(session);
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invoke(allocator, structSegmt1, structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out NullPointerException in the case of the null value upon return");
+ }
+ }
+
+ /* UnsupportedOperationException is thrown out from MemorySegment.address() in upcall in JDK19 if
+ * the memory segment is not native, which is based on different implemenations in OpenJDK
+ * as compared to JDK17/20.
+ */
+ @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = "A NULL memory address is not allowed.*")
+ public void test_nullAddrForReturnPtr() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout, ADDRESS);
+ Addressable functionSymbol = nativeLibLookup.lookup("add2IntStructs_returnStructPointerByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (MemorySession session = MemorySession.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStructPointer_nullAddr,
+ FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout), session);
+ SegmentAllocator allocator = SegmentAllocator.newNativeArena(session);
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemoryAddress resultAddr = (MemoryAddress)mh.invoke(structSegmt1, structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out NullPointerException in the case of the null memory address upon return");
+ }
+ }
+
+ /* In JDK19, an UnsupportedOperationException by MemorySegment.address() upon return
+ * in upcall in the case of the heap segment.
+ */
+ @Test(expectedExceptions = UnsupportedOperationException.class, expectedExceptionsMessageRegExp = "Cannot obtain address of on-heap segment.*")
+ public void test_heapSegmentForReturnPtr() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout, ADDRESS);
+ Addressable functionSymbol = nativeLibLookup.lookup("add2IntStructs_returnStructPointerByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (MemorySession session = MemorySession.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStructPointer_heapSegmt,
+ FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout), session);
+ SegmentAllocator allocator = SegmentAllocator.newNativeArena(session);
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultAddr = (MemorySegment)mh.invoke(structSegmt1, structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out UnsupportedOperationException in the case of the heap segment upon return");
+ }
+ }
+
+ public void test_heapSegmentForReturnStruct() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout, ADDRESS);
+ Addressable functionSymbol = nativeLibLookup.lookup("add2IntStructs_returnStructByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (MemorySession session = MemorySession.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStruct_heapSegmt,
+ FunctionDescriptor.of(structLayout, structLayout, structLayout), session);
+ SegmentAllocator allocator = SegmentAllocator.newNativeArena(session);
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invoke(allocator, structSegmt1, structSegmt2, upcallFuncAddr);
+ Assert.assertEquals(intHandle1.get(resultSegmt), 110224466);
+ Assert.assertEquals(intHandle2.get(resultSegmt), 89113354);
+ }
+ }
}
diff --git a/test/functional/Java19andUp/src/org/openj9/test/jep424/upcall/UpcallMethodHandles.java b/test/functional/Java19andUp/src/org/openj9/test/jep424/upcall/UpcallMethodHandles.java
index f2ce1af7c72..48ab8cec22c 100644
--- a/test/functional/Java19andUp/src/org/openj9/test/jep424/upcall/UpcallMethodHandles.java
+++ b/test/functional/Java19andUp/src/org/openj9/test/jep424/upcall/UpcallMethodHandles.java
@@ -188,7 +188,12 @@ public class UpcallMethodHandles {
public static final MethodHandle MH_add2IntStructs_returnStruct;
public static final MethodHandle MH_add2IntStructs_returnStruct_throwException;
public static final MethodHandle MH_add2IntStructs_returnStruct_nestedUpcall;
+ public static final MethodHandle MH_add2IntStructs_returnStruct_nullValue;
+ public static final MethodHandle MH_add2IntStructs_returnStruct_heapSegmt;
public static final MethodHandle MH_add2IntStructs_returnStructPointer;
+ public static final MethodHandle MH_add2IntStructs_returnStructPointer_nullValue;
+ public static final MethodHandle MH_add2IntStructs_returnStructPointer_nullAddr;
+ public static final MethodHandle MH_add2IntStructs_returnStructPointer_heapSegmt;
public static final MethodHandle MH_add3IntStructs_returnStruct;
public static final MethodHandle MH_addLongAndLongsFromStruct;
@@ -392,7 +397,12 @@ public class UpcallMethodHandles {
MH_add2IntStructs_returnStruct = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_add2IntStructs_returnStruct_throwException = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_throwException", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_add2IntStructs_returnStruct_nestedUpcall = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_nestedUpcall", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStruct_nullValue = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_nullValue", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStruct_heapSegmt = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_heapSegmt", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_add2IntStructs_returnStructPointer = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStructPointer", MT_Addr_MemAddr_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStructPointer_nullValue = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStructPointer_nullValue", MT_Addr_MemAddr_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStructPointer_nullAddr = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStructPointer_nullAddr", MT_Addr_MemAddr_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStructPointer_heapSegmt = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStructPointer_heapSegmt", MT_Addr_MemAddr_MemSegmt); //$NON-NLS-1$
MH_add3IntStructs_returnStruct = lookup.findStatic(UpcallMethodHandles.class, "add3IntStructs_returnStruct", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_addLongAndLongsFromStruct = lookup.findStatic(UpcallMethodHandles.class, "addLongAndLongsFromStruct", MT_Long_Long_MemSegmt); //$NON-NLS-1$
@@ -1329,6 +1339,16 @@ public static MemorySegment add2IntStructs_returnStruct_nestedUpcall(MemorySegme
return resultSegmt;
}
+ public static MemorySegment add2IntStructs_returnStruct_nullValue(MemorySegment arg1, MemorySegment arg2) {
+ return null;
+ }
+
+ public static MemorySegment add2IntStructs_returnStruct_heapSegmt(MemorySegment arg1, MemorySegment arg2) {
+ int intStruct_Elem1 = arg1.get(JAVA_INT, 0) + arg2.get(JAVA_INT, 0);
+ int intStruct_Elem2 = arg1.get(JAVA_INT, 4) + arg2.get(JAVA_INT, 4);
+ return MemorySegment.ofArray(new int[]{intStruct_Elem1, intStruct_Elem2});
+ }
+
public static Addressable add2IntStructs_returnStructPointer(MemoryAddress arg1Addr, MemorySegment arg2) {
int intSum_Elem1 = arg1Addr.get(JAVA_INT, 0) + arg2.get(JAVA_INT, 0);
int intSum_Elem2 = arg1Addr.get(JAVA_INT, 4) + arg2.get(JAVA_INT, 4);
@@ -1337,6 +1357,21 @@ public static Addressable add2IntStructs_returnStructPointer(MemoryAddress arg1A
return arg1Addr;
}
+ public static Addressable add2IntStructs_returnStructPointer_nullValue(MemoryAddress arg1Addr, MemorySegment arg2) {
+ return null;
+ }
+
+ public static Addressable add2IntStructs_returnStructPointer_nullAddr(MemoryAddress arg1Addr, MemorySegment arg2) {
+ return MemoryAddress.NULL;
+ }
+
+ public static Addressable add2IntStructs_returnStructPointer_heapSegmt(MemoryAddress arg1Addr, MemorySegment arg2) {
+ int intSum_Elem1 = arg1Addr.get(JAVA_INT, 0) + arg2.get(JAVA_INT, 0);
+ int intSum_Elem2 = arg1Addr.get(JAVA_INT, 4) + arg2.get(JAVA_INT, 4);
+ MemorySegment resultSegmt = MemorySegment.ofArray(new int[]{intSum_Elem1, intSum_Elem2});
+ return resultSegmt.address();
+ }
+
public static MemorySegment add3IntStructs_returnStruct(MemorySegment arg1, MemorySegment arg2) {
GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"), JAVA_INT.withName("elem3"));
MemorySegment intStructSegmt = MemorySegment.allocateNative(structLayout, session);
diff --git a/test/functional/Java20andUp/src/org/openj9/test/jep434/downcall/InvalidDownCallTests.java b/test/functional/Java20andUp/src/org/openj9/test/jep434/downcall/InvalidDownCallTests.java
index d490e8798af..f9fb76e816e 100644
--- a/test/functional/Java20andUp/src/org/openj9/test/jep434/downcall/InvalidDownCallTests.java
+++ b/test/functional/Java20andUp/src/org/openj9/test/jep434/downcall/InvalidDownCallTests.java
@@ -30,6 +30,7 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.VarHandle;
+import java.lang.invoke.WrongMethodTypeException;
import java.lang.foreign.Arena;
import java.lang.foreign.Linker;
@@ -82,4 +83,110 @@ public void test_invalidMemoryLayoutForReturnType() throws Throwable {
MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
fail("Failed to throw out IllegalArgumentException in the case of the invalid MemoryLayout");
}
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullValueForPtrArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("addIntAndIntsFromStructPointer").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ int result = (int)mh.invoke(19202122, null);
+ fail("Failed to throw out NullPointerException in the case of the null value");
+ }
+
+ @Test(expectedExceptions = WrongMethodTypeException.class)
+ public void test_nullValueForStructArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStruct").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invokeExact(allocator, structSegmt1, null);
+ fail("Failed to throw out WrongMethodTypeException in the case of the null value");
+ }
+ }
+
+ public void test_nullSegmentForPtrArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("validateNullAddrArgument").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ int result = (int)mh.invoke(19202122, MemorySegment.NULL);
+ Assert.assertEquals(result, 19202122);
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullSegmentForStructArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStruct").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invokeExact(allocator, structSegmt1, MemorySegment.NULL);
+ fail("Failed to throw out NullPointerException in the case of the null segment");
+ }
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Heap segment not allowed.*")
+ public void test_heapSegmentForPtrArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("addIntAndIntsFromStructPointer").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ MemorySegment structSegmt = MemorySegment.ofArray(new int[]{11121314, 15161718});
+ int result = (int)mh.invoke(19202122, structSegmt);
+ fail("Failed to throw out IllegalArgumentException in the case of the heap segment");
+ }
+
+ public void test_heapSegmentForStructArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStruct").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = MemorySegment.ofArray(new int[]{99001122, 33445566});
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invokeExact(allocator, structSegmt1, structSegmt2);
+ Assert.assertEquals(intHandle1.get(resultSegmt), 110224466);
+ Assert.assertEquals(intHandle2.get(resultSegmt), 89113354);
+ }
+ }
}
diff --git a/test/functional/Java20andUp/src/org/openj9/test/jep434/upcall/InvalidUpCallTests.java b/test/functional/Java20andUp/src/org/openj9/test/jep434/upcall/InvalidUpCallTests.java
index 70d73df834c..567c430e547 100644
--- a/test/functional/Java20andUp/src/org/openj9/test/jep434/upcall/InvalidUpCallTests.java
+++ b/test/functional/Java20andUp/src/org/openj9/test/jep434/upcall/InvalidUpCallTests.java
@@ -106,4 +106,161 @@ public void test_nestedUpcall_throwExceptionFromUpcallMethod() throws Throwable
fail("Failed to throw out IllegalArgumentException from the nested upcall");
}
}
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullValueForReturnPtr() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStructPointerByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStructPointer_nullValue,
+ FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout), arena.scope());
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultAddr = (MemorySegment)mh.invoke(structSegmt1, structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out NullPointerException in the case of the null value upon return");
+ }
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullValueForReturnStruct() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStructByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStruct_nullValue,
+ FunctionDescriptor.of(structLayout, structLayout, structLayout), arena.scope());
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invoke(allocator, structSegmt1, structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out NullPointerException in the case of the null value upon return");
+ }
+ }
+
+ public void test_nullSegmentForReturnPtr() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("validateReturnNullAddrByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStructPointer_nullSegmt,
+ FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout), arena.scope());
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultAddr = (MemorySegment)mh.invoke(structSegmt1, structSegmt2, upcallFuncAddr);
+ MemorySegment resultSegmt = MemorySegment.ofAddress(resultAddr.address(), structLayout.byteSize(), arena.scope());
+ Assert.assertEquals(resultSegmt.get(JAVA_INT, 0), 11223344);
+ Assert.assertEquals(resultSegmt.get(JAVA_INT, 4), 55667788);
+ }
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullSegmentForReturnStruct() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStructByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStruct_nullSegmt,
+ FunctionDescriptor.of(structLayout, structLayout, structLayout), arena.scope());
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invoke(allocator, structSegmt1, structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out NullPointerException in the case of the null segment upon return");
+ }
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Heap segment not allowed.*")
+ public void test_heapSegmentForReturnPtr() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStructPointerByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStructPointer_heapSegmt,
+ FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout), arena.scope());
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultAddr = (MemorySegment)mh.invoke(structSegmt1, structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out IllegalArgumentException in the case of the heap segment upon return");
+ }
+ }
+
+ public void test_heapSegmentForReturnStruct() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStructByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStruct_heapSegmt,
+ FunctionDescriptor.of(structLayout, structLayout, structLayout), arena.scope());
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invoke(allocator, structSegmt1, structSegmt2, upcallFuncAddr);
+ Assert.assertEquals(intHandle1.get(resultSegmt), 110224466);
+ Assert.assertEquals(intHandle2.get(resultSegmt), 89113354);
+ }
+ }
}
diff --git a/test/functional/Java20andUp/src/org/openj9/test/jep434/upcall/UpcallMethodHandles.java b/test/functional/Java20andUp/src/org/openj9/test/jep434/upcall/UpcallMethodHandles.java
index fc6908bca87..18a96f0f9a6 100644
--- a/test/functional/Java20andUp/src/org/openj9/test/jep434/upcall/UpcallMethodHandles.java
+++ b/test/functional/Java20andUp/src/org/openj9/test/jep434/upcall/UpcallMethodHandles.java
@@ -187,7 +187,13 @@ public class UpcallMethodHandles {
public static final MethodHandle MH_add2IntStructs_returnStruct;
public static final MethodHandle MH_add2IntStructs_returnStruct_throwException;
public static final MethodHandle MH_add2IntStructs_returnStruct_nestedUpcall;
+ public static final MethodHandle MH_add2IntStructs_returnStruct_nullValue;
+ public static final MethodHandle MH_add2IntStructs_returnStruct_nullSegmt;
+ public static final MethodHandle MH_add2IntStructs_returnStruct_heapSegmt;
public static final MethodHandle MH_add2IntStructs_returnStructPointer;
+ public static final MethodHandle MH_add2IntStructs_returnStructPointer_nullValue;
+ public static final MethodHandle MH_add2IntStructs_returnStructPointer_nullSegmt;
+ public static final MethodHandle MH_add2IntStructs_returnStructPointer_heapSegmt;
public static final MethodHandle MH_add3IntStructs_returnStruct;
public static final MethodHandle MH_addLongAndLongsFromStruct;
@@ -391,7 +397,13 @@ public class UpcallMethodHandles {
MH_add2IntStructs_returnStruct = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_add2IntStructs_returnStruct_throwException = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_throwException", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_add2IntStructs_returnStruct_nestedUpcall = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_nestedUpcall", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStruct_nullValue = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_nullValue", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStruct_nullSegmt = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_nullSegmt", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStruct_heapSegmt = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_heapSegmt", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_add2IntStructs_returnStructPointer = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStructPointer", MT_Segmt_MemSegmt_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStructPointer_nullValue = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStructPointer_nullValue", MT_Segmt_MemSegmt_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStructPointer_nullSegmt = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStructPointer_nullSegmt", MT_Segmt_MemSegmt_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStructPointer_heapSegmt = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStructPointer_heapSegmt", MT_Segmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_add3IntStructs_returnStruct = lookup.findStatic(UpcallMethodHandles.class, "add3IntStructs_returnStruct", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_addLongAndLongsFromStruct = lookup.findStatic(UpcallMethodHandles.class, "addLongAndLongsFromStruct", MT_Long_Long_MemSegmt); //$NON-NLS-1$
@@ -1382,6 +1394,20 @@ public static MemorySegment add2IntStructs_returnStruct_nestedUpcall(MemorySegme
return resultSegmt;
}
+ public static MemorySegment add2IntStructs_returnStruct_nullValue(MemorySegment arg1, MemorySegment arg2) {
+ return null;
+ }
+
+ public static MemorySegment add2IntStructs_returnStruct_nullSegmt(MemorySegment arg1, MemorySegment arg2) {
+ return MemorySegment.NULL;
+ }
+
+ public static MemorySegment add2IntStructs_returnStruct_heapSegmt(MemorySegment arg1, MemorySegment arg2) {
+ int intStruct_Elem1 = arg1.get(JAVA_INT, 0) + arg2.get(JAVA_INT, 0);
+ int intStruct_Elem2 = arg1.get(JAVA_INT, 4) + arg2.get(JAVA_INT, 4);
+ return MemorySegment.ofArray(new int[]{intStruct_Elem1, intStruct_Elem2});
+ }
+
public static MemorySegment add2IntStructs_returnStructPointer(MemorySegment arg1Addr, MemorySegment arg2) {
GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
MemorySegment arg1Segmt = MemorySegment.ofAddress(arg1Addr.address(), structLayout.byteSize(), scope);
@@ -1392,6 +1418,22 @@ public static MemorySegment add2IntStructs_returnStructPointer(MemorySegment arg
return arg1Addr;
}
+ public static MemorySegment add2IntStructs_returnStructPointer_nullValue(MemorySegment arg1Addr, MemorySegment arg2) {
+ return null;
+ }
+
+ public static MemorySegment add2IntStructs_returnStructPointer_nullSegmt(MemorySegment arg1Addr, MemorySegment arg2) {
+ return MemorySegment.NULL;
+ }
+
+ public static MemorySegment add2IntStructs_returnStructPointer_heapSegmt(MemorySegment arg1Addr, MemorySegment arg2) {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ MemorySegment arg1Segmt = MemorySegment.ofAddress(arg1Addr.address(), structLayout.byteSize(), scope);
+ int intSum_Elem1 = arg1Segmt.get(JAVA_INT, 0) + arg2.get(JAVA_INT, 0);
+ int intSum_Elem2 = arg1Segmt.get(JAVA_INT, 4) + arg2.get(JAVA_INT, 4);
+ return MemorySegment.ofArray(new int[]{intSum_Elem1, intSum_Elem2});
+ }
+
public static MemorySegment add3IntStructs_returnStruct(MemorySegment arg1, MemorySegment arg2) {
GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"), JAVA_INT.withName("elem3"));
MemorySegment intStructSegmt = MemorySegment.allocateNative(structLayout, scope);
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/InvalidDownCallTests.java b/test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/InvalidDownCallTests.java
deleted file mode 100644
index 7272e3b18f4..00000000000
--- a/test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/InvalidDownCallTests.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*******************************************************************************
- * Copyright IBM Corp. and others 2023
- *
- * This program and the accompanying materials are made available under
- * the terms of the Eclipse Public License 2.0 which accompanies this
- * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
- * or the Apache License, Version 2.0 which accompanies this distribution and
- * is available at https://www.apache.org/licenses/LICENSE-2.0.
- *
- * This Source Code may also be made available under the following
- * Secondary Licenses when the conditions for such availability set
- * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
- * General Public License, version 2 with the GNU Classpath
- * Exception [1] and GNU General Public License, version 2 with the
- * OpenJDK Assembly Exception [2].
- *
- * [1] https://www.gnu.org/software/classpath/license.html
- * [2] https://openjdk.org/legal/assembly-exception.html
- *
- * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
- *******************************************************************************/
-package org.openj9.test.jep442.downcall;
-
-import org.testng.annotations.Test;
-import org.testng.Assert;
-import org.testng.AssertJUnit;
-import static org.testng.Assert.fail;
-
-import java.lang.invoke.MethodHandle;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.VarHandle;
-
-import java.lang.foreign.Arena;
-import java.lang.foreign.Linker;
-import java.lang.foreign.FunctionDescriptor;
-import java.lang.foreign.GroupLayout;
-import java.lang.foreign.MemoryLayout;
-import java.lang.foreign.MemoryLayout.PathElement;
-import java.lang.foreign.MemorySegment;
-import java.lang.foreign.SegmentAllocator;
-import java.lang.foreign.SequenceLayout;
-import java.lang.foreign.SymbolLookup;
-import static java.lang.foreign.ValueLayout.*;
-
-/**
- * Test cases for JEP 442: Foreign Linker API (Third Preview) for primitive types in downcall,
- * which verify the illegal cases including unsupported layouts, etc.
- * Note: the majority of illegal cases are removed given the corresponding method type
- * is deduced from the function descriptor which is verified in OpenJDK.
- */
-@Test(groups = { "level.sanity" })
-public class InvalidDownCallTests {
- private static Linker linker = Linker.nativeLinker();
-
- static {
- System.loadLibrary("clinkerffitests");
- }
- private static final SymbolLookup nativeLibLookup = SymbolLookup.loaderLookup();
- private static final SymbolLookup defaultLibLookup = linker.defaultLookup();
-
- @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Unsupported layout.*")
- public void test_invalidMemoryLayoutForIntType() throws Throwable {
- FunctionDescriptor fd = FunctionDescriptor.ofVoid(JAVA_INT, MemoryLayout.paddingLayout(32));
- MemorySegment functionSymbol = nativeLibLookup.find("add2IntsReturnVoid").get();
- MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
- fail("Failed to throw out IllegalArgumentException in the case of the invalid MemoryLayout");
- }
-
- @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Unsupported layout.*")
- public void test_invalidMemoryLayoutForMemAddr() throws Throwable {
- MemorySegment functionSymbol = defaultLibLookup.find("strlen").get();
- FunctionDescriptor fd = FunctionDescriptor.of(JAVA_LONG, MemoryLayout.paddingLayout(64));
- MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
- fail("Failed to throw out IllegalArgumentException in the case of the invalid MemoryLayout");
- }
-
- @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Unsupported layout.*")
- public void test_invalidMemoryLayoutForReturnType() throws Throwable {
- MemorySegment functionSymbol = defaultLibLookup.find("strlen").get();
- FunctionDescriptor fd = FunctionDescriptor.of(MemoryLayout.paddingLayout(64), JAVA_LONG);
- MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
- fail("Failed to throw out IllegalArgumentException in the case of the invalid MemoryLayout");
- }
-}
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/InvalidUpCallTests.java b/test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/InvalidUpCallTests.java
deleted file mode 100644
index eda71618c20..00000000000
--- a/test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/InvalidUpCallTests.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*******************************************************************************
- * Copyright IBM Corp. and others 2023
- *
- * This program and the accompanying materials are made available under
- * the terms of the Eclipse Public License 2.0 which accompanies this
- * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
- * or the Apache License, Version 2.0 which accompanies this distribution and
- * is available at https://www.apache.org/licenses/LICENSE-2.0.
- *
- * This Source Code may also be made available under the following
- * Secondary Licenses when the conditions for such availability set
- * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
- * General Public License, version 2 with the GNU Classpath
- * Exception [1] and GNU General Public License, version 2 with the
- * OpenJDK Assembly Exception [2].
- *
- * [1] https://www.gnu.org/software/classpath/license.html
- * [2] https://openjdk.org/legal/assembly-exception.html
- *
- * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
- *******************************************************************************/
-package org.openj9.test.jep442.upcall;
-
-import org.testng.annotations.Test;
-import org.testng.Assert;
-import org.testng.AssertJUnit;
-import static org.testng.Assert.fail;
-
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.VarHandle;
-
-import java.lang.foreign.Arena;
-import java.lang.foreign.FunctionDescriptor;
-import java.lang.foreign.GroupLayout;
-import java.lang.foreign.Linker;
-import java.lang.foreign.MemoryLayout;
-import java.lang.foreign.MemoryLayout.PathElement;
-import java.lang.foreign.MemorySegment;
-import java.lang.foreign.SegmentAllocator;
-import java.lang.foreign.SequenceLayout;
-import java.lang.foreign.SymbolLookup;
-import java.lang.foreign.ValueLayout;
-import static java.lang.foreign.ValueLayout.*;
-
-/**
- * Test cases for JEP 442: Foreign Linker API (Third Preview) in upcall,
- * which verify the illegal cases including the returned segment, etc.
- */
-@Test(groups = { "level.sanity" })
-public class InvalidUpCallTests {
- private static Linker linker = Linker.nativeLinker();
-
- static {
- System.loadLibrary("clinkerffitests");
- }
- private static final SymbolLookup nativeLibLookup = SymbolLookup.loaderLookup();
-
- @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "An exception is thrown from the upcall method")
- public void test_throwExceptionFromUpcallMethod() throws Throwable {
- GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
- VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
- VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
-
- FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout, ADDRESS);
- MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStructByUpcallMH").get();
- MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
-
- try (Arena arena = Arena.openConfined()) {
- MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStruct_throwException,
- FunctionDescriptor.of(structLayout, structLayout, structLayout), arena.scope());
- SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
- MemorySegment structSegmt1 = allocator.allocate(structLayout);
- intHandle1.set(structSegmt1, 11223344);
- intHandle2.set(structSegmt1, 55667788);
- MemorySegment structSegmt2 = allocator.allocate(structLayout);
- intHandle1.set(structSegmt2, 99001122);
- intHandle2.set(structSegmt2, 33445566);
-
- MemorySegment resultSegmt = (MemorySegment)mh.invoke(allocator, structSegmt1, structSegmt2, upcallFuncAddr);
- fail("Failed to throw out IllegalArgumentException from the the upcall method");
- }
- }
-
- @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "An exception is thrown from the upcall method")
- public void test_nestedUpcall_throwExceptionFromUpcallMethod() throws Throwable {
- GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
- VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
- VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
-
- FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout, ADDRESS);
- MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStructByUpcallMH").get();
- MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
-
- try (Arena arena = Arena.openConfined()) {
- MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStruct_nestedUpcall,
- FunctionDescriptor.of(structLayout, structLayout, structLayout), arena.scope());
- SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
- MemorySegment structSegmt1 = allocator.allocate(structLayout);
- intHandle1.set(structSegmt1, 11223344);
- intHandle2.set(structSegmt1, 55667788);
- MemorySegment structSegmt2 = allocator.allocate(structLayout);
- intHandle1.set(structSegmt2, 99001122);
- intHandle2.set(structSegmt2, 33445566);
-
- MemorySegment resultSegmt = (MemorySegment)mh.invoke(allocator, structSegmt1, structSegmt2, upcallFuncAddr);
- fail("Failed to throw out IllegalArgumentException from the nested upcall");
- }
- }
-}
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/InvalidDownCallTests.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/InvalidDownCallTests.java
new file mode 100644
index 00000000000..ab8df6e7344
--- /dev/null
+++ b/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/InvalidDownCallTests.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Copyright IBM Corp. and others 2023
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which accompanies this
+ * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
+ * or the Apache License, Version 2.0 which accompanies this distribution and
+ * is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * This Source Code may also be made available under the following
+ * Secondary Licenses when the conditions for such availability set
+ * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
+ * General Public License, version 2 with the GNU Classpath
+ * Exception [1] and GNU General Public License, version 2 with the
+ * OpenJDK Assembly Exception [2].
+ *
+ * [1] https://www.gnu.org/software/classpath/license.html
+ * [2] https://openjdk.org/legal/assembly-exception.html
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
+ *******************************************************************************/
+package org.openj9.test.jep442.downcall;
+
+import org.testng.annotations.Test;
+import org.testng.Assert;
+import org.testng.AssertJUnit;
+import static org.testng.Assert.fail;
+
+import java.lang.invoke.MethodHandle;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.VarHandle;
+import java.lang.invoke.WrongMethodTypeException;
+
+import java.lang.foreign.Arena;
+import java.lang.foreign.Linker;
+import java.lang.foreign.FunctionDescriptor;
+import java.lang.foreign.GroupLayout;
+import java.lang.foreign.MemoryLayout;
+import java.lang.foreign.MemoryLayout.PathElement;
+import java.lang.foreign.MemorySegment;
+import java.lang.foreign.SegmentAllocator;
+import java.lang.foreign.SequenceLayout;
+import java.lang.foreign.SymbolLookup;
+import static java.lang.foreign.ValueLayout.*;
+
+/**
+ * Test cases for JEP 442: Foreign Linker API (Third Preview) for primitive types in downcall,
+ * which verify the illegal cases including unsupported layouts, etc.
+ * Note: the majority of illegal cases are removed given the corresponding method type
+ * is deduced from the function descriptor which is verified in OpenJDK.
+ */
+@Test(groups = { "level.sanity" })
+public class InvalidDownCallTests {
+ private static Linker linker = Linker.nativeLinker();
+
+ static {
+ System.loadLibrary("clinkerffitests");
+ }
+ private static final SymbolLookup nativeLibLookup = SymbolLookup.loaderLookup();
+ private static final SymbolLookup defaultLibLookup = linker.defaultLookup();
+
+ @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Unsupported layout.*")
+ public void test_invalidMemoryLayoutForIntType() throws Throwable {
+ FunctionDescriptor fd = FunctionDescriptor.ofVoid(JAVA_INT, MemoryLayout.paddingLayout(32));
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntsReturnVoid").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+ fail("Failed to throw out IllegalArgumentException in the case of the invalid MemoryLayout");
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Unsupported layout.*")
+ public void test_invalidMemoryLayoutForMemAddr() throws Throwable {
+ MemorySegment functionSymbol = defaultLibLookup.find("strlen").get();
+ FunctionDescriptor fd = FunctionDescriptor.of(JAVA_LONG, MemoryLayout.paddingLayout(64));
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+ fail("Failed to throw out IllegalArgumentException in the case of the invalid MemoryLayout");
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Unsupported layout.*")
+ public void test_invalidMemoryLayoutForReturnType() throws Throwable {
+ MemorySegment functionSymbol = defaultLibLookup.find("strlen").get();
+ FunctionDescriptor fd = FunctionDescriptor.of(MemoryLayout.paddingLayout(64), JAVA_LONG);
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+ fail("Failed to throw out IllegalArgumentException in the case of the invalid MemoryLayout");
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullValueForPtrArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("addIntAndIntsFromStructPointer").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ int result = (int)mh.invoke(19202122, null);
+ fail("Failed to throw out NullPointerException in the case of the null value");
+ }
+
+ @Test(expectedExceptions = WrongMethodTypeException.class)
+ public void test_nullValueForStructArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStruct").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invokeExact(allocator, structSegmt1, null);
+ fail("Failed to throw out WrongMethodTypeException in the case of the null value");
+ }
+ }
+
+ public void test_nullSegmentForPtrArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("validateNullAddrArgument").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ int result = (int)mh.invoke(19202122, MemorySegment.NULL);
+ Assert.assertEquals(result, 19202122);
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullSegmentForStructArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStruct").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invokeExact(allocator, structSegmt1, MemorySegment.NULL);
+ fail("Failed to throw out NullPointerException in the case of the null segment");
+ }
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Heap segment not allowed.*")
+ public void test_heapSegmentForPtrArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("addIntAndIntsFromStructPointer").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ MemorySegment structSegmt = MemorySegment.ofArray(new int[]{11121314, 15161718});
+ int result = (int)mh.invoke(19202122, structSegmt);
+ fail("Failed to throw out IllegalArgumentException in the case of the heap segment");
+ }
+
+ public void test_heapSegmentForStructArgument() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStruct").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = MemorySegment.ofArray(new int[]{99001122, 33445566});
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invokeExact(allocator, structSegmt1, structSegmt2);
+ Assert.assertEquals(intHandle1.get(resultSegmt), 110224466);
+ Assert.assertEquals(intHandle2.get(resultSegmt), 89113354);
+ }
+ }
+}
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/MultiCallTests.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/MultiCallTests.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/MultiCallTests.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/MultiCallTests.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/MultiThreadingTests1.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/MultiThreadingTests1.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/MultiThreadingTests1.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/MultiThreadingTests1.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/MultiThreadingTests2.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/MultiThreadingTests2.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/MultiThreadingTests2.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/MultiThreadingTests2.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/MultiThreadingTests3.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/MultiThreadingTests3.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/MultiThreadingTests3.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/MultiThreadingTests3.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/MultiThreadingTests4.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/MultiThreadingTests4.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/MultiThreadingTests4.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/MultiThreadingTests4.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/MultiThreadingTests5.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/MultiThreadingTests5.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/MultiThreadingTests5.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/MultiThreadingTests5.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/PrimitiveTypeTests1.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/PrimitiveTypeTests1.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/PrimitiveTypeTests1.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/PrimitiveTypeTests1.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/PrimitiveTypeTests2.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/PrimitiveTypeTests2.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/PrimitiveTypeTests2.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/PrimitiveTypeTests2.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/StructTests1.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/StructTests1.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/StructTests1.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/StructTests1.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/StructTests2.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/StructTests2.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/downcall/StructTests2.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/StructTests2.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/InvalidUpCallTests.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/InvalidUpCallTests.java
new file mode 100644
index 00000000000..090a76ba1d3
--- /dev/null
+++ b/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/InvalidUpCallTests.java
@@ -0,0 +1,266 @@
+/*******************************************************************************
+ * Copyright IBM Corp. and others 2023
+ *
+ * This program and the accompanying materials are made available under
+ * the terms of the Eclipse Public License 2.0 which accompanies this
+ * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
+ * or the Apache License, Version 2.0 which accompanies this distribution and
+ * is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * This Source Code may also be made available under the following
+ * Secondary Licenses when the conditions for such availability set
+ * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
+ * General Public License, version 2 with the GNU Classpath
+ * Exception [1] and GNU General Public License, version 2 with the
+ * OpenJDK Assembly Exception [2].
+ *
+ * [1] https://www.gnu.org/software/classpath/license.html
+ * [2] https://openjdk.org/legal/assembly-exception.html
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
+ *******************************************************************************/
+package org.openj9.test.jep442.upcall;
+
+import org.testng.annotations.Test;
+import org.testng.Assert;
+import org.testng.AssertJUnit;
+import static org.testng.Assert.fail;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.VarHandle;
+
+import java.lang.foreign.Arena;
+import java.lang.foreign.FunctionDescriptor;
+import java.lang.foreign.GroupLayout;
+import java.lang.foreign.Linker;
+import java.lang.foreign.MemoryLayout;
+import java.lang.foreign.MemoryLayout.PathElement;
+import java.lang.foreign.MemorySegment;
+import java.lang.foreign.SegmentAllocator;
+import java.lang.foreign.SequenceLayout;
+import java.lang.foreign.SymbolLookup;
+import java.lang.foreign.ValueLayout;
+import static java.lang.foreign.ValueLayout.*;
+
+/**
+ * Test cases for JEP 442: Foreign Linker API (Third Preview) in upcall,
+ * which verify the illegal cases including the returned segment, etc.
+ */
+@Test(groups = { "level.sanity" })
+public class InvalidUpCallTests {
+ private static Linker linker = Linker.nativeLinker();
+
+ static {
+ System.loadLibrary("clinkerffitests");
+ }
+ private static final SymbolLookup nativeLibLookup = SymbolLookup.loaderLookup();
+
+ @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "An exception is thrown from the upcall method")
+ public void test_throwExceptionFromUpcallMethod() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStructByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStruct_throwException,
+ FunctionDescriptor.of(structLayout, structLayout, structLayout), arena.scope());
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invoke(allocator, structSegmt1, structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out IllegalArgumentException from the the upcall method");
+ }
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "An exception is thrown from the upcall method")
+ public void test_nestedUpcall_throwExceptionFromUpcallMethod() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStructByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStruct_nestedUpcall,
+ FunctionDescriptor.of(structLayout, structLayout, structLayout), arena.scope());
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invoke(allocator, structSegmt1, structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out IllegalArgumentException from the nested upcall");
+ }
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullValueForReturnPtr() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStructPointerByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStructPointer_nullValue,
+ FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout), arena.scope());
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultAddr = (MemorySegment)mh.invoke(structSegmt1, structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out NullPointerException in the case of the null value upon return");
+ }
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullValueForReturnStruct() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStructByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStruct_nullValue,
+ FunctionDescriptor.of(structLayout, structLayout, structLayout), arena.scope());
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invoke(allocator, structSegmt1, structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out NullPointerException in the case of the null value upon return");
+ }
+ }
+
+ public void test_nullSegmentForReturnPtr() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("validateReturnNullAddrByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStructPointer_nullSegmt,
+ FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout), arena.scope());
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultAddr = (MemorySegment)mh.invoke(structSegmt1, structSegmt2, upcallFuncAddr);
+ MemorySegment resultSegmt = MemorySegment.ofAddress(resultAddr.address(), structLayout.byteSize(), arena.scope());
+ Assert.assertEquals(resultSegmt.get(JAVA_INT, 0), 11223344);
+ Assert.assertEquals(resultSegmt.get(JAVA_INT, 4), 55667788);
+ }
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void test_nullSegmentForReturnStruct() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStructByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStruct_nullSegmt,
+ FunctionDescriptor.of(structLayout, structLayout, structLayout), arena.scope());
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invoke(allocator, structSegmt1, structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out NullPointerException in the case of the null segment upon return");
+ }
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Heap segment not allowed.*")
+ public void test_heapSegmentForReturnPtr() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStructPointerByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStructPointer_heapSegmt,
+ FunctionDescriptor.of(ADDRESS, ADDRESS, structLayout), arena.scope());
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultAddr = (MemorySegment)mh.invoke(structSegmt1, structSegmt2, upcallFuncAddr);
+ fail("Failed to throw out IllegalArgumentException in the case of the heap segment upon return");
+ }
+ }
+
+ public void test_heapSegmentForReturnStruct() throws Throwable {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ VarHandle intHandle1 = structLayout.varHandle(PathElement.groupElement("elem1"));
+ VarHandle intHandle2 = structLayout.varHandle(PathElement.groupElement("elem2"));
+
+ FunctionDescriptor fd = FunctionDescriptor.of(structLayout, structLayout, structLayout, ADDRESS);
+ MemorySegment functionSymbol = nativeLibLookup.find("add2IntStructs_returnStructByUpcallMH").get();
+ MethodHandle mh = linker.downcallHandle(functionSymbol, fd);
+
+ try (Arena arena = Arena.openConfined()) {
+ MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_add2IntStructs_returnStruct_heapSegmt,
+ FunctionDescriptor.of(structLayout, structLayout, structLayout), arena.scope());
+ SegmentAllocator allocator = SegmentAllocator.nativeAllocator(arena.scope());
+ MemorySegment structSegmt1 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt1, 11223344);
+ intHandle2.set(structSegmt1, 55667788);
+ MemorySegment structSegmt2 = allocator.allocate(structLayout);
+ intHandle1.set(structSegmt2, 99001122);
+ intHandle2.set(structSegmt2, 33445566);
+
+ MemorySegment resultSegmt = (MemorySegment)mh.invoke(allocator, structSegmt1, structSegmt2, upcallFuncAddr);
+ Assert.assertEquals(intHandle1.get(resultSegmt), 110224466);
+ Assert.assertEquals(intHandle2.get(resultSegmt), 89113354);
+ }
+ }
+}
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/MultiUpcallMHTests.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/MultiUpcallMHTests.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/MultiUpcallMHTests.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/MultiUpcallMHTests.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/MultiUpcallThrdsMHTests1.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/MultiUpcallThrdsMHTests1.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/MultiUpcallThrdsMHTests1.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/MultiUpcallThrdsMHTests1.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/MultiUpcallThrdsMHTests2.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/MultiUpcallThrdsMHTests2.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/MultiUpcallThrdsMHTests2.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/MultiUpcallThrdsMHTests2.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/UpcallMHWithMixedSigStruTests.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/UpcallMHWithMixedSigStruTests.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/UpcallMHWithMixedSigStruTests.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/UpcallMHWithMixedSigStruTests.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/UpcallMHWithPrimTests.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/UpcallMHWithPrimTests.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/UpcallMHWithPrimTests.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/UpcallMHWithPrimTests.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/UpcallMHWithStructTests.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/UpcallMHWithStructTests.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/UpcallMHWithStructTests.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/UpcallMHWithStructTests.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/UpcallMethodHandles.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/UpcallMethodHandles.java
similarity index 97%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/UpcallMethodHandles.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/UpcallMethodHandles.java
index ba340a55b29..3dccc71b2cc 100644
--- a/test/functional/Java21andUp/src/org/openj9/test/jep434/upcall/UpcallMethodHandles.java
+++ b/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/UpcallMethodHandles.java
@@ -187,7 +187,13 @@ public class UpcallMethodHandles {
public static final MethodHandle MH_add2IntStructs_returnStruct;
public static final MethodHandle MH_add2IntStructs_returnStruct_throwException;
public static final MethodHandle MH_add2IntStructs_returnStruct_nestedUpcall;
+ public static final MethodHandle MH_add2IntStructs_returnStruct_nullValue;
+ public static final MethodHandle MH_add2IntStructs_returnStruct_nullSegmt;
+ public static final MethodHandle MH_add2IntStructs_returnStruct_heapSegmt;
public static final MethodHandle MH_add2IntStructs_returnStructPointer;
+ public static final MethodHandle MH_add2IntStructs_returnStructPointer_nullValue;
+ public static final MethodHandle MH_add2IntStructs_returnStructPointer_nullSegmt;
+ public static final MethodHandle MH_add2IntStructs_returnStructPointer_heapSegmt;
public static final MethodHandle MH_add3IntStructs_returnStruct;
public static final MethodHandle MH_addLongAndLongsFromStruct;
@@ -391,7 +397,13 @@ public class UpcallMethodHandles {
MH_add2IntStructs_returnStruct = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_add2IntStructs_returnStruct_throwException = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_throwException", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_add2IntStructs_returnStruct_nestedUpcall = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_nestedUpcall", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStruct_nullValue = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_nullValue", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStruct_nullSegmt = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_nullSegmt", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStruct_heapSegmt = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStruct_heapSegmt", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_add2IntStructs_returnStructPointer = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStructPointer", MT_Segmt_MemSegmt_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStructPointer_nullValue = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStructPointer_nullValue", MT_Segmt_MemSegmt_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStructPointer_nullSegmt = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStructPointer_nullSegmt", MT_Segmt_MemSegmt_MemSegmt); //$NON-NLS-1$
+ MH_add2IntStructs_returnStructPointer_heapSegmt = lookup.findStatic(UpcallMethodHandles.class, "add2IntStructs_returnStructPointer_heapSegmt", MT_Segmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_add3IntStructs_returnStruct = lookup.findStatic(UpcallMethodHandles.class, "add3IntStructs_returnStruct", MT_MemSegmt_MemSegmt_MemSegmt); //$NON-NLS-1$
MH_addLongAndLongsFromStruct = lookup.findStatic(UpcallMethodHandles.class, "addLongAndLongsFromStruct", MT_Long_Long_MemSegmt); //$NON-NLS-1$
@@ -1382,6 +1394,20 @@ public static MemorySegment add2IntStructs_returnStruct_nestedUpcall(MemorySegme
return resultSegmt;
}
+ public static MemorySegment add2IntStructs_returnStruct_nullValue(MemorySegment arg1, MemorySegment arg2) {
+ return null;
+ }
+
+ public static MemorySegment add2IntStructs_returnStruct_nullSegmt(MemorySegment arg1, MemorySegment arg2) {
+ return MemorySegment.NULL;
+ }
+
+ public static MemorySegment add2IntStructs_returnStruct_heapSegmt(MemorySegment arg1, MemorySegment arg2) {
+ int intStruct_Elem1 = arg1.get(JAVA_INT, 0) + arg2.get(JAVA_INT, 0);
+ int intStruct_Elem2 = arg1.get(JAVA_INT, 4) + arg2.get(JAVA_INT, 4);
+ return MemorySegment.ofArray(new int[]{intStruct_Elem1, intStruct_Elem2});
+ }
+
public static MemorySegment add2IntStructs_returnStructPointer(MemorySegment arg1Addr, MemorySegment arg2) {
GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
MemorySegment arg1Segmt = MemorySegment.ofAddress(arg1Addr.address(), structLayout.byteSize(), scope);
@@ -1392,6 +1418,22 @@ public static MemorySegment add2IntStructs_returnStructPointer(MemorySegment arg
return arg1Addr;
}
+ public static MemorySegment add2IntStructs_returnStructPointer_nullValue(MemorySegment arg1Addr, MemorySegment arg2) {
+ return null;
+ }
+
+ public static MemorySegment add2IntStructs_returnStructPointer_nullSegmt(MemorySegment arg1Addr, MemorySegment arg2) {
+ return MemorySegment.NULL;
+ }
+
+ public static MemorySegment add2IntStructs_returnStructPointer_heapSegmt(MemorySegment arg1Addr, MemorySegment arg2) {
+ GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"));
+ MemorySegment arg1Segmt = MemorySegment.ofAddress(arg1Addr.address(), structLayout.byteSize(), scope);
+ int intSum_Elem1 = arg1Segmt.get(JAVA_INT, 0) + arg2.get(JAVA_INT, 0);
+ int intSum_Elem2 = arg1Segmt.get(JAVA_INT, 4) + arg2.get(JAVA_INT, 4);
+ return MemorySegment.ofArray(new int[]{intSum_Elem1, intSum_Elem2});
+ }
+
public static MemorySegment add3IntStructs_returnStruct(MemorySegment arg1, MemorySegment arg2) {
GroupLayout structLayout = MemoryLayout.structLayout(JAVA_INT.withName("elem1"), JAVA_INT.withName("elem2"), JAVA_INT.withName("elem3"));
MemorySegment intStructSegmt = MemorySegment.allocateNative(structLayout, scope);
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/valist/ApiTests.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/valist/ApiTests.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/valist/ApiTests.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/valist/ApiTests.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/valist/DowncallTests.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/valist/DowncallTests.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/valist/DowncallTests.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/valist/DowncallTests.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/valist/UpcallTests.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/valist/UpcallTests.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/valist/UpcallTests.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/valist/UpcallTests.java
diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep434/valist/VaListUpcallMethodHandles.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/valist/VaListUpcallMethodHandles.java
similarity index 100%
rename from test/functional/Java21andUp/src/org/openj9/test/jep434/valist/VaListUpcallMethodHandles.java
rename to test/functional/Java21andUp/src/org/openj9/test/jep442/valist/VaListUpcallMethodHandles.java