49
49
import java .lang .foreign .ValueLayout ;
50
50
/*[IF JAVA_SPEC_VERSION >= 22]*/
51
51
import jdk .internal .access .SharedSecrets ;
52
+ import jdk .internal .foreign .AbstractMemorySegmentImpl ;
52
53
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
54
+ import jdk .internal .foreign .MemorySessionImpl ;
53
55
import jdk .internal .foreign .Utils ;
54
56
import jdk .internal .foreign .abi .LinkerOptions ;
55
- import jdk .internal .foreign .MemorySessionImpl ;
56
57
/*[ELSE] JAVA_SPEC_VERSION >= 21 */
57
58
import jdk .incubator .foreign .Addressable ;
58
59
import jdk .incubator .foreign .FunctionDescriptor ;
@@ -89,6 +90,39 @@ public class InternalDowncallHandler {
89
90
private MemoryLayout realReturnLayout ;
90
91
private MethodHandle boundMH ;
91
92
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
+
92
126
/* The hashtables of sessions/scopes is intended for multithreading in which case
93
127
* the same downcall handler might hold various sessions/scopes being used by
94
128
* different threads in downcall.
@@ -151,11 +185,16 @@ public class InternalDowncallHandler {
151
185
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
152
186
private static synchronized native void resolveRequiredFields ();
153
187
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
+ );
159
198
160
199
private static final class PrivateClassLock {
161
200
PrivateClassLock () {}
@@ -266,10 +305,25 @@ private void validateMemScope(ResourceScope memScope) throws IllegalStateExcepti
266
305
/* Intended for memSegmtOfPtrToLongArgFilter that converts the memory segment
267
306
* of the passed-in pointer argument to long.
268
307
*/
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 );
271
310
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 ;
273
327
}
274
328
/*[ELSE] JAVA_SPEC_VERSION >= 21 */
275
329
/* Intended for memAddrToLongArgFilter that converts the memory address to long. */
@@ -414,10 +468,14 @@ public InternalDowncallHandler(MethodType functionMethodType, FunctionDescriptor
414
468
scopeHandleMap = new ConcurrentHashMap <>();
415
469
/*[ENDIF] JAVA_SPEC_VERSION == 17 */
416
470
471
+ /*[IF JAVA_SPEC_VERSION >= 22]*/
472
+ heapArgInfo = new ThreadLocal <>();
473
+ /*[ENDIF] JAVA_SPEC_VERSION >= 22 */
474
+
417
475
try {
418
476
/*[IF JAVA_SPEC_VERSION >= 21]*/
419
477
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 ));
421
479
/*[ELSE] JAVA_SPEC_VERSION >= 21 */
422
480
memAddrToLongArgFilter = lookup .bind (this , "memAddrToLongArg" , methodType (long .class , MemoryAddress .class ));
423
481
/*[ENDIF] JAVA_SPEC_VERSION >= 21 */
@@ -603,7 +661,7 @@ private MethodHandle getArgumentFilter(Class<?> argTypeClass, MemoryLayout argLa
603
661
* Note: AddressLayout is introduced in JDK21 to replace OfAddress.
604
662
*/
605
663
if (argLayout instanceof AddressLayout ) {
606
- filterMH = memSegmtOfPtrToLongArgFilter ;
664
+ filterMH = MethodHandles . insertArguments ( memSegmtOfPtrToLongArgFilter , 1 , linkerOpts ) ;
607
665
} else
608
666
/*[ENDIF] JAVA_SPEC_VERSION >= 21 */
609
667
{
@@ -785,6 +843,9 @@ Object runNativeMethod(Addressable downcallAddr, SegmentAllocator segmtAllocator
785
843
/*[ENDIF] JAVA_SPEC_VERSION >= 21 */
786
844
787
845
long returnVal ;
846
+ /*[IF JAVA_SPEC_VERSION >= 22]*/
847
+ HeapArgInfo info = heapArgInfo .get ();
848
+ /*[ENDIF] JAVA_SPEC_VERSION >= 22 */
788
849
/* The scope associated with memory specific arguments must be kept alive
789
850
* during the downcall since JDK17, including the downcall adddress.
790
851
*
@@ -795,6 +856,8 @@ Object runNativeMethod(Addressable downcallAddr, SegmentAllocator segmtAllocator
795
856
SetDependency (arena .scope ());
796
857
returnVal = invokeNative (
797
858
/*[IF JAVA_SPEC_VERSION >= 22]*/
859
+ (info != null ) ? info .bases : null ,
860
+ (info != null ) ? info .offsets : null ,
798
861
linkerOpts .isCritical (),
799
862
/*[ELSE] JAVA_SPEC_VERSION >= 22 */
800
863
linkerOpts .isTrivial (),
@@ -811,6 +874,16 @@ Object runNativeMethod(Addressable downcallAddr, SegmentAllocator segmtAllocator
811
874
releaseScope ();
812
875
/*[ENDIF] JAVA_SPEC_VERSION >= 21 */
813
876
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
+
814
887
/* This struct specific MemorySegment object returns to the current thread in the multithreading environment,
815
888
* in which case the native invocations from threads end up with distinct returned structs.
816
889
*/
0 commit comments