Skip to content

Commit 8cad043

Browse files
committed
8336768: Allow captureCallState and critical linker options to be combined
Reviewed-by: mcimadamore
1 parent 63af2f4 commit 8cad043

File tree

14 files changed

+180
-88
lines changed

14 files changed

+180
-88
lines changed

src/java.base/share/classes/java/lang/foreign/Linker.java

-2
Original file line numberDiff line numberDiff line change
@@ -852,8 +852,6 @@ static Option firstVariadicArg(int index) {
852852
* // use errno
853853
* }
854854
* }
855-
* <p>
856-
* This linker option can not be combined with {@link #critical}.
857855
*
858856
* @param capturedState the names of the values to save
859857
* @throws IllegalArgumentException if at least one of the provided

src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequence.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -195,6 +195,10 @@ public boolean needsTransition() {
195195
return !linkerOptions.isCritical();
196196
}
197197

198+
public boolean usingAddressPairs() {
199+
return linkerOptions.allowsHeapAccess();
200+
}
201+
198202
public int numLeadingParams() {
199203
return 2 + (linkerOptions.hasCapturedCallState() ? 1 : 0); // 2 for addr, allocator
200204
}

src/java.base/share/classes/jdk/internal/foreign/abi/CallingSequenceBuilder.java

+12-3
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,18 @@ public CallingSequence build() {
108108
MethodType calleeMethodType;
109109
if (!forUpcall) {
110110
if (linkerOptions.hasCapturedCallState()) {
111-
addArgumentBinding(0, MemorySegment.class, ValueLayout.ADDRESS, List.of(
112-
Binding.unboxAddress(),
113-
Binding.vmStore(abi.capturedStateStorage(), long.class)));
111+
if (linkerOptions.allowsHeapAccess()) {
112+
addArgumentBinding(0, MemorySegment.class, ValueLayout.ADDRESS, List.of(
113+
Binding.dup(),
114+
Binding.segmentBase(),
115+
Binding.vmStore(abi.capturedStateStorage(), Object.class),
116+
Binding.segmentOffsetAllowHeap(),
117+
Binding.vmStore(null, long.class)));
118+
} else {
119+
addArgumentBinding(0, MemorySegment.class, ValueLayout.ADDRESS, List.of(
120+
Binding.unboxAddress(),
121+
Binding.vmStore(abi.capturedStateStorage(), long.class)));
122+
}
114123
}
115124
addArgumentBinding(0, MemorySegment.class, ValueLayout.ADDRESS, List.of(
116125
Binding.unboxAddress(),

src/java.base/share/classes/jdk/internal/foreign/abi/DowncallLinker.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ public MethodHandle getBoundMethodHandle() {
8484
leafType,
8585
callingSequence.needsReturnBuffer(),
8686
callingSequence.capturedStateMask(),
87-
callingSequence.needsTransition()
87+
callingSequence.needsTransition(),
88+
callingSequence.usingAddressPairs()
8889
);
8990
MethodHandle handle = JLIA.nativeMethodHandle(nep);
9091

src/java.base/share/classes/jdk/internal/foreign/abi/LinkerOptions.java

+1-5
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,7 @@ private static LinkerOptions forShared(BiConsumer<LinkerOptionImpl, FunctionDesc
6363
optionMap.put(option.getClass(), opImpl);
6464
}
6565

66-
LinkerOptions linkerOptions = new LinkerOptions(optionMap);
67-
if (linkerOptions.hasCapturedCallState() && linkerOptions.isCritical()) {
68-
throw new IllegalArgumentException("Incompatible linker options: captureCallState, critical");
69-
}
70-
return linkerOptions;
66+
return new LinkerOptions(optionMap);
7167
}
7268

7369
public static LinkerOptions empty() {

src/java.base/share/classes/jdk/internal/foreign/abi/NativeEntryPoint.java

+22-9
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,12 @@ public static NativeEntryPoint make(ABIDescriptor abi,
6060
MethodType methodType,
6161
boolean needsReturnBuffer,
6262
int capturedStateMask,
63-
boolean needsTransition) {
63+
boolean needsTransition,
64+
boolean usingAddressPairs) {
6465
if (returnMoves.length > 1 != needsReturnBuffer) {
6566
throw new AssertionError("Multiple register return, but needsReturnBuffer was false");
6667
}
67-
checkType(methodType, needsReturnBuffer, capturedStateMask);
68+
checkMethodType(methodType, needsReturnBuffer, capturedStateMask, usingAddressPairs);
6869

6970
CacheKey key = new CacheKey(methodType, abi, Arrays.asList(argMoves), Arrays.asList(returnMoves),
7071
needsReturnBuffer, capturedStateMask, needsTransition);
@@ -80,14 +81,26 @@ public static NativeEntryPoint make(ABIDescriptor abi,
8081
});
8182
}
8283

83-
private static void checkType(MethodType methodType, boolean needsReturnBuffer, int savedValueMask) {
84-
if (methodType.parameterType(0) != long.class) {
85-
throw new AssertionError("Address expected as first param: " + methodType);
84+
private static void checkMethodType(MethodType methodType, boolean needsReturnBuffer, int savedValueMask,
85+
boolean usingAddressPairs) {
86+
int checkIdx = 0;
87+
checkParamType(methodType, checkIdx++, long.class, "Function address");
88+
if (needsReturnBuffer) {
89+
checkParamType(methodType, checkIdx++, long.class, "Return buffer address");
8690
}
87-
int checkIdx = 1;
88-
if ((needsReturnBuffer && methodType.parameterType(checkIdx++) != long.class)
89-
|| (savedValueMask != 0 && methodType.parameterType(checkIdx) != long.class)) {
90-
throw new AssertionError("return buffer and/or preserved value address expected: " + methodType);
91+
if (savedValueMask != 0) { // capturing call state
92+
if (usingAddressPairs) {
93+
checkParamType(methodType, checkIdx++, Object.class, "Capture state heap base");
94+
checkParamType(methodType, checkIdx, long.class, "Capture state offset");
95+
} else {
96+
checkParamType(methodType, checkIdx, long.class, "Capture state address");
97+
}
98+
}
99+
}
100+
101+
private static void checkParamType(MethodType methodType, int checkIdx, Class<?> expectedType, String name) {
102+
if (methodType.parameterType(checkIdx) != expectedType) {
103+
throw new AssertionError(name + " expected at index " + checkIdx + ": " + methodType);
91104
}
92105
}
93106

src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,14 @@ private static Object doDowncall(SegmentAllocator returnAllocator, Object[] args
163163
acquiredSessions.add(targetImpl);
164164

165165
MemorySegment capturedState = null;
166+
Object captureStateHeapBase = null;
166167
if (invData.capturedStateMask() != 0) {
167168
capturedState = SharedUtils.checkCaptureSegment((MemorySegment) args[argStart++]);
169+
if (!invData.allowsHeapAccess) {
170+
SharedUtils.checkNative(capturedState);
171+
} else {
172+
captureStateHeapBase = capturedState.heapBase().orElse(null);
173+
}
168174
MemorySessionImpl capturedStateImpl = ((AbstractMemorySegmentImpl) capturedState).sessionImpl();
169175
capturedStateImpl.acquire0();
170176
acquiredSessions.add(capturedStateImpl);
@@ -199,7 +205,8 @@ private static Object doDowncall(SegmentAllocator returnAllocator, Object[] args
199205
retSeg = (invData.returnLayout() instanceof GroupLayout ? returnAllocator : arena).allocate(invData.returnLayout);
200206
}
201207

202-
LibFallback.doDowncall(invData.cif, target, retSeg, argPtrs, capturedState, invData.capturedStateMask(),
208+
LibFallback.doDowncall(invData.cif, target, retSeg, argPtrs,
209+
captureStateHeapBase, capturedState, invData.capturedStateMask(),
203210
heapBases, args.length);
204211

205212
Reference.reachabilityFence(invData.cif());

src/java.base/share/classes/jdk/internal/foreign/abi/fallback/LibFallback.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,11 @@ private static boolean tryLoadLibrary() {
9090
* @see jdk.internal.foreign.abi.CapturableState
9191
*/
9292
static void doDowncall(MemorySegment cif, MemorySegment target, MemorySegment retPtr, MemorySegment argPtrs,
93-
MemorySegment capturedState, int capturedStateMask,
93+
Object captureStateHeapBase, MemorySegment capturedState, int capturedStateMask,
9494
Object[] heapBases, int numArgs) {
9595
doDowncall(cif.address(), target.address(),
9696
retPtr == null ? 0 : retPtr.address(), argPtrs.address(),
97+
captureStateHeapBase,
9798
capturedState == null ? 0 : capturedState.address(), capturedStateMask,
9899
heapBases, numArgs);
99100
}
@@ -212,7 +213,7 @@ private static void checkStatus(int code) {
212213
private static native int createClosure(long cif, Object userData, long[] ptrs);
213214
private static native void freeClosure(long closureAddress, long globalTarget);
214215
private static native void doDowncall(long cif, long fn, long rvalue, long avalues,
215-
long capturedState, int capturedStateMask,
216+
Object captureStateHeapBase, long capturedState, int capturedStateMask,
216217
Object[] heapBases, int numArgs);
217218

218219
private static native int ffi_prep_cif(long cif, int abi, int nargs, long rtype, long atypes);

src/java.base/share/native/libfallbackLinker/fallbackLinker.c

+19-7
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,16 @@ static void do_capture_state(int32_t* value_ptr, int captured_state_mask) {
112112

113113
JNIEXPORT void JNICALL
114114
Java_jdk_internal_foreign_abi_fallback_LibFallback_doDowncall(JNIEnv* env, jclass cls, jlong cif, jlong fn, jlong rvalue,
115-
jlong avalues, jlong jcaptured_state, jint captured_state_mask,
115+
jlong avalues,
116+
jarray capture_state_heap_base, jlong captured_state_offset,
117+
jint captured_state_mask,
116118
jarray heapBases, jint numArgs) {
117119
void** carrays;
120+
int capture_state_hb_offset = numArgs;
121+
int32_t* captured_state_addr = jlong_to_ptr(captured_state_offset);
118122
if (heapBases != NULL) {
119123
void** aptrs = jlong_to_ptr(avalues);
120-
carrays = malloc(sizeof(void*) * numArgs);
124+
carrays = malloc(sizeof(void*) * (numArgs + 1));
121125
for (int i = 0; i < numArgs; i++) {
122126
jarray hb = (jarray) (*env)->GetObjectArrayElement(env, heapBases, i);
123127
if (hb != NULL) {
@@ -130,24 +134,32 @@ Java_jdk_internal_foreign_abi_fallback_LibFallback_doDowncall(JNIEnv* env, jclas
130134
*((void**)aptrs[i]) = arrayPtr + offset;
131135
}
132136
}
137+
if (capture_state_heap_base != NULL) {
138+
jboolean isCopy;
139+
jbyte* arrayPtr = (*env)->GetPrimitiveArrayCritical(env, capture_state_heap_base, &isCopy);
140+
carrays[capture_state_hb_offset] = arrayPtr;
141+
captured_state_addr = (int32_t*) (arrayPtr + captured_state_offset);
142+
}
133143
}
134144

135145
ffi_call(jlong_to_ptr(cif), jlong_to_ptr(fn), jlong_to_ptr(rvalue), jlong_to_ptr(avalues));
136146

147+
if (captured_state_mask != 0) {
148+
do_capture_state(captured_state_addr, captured_state_mask);
149+
}
150+
137151
if (heapBases != NULL) {
138152
for (int i = 0; i < numArgs; i++) {
139153
jarray hb = (jarray) (*env)->GetObjectArrayElement(env, heapBases, i);
140154
if (hb != NULL) {
141155
(*env)->ReleasePrimitiveArrayCritical(env, hb, carrays[i], JNI_COMMIT);
142156
}
143157
}
158+
if (capture_state_heap_base != NULL) {
159+
(*env)->ReleasePrimitiveArrayCritical(env, capture_state_heap_base, carrays[capture_state_hb_offset], JNI_COMMIT);
160+
}
144161
free(carrays);
145162
}
146-
147-
if (captured_state_mask != 0) {
148-
int32_t* captured_state = jlong_to_ptr(jcaptured_state);
149-
do_capture_state(captured_state, captured_state_mask);
150-
}
151163
}
152164

153165
static void do_upcall(ffi_cif* cif, void* ret, void** args, void* user_data) {

test/jdk/java/foreign/TestIllegalLink.java

-5
Original file line numberDiff line numberDiff line change
@@ -192,11 +192,6 @@ public static Object[][] types() {
192192
NO_OPTIONS,
193193
"has unexpected size"
194194
},
195-
{
196-
FunctionDescriptor.ofVoid(),
197-
new Linker.Option[]{Linker.Option.critical(false), Linker.Option.captureCallState("errno")},
198-
"Incompatible linker options: captureCallState, critical"
199-
},
200195
}));
201196

202197
for (ValueLayout illegalLayout : List.of(C_CHAR, ValueLayout.JAVA_CHAR, C_BOOL, C_SHORT, C_FLOAT)) {

0 commit comments

Comments
 (0)