Skip to content

Commit 22869c2

Browse files
Aditi SrinivasAditi Srinivas
authored andcommitted
Refactor HeapArgInfo to Support Recursive Downcalls
Fix for Issue #21944 Fix for failing java/foreign/TestBufferStack.java test. Replaced single HeapArgInfo with a thread-local Deque. To track multiple argument sets for recursions. Each downcall pushes a new HeapArgInfo into Deque. Clears the most recent entry after downcall completion.
1 parent 1f597d2 commit 22869c2

File tree

1 file changed

+40
-16
lines changed

1 file changed

+40
-16
lines changed

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

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
package openj9.internal.foreign.abi;
2424

2525
/*[IF JAVA_SPEC_VERSION >= 22]*/
26+
import java.util.ArrayDeque;
2627
import java.util.Arrays;
28+
import java.util.Deque;
2729
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
2830
import java.util.HashMap;
2931
import java.util.List;
@@ -123,7 +125,18 @@ void clear() {
123125
}
124126
}
125127

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);
127140
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
128141

129142
/* The hashtables of sessions/scopes is intended for multithreading in which case
@@ -311,7 +324,8 @@ private void validateMemScope(ResourceScope memScope) throws IllegalStateExcepti
311324
*/
312325
private final long memSegmtOfPtrToLongArg(MemorySegment argValue, LinkerOptions options) throws IllegalStateException {
313326
/*[IF JAVA_SPEC_VERSION >= 22]*/
314-
HeapArgInfo info = heapArgInfo.get();
327+
Deque<HeapArgInfo> infoStack = heapArgInfo.get();
328+
HeapArgInfo info = infoStack.peek();
315329
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
316330

317331
try {
@@ -323,18 +337,21 @@ private final long memSegmtOfPtrToLongArg(MemorySegment argValue, LinkerOptions
323337
* is captured so as to reset the internal index and avoid retaining the references
324338
* to the unreachable objects.
325339
*/
326-
if (info != null) {
327-
info.clear();
340+
if (!createHeapArgInfo.get()) {
341+
infoStack.pop();
342+
createHeapArgInfo.set(Boolean.TRUE);
328343
}
329344
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
330345
throw e;
331346
}
332347

333348
long address = argValue.address();
334349
/*[IF JAVA_SPEC_VERSION >= 22]*/
335-
if (info == null) {
350+
351+
if (createHeapArgInfo.get()) {
336352
info = new HeapArgInfo(argLayoutArray.length);
337-
heapArgInfo.set(info);
353+
infoStack.push(info);
354+
createHeapArgInfo.set(Boolean.FALSE);
338355
}
339356

340357
if (!argValue.isNative() && options.allowsHeapAccess()) {
@@ -369,9 +386,10 @@ private final long memSegmtToLongArg(MemorySegment argValue) throws IllegalState
369386
* is captured so as to reset the internal index and avoid retaining the references
370387
* to the unreachable objects.
371388
*/
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);
375393
}
376394
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
377395
throw e;
@@ -506,10 +524,6 @@ public InternalDowncallHandler(MethodType functionMethodType, FunctionDescriptor
506524
scopeHandleMap = new ConcurrentHashMap<>();
507525
/*[ENDIF] JAVA_SPEC_VERSION == 17 */
508526

509-
/*[IF JAVA_SPEC_VERSION >= 22]*/
510-
heapArgInfo = new ThreadLocal<>();
511-
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
512-
513527
try {
514528
/*[IF JAVA_SPEC_VERSION >= 21]*/
515529
longObjToMemSegmtRetFilter = lookup.bind(this, "longObjToMemSegmtRet", methodType(MemorySegment.class, Object.class));
@@ -882,7 +896,17 @@ Object runNativeMethod(Addressable downcallAddr, SegmentAllocator segmtAllocator
882896

883897
long returnVal;
884898
/*[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+
}
886910
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */
887911
/* The scope associated with memory specific arguments must be kept alive
888912
* during the downcall since JDK17, including the downcall adddress.
@@ -936,8 +960,8 @@ Object runNativeMethod(Addressable downcallAddr, SegmentAllocator segmtAllocator
936960
* so as to reset the internal index and avoid retaining the references to the
937961
* unreachable objects.
938962
*/
939-
if (info != null) {
940-
info.clear();
963+
if (pointerArgs) {
964+
infoStack.pop();
941965
}
942966
}
943967
/*[ENDIF] JAVA_SPEC_VERSION >= 22 */

0 commit comments

Comments
 (0)