27
27
import static jdk .graal .compiler .core .common .spi .ForeignCallDescriptor .CallSideEffect .HAS_SIDE_EFFECT ;
28
28
29
29
import java .lang .constant .DirectMethodHandleDesc ;
30
+ import java .lang .foreign .MemorySegment ;
31
+ import java .lang .foreign .MemorySegment .Scope ;
30
32
import java .lang .invoke .MethodHandle ;
31
33
import java .util .HashMap ;
32
34
import java .util .Locale ;
42
44
import org .graalvm .word .LocationIdentity ;
43
45
import org .graalvm .word .Pointer ;
44
46
47
+ import com .oracle .svm .core .ForeignSupport ;
45
48
import com .oracle .svm .core .FunctionPointerHolder ;
46
49
import com .oracle .svm .core .OS ;
47
50
import com .oracle .svm .core .SubstrateOptions ;
48
51
import com .oracle .svm .core .SubstrateUtil ;
49
52
import com .oracle .svm .core .Uninterruptible ;
53
+ import com .oracle .svm .core .c .InvokeJavaFunctionPointer ;
50
54
import com .oracle .svm .core .headers .LibC ;
51
55
import com .oracle .svm .core .headers .WindowsAPIs ;
56
+ import com .oracle .svm .core .image .DisallowedImageHeapObjects .DisallowedObjectReporter ;
52
57
import com .oracle .svm .core .snippets .SnippetRuntime ;
53
58
import com .oracle .svm .core .snippets .SubstrateForeignCallTarget ;
54
59
import com .oracle .svm .core .util .BasedOnJDKFile ;
57
62
import jdk .graal .compiler .api .replacements .Fold ;
58
63
import jdk .graal .compiler .word .Word ;
59
64
import jdk .internal .foreign .CABI ;
65
+ import jdk .internal .foreign .MemorySessionImpl ;
60
66
import jdk .internal .foreign .abi .CapturableState ;
61
67
62
- public class ForeignFunctionsRuntime {
68
+ public class ForeignFunctionsRuntime implements ForeignSupport {
63
69
@ Fold
64
70
public static ForeignFunctionsRuntime singleton () {
65
71
return ImageSingletons .lookup (ForeignFunctionsRuntime .class );
66
72
}
67
73
68
- private final AbiUtils .TrampolineTemplate trampolineTemplate = AbiUtils . singleton (). generateTrampolineTemplate () ;
74
+ private final AbiUtils .TrampolineTemplate trampolineTemplate ;
69
75
private final EconomicMap <NativeEntryPointInfo , FunctionPointerHolder > downcallStubs = EconomicMap .create ();
70
76
private final EconomicMap <DirectMethodHandleDesc , FunctionPointerHolder > directUpcallStubs = EconomicMap .create ();
71
77
private final EconomicMap <JavaEntryPointInfo , FunctionPointerHolder > upcallStubs = EconomicMap .create ();
@@ -77,7 +83,8 @@ public static ForeignFunctionsRuntime singleton() {
77
83
private BiConsumer <Long , DirectMethodHandleDesc > usingSpecializedUpcallListener ;
78
84
79
85
@ Platforms (Platform .HOSTED_ONLY .class )
80
- public ForeignFunctionsRuntime () {
86
+ public ForeignFunctionsRuntime (AbiUtils abiUtils ) {
87
+ this .trampolineTemplate = abiUtils .generateTrampolineTemplate ();
81
88
}
82
89
83
90
public static boolean areFunctionCallsSupported () {
@@ -224,6 +231,60 @@ private static String generateMessage(JavaEntryPointInfo jep) {
224
231
}
225
232
}
226
233
234
+ /**
235
+ * Arguments follow the same structure as described in {@link NativeEntryPointInfo}, with an
236
+ * additional {@link Target_jdk_internal_foreign_abi_NativeEntryPoint} (NEP) as the last
237
+ * argument, i.e.
238
+ *
239
+ * <pre>
240
+ * {@code
241
+ * [return buffer address] <call address> [capture state address] <actual arg 1> <actual arg 2> ... <NEP>
242
+ * }
243
+ * </pre>
244
+ *
245
+ * where <actual arg i>s are the arguments which end up being passed to the C native function
246
+ */
247
+ @ Override
248
+ public Object linkToNative (Object ... args ) throws Throwable {
249
+ Target_jdk_internal_foreign_abi_NativeEntryPoint nep = (Target_jdk_internal_foreign_abi_NativeEntryPoint ) args [args .length - 1 ];
250
+ StubPointer pointer = Word .pointer (nep .downcallStubAddress );
251
+ /* The nep argument will be dropped in the invoked function */
252
+ return pointer .invoke (args );
253
+ }
254
+
255
+ @ Override
256
+ public void onMemorySegmentReachable (Object memorySegmentObj , DisallowedObjectReporter reporter ) {
257
+ VMError .guarantee (memorySegmentObj instanceof MemorySegment );
258
+
259
+ MemorySegment memorySegment = (MemorySegment ) memorySegmentObj ;
260
+ if (memorySegment .isNative () && !MemorySegment .NULL .equals (memorySegment )) {
261
+ throw reporter .raise ("Detected a native MemorySegment in the image heap. " +
262
+ "A native MemorySegment has a pointer to unmanaged C memory, and C memory from the image generator is not available at image runtime." , memorySegment ,
263
+ "Try avoiding to initialize the class that called 'MemorySegment.ofAddress'." );
264
+ }
265
+ }
266
+
267
+ @ Override
268
+ @ BasedOnJDKFile ("https://github.com/openjdk/jdk/blob/jdk-25+21/src/java.base/share/classes/java/lang/foreign/MemorySegment.java#L2708" )
269
+ public void onScopeReachable (Object scopeObj , DisallowedObjectReporter reporter ) {
270
+ VMError .guarantee (scopeObj instanceof Scope );
271
+
272
+ /*
273
+ * We never allow memory sessions with state 'OPEN' to be included in the image heap because
274
+ * native memory may be associated with them which will be attempted to be free'd if the
275
+ * session is closed. Non-closable or closed sessions are allowed.
276
+ *
277
+ * Note: This assumes that there is only one implementor of interface Scope which is
278
+ * MemorySessionImpl. If JDK's class hierarchy changes, we need to adapt this as well.
279
+ */
280
+ if (scopeObj instanceof MemorySessionImpl memorySessionImpl && memorySessionImpl .isAlive () && memorySessionImpl .isCloseable ()) {
281
+ throw reporter .raise ("Detected an open but closable MemorySegment.Scope in the image heap. " +
282
+ "A MemorySegment.Scope may have associated unmanaged C memory that will be attempted to be free'd if the scope is closed. " +
283
+ "However, C memory from the image generator is no longer available at image runtime." , memorySessionImpl ,
284
+ "Try avoiding to initialize the class that called 'Arena.ofConfined/ofShared'." );
285
+ }
286
+ }
287
+
227
288
/**
228
289
* Workaround for CapturableState.mask() being interruptible.
229
290
*/
@@ -276,3 +337,8 @@ public static void captureCallState(int statesToCapture, CIntPointer captureBuff
276
337
public static final SnippetRuntime .SubstrateForeignCallDescriptor CAPTURE_CALL_STATE = SnippetRuntime .findForeignCall (ForeignFunctionsRuntime .class ,
277
338
"captureCallState" , HAS_SIDE_EFFECT , LocationIdentity .any ());
278
339
}
340
+
341
+ interface StubPointer extends CFunctionPointer {
342
+ @ InvokeJavaFunctionPointer
343
+ Object invoke (Object ... args );
344
+ }
0 commit comments