Skip to content

Commit a78d091

Browse files
authored
Merge pull request #19008 from ChengJin01/enable_heap_arg_downcall_v0.44.0
[FFI/v0.44] Enable heap related code in downcall
2 parents 2ffefee + b5015d9 commit a78d091

File tree

18 files changed

+1039
-105
lines changed

18 files changed

+1039
-105
lines changed

jcl/src/java.base/share/classes/openj9/internal/foreign/abi/InternalDowncallHandler.java

Lines changed: 84 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,11 @@
4949
import java.lang.foreign.ValueLayout;
5050
/*[IF JAVA_SPEC_VERSION >= 22]*/
5151
import jdk.internal.access.SharedSecrets;
52+
import jdk.internal.foreign.AbstractMemorySegmentImpl;
5253
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
54+
import jdk.internal.foreign.MemorySessionImpl;
5355
import jdk.internal.foreign.Utils;
5456
import jdk.internal.foreign.abi.LinkerOptions;
55-
import jdk.internal.foreign.MemorySessionImpl;
5657
/*[ELSE] JAVA_SPEC_VERSION >= 21 */
5758
import jdk.incubator.foreign.Addressable;
5859
import jdk.incubator.foreign.FunctionDescriptor;
@@ -89,6 +90,39 @@ public class InternalDowncallHandler {
8990
private MemoryLayout realReturnLayout;
9091
private MethodHandle boundMH;
9192

93+
/*[IF JAVA_SPEC_VERSION >= 22]*/
94+
/* The identifier denotes the passed-in argument is a heap segment which helps
95+
* extract the address from the heap argument's base object in native.
96+
*/
97+
private static final long DOWNCALL_HEAP_ARGUMENT_ID = 0xFFFFFFFFFFFFFFFFL;
98+
99+
/* The ThreadLocal holds the information of the heap argument which includes
100+
* the base object array, the offset array plus the current heap argument index
101+
* for the current thread in multithreading. The heap base array stores the base
102+
* object (which contains the heap address as defined in OpenJDK) of the heap
103+
* arguments to extract the heap address from the base object in native.
104+
*/
105+
private static final class HeapArgInfo {
106+
final Object[] bases;
107+
final long[] offsets;
108+
int index;
109+
110+
HeapArgInfo(int size) {
111+
bases = new Object[size];
112+
offsets = new long[size];
113+
index = 0;
114+
}
115+
116+
void append(Object base, long offset) {
117+
bases[index] = base;
118+
offsets[index] = offset;
119+
index += 1;
120+
}
121+
}
122+
123+
private final ThreadLocal<HeapArgInfo> heapArgInfo;
124+
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
125+
92126
/* The hashtables of sessions/scopes is intended for multithreading in which case
93127
* the same downcall handler might hold various sessions/scopes being used by
94128
* different threads in downcall.
@@ -151,11 +185,16 @@ public class InternalDowncallHandler {
151185
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
152186
private static synchronized native void resolveRequiredFields();
153187
private native void initCifNativeThunkData(String[] argLayouts, String retLayout, boolean newArgTypes, int varArgIndex);
154-
/*[IF JAVA_SPEC_VERSION >= 21]*/
155-
private native long invokeNative(boolean isInTrivialDownCall, long returnStateMemAddr, long returnStructMemAddr, long functionAddress, long calloutThunk, long[] argValues);
156-
/*[ELSE] JAVA_SPEC_VERSION >= 21 */
157-
private native long invokeNative(long returnStructMemAddr, long functionAddress, long calloutThunk, long[] argValues);
158-
/*[ENDIF] JAVA_SPEC_VERSION >= 21 */
188+
private native long invokeNative(
189+
/*[IF JAVA_SPEC_VERSION >= 22]*/
190+
Object[] bases,
191+
long[] offsets,
192+
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
193+
/*[IF JAVA_SPEC_VERSION >= 21]*/
194+
boolean isInCriticalDownCall, long returnStateMemAddr,
195+
/*[ENDIF] JAVA_SPEC_VERSION >= 21 */
196+
long returnStructMemAddr, long functionAddress, long calloutThunk, long[] argValues
197+
);
159198

160199
private static final class PrivateClassLock {
161200
PrivateClassLock() {}
@@ -266,10 +305,25 @@ private void validateMemScope(ResourceScope memScope) throws IllegalStateExcepti
266305
/* Intended for memSegmtOfPtrToLongArgFilter that converts the memory segment
267306
* of the passed-in pointer argument to long.
268307
*/
269-
private final long memSegmtOfPtrToLongArg(MemorySegment argValue) throws IllegalStateException {
270-
UpcallMHMetaData.validateNativeArgRetSegmentOfPtr(argValue);
308+
private final long memSegmtOfPtrToLongArg(MemorySegment argValue, LinkerOptions options) throws IllegalStateException {
309+
UpcallMHMetaData.validateNativeArgRetSegmentOfPtr(argValue, options);
271310
addMemArgScope(argValue.scope());
272-
return argValue.address();
311+
312+
long address = argValue.address();
313+
/*[IF JAVA_SPEC_VERSION >= 22]*/
314+
if (!argValue.isNative() && options.allowsHeapAccess()) {
315+
HeapArgInfo info = heapArgInfo.get();
316+
if (info == null) {
317+
info = new HeapArgInfo(argLayoutArray.length);
318+
heapArgInfo.set(info);
319+
}
320+
/* Store the heap argument's base object and offset. */
321+
AbstractMemorySegmentImpl segment = (AbstractMemorySegmentImpl)argValue;
322+
info.append(segment.unsafeGetBase(), segment.unsafeGetOffset());
323+
address = DOWNCALL_HEAP_ARGUMENT_ID;
324+
}
325+
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
326+
return address;
273327
}
274328
/*[ELSE] JAVA_SPEC_VERSION >= 21 */
275329
/* Intended for memAddrToLongArgFilter that converts the memory address to long. */
@@ -414,10 +468,14 @@ public InternalDowncallHandler(MethodType functionMethodType, FunctionDescriptor
414468
scopeHandleMap = new ConcurrentHashMap<>();
415469
/*[ENDIF] JAVA_SPEC_VERSION == 17 */
416470

471+
/*[IF JAVA_SPEC_VERSION >= 22]*/
472+
heapArgInfo = new ThreadLocal<>();
473+
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
474+
417475
try {
418476
/*[IF JAVA_SPEC_VERSION >= 21]*/
419477
longObjToMemSegmtRetFilter = lookup.bind(this, "longObjToMemSegmtRet", methodType(MemorySegment.class, Object.class));
420-
memSegmtOfPtrToLongArgFilter = lookup.bind(this, "memSegmtOfPtrToLongArg", methodType(long.class, MemorySegment.class));
478+
memSegmtOfPtrToLongArgFilter = lookup.bind(this, "memSegmtOfPtrToLongArg", methodType(long.class, MemorySegment.class, LinkerOptions.class));
421479
/*[ELSE] JAVA_SPEC_VERSION >= 21 */
422480
memAddrToLongArgFilter = lookup.bind(this, "memAddrToLongArg", methodType(long.class, MemoryAddress.class));
423481
/*[ENDIF] JAVA_SPEC_VERSION >= 21 */
@@ -603,7 +661,7 @@ private MethodHandle getArgumentFilter(Class<?> argTypeClass, MemoryLayout argLa
603661
* Note: AddressLayout is introduced in JDK21 to replace OfAddress.
604662
*/
605663
if (argLayout instanceof AddressLayout) {
606-
filterMH = memSegmtOfPtrToLongArgFilter;
664+
filterMH = MethodHandles.insertArguments(memSegmtOfPtrToLongArgFilter, 1, linkerOpts);
607665
} else
608666
/*[ENDIF] JAVA_SPEC_VERSION >= 21 */
609667
{
@@ -785,6 +843,9 @@ Object runNativeMethod(Addressable downcallAddr, SegmentAllocator segmtAllocator
785843
/*[ENDIF] JAVA_SPEC_VERSION >= 21 */
786844

787845
long returnVal;
846+
/*[IF JAVA_SPEC_VERSION >= 22]*/
847+
HeapArgInfo info = heapArgInfo.get();
848+
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
788849
/* The scope associated with memory specific arguments must be kept alive
789850
* during the downcall since JDK17, including the downcall adddress.
790851
*
@@ -795,6 +856,8 @@ Object runNativeMethod(Addressable downcallAddr, SegmentAllocator segmtAllocator
795856
SetDependency(arena.scope());
796857
returnVal = invokeNative(
797858
/*[IF JAVA_SPEC_VERSION >= 22]*/
859+
(info != null) ? info.bases : null,
860+
(info != null) ? info.offsets : null,
798861
linkerOpts.isCritical(),
799862
/*[ELSE] JAVA_SPEC_VERSION >= 22 */
800863
linkerOpts.isTrivial(),
@@ -811,6 +874,16 @@ Object runNativeMethod(Addressable downcallAddr, SegmentAllocator segmtAllocator
811874
releaseScope();
812875
/*[ENDIF] JAVA_SPEC_VERSION >= 21 */
813876

877+
/*[IF JAVA_SPEC_VERSION >= 22]*/
878+
/* Reset the heap argument information for the current thread so as to
879+
* update the base object of different heap arguments passed by the same
880+
* downcall handler within the current thread.
881+
*/
882+
if (info != null) {
883+
heapArgInfo.remove();
884+
}
885+
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
886+
814887
/* This struct specific MemorySegment object returns to the current thread in the multithreading environment,
815888
* in which case the native invocations from threads end up with distinct returned structs.
816889
*/

jcl/src/java.base/share/classes/openj9/internal/foreign/abi/InternalUpcallHandler.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ public final class InternalUpcallHandler {
6262
private final MemoryLayout realReturnLayout;
6363
private final long thunkAddr;
6464
private UpcallMHMetaData metaData;
65+
/*[IF JAVA_SPEC_VERSION >= 21]*/
66+
private final LinkerOptions linkerOpts;
67+
/*[ENDIF] JAVA_SPEC_VERSION >= 21 */
6568

6669
static final Lookup lookup = MethodHandles.lookup();
6770

@@ -76,7 +79,7 @@ public final class InternalUpcallHandler {
7679
static {
7780
try {
7881
/*[IF JAVA_SPEC_VERSION >= 21]*/
79-
argRetSegmtOfPtrFilter = lookup.findStatic(InternalUpcallHandler.class, "argRetSegmtOfPtr", methodType(MemorySegment.class, MemorySegment.class, MemoryLayout.class));
82+
argRetSegmtOfPtrFilter = lookup.findStatic(InternalUpcallHandler.class, "argRetSegmtOfPtr", methodType(MemorySegment.class, MemorySegment.class, MemoryLayout.class, LinkerOptions.class));
8083
/*[ELSE] JAVA_SPEC_VERSION >= 21 */
8184
argRetAddrOfPtrFilter = lookup.findStatic(InternalUpcallHandler.class, "argRetAddrOfPtr", methodType(MemoryAddress.class, MemoryAddress.class));
8285
/*[ENDIF] JAVA_SPEC_VERSION >= 21 */
@@ -90,8 +93,8 @@ public final class InternalUpcallHandler {
9093
* of the passed-in pointer argument.
9194
*/
9295
/*[IF JAVA_SPEC_VERSION >= 21]*/
93-
private static MemorySegment argRetSegmtOfPtr(MemorySegment argValue, MemoryLayout layout) throws IllegalStateException {
94-
UpcallMHMetaData.validateNativeArgRetSegmentOfPtr(argValue);
96+
private static MemorySegment argRetSegmtOfPtr(MemorySegment argValue, MemoryLayout layout, LinkerOptions options) throws IllegalStateException {
97+
UpcallMHMetaData.validateNativeArgRetSegmentOfPtr(argValue, options);
9598
return UpcallMHMetaData.getArgRetAlignedSegmentOfPtr(argValue.address(), layout);
9699
}
97100
/*[ELSE] JAVA_SPEC_VERSION >= 21 */
@@ -136,6 +139,9 @@ public InternalUpcallHandler(MethodHandle target, MethodType mt, FunctionDescrip
136139
List<MemoryLayout> argLayouts = cDesc.argumentLayouts();
137140
argLayoutArray = argLayouts.toArray(new MemoryLayout[argLayouts.size()]);
138141
realReturnLayout = cDesc.returnLayout().orElse(null); // Set to null for void
142+
/*[IF JAVA_SPEC_VERSION >= 21]*/
143+
linkerOpts = options;
144+
/*[ENDIF] JAVA_SPEC_VERSION >= 21 */
139145

140146
/*[IF JAVA_SPEC_VERSION == 17]*/
141147
/* The layout check against the method type is still required for Java 17 in that both
@@ -244,7 +250,7 @@ else if (argTypeClass == MemoryAddress.class) {
244250
else if (argLayout instanceof ValueLayout) {
245251
/*[IF JAVA_SPEC_VERSION >= 21]*/
246252
if (argLayout instanceof AddressLayout) {
247-
filterMH = MethodHandles.insertArguments(argRetSegmtOfPtrFilter, 1, argLayout);
253+
filterMH = MethodHandles.insertArguments(argRetSegmtOfPtrFilter, 1, argLayout, linkerOpts);
248254
} else
249255
/*[ENDIF] JAVA_SPEC_VERSION >= 21 */
250256
{

jcl/src/java.base/share/classes/openj9/internal/foreign/abi/UpcallMHMetaData.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,20 @@
3434
import java.lang.foreign.MemorySegment;
3535
import java.lang.foreign.MemoryLayout;
3636
import java.lang.foreign.MemorySegment.Scope;
37+
import jdk.internal.foreign.MemorySessionImpl;
3738
import jdk.internal.foreign.Utils;
3839
import jdk.internal.foreign.abi.LinkerOptions;
39-
import jdk.internal.foreign.MemorySessionImpl;
4040
/*[ELSE] JAVA_SPEC_VERSION >= 21 */
4141
import jdk.incubator.foreign.Addressable;
4242
import jdk.incubator.foreign.MemoryAddress;
4343
import jdk.incubator.foreign.MemorySegment;
4444
import jdk.incubator.foreign.ResourceScope;
4545
/*[ENDIF] JAVA_SPEC_VERSION >= 21 */
4646

47+
/*[IF JAVA_SPEC_VERSION >= 22]*/
48+
import static java.lang.foreign.ValueLayout.*;
49+
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
50+
4751
/**
4852
* The meta data consists of the callee MH and a cache of 2 elements for MH resolution,
4953
* which are used to generate an upcall handler to the requested java method.
@@ -127,11 +131,15 @@ static MemorySegment getArgRetAlignedSegmentOfPtr(long addrValue, MemoryLayout l
127131
* The method is shared in downcall and upcall.
128132
*/
129133
/*[IF JAVA_SPEC_VERSION >= 21]*/
130-
static void validateNativeArgRetSegmentOfPtr(MemorySegment argRetSegmentOfPtr) {
134+
static void validateNativeArgRetSegmentOfPtr(MemorySegment argRetSegmentOfPtr, LinkerOptions options) {
131135
if (argRetSegmentOfPtr == null) {
132136
throw new NullPointerException("A null pointer is not allowed.");
133137
}
134-
if (!argRetSegmentOfPtr.isNative()) {
138+
if (!argRetSegmentOfPtr.isNative()
139+
/*[IF JAVA_SPEC_VERSION >= 22]*/
140+
&& !options.allowsHeapAccess()
141+
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
142+
) {
135143
throw new IllegalArgumentException("Heap segment not allowed: " + argRetSegmentOfPtr);
136144
}
137145
}

runtime/oti/j9nonbuilder.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5437,7 +5437,7 @@ typedef struct J9VMThread {
54375437
J9VMContinuation **continuationT1Cache;
54385438
#endif /* JAVA_SPEC_VERSION >= 19 */
54395439
#if JAVA_SPEC_VERSION >= 21
5440-
BOOLEAN isInTrivialDownCall;
5440+
BOOLEAN isInCriticalDownCall;
54415441
#endif /* JAVA_SPEC_VERSION >= 21 */
54425442
} J9VMThread;
54435443

@@ -6062,6 +6062,9 @@ typedef struct J9JavaVM {
60626062
#define J9JAVAVM_DISCONTIGUOUS_INDEXABLE_HEADER_SIZE(vm) ((vm)->discontiguousIndexableHeaderSize)
60636063

60646064
#if JAVA_SPEC_VERSION >= 16
6065+
#if JAVA_SPEC_VERSION >= 22
6066+
#define J9_FFI_DOWNCALL_HEAP_ARGUMENT_ID J9CONST_U64(0xFFFFFFFFFFFFFFFF)
6067+
#endif /* JAVA_SPEC_VERSION >= 22 */
60656068

60666069
/* The mask for the signature type identifier */
60676070
#define J9_FFI_UPCALL_SIG_TYPE_MASK 0xF

runtime/tests/clinkerffi/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,14 @@ omr_add_exports(clinkerffitests
332332
addShortAndBytesFromUnion_Nested4ByteStruct
333333
addIntAndIntShortFromUnion_Nested2ShortStruct
334334
addIntAndShortsFromUnion_Nested4ShortStruct
335+
addBoolsFromMultipleStructPtrs_returnStruct
336+
addBytesFromMultipleStructPtrs_returnStruct
337+
addCharsFromMultipleStructPtrs_returnStruct
338+
addShortsFromMultipleStructPtrs_returnStruct
339+
addIntsFromMultipleStructPtrs_returnStruct
340+
addLongsFromMultipleStructPtrs_returnStruct
341+
addFloatsFromMultipleStructPtrs_returnStruct
342+
addDoublesFromMultipleStructPtrs_returnStruct
335343
add2BoolsWithOrByUpcallMH
336344
addBoolAndBoolFromPointerWithOrByUpcallMH
337345
addBoolAndBoolFromNativePtrWithOrByUpcallMH

0 commit comments

Comments
 (0)