From 5929664b380d058e27a93930c9bfa9fe06661019 Mon Sep 17 00:00:00 2001 From: ChengJin01 Date: Fri, 14 Jul 2023 00:21:36 -0400 Subject: [PATCH] [FFI/Jtreg_JDK21] Detect the downcall linker option in upcall The changes aim to capture the linker option intended for the trivial downcall during the upcall given the option is only used to enable the trivial downcall without upcall involved. Fixes: #17820 Note: The changes with related test cases cover two aspects separately: [1] remove the VMAccess in the downcall for the benefit of the JIT. [2] capture the invalid linker option in upcall dispatcher and throw out the exception after jumping back to the downcall site. Signed-off-by: ChengJin01 --- .../foreign/abi/InternalDowncallHandler.java | 220 +++++++----------- .../foreign/abi/InternalUpcallHandler.java | 45 +--- .../foreign/abi/LayoutStrPreprocessor.java | 38 +-- .../foreign/abi/UpcallMHMetaData.java | 30 +-- runtime/nls/j9vm/j9vm.nls | 7 + runtime/oti/j9nonbuilder.h | 3 + runtime/tests/clinkerffi/CMakeLists.txt | 2 + runtime/tests/clinkerffi/downcall.c | 12 + runtime/tests/clinkerffi/module.xml | 2 + runtime/tests/clinkerffi/upcall.c | 15 ++ runtime/vm/BytecodeInterpreter.hpp | 42 +++- runtime/vm/UpcallVMHelpers.cpp | 14 ++ runtime/vm/bindnatv.cpp | 6 +- runtime/vm/vmthread.cpp | 3 + .../jep442/downcall/PrimitiveTypeTests1.java | 9 + .../jep442/downcall/PrimitiveTypeTests2.java | 9 + .../jep442/upcall/InvalidUpCallTests.java | 16 +- .../jep442/upcall/UpcallMethodHandles.java | 7 + 18 files changed, 247 insertions(+), 233 deletions(-) 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 1a05927c054..830558b9af8 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 @@ -1,4 +1,4 @@ -/*[INCLUDE-IF JAVA_SPEC_VERSION >= 20]*/ +/*[INCLUDE-IF JAVA_SPEC_VERSION >= 21]*/ /******************************************************************************* * Copyright IBM Corp. and others 2022 * @@ -24,9 +24,9 @@ import java.util.HashMap; import java.util.List; -/*[IF JAVA_SPEC_VERSION >= 20]*/ +/*[IF JAVA_SPEC_VERSION >= 21]*/ import java.util.Objects; -/*[ENDIF] JAVA_SPEC_VERSION >= 20 */ +/*[ENDIF] JAVA_SPEC_VERSION >= 21 */ import java.util.concurrent.ConcurrentHashMap; import java.util.Set; @@ -37,27 +37,20 @@ import static java.lang.invoke.MethodType.methodType; import java.lang.invoke.WrongMethodTypeException; -/*[IF JAVA_SPEC_VERSION >= 20]*/ /*[IF JAVA_SPEC_VERSION >= 21]*/ import java.lang.foreign.AddressLayout; -/*[ENDIF] JAVA_SPEC_VERSION >= 21 */ import java.lang.foreign.Arena; import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; -/*[IF JAVA_SPEC_VERSION >= 21]*/ import java.lang.foreign.MemorySegment.Scope; -/*[ENDIF] JAVA_SPEC_VERSION >= 21 */ import java.lang.foreign.SegmentAllocator; -/*[IF JAVA_SPEC_VERSION == 20]*/ -import java.lang.foreign.SegmentScope; -/*[ENDIF] JAVA_SPEC_VERSION == 20 */ import java.lang.foreign.ValueLayout; import jdk.internal.foreign.Utils; import jdk.internal.foreign.abi.LinkerOptions; import jdk.internal.foreign.MemorySessionImpl; -/*[ELSE] JAVA_SPEC_VERSION >= 20 */ +/*[ELSE] JAVA_SPEC_VERSION >= 21 */ import jdk.incubator.foreign.Addressable; import jdk.incubator.foreign.FunctionDescriptor; import jdk.incubator.foreign.GroupLayout; @@ -68,14 +61,12 @@ import jdk.incubator.foreign.ResourceScope.Handle; import jdk.incubator.foreign.SegmentAllocator; import jdk.incubator.foreign.ValueLayout; -/*[ENDIF] JAVA_SPEC_VERSION >= 20 */ +/*[ENDIF] JAVA_SPEC_VERSION >= 21 */ -/*[IF JAVA_SPEC_VERSION >= 20]*/ -import static java.lang.foreign.ValueLayout.*; /*[IF JAVA_SPEC_VERSION >= 21]*/ +import static java.lang.foreign.ValueLayout.*; import static jdk.internal.foreign.abi.SharedUtils.*; /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ -/*[ENDIF] JAVA_SPEC_VERSION >= 20 */ /** * The internal implementation of downcall handler wraps up a method handle enabling @@ -86,9 +77,9 @@ public class InternalDowncallHandler { private final MethodType funcMethodType; private final FunctionDescriptor funcDescriptor; - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ private final LinkerOptions linkerOpts; - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ private long cifNativeThunkAddr; private long argTypesAddr; private MemoryLayout[] argLayoutArray; @@ -100,8 +91,6 @@ public class InternalDowncallHandler { */ /*[IF JAVA_SPEC_VERSION >= 21]*/ private Set memArgScopeSet; - /*[ELSEIF JAVA_SPEC_VERSION == 20]*/ - private Set memArgScopeSet; /*[ELSE] JAVA_SPEC_VERSION >= 21 */ private Set memArgScopeSet; /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ @@ -124,11 +113,11 @@ public class InternalDowncallHandler { private static final MethodHandle intToLongArgFilter; private static final MethodHandle floatToLongArgFilter; private static final MethodHandle doubleToLongArgFilter; - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ private MethodHandle memSegmtOfPtrToLongArgFilter; - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ private MethodHandle memAddrToLongArgFilter; - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ private MethodHandle memSegmtToLongArgFilter; /* Return value filters that convert the Long object to the primitive types/MemoryAddress/MemorySegment. */ @@ -141,20 +130,20 @@ public class InternalDowncallHandler { private static final MethodHandle longObjToLongRetFilter; private static final MethodHandle longObjToFloatRetFilter; private static final MethodHandle longObjToDoubleRetFilter; - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ private MethodHandle longObjToMemSegmtRetFilter; - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ private static final MethodHandle longObjToMemAddrRetFilter; - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ private static final MethodHandle objToMemSegmtRetFilter; private static synchronized native void resolveRequiredFields(); private native void initCifNativeThunkData(String[] argLayouts, String retLayout, boolean newArgTypes, int varArgIndex); - /*[IF JAVA_SPEC_VERSION >= 20]*/ - private native long invokeNative(long returnStateMemAddr, long returnStructMemAddr, long functionAddress, long calloutThunk, long[] argValues); - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[IF JAVA_SPEC_VERSION >= 21]*/ + private native long invokeNative(boolean isInTrivialDownCall, long returnStateMemAddr, long returnStructMemAddr, long functionAddress, long calloutThunk, long[] argValues); + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ private native long invokeNative(long returnStructMemAddr, long functionAddress, long calloutThunk, long[] argValues); - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ private static final class PrivateClassLock { PrivateClassLock() {} @@ -239,8 +228,6 @@ private static final long floatToLongArg(float argValue) { */ /*[IF JAVA_SPEC_VERSION >= 21]*/ private final void addMemArgScope(Scope memArgScope) throws IllegalStateException - /*[ELSEIF JAVA_SPEC_VERSION == 20]*/ - private final void addMemArgScope(SegmentScope memArgScope) throws IllegalStateException /*[ELSE] JAVA_SPEC_VERSION >= 21 */ private final void addMemArgScope(ResourceScope memArgScope) throws IllegalStateException /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ @@ -254,8 +241,6 @@ private final void addMemArgScope(ResourceScope memArgScope) throws IllegalState /* Validate the memory related scope to ensure that it is kept alive during the downcall. */ /*[IF JAVA_SPEC_VERSION >= 21]*/ private void validateMemScope(Scope memScope) throws IllegalStateException - /*[ELSEIF JAVA_SPEC_VERSION == 20]*/ - private void validateMemScope(SegmentScope memScope) throws IllegalStateException /*[ELSE] JAVA_SPEC_VERSION >= 21 */ private void validateMemScope(ResourceScope memScope) throws IllegalStateException /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ @@ -265,7 +250,7 @@ private void validateMemScope(ResourceScope memScope) throws IllegalStateExcepti } } - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ /* Intended for memSegmtOfPtrToLongArgFilter that converts the memory segment * of the passed-in pointer argument to long. */ @@ -274,23 +259,23 @@ private final long memSegmtOfPtrToLongArg(MemorySegment argValue) throws Illegal addMemArgScope(argValue.scope()); return argValue.address(); } - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ /* Intended for memAddrToLongArgFilter that converts the memory address to long. */ private final long memAddrToLongArg(MemoryAddress argValue) throws IllegalStateException { UpcallMHMetaData.validateNativeArgRetAddrOfPtr(argValue); addMemArgScope(argValue.scope()); return argValue.toRawLongValue(); } - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ /* Intended for memSegmtToLongArgFilter that converts the memory segment to long. */ private final long memSegmtToLongArg(MemorySegment argValue) throws IllegalStateException { addMemArgScope(argValue.scope()); - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ return UpcallMHMetaData.getNativeArgRetSegment(argValue).address(); - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ return UpcallMHMetaData.getNativeArgRetSegment(argValue).address().toRawLongValue(); - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ } /* Intended for longObjToVoidRetFilter that converts the Long object to void. */ @@ -341,31 +326,22 @@ private static final double longObjToDoubleRet(Object retValue) { return Double.longBitsToDouble(tmpValue); } - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ /* Intended for longObjToMemSegmtRetFilter that converts the Long object to the memory segment. */ private MemorySegment longObjToMemSegmtRet(Object retValue) { long tmpValue = ((Long)retValue).longValue(); - /*[IF JAVA_SPEC_VERSION >= 21]*/ /* Return the created segment with the given pointer address when the address is valid * against the specified target layout if exists. */ return UpcallMHMetaData.getArgRetAlignedSegmentOfPtr(tmpValue, realReturnLayout); - /*[ELSE] JAVA_SPEC_VERSION >= 21 */ - /* Utils.pointeeSize() introduced in JDK20 calls isUnbounded() for the ADDRESS layout - * to determine whether the specified address layout is an unbounded address or not. - * For an unbounded address, it returns Long.MAX_VALUE for direct access; otherwise, - * it returns zero in which case the address can't be directly accessed. - */ - return MemorySegment.ofAddress(tmpValue, Utils.pointeeSize(realReturnLayout)); - /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ } - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ /* Intended for longObjToMemAddrRetFilter that converts the Long object to the memory address. */ private static final MemoryAddress longObjToMemAddrRet(Object retValue) { long tmpValue = ((Long)retValue).longValue(); return MemoryAddress.ofLong(tmpValue); } - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ /* Intended for objToMemSegmtRetFilter that simply casts the passed-in object to the memory segment * given the requested the memory segment is directly returned from runNativeMethod(). @@ -376,7 +352,7 @@ private static final MemorySegment objToMemSegmtRet(Object retValue) { return (MemorySegment)retValue; } - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ /** * The internal constructor is responsible for mapping the preprocessed layouts * of return type & argument types to the underlying prep_cif in native. @@ -386,7 +362,7 @@ private static final MemorySegment objToMemSegmtRet(Object retValue) { * @param options the linker options indicating additional linking requirements to the linker */ public InternalDowncallHandler(MethodType functionMethodType, FunctionDescriptor functionDescriptor, LinkerOptions options) - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ /** * The internal constructor is responsible for mapping the preprocessed layouts * of return type & argument types to the underlying prep_cif in native. @@ -395,7 +371,7 @@ public InternalDowncallHandler(MethodType functionMethodType, FunctionDescriptor * @param funcDesc the function descriptor of the specified native function */ public InternalDowncallHandler(MethodType functionMethodType, FunctionDescriptor functionDescriptor) - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ { realReturnLayout = functionDescriptor.returnLayout().orElse(null); // set to null for void List argLayouts = functionDescriptor.argumentLayouts(); @@ -414,9 +390,9 @@ public InternalDowncallHandler(MethodType functionMethodType, FunctionDescriptor funcMethodType = functionMethodType; funcDescriptor = functionDescriptor; - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ linkerOpts = options; - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ cifNativeThunkAddr = 0; argTypesAddr = 0; @@ -427,12 +403,12 @@ public InternalDowncallHandler(MethodType functionMethodType, FunctionDescriptor /*[ENDIF] JAVA_SPEC_VERSION == 17 */ try { - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ longObjToMemSegmtRetFilter = lookup.bind(this, "longObjToMemSegmtRet", methodType(MemorySegment.class, Object.class)); memSegmtOfPtrToLongArgFilter = lookup.bind(this, "memSegmtOfPtrToLongArg", methodType(long.class, MemorySegment.class)); - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ memAddrToLongArgFilter = lookup.bind(this, "memAddrToLongArg", methodType(long.class, MemoryAddress.class)); - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ memSegmtToLongArgFilter = lookup.bind(this, "memSegmtToLongArg", methodType(long.class, MemorySegment.class)); } catch (ReflectiveOperationException e) { throw new InternalError(e); @@ -475,11 +451,11 @@ private void generateAdapter() { * e.g. C_INT without the layout name = b32[abi/kind=INT] * and C_INT with the layout name = b32(int)[abi/kind=INT,layout/name=int] */ - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ int varArgIdx = LayoutStrPreprocessor.getVarArgIndex(funcDescriptor, linkerOpts); - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ int varArgIdx = LayoutStrPreprocessor.getVarArgIndex(funcDescriptor); - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ String argRetLayoutStrsLine = ((varArgIdx >= 0) ? varArgIdx : "") + argLayoutStrsLine.toString() + retLayoutStr; Integer argRetLayoutStrLineHash = Integer.valueOf(argRetLayoutStrsLine.hashCode()); Integer argLayoutStrsLineHash = Integer.valueOf(argLayoutStrsLine.toString().hashCode()); @@ -513,17 +489,11 @@ private void generateAdapter() { */ public MethodHandle getBoundMethodHandle() { try { - /*[IF JAVA_SPEC_VERSION >= 20]*/ - Class downcallAddrClass = MemorySegment.class; - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ - Class downcallAddrClass = Addressable.class; - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ - - /*[IF JAVA_SPEC_VERSION >= 20]*/ - MethodType nativeMethodType = methodType(Object.class, downcallAddrClass, SegmentAllocator.class, MemorySegment.class, long[].class); - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ - MethodType nativeMethodType = methodType(Object.class, downcallAddrClass, SegmentAllocator.class, long[].class); - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[IF JAVA_SPEC_VERSION >= 21]*/ + MethodType nativeMethodType = methodType(Object.class, MemorySegment.class, SegmentAllocator.class, MemorySegment.class, long[].class); + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ + MethodType nativeMethodType = methodType(Object.class, Addressable.class, SegmentAllocator.class, long[].class); + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ MethodHandle boundHandle = lookup.bind(this, "runNativeMethod", nativeMethodType); @@ -539,15 +509,15 @@ public MethodHandle getBoundMethodHandle() { private MethodHandle permuteMH(MethodHandle targetHandle, MethodType nativeMethodType) throws NullPointerException, WrongMethodTypeException { Class[] argTypeClasses = nativeMethodType.parameterArray(); int nativeArgCount = argTypeClasses.length; - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ /* Skip the native function address, the segment allocator and the segment * for the execution state to the native function's arguments. */ int argPosition = 3; - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ /* Skip the native function address and the segment allocator to the native function's arguments. */ int argPosition = 2; - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ MethodHandle resultHandle = targetHandle.asCollector(argPosition, long[].class, nativeArgCount); /* Convert the argument values to long via filterArguments() prior to the native call. */ @@ -561,14 +531,14 @@ private MethodHandle permuteMH(MethodHandle targetHandle, MethodType nativeMetho MethodHandle retFilter = getReturnValFilter(nativeMethodType.returnType()); resultHandle = MethodHandles.filterReturnValue(resultHandle, retFilter); - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ /* Set a placeholder with a NULL segment if there is no request * for the execution state from downcall in the linker options. */ if (!linkerOpts.hasCapturedCallState()) { resultHandle = MethodHandles.insertArguments(resultHandle, 2, MemorySegment.NULL); } - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ return resultHandle; } @@ -599,20 +569,14 @@ private MethodHandle getArgumentFilter(Class argTypeClass, MemoryLayout argLa } else /*[ENDIF] JAVA_SPEC_VERSION == 17 */ if (argTypeClass == MemorySegment.class) { - /*[IF JAVA_SPEC_VERSION >= 20]*/ /*[IF JAVA_SPEC_VERSION >= 21]*/ /* The address layout for pointer might come with different representations of ADDRESS. * Note: AddressLayout is introduced in JDK21 to replace OfAddress. */ - if (argLayout instanceof AddressLayout) - /*[ELSE] JAVA_SPEC_VERSION >= 21 */ - /* The address layout for pointer might come with different representations of ADDRESS. */ - if (argLayout instanceof OfAddress) - /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ - { + if (argLayout instanceof AddressLayout) { filterMH = memSegmtOfPtrToLongArgFilter; } else - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ { filterMH = memSegmtToLongArgFilter; } @@ -651,24 +615,17 @@ private MethodHandle getReturnValFilter(Class returnType) { } else /*[ENDIF] JAVA_SPEC_VERSION == 17 */ if (returnType == MemorySegment.class) { - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ /* A returned pointer is wrapped as a zero-sized memory segment given all * MemoryAdress related classes are removed against the latest APIs as - * specified in JDK20+. - */ - /*[IF JAVA_SPEC_VERSION >= 21]*/ - /* The address layout for pointer might come with different representations of ADDRESS. + * specified in JDK20+ in which case the address layout for pointer might + * come with different representations of ADDRESS. * Note: AddressLayout is introduced in JDK21 to replace OfAddress. */ - if ((realReturnLayout != null) && (realReturnLayout instanceof AddressLayout)) - /*[ELSE] JAVA_SPEC_VERSION >= 21 */ - /* The address layout for pointer might come with different representations of ADDRESS. */ - if ((realReturnLayout != null) && (realReturnLayout instanceof OfAddress)) - /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ - { + if ((realReturnLayout != null) && (realReturnLayout instanceof AddressLayout)) { filterMH = longObjToMemSegmtRetFilter; } else - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ { filterMH = objToMemSegmtRetFilter; } @@ -677,23 +634,13 @@ private MethodHandle getReturnValFilter(Class returnType) { return filterMH; } - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ /* Set up the dependency from the sessions of memory related arguments to the specified session * so as to keep these arguments' session alive till the specified session is closed. */ - /*[IF JAVA_SPEC_VERSION >= 21]*/ - private void SetDependency(Scope session) - /*[ELSE] JAVA_SPEC_VERSION >= 21 */ - private void SetDependency(SegmentScope session) - /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ - { + private void SetDependency(Scope session) { Objects.requireNonNull(session); - /*[IF JAVA_SPEC_VERSION >= 21]*/ - for (Scope memArgSession : memArgScopeSet) - /*[ELSE] JAVA_SPEC_VERSION >= 21 */ - for (SegmentScope memArgSession : memArgScopeSet) - /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ - { + for (Scope memArgSession : memArgScopeSet) { if (memArgSession.isAlive()) { MemorySessionImpl memArgSessionImpl = (MemorySessionImpl)memArgSession; Thread owner = memArgSessionImpl.ownerThread(); @@ -707,7 +654,7 @@ private void SetDependency(SegmentScope session) } } } - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ /* Occupy the scope by setting the scope's state in downcall so as to keep these * arguments' scope alive till the specified session is closed. */ @@ -741,37 +688,37 @@ private void releaseScope() { } } } - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ /* Return the valid downcall related memory address by doing the validity check * on the address's scope in OpenJ9 since the related code and APIs were adjusted * in JDK20 in which case the scope check on the downcall in address() in OpenJDK * was entirely removed. */ - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ private long getValidDowncallMemAddr(MemorySegment memAddr) { validateMemScope(memAddr.scope()); return memAddr.address(); } - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ private long getValidDowncallMemAddr(Addressable memAddr) { validateMemScope(memAddr.address().scope()); return memAddr.address().toRawLongValue(); } - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ /* The method (bound by the method handle to the native code) intends to invoke the C function via the inlined code. */ - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ Object runNativeMethod(MemorySegment downcallAddr, SegmentAllocator segmtAllocator, MemorySegment stateSegmt, long[] args) throws IllegalArgumentException, IllegalStateException - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ Object runNativeMethod(Addressable downcallAddr, SegmentAllocator segmtAllocator, long[] args) throws IllegalArgumentException, IllegalStateException - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ { - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ if (downcallAddr == MemorySegment.NULL) - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ if (downcallAddr.address() == MemoryAddress.NULL) - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ { throw new IllegalArgumentException("A non-null memory address is expected for downcall"); } @@ -791,44 +738,39 @@ Object runNativeMethod(Addressable downcallAddr, SegmentAllocator segmtAllocator if (retStruSegmt == null) { throw new OutOfMemoryError("Failed to allocate native memory for the returned memory segment"); } - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ retMemAddr = retStruSegmt.address(); - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ retMemAddr = retStruSegmt.address().toRawLongValue(); - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ } /* Add the scopes of the downcall related memory addresses to the set * to ensure they are kept alive till the downcall is finished. */ - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ addMemArgScope(downcallAddr.scope()); addMemArgScope(stateSegmt.scope()); - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ addMemArgScope(downcallAddr.address().scope()); - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ - long returnVal = 0; + long returnVal; /* The scope associated with memory specific arguments must be kept alive * during the downcall since JDK17, including the downcall adddress. * - *Note: memArgScopeSet is not empty with the downcall address added to the set. + * Note: memArgScopeSet is not empty with the downcall address added to the set. */ - /*[IF JAVA_SPEC_VERSION >= 20]*/ /*[IF JAVA_SPEC_VERSION >= 21]*/ - try (Arena arena = Arena.ofConfined()) - /*[ELSE] JAVA_SPEC_VERSION >= 21 */ - try (Arena arena = Arena.openConfined()) - /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ - { + try (Arena arena = Arena.ofConfined()) { SetDependency(arena.scope()); - returnVal = invokeNative(getValidDowncallMemAddr(stateSegmt), retMemAddr, getValidDowncallMemAddr(downcallAddr), cifNativeThunkAddr, args); + returnVal = invokeNative(linkerOpts.isTrivial(), getValidDowncallMemAddr(stateSegmt), retMemAddr, getValidDowncallMemAddr(downcallAddr), cifNativeThunkAddr, args); } - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ acquireScope(); returnVal = invokeNative(retMemAddr, getValidDowncallMemAddr(downcallAddr), cifNativeThunkAddr, args); releaseScope(); - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ /* This struct specific MemorySegment object returns to the current thread in the multithreading environment, * in which case the native invocations from threads end up with distinct returned structs. diff --git a/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/InternalUpcallHandler.java b/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/InternalUpcallHandler.java index 68bd70b0324..f8e6894a507 100644 --- a/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/InternalUpcallHandler.java +++ b/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/InternalUpcallHandler.java @@ -1,4 +1,4 @@ -/*[INCLUDE-IF JAVA_SPEC_VERSION >= 20]*/ +/*[INCLUDE-IF JAVA_SPEC_VERSION >= 21]*/ /******************************************************************************* * Copyright IBM Corp. and others 2022 * @@ -32,25 +32,16 @@ import java.util.List; import java.util.Set; -/*[IF JAVA_SPEC_VERSION >= 20]*/ /*[IF JAVA_SPEC_VERSION >= 21]*/ import java.lang.foreign.AddressLayout; import java.lang.foreign.Arena; -/*[ENDIF] JAVA_SPEC_VERSION >= 21 */ import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; -/*[IF JAVA_SPEC_VERSION >= 21]*/ import jdk.internal.foreign.abi.LinkerOptions; -/*[ELSE] JAVA_SPEC_VERSION >= 21 */ -import java.lang.foreign.SegmentScope; -/*[ENDIF] JAVA_SPEC_VERSION >= 21 */ import java.lang.foreign.ValueLayout; -/*[IF JAVA_SPEC_VERSION == 20]*/ -import java.lang.foreign.ValueLayout.OfAddress; -/*[ENDIF] JAVA_SPEC_VERSION == 20 */ -/*[ELSE] JAVA_SPEC_VERSION >= 20 */ +/*[ELSE] JAVA_SPEC_VERSION >= 21 */ import jdk.incubator.foreign.FunctionDescriptor; import jdk.incubator.foreign.GroupLayout; import jdk.incubator.foreign.MemoryAddress; @@ -58,7 +49,7 @@ import jdk.incubator.foreign.MemorySegment; import jdk.incubator.foreign.ResourceScope; import jdk.incubator.foreign.ValueLayout; -/*[ENDIF] JAVA_SPEC_VERSION >= 20 */ +/*[ENDIF] JAVA_SPEC_VERSION >= 21 */ /** * The internal implementation of upcall handler wraps up an upcall handle @@ -75,19 +66,17 @@ public final class InternalUpcallHandler { static final Lookup lookup = MethodHandles.lookup(); /* The argument filters intended to validate the pointer/struct arguments/return value of the upcall method. */ - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ private static final MethodHandle argRetSegmtOfPtrFilter; - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ private static final MethodHandle argRetAddrOfPtrFilter; - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ private static final MethodHandle argRetSegmtFilter; static { try { /*[IF JAVA_SPEC_VERSION >= 21]*/ argRetSegmtOfPtrFilter = lookup.findStatic(InternalUpcallHandler.class, "argRetSegmtOfPtr", methodType(MemorySegment.class, MemorySegment.class, MemoryLayout.class)); - /*[ELSEIF JAVA_SPEC_VERSION == 20]*/ - argRetSegmtOfPtrFilter = lookup.findStatic(InternalUpcallHandler.class, "argRetSegmtOfPtr", methodType(MemorySegment.class, MemorySegment.class)); /*[ELSE] JAVA_SPEC_VERSION >= 21 */ argRetAddrOfPtrFilter = lookup.findStatic(InternalUpcallHandler.class, "argRetAddrOfPtr", methodType(MemoryAddress.class, MemoryAddress.class)); /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ @@ -105,11 +94,6 @@ private static MemorySegment argRetSegmtOfPtr(MemorySegment argValue, MemoryLayo UpcallMHMetaData.validateNativeArgRetSegmentOfPtr(argValue); return UpcallMHMetaData.getArgRetAlignedSegmentOfPtr(argValue.address(), layout); } - /*[ELSEIF JAVA_SPEC_VERSION == 20]*/ - private static MemorySegment argRetSegmtOfPtr(MemorySegment argValue) throws IllegalStateException { - UpcallMHMetaData.validateNativeArgRetSegmentOfPtr(argValue); - return argValue; - } /*[ELSE] JAVA_SPEC_VERSION >= 21 */ private static MemoryAddress argRetAddrOfPtr(MemoryAddress argValue) throws IllegalStateException { UpcallMHMetaData.validateNativeArgRetAddrOfPtr(argValue); @@ -136,17 +120,6 @@ private static MemorySegment argRetSegmt(MemorySegment argValue) throws IllegalS * @param options the LinkerOptions indicating additional linking requirements to the linker */ public InternalUpcallHandler(MethodHandle target, MethodType mt, FunctionDescriptor cDesc, Arena arena, LinkerOptions options) - /*[ELSEIF JAVA_SPEC_VERSION == 20]*/ - /** - * The constructor creates an upcall handler specific to the requested java method - * by generating a native thunk in upcall on a given platform. - * - * @param target the target method handle in upcall - * @param mt the method type of the target method handle - * @param cDesc the function descriptor of the target method handle - * @param scope the segment scope related to the upcall handler - */ - public InternalUpcallHandler(MethodHandle target, MethodType mt, FunctionDescriptor cDesc, SegmentScope scope) /*[ELSE] JAVA_SPEC_VERSION >= 21 */ /** * The constructor creates an upcall handler specific to the requested java method @@ -196,8 +169,6 @@ public long upcallThunkAddr() { */ /*[IF JAVA_SPEC_VERSION >= 21]*/ private long getUpcallThunkAddr(MethodHandle target, Arena arena, LinkerOptions options) - /*[ELSEIF JAVA_SPEC_VERSION == 20]*/ - private long getUpcallThunkAddr(MethodHandle target, SegmentScope scope) /*[ELSE] JAVA_SPEC_VERSION >= 21 */ private long getUpcallThunkAddr(MethodHandle target, ResourceScope scope) /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ @@ -275,10 +246,6 @@ else if (argLayout instanceof ValueLayout) { if (argLayout instanceof AddressLayout) { filterMH = MethodHandles.insertArguments(argRetSegmtOfPtrFilter, 1, argLayout); } else - /*[ELSEIF JAVA_SPEC_VERSION == 20]*/ - if (argLayout instanceof OfAddress) { - filterMH = argRetSegmtOfPtrFilter; - } else /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ { /* The filter for primitive is a placeholder without any conversion involved. */ diff --git a/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/LayoutStrPreprocessor.java b/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/LayoutStrPreprocessor.java index a1a64420ba1..63b22136184 100644 --- a/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/LayoutStrPreprocessor.java +++ b/jcl/src/java.base/share/classes/openj9/internal/foreign/abi/LayoutStrPreprocessor.java @@ -1,4 +1,4 @@ -/*[INCLUDE-IF JAVA_SPEC_VERSION >= 20]*/ +/*[INCLUDE-IF JAVA_SPEC_VERSION >= 21]*/ /******************************************************************************* * Copyright IBM Corp. and others 2022 * @@ -24,7 +24,7 @@ import java.util.List; -/*[IF JAVA_SPEC_VERSION >= 20]*/ +/*[IF JAVA_SPEC_VERSION >= 21]*/ import java.lang.foreign.FunctionDescriptor; import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; @@ -33,7 +33,7 @@ import java.lang.foreign.SequenceLayout; import java.lang.foreign.ValueLayout; import jdk.internal.foreign.abi.LinkerOptions; -/*[ELSE] JAVA_SPEC_VERSION >= 20 */ +/*[ELSE] JAVA_SPEC_VERSION >= 21 */ import jdk.incubator.foreign.CLinker.TypeKind; import static jdk.incubator.foreign.CLinker.TypeKind.*; import jdk.incubator.foreign.FunctionDescriptor; @@ -42,7 +42,7 @@ import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.SequenceLayout; import jdk.incubator.foreign.ValueLayout; -/*[ENDIF] JAVA_SPEC_VERSION >= 20 */ +/*[ENDIF] JAVA_SPEC_VERSION >= 21 */ /** * The methods of the class are used to preprocess the layout specified in the function @@ -87,11 +87,11 @@ final class LayoutStrPreprocessor { /*[ENDIF] JAVA_SPEC_VERSION == 17 */ /* Get the index of the variadic argument layout in the function descriptor if exists. */ - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ static int getVarArgIndex(FunctionDescriptor funcDesc, LinkerOptions options) - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ static int getVarArgIndex(FunctionDescriptor funcDesc) - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ { List argLayouts = funcDesc.argumentLayouts(); int argLayoutsSize = argLayouts.size(); @@ -101,11 +101,11 @@ static int getVarArgIndex(FunctionDescriptor funcDesc) int varArgIdx = -1; for (int argIndex = 0; argIndex < argLayoutsSize; argIndex++) { - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ if (options.isVarargsIndex(argIndex)) - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ if (argLayouts.get(argIndex).attribute(VARARGS_ATTR_NAME).isPresent()) - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ { varArgIdx = argIndex; break; @@ -201,11 +201,11 @@ private static StringBuilder preprocessLayout(MemoryLayout targetLayout, boolean targetLayoutString.append(getPrimitiveTypeSymbol(valueLayout)); } else if (targetLayout instanceof SequenceLayout arrayLayout) { /* Intended for nested arrays. */ MemoryLayout elementLayout = arrayLayout.elementLayout(); - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ long elementCount = arrayLayout.elementCount(); - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ long elementCount = arrayLayout.elementCount().getAsLong(); - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ /* The padding bytes is required in the native signature for upcall thunk generation. */ if (isPaddingLayout(elementLayout) && !isDownCall) { @@ -243,15 +243,15 @@ private static StringBuilder preprocessLayout(MemoryLayout targetLayout, boolean /* Determine whether the specfied layout is a padding layout or not. */ private static boolean isPaddingLayout(MemoryLayout targetLayout) { - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ return targetLayout instanceof PaddingLayout; - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ return targetLayout.isPadding(); - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ } /* Map the specified primitive layout's kind to the symbol for primitive type in VM Spec. */ - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ private static String getPrimitiveTypeSymbol(ValueLayout targetLayout) { Class javaType = targetLayout.carrier(); String typeSymbol = ""; @@ -274,7 +274,7 @@ private static String getPrimitiveTypeSymbol(ValueLayout targetLayout) { return typeSymbol; } - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ private static String getPrimitiveTypeSymbol(ValueLayout targetLayout) { /* Extract the kind from the specified layout with the ATTR_NAME "abi/kind". * e.g. b32[abi/kind=INT] @@ -313,5 +313,5 @@ private static String getPrimitiveTypeSymbol(ValueLayout targetLayout) { return typeSymbol; } - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ } 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 babdf95372f..407bb558881 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 @@ -1,4 +1,4 @@ -/*[INCLUDE-IF JAVA_SPEC_VERSION >= 20]*/ +/*[INCLUDE-IF JAVA_SPEC_VERSION >= 21]*/ /******************************************************************************* * Copyright IBM Corp. and others 2022 * @@ -28,27 +28,21 @@ import java.util.Optional; /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ -/*[IF JAVA_SPEC_VERSION >= 20]*/ /*[IF JAVA_SPEC_VERSION >= 21]*/ import java.lang.foreign.AddressLayout; -/*[ENDIF] JAVA_SPEC_VERSION >= 21 */ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -/*[IF JAVA_SPEC_VERSION >= 21]*/ import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment.Scope; import jdk.internal.foreign.Utils; import jdk.internal.foreign.abi.LinkerOptions; -/*[ELSE] JAVA_SPEC_VERSION >= 21 */ -import java.lang.foreign.SegmentScope; -/*[ENDIF] JAVA_SPEC_VERSION >= 21 */ import jdk.internal.foreign.MemorySessionImpl; -/*[ELSE] JAVA_SPEC_VERSION >= 20 */ +/*[ELSE] JAVA_SPEC_VERSION >= 21 */ 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 */ +/*[ENDIF] JAVA_SPEC_VERSION >= 21 */ /** * The meta data consists of the callee MH and a cache of 2 elements for MH resolution, @@ -78,8 +72,6 @@ final class UpcallMHMetaData { /*[IF JAVA_SPEC_VERSION >= 21]*/ private Scope scope; - /*[ELSEIF JAVA_SPEC_VERSION == 20]*/ - private SegmentScope scope; /*[ELSE] JAVA_SPEC_VERSION >= 21 */ private ResourceScope scope; /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ @@ -96,8 +88,6 @@ final class UpcallMHMetaData { /*[IF JAVA_SPEC_VERSION >= 21]*/ UpcallMHMetaData(MethodHandle targetHandle, int nativeArgCount, Scope scope, LinkerOptions options) - /*[ELSEIF JAVA_SPEC_VERSION == 20]*/ - UpcallMHMetaData(MethodHandle targetHandle, int nativeArgCount, SegmentScope scope) /*[ELSE] JAVA_SPEC_VERSION >= 21 */ UpcallMHMetaData(MethodHandle targetHandle, int nativeArgCount, ResourceScope scope) /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ @@ -112,8 +102,6 @@ final class UpcallMHMetaData { */ /*[IF JAVA_SPEC_VERSION >= 21]*/ this.scope = ((scope != null) && (((MemorySessionImpl)scope).ownerThread() != null)) ? scope : Arena.global().scope(); - /*[ELSEIF JAVA_SPEC_VERSION == 20]*/ - this.scope = ((scope != null) && (((MemorySessionImpl)scope).ownerThread() != null)) ? scope : SegmentScope.global(); /*[ELSE] JAVA_SPEC_VERSION >= 21 */ this.scope = ((scope != null) && (scope.ownerThread() != null)) ? scope : ResourceScope.globalScope(); /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ @@ -144,7 +132,7 @@ static MemorySegment getArgRetAlignedSegmentOfPtr(long addrValue, MemoryLayout l * Note: * The method is shared in downcall and upcall. */ - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ static void validateNativeArgRetSegmentOfPtr(MemorySegment argRetSegmentOfPtr) { if (argRetSegmentOfPtr == null) { throw new NullPointerException("A null pointer is not allowed."); @@ -153,7 +141,7 @@ static void validateNativeArgRetSegmentOfPtr(MemorySegment argRetSegmentOfPtr) { throw new IllegalArgumentException("Heap segment not allowed: " + argRetSegmentOfPtr); } } - /*[ELSE] JAVA_SPEC_VERSION >= 20 */ + /*[ELSE] JAVA_SPEC_VERSION >= 21 */ static void validateNativeArgRetAddrOfPtr(MemoryAddress argRetAddrOfPtr) { if (argRetAddrOfPtr == null) { throw new NullPointerException("A null pointer is not allowed."); @@ -162,7 +150,7 @@ static void validateNativeArgRetAddrOfPtr(MemoryAddress argRetAddrOfPtr) { throw new IllegalArgumentException("A heap address is not allowed: " + argRetAddrOfPtr); } } - /*[ENDIF] JAVA_SPEC_VERSION >= 20 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ /* Determine whether the passed-in/returned segment is allocated in the native memory or not * and return the segment if valid; otherwise, return the newly allocated native segment with @@ -175,12 +163,12 @@ static MemorySegment getNativeArgRetSegment(MemorySegment argRetSegment) { if (argRetSegment == null) { throw new NullPointerException("A null value is not allowed for struct."); } - /*[IF JAVA_SPEC_VERSION >= 20]*/ + /*[IF JAVA_SPEC_VERSION >= 21]*/ /* 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 */ + /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ MemorySegment nativeSegment = argRetSegment; /* Copy all values in the heap segment to a newly allocated native segment @@ -192,8 +180,6 @@ static MemorySegment getNativeArgRetSegment(MemorySegment argRetSegment) { * MemorySegment.allocateNative() is removed since JDK21+. */ nativeSegment = Arena.global().allocate(argRetSegment.byteSize()); - /*[ELSEIF JAVA_SPEC_VERSION == 20]*/ - nativeSegment = MemorySegment.allocateNative(argRetSegment.byteSize(), SegmentScope.global()); /*[ELSE] JAVA_SPEC_VERSION >= 21 */ nativeSegment = MemorySegment.allocateNative(argRetSegment.byteSize(), ResourceScope.globalScope()); /*[ENDIF] JAVA_SPEC_VERSION >= 21 */ diff --git a/runtime/nls/j9vm/j9vm.nls b/runtime/nls/j9vm/j9vm.nls index 29ead402dab..8bde591732a 100644 --- a/runtime/nls/j9vm/j9vm.nls +++ b/runtime/nls/j9vm/j9vm.nls @@ -2145,3 +2145,10 @@ J9NLS_VM_CRIU_RESTORE_INITIALIZE_DUMP_FAILED.explanation=CRIUSupport::checkpoint J9NLS_VM_CRIU_RESTORE_INITIALIZE_DUMP_FAILED.system_action=The JVM will throw a JVMRestoreException. J9NLS_VM_CRIU_RESTORE_INITIALIZE_DUMP_FAILED.user_response=Check documentation for CRIUSupport restore options. # END NON-TRANSLATABLE + +J9NLS_VM_ILLEGAL_THREAD_STATE_UPCALL=The JVM failed to proceed due to the wrong thread state for upcall +# START NON-TRANSLATABLE +J9NLS_VM_ILLEGAL_THREAD_STATE_UPCALL.explanation=An error occurred when the JVM attempted to perform upcall in the trivial downcall +J9NLS_VM_ILLEGAL_THREAD_STATE_UPCALL.system_action=The JVM will throw a IllegalThreadStateException. +J9NLS_VM_ILLEGAL_THREAD_STATE_UPCALL.user_response=Ensure the specified linker options for downcall are valid. +# END NON-TRANSLATABLE diff --git a/runtime/oti/j9nonbuilder.h b/runtime/oti/j9nonbuilder.h index eb6fe3f9a13..04b1aff0f31 100644 --- a/runtime/oti/j9nonbuilder.h +++ b/runtime/oti/j9nonbuilder.h @@ -5384,6 +5384,9 @@ typedef struct J9VMThread { j9object_t scopedValueCache; J9VMContinuation **continuationT1Cache; #endif /* JAVA_SPEC_VERSION >= 19 */ +#if JAVA_SPEC_VERSION >= 21 + BOOLEAN isInTrivialDownCall; +#endif /* JAVA_SPEC_VERSION >= 21 */ } J9VMThread; #define J9VMTHREAD_ALIGNMENT 0x100 diff --git a/runtime/tests/clinkerffi/CMakeLists.txt b/runtime/tests/clinkerffi/CMakeLists.txt index 6ac5983ab51..813d001c8f9 100644 --- a/runtime/tests/clinkerffi/CMakeLists.txt +++ b/runtime/tests/clinkerffi/CMakeLists.txt @@ -165,6 +165,7 @@ omr_add_exports(clinkerffitests add2DoubleStructs_returnStructPointer add3DoubleStructs_returnStruct validateNullAddrArgument + validateTrivialOption add2BoolsWithOrByUpcallMH addBoolAndBoolFromPointerWithOrByUpcallMH addBoolAndBoolFromNativePtrWithOrByUpcallMH @@ -407,6 +408,7 @@ omr_add_exports(clinkerffitests addDoubleFloatOfStructsFromVaListByUpcallMH addNegBytesFromStructByUpcallMH addNegShortsFromStructByUpcallMH + captureTrivialOptionByUpcallMH ) install( diff --git a/runtime/tests/clinkerffi/downcall.c b/runtime/tests/clinkerffi/downcall.c index 0ced25e220f..e79e2c04fbb 100644 --- a/runtime/tests/clinkerffi/downcall.c +++ b/runtime/tests/clinkerffi/downcall.c @@ -2007,3 +2007,15 @@ validateNullAddrArgument(int arg1, stru_Int_Int *arg2) { return arg1; } + +/** + * Validate the linker option for the trivial downcall. + * + * @param arg1 an integer + * @return the passed-in argument + */ +int +validateTrivialOption(int arg1) +{ + return arg1; +} diff --git a/runtime/tests/clinkerffi/module.xml b/runtime/tests/clinkerffi/module.xml index 919cb47f714..f725535edc2 100644 --- a/runtime/tests/clinkerffi/module.xml +++ b/runtime/tests/clinkerffi/module.xml @@ -156,6 +156,7 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-ex + @@ -398,6 +399,7 @@ SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-ex + diff --git a/runtime/tests/clinkerffi/upcall.c b/runtime/tests/clinkerffi/upcall.c index 6b1112c4f4a..5d9fa4add46 100644 --- a/runtime/tests/clinkerffi/upcall.c +++ b/runtime/tests/clinkerffi/upcall.c @@ -2896,3 +2896,18 @@ addNegShortsFromStructByUpcallMH(short arg1, stru_Short_Short arg2, short (*upca short shortSum = (*upcallMH)(arg1, arg2, arg2.elem1, arg2.elem2); return shortSum; } + +/** + * Capture the linker option for the trivial downcall during the upcall. + * + * @param arg1 an integer + * @return the passed-in argument + * + * Note: + * The upcall is invalid in the case of the trivial downcall. + */ +int +captureTrivialOptionByUpcallMH(int arg1, int (*upcallMH)(int)) +{ + return (*upcallMH)(arg1); +} diff --git a/runtime/vm/BytecodeInterpreter.hpp b/runtime/vm/BytecodeInterpreter.hpp index a7494fb90e8..ee1029792b7 100644 --- a/runtime/vm/BytecodeInterpreter.hpp +++ b/runtime/vm/BytecodeInterpreter.hpp @@ -5109,15 +5109,15 @@ class INTERPRETER_CLASS } #if JAVA_SPEC_VERSION >= 16 -#if JAVA_SPEC_VERSION >= 20 +#if JAVA_SPEC_VERSION >= 21 /* openj9.internal.foreign.abi.InternalDowncallHandler: - * private native long invokeNative(long returnStateMemAddr, long returnStructMemAddr, long functionAddr, long calloutThunk, long[] argValues); + * private native long invokeNative(boolean isInTrivialDownCall, long returnStateMemAddr, long returnStructMemAddr, long functionAddr, long calloutThunk, long[] argValues); */ -#else /* JAVA_SPEC_VERSION >= 20 */ +#else /* JAVA_SPEC_VERSION >= 21 */ /* openj9.internal.foreign.abi.InternalDowncallHandler: * private native long invokeNative(long returnStructMemAddr, long functionAddr, long calloutThunk, long[] argValues); */ -#endif /* JAVA_SPEC_VERSION >= 20 */ +#endif /* JAVA_SPEC_VERSION >= 21 */ VMINLINE VM_BytecodeAction inlInternalDowncallHandlerInvokeNative(REGISTER_ARGS_LIST) { @@ -5146,12 +5146,12 @@ class INTERPRETER_CLASS UDATA *returnStorage = &(_currentThread->returnValue); U_64 *ffiArgs = _currentThread->ffiArgs; U_64 sFfiArgs[16]; -#if JAVA_SPEC_VERSION >= 20 - UDATA argSlots = 10; +#if JAVA_SPEC_VERSION >= 21 + UDATA argSlots = 11; I_32 *returnState = NULL; -#else /* JAVA_SPEC_VERSION >= 20 */ +#else /* JAVA_SPEC_VERSION >= 21 */ UDATA argSlots = 8; -#endif /* JAVA_SPEC_VERSION >= 20 */ +#endif /* JAVA_SPEC_VERSION >= 21 */ j9object_t argValues = *(j9object_t *)_sp; /* argValues */ ffi_cif *cif = (ffi_cif *)(UDATA)*(I_64 *)(_sp + 1); /* calloutThunk */ @@ -5175,6 +5175,11 @@ class INTERPRETER_CLASS returnState = (I_32 *)(UDATA)*(I_64 *)(_sp + 7); /* returnStateMemAddr */ #endif /* JAVA_SPEC_VERSION >= 20 */ +#if JAVA_SPEC_VERSION >= 21 + /* Set the linker option to the current thread for the trivial downcall. */ + _currentThread->isInTrivialDownCall = (0 == *(U_32*)(_sp + 9)) ? FALSE : TRUE; +#endif /* JAVA_SPEC_VERSION >= 21 */ + if (isMinimal) { values = sValues; pointerValues = spValues; @@ -5253,7 +5258,13 @@ class INTERPRETER_CLASS _currentThread->callOutCount += 1; #endif /* JAVA_SPEC_VERSION >= 19 */ updateVMStruct(REGISTER_ARGS); - VM_VMAccess::inlineExitVMToJNI(_currentThread); +#if JAVA_SPEC_VERSION >= 21 + /* Only exit to JNI for non-trivial downcalls for better performance. */ + if (!_currentThread->isInTrivialDownCall) +#endif /* JAVA_SPEC_VERSION >= 21 */ + { + VM_VMAccess::inlineExitVMToJNI(_currentThread); + } VM_VMHelpers::beforeJNICall(_currentThread); #if FFI_NATIVE_RAW_API ffiCallWithSetJmpForUpcall(_currentThread, cif, function, returnStorage, values, values_raw); @@ -5261,7 +5272,13 @@ class INTERPRETER_CLASS ffiCallWithSetJmpForUpcall(_currentThread, cif, function, returnStorage, values); #endif /* FFI_NATIVE_RAW_API */ VM_VMHelpers::afterJNICall(_currentThread); - VM_VMAccess::inlineEnterVMFromJNI(_currentThread); +#if JAVA_SPEC_VERSION >= 21 + /* Re-enter VM after non-trivial downcalls. */ + if (!_currentThread->isInTrivialDownCall) +#endif /* JAVA_SPEC_VERSION >= 21 */ + { + VM_VMAccess::inlineEnterVMFromJNI(_currentThread); + } VMStructHasBeenUpdated(REGISTER_ARGS); #if JAVA_SPEC_VERSION >= 19 _currentThread->callOutCount -= 1; @@ -5283,6 +5300,11 @@ class INTERPRETER_CLASS returnDoubleFromINL(REGISTER_ARGS, _currentThread->returnValue, argSlots); done: +#if JAVA_SPEC_VERSION >= 21 + /* Clear the trivial downcall flag. */ + _currentThread->isInTrivialDownCall = FALSE; +#endif /* JAVA_SPEC_VERSION >= 21 */ + if (!isMinimal) { j9mem_free_memory(values); j9mem_free_memory(pointerValues); diff --git a/runtime/vm/UpcallVMHelpers.cpp b/runtime/vm/UpcallVMHelpers.cpp index a456d726f8e..6da24c8ca89 100644 --- a/runtime/vm/UpcallVMHelpers.cpp +++ b/runtime/vm/UpcallVMHelpers.cpp @@ -289,6 +289,17 @@ native2InterpJavaUpcallImpl(J9UpcallMetaData *data, void *argsListPointer) bool isCurThrdAllocated = false; U_64 returnStorage = 0; +#if JAVA_SPEC_VERSION >= 21 + /* Capture the invalid linker option (intended for the trivial downcall as specified in JDK21) in upcall + * by throwing out an exception so as to remind users of the incorrect behavior in applications rather + * than ending up with an assertion failure by crashing the JVM in the RI implementation. + */ + if (downCallThread->isInTrivialDownCall) { + setCurrentExceptionNLS(downCallThread, J9VMCONSTANTPOOL_JAVALANGILLEGALTHREADSTATEEXCEPTION, J9NLS_VM_ILLEGAL_THREAD_STATE_UPCALL); + goto illegalState; + } +#endif /* JAVA_SPEC_VERSION => 21 */ + /* Determine whether to use the current thread or create a new one * when there is no java thread attached to the native thread * created directly in native. @@ -435,6 +446,9 @@ native2InterpJavaUpcallImpl(J9UpcallMetaData *data, void *argsListPointer) currentThread = NULL; } +#if JAVA_SPEC_VERSION >= 21 +illegalState: +#endif /* JAVA_SPEC_VERSION => 21 */ /* Restore back to the setjump site in the call-out native * to handle the captured exception. * diff --git a/runtime/vm/bindnatv.cpp b/runtime/vm/bindnatv.cpp index f9373fc1ed3..a594d3e27bf 100644 --- a/runtime/vm/bindnatv.cpp +++ b/runtime/vm/bindnatv.cpp @@ -298,11 +298,11 @@ static inlMapping mappings[] = { #else /* JAVA_SPEC_VERSION >= 11 */ { "Java_sun_reflect_Reflection_getClassAccessFlags__Ljava_lang_Class_2", J9_BCLOOP_SEND_TARGET_INL_REFLECTION_GETCLASSACCESSFLAGS }, #endif /* JAVA_SPEC_VERSION >= 11 */ -#if JAVA_SPEC_VERSION >= 20 - { "Java_openj9_internal_foreign_abi_InternalDowncallHandler_invokeNative__JJJJ_3J", J9_BCLOOP_SEND_TARGET_INL_INTERNALDOWNCALLHANDLER_INVOKENATIVE }, +#if JAVA_SPEC_VERSION >= 21 + { "Java_openj9_internal_foreign_abi_InternalDowncallHandler_invokeNative__ZJJJJ_3J", J9_BCLOOP_SEND_TARGET_INL_INTERNALDOWNCALLHANDLER_INVOKENATIVE }, #elif JAVA_SPEC_VERSION >= 16 { "Java_openj9_internal_foreign_abi_InternalDowncallHandler_invokeNative__JJJ_3J", J9_BCLOOP_SEND_TARGET_INL_INTERNALDOWNCALLHANDLER_INVOKENATIVE }, -#endif /* JAVA_SPEC_VERSION >= 20 */ +#endif /* JAVA_SPEC_VERSION >= 21 */ #if JAVA_SPEC_VERSION >= 19 { "Java_jdk_internal_vm_Continuation_enterImpl__", J9_BCLOOP_SEND_TARGET_ENTER_CONTINUATION }, { "Java_jdk_internal_vm_Continuation_yieldImpl__Z", J9_BCLOOP_SEND_TARGET_YIELD_CONTINUATION }, diff --git a/runtime/vm/vmthread.cpp b/runtime/vm/vmthread.cpp index b2a080a0f44..c071ccb8313 100644 --- a/runtime/vm/vmthread.cpp +++ b/runtime/vm/vmthread.cpp @@ -267,6 +267,9 @@ allocateVMThread(J9JavaVM * vm, omrthread_t osThread, UDATA privateFlags, void * newThread->ffiArgCount = 0; newThread->jmpBufEnvPtr = NULL; #endif /* JAVA_SPEC_VERSION >= 16 */ +#if JAVA_SPEC_VERSION >= 21 + newThread->isInTrivialDownCall = FALSE; +#endif /* JAVA_SPEC_VERSION >= 21 */ #if JAVA_SPEC_VERSION >= 19 newThread->currentContinuation = NULL; diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/PrimitiveTypeTests1.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/PrimitiveTypeTests1.java index 7217aaf9126..8b56aed80bf 100644 --- a/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/PrimitiveTypeTests1.java +++ b/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/PrimitiveTypeTests1.java @@ -301,4 +301,13 @@ public void test_printfFromDefaultLibWithMemAddr_LinkerOption_1() throws Throwab MemorySegment formatSegmt = arena.allocateUtf8String("\n%d + %d = %d\n"); mh.invoke(formatSegmt, 15, 27, 42); } + + @Test + public void test_validateTrivialOption_1() throws Throwable { + FunctionDescriptor fd = FunctionDescriptor.of(JAVA_INT, JAVA_INT); + MemorySegment functionSymbol = nativeLibLookup.find("validateTrivialOption").get(); + MethodHandle mh = linker.downcallHandle(functionSymbol, fd, Linker.Option.isTrivial()); + int result = (int)mh.invokeExact(111); + Assert.assertEquals(result, 111); + } } diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/PrimitiveTypeTests2.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/PrimitiveTypeTests2.java index a4633aa2aba..5f88bb145eb 100644 --- a/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/PrimitiveTypeTests2.java +++ b/test/functional/Java21andUp/src/org/openj9/test/jep442/downcall/PrimitiveTypeTests2.java @@ -301,4 +301,13 @@ public void test_printfFromDefaultLibWithMemAddr_LinkerOption_2() throws Throwab MemorySegment formatSegmt = arena.allocateUtf8String("\n%d + %d = %d\n"); mh.invoke(functionSymbol, formatSegmt, 15, 27, 42); } + + @Test + public void test_validateTrivialOption_2() throws Throwable { + FunctionDescriptor fd = FunctionDescriptor.of(JAVA_INT, JAVA_INT); + MemorySegment functionSymbol = nativeLibLookup.find("validateTrivialOption").get(); + MethodHandle mh = linker.downcallHandle(fd, Linker.Option.isTrivial()); + int result = (int)mh.invokeExact(functionSymbol, 111); + Assert.assertEquals(result, 111); + } } 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 index 08cea407cdc..65bd24dcb81 100644 --- a/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/InvalidUpCallTests.java +++ b/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/InvalidUpCallTests.java @@ -291,7 +291,7 @@ public void test_InvalidLinkerOptions_captureCallState() throws Throwable { } @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Not supported for upcall.*") - public void test_InvalidLinkerOptions_isTrivial() throws Throwable { + public void test_InvalidLinkerOptions_isTrivial_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")); @@ -306,4 +306,18 @@ public void test_InvalidLinkerOptions_isTrivial() throws Throwable { fail("Failed to throw out IllegalArgumentException in the case of the invalid linker option for upcall."); } } + + @Test(expectedExceptions = IllegalThreadStateException.class, expectedExceptionsMessageRegExp = ".* wrong thread state for upcall") + public void test_InvalidLinkerOptions_isTrivial_2() throws Throwable { + FunctionDescriptor fd = FunctionDescriptor.of(JAVA_INT, JAVA_INT, ADDRESS); + MemorySegment functionSymbol = nativeLibLookup.find("captureTrivialOptionByUpcallMH").get(); + MethodHandle mh = linker.downcallHandle(functionSymbol, fd, Linker.Option.isTrivial()); + + try (Arena arena = Arena.ofConfined()) { + MemorySegment upcallFuncAddr = linker.upcallStub(UpcallMethodHandles.MH_captureTrivialOption, + FunctionDescriptor.of(JAVA_INT, JAVA_INT), arena); + int result = (int)mh.invoke(111, upcallFuncAddr); + fail("Failed to throw out IllegalThreadStateException in the case of the invalid upcall during the trivial downcall."); + } + } } diff --git a/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/UpcallMethodHandles.java b/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/UpcallMethodHandles.java index 327061f61c7..9847aac23a6 100644 --- a/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/UpcallMethodHandles.java +++ b/test/functional/Java21andUp/src/org/openj9/test/jep442/upcall/UpcallMethodHandles.java @@ -273,6 +273,7 @@ public class UpcallMethodHandles { public static final MethodHandle MH_addNegBytesFromStruct; public static final MethodHandle MH_addNegShortsFromStruct; + public static final MethodHandle MH_captureTrivialOption; private static Linker linker = Linker.nativeLinker(); @@ -486,6 +487,7 @@ public class UpcallMethodHandles { MH_addNegBytesFromStruct = lookup.findStatic(UpcallMethodHandles.class, "addNegBytesFromStruct", MT_Byte_Byte_MemSegmt.appendParameterTypes(byte.class, byte.class)); //$NON-NLS-1$ MH_addNegShortsFromStruct = lookup.findStatic(UpcallMethodHandles.class, "addNegShortsFromStruct", MT_Short_Short_MemSegmt.appendParameterTypes(short.class, short.class)); //$NON-NLS-1$ + MH_captureTrivialOption = lookup.findStatic(UpcallMethodHandles.class, "captureTrivialOption", methodType(int.class, int.class)); //$NON-NLS-1$ } catch (IllegalAccessException | NoSuchMethodException e) { throw new InternalError(e); @@ -2067,4 +2069,9 @@ public static short addNegShortsFromStruct(short arg1, MemorySegment arg2, shor short shortSum = (short)(arg1 + arg2_elem1 + arg2_elem2 + arg3 + arg4); return shortSum; } + + public static int captureTrivialOption(int intArg1) { + Assert.fail("The method shouldn't be invoked during the trivial downcall."); + return intArg1; + } }