23
23
package openj9 .internal .foreign .abi ;
24
24
25
25
/*[IF JAVA_SPEC_VERSION >= 22]*/
26
+ import java .util .ArrayDeque ;
26
27
import java .util .Arrays ;
28
+ import java .util .Deque ;
27
29
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
28
30
import java .util .HashMap ;
29
31
import java .util .List ;
@@ -123,7 +125,18 @@ void clear() {
123
125
}
124
126
}
125
127
126
- private final ThreadLocal <HeapArgInfo > heapArgInfo ;
128
+ /* heapArgInfo holds a per-thread stack of HeapArgInfo structures.
129
+ * Each entry tracks Java references to heap-allocated memory segments
130
+ * Required for recursive downcalls.
131
+ * Each downcall maintains its own set of references until completion.
132
+ *
133
+ * createHeapArgInfo controls when a new entry should be created.
134
+ * If true, a new HeapArgInfo is pushed for the current downcall.
135
+ * A single downcall may have multiple pointer arguments,
136
+ * and all of them share the same entry.
137
+ */
138
+ private static final ThreadLocal <Deque <HeapArgInfo >> heapArgInfo = ThreadLocal .withInitial (ArrayDeque ::new );
139
+ private static final ThreadLocal <Boolean > createHeapArgInfo = ThreadLocal .withInitial (()->Boolean .TRUE );
127
140
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
128
141
129
142
/* The hashtables of sessions/scopes is intended for multithreading in which case
@@ -311,7 +324,8 @@ private void validateMemScope(ResourceScope memScope) throws IllegalStateExcepti
311
324
*/
312
325
private final long memSegmtOfPtrToLongArg (MemorySegment argValue , LinkerOptions options ) throws IllegalStateException {
313
326
/*[IF JAVA_SPEC_VERSION >= 22]*/
314
- HeapArgInfo info = heapArgInfo .get ();
327
+ Deque <HeapArgInfo > infoStack = heapArgInfo .get ();
328
+ HeapArgInfo info = infoStack .peek ();
315
329
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
316
330
317
331
try {
@@ -323,18 +337,21 @@ private final long memSegmtOfPtrToLongArg(MemorySegment argValue, LinkerOptions
323
337
* is captured so as to reset the internal index and avoid retaining the references
324
338
* to the unreachable objects.
325
339
*/
326
- if (info != null ) {
327
- info .clear ();
340
+ if (!createHeapArgInfo .get ()) {
341
+ infoStack .pop ();
342
+ createHeapArgInfo .set (Boolean .TRUE );
328
343
}
329
344
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
330
345
throw e ;
331
346
}
332
347
333
348
long address = argValue .address ();
334
349
/*[IF JAVA_SPEC_VERSION >= 22]*/
335
- if (info == null ) {
350
+
351
+ if (createHeapArgInfo .get ()) {
336
352
info = new HeapArgInfo (argLayoutArray .length );
337
- heapArgInfo .set (info );
353
+ infoStack .push (info );
354
+ createHeapArgInfo .set (Boolean .FALSE );
338
355
}
339
356
340
357
if (!argValue .isNative () && options .allowsHeapAccess ()) {
@@ -369,9 +386,10 @@ private final long memSegmtToLongArg(MemorySegment argValue) throws IllegalState
369
386
* is captured so as to reset the internal index and avoid retaining the references
370
387
* to the unreachable objects.
371
388
*/
372
- HeapArgInfo info = heapArgInfo .get ();
373
- if (info != null ) {
374
- info .clear ();
389
+ Deque <HeapArgInfo > infoStack = heapArgInfo .get ();
390
+ if (!createHeapArgInfo .get ()) {
391
+ infoStack .pop ();
392
+ createHeapArgInfo .set (Boolean .TRUE );
375
393
}
376
394
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
377
395
throw e ;
@@ -506,10 +524,6 @@ public InternalDowncallHandler(MethodType functionMethodType, FunctionDescriptor
506
524
scopeHandleMap = new ConcurrentHashMap <>();
507
525
/*[ENDIF] JAVA_SPEC_VERSION == 17 */
508
526
509
- /*[IF JAVA_SPEC_VERSION >= 22]*/
510
- heapArgInfo = new ThreadLocal <>();
511
- /*[ENDIF] JAVA_SPEC_VERSION >= 22 */
512
-
513
527
try {
514
528
/*[IF JAVA_SPEC_VERSION >= 21]*/
515
529
longObjToMemSegmtRetFilter = lookup .bind (this , "longObjToMemSegmtRet" , methodType (MemorySegment .class , Object .class ));
@@ -882,7 +896,17 @@ Object runNativeMethod(Addressable downcallAddr, SegmentAllocator segmtAllocator
882
896
883
897
long returnVal ;
884
898
/*[IF JAVA_SPEC_VERSION >= 22]*/
885
- HeapArgInfo info = heapArgInfo .get ();
899
+ Deque <HeapArgInfo > infoStack = heapArgInfo .get ();
900
+ HeapArgInfo info ;
901
+ /* Check if current downcall has pointer arguments. */
902
+ boolean pointerArgs = true ;
903
+ if (createHeapArgInfo .get ()) {
904
+ info = null ;
905
+ pointerArgs = false ;
906
+ } else {
907
+ info = infoStack .peek ();
908
+ createHeapArgInfo .set (Boolean .TRUE );
909
+ }
886
910
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
887
911
/* The scope associated with memory specific arguments must be kept alive
888
912
* during the downcall since JDK17, including the downcall adddress.
@@ -936,8 +960,8 @@ Object runNativeMethod(Addressable downcallAddr, SegmentAllocator segmtAllocator
936
960
* so as to reset the internal index and avoid retaining the references to the
937
961
* unreachable objects.
938
962
*/
939
- if (info != null ) {
940
- info . clear ();
963
+ if (pointerArgs ) {
964
+ infoStack . pop ();
941
965
}
942
966
}
943
967
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
0 commit comments