2727import static jdk .graal .compiler .core .common .spi .ForeignCallDescriptor .CallSideEffect .HAS_SIDE_EFFECT ;
2828
2929import java .lang .constant .DirectMethodHandleDesc ;
30+ import java .lang .foreign .MemorySegment ;
31+ import java .lang .foreign .MemorySegment .Scope ;
3032import java .lang .invoke .MethodHandle ;
3133import java .util .HashMap ;
3234import java .util .Locale ;
4244import org .graalvm .word .LocationIdentity ;
4345import org .graalvm .word .Pointer ;
4446
47+ import com .oracle .svm .core .ForeignSupport ;
4548import com .oracle .svm .core .FunctionPointerHolder ;
4649import com .oracle .svm .core .OS ;
4750import com .oracle .svm .core .SubstrateOptions ;
4851import com .oracle .svm .core .SubstrateUtil ;
4952import com .oracle .svm .core .Uninterruptible ;
53+ import com .oracle .svm .core .c .InvokeJavaFunctionPointer ;
5054import com .oracle .svm .core .headers .LibC ;
5155import com .oracle .svm .core .headers .WindowsAPIs ;
56+ import com .oracle .svm .core .image .DisallowedImageHeapObjects .DisallowedObjectReporter ;
5257import com .oracle .svm .core .snippets .SnippetRuntime ;
5358import com .oracle .svm .core .snippets .SubstrateForeignCallTarget ;
5459import com .oracle .svm .core .util .BasedOnJDKFile ;
5762import jdk .graal .compiler .api .replacements .Fold ;
5863import jdk .graal .compiler .word .Word ;
5964import jdk .internal .foreign .CABI ;
65+ import jdk .internal .foreign .MemorySessionImpl ;
6066import jdk .internal .foreign .abi .CapturableState ;
6167
62- public class ForeignFunctionsRuntime {
68+ public class ForeignFunctionsRuntime implements ForeignSupport {
6369 @ Fold
6470 public static ForeignFunctionsRuntime singleton () {
6571 return ImageSingletons .lookup (ForeignFunctionsRuntime .class );
6672 }
6773
68- private final AbiUtils .TrampolineTemplate trampolineTemplate = AbiUtils . singleton (). generateTrampolineTemplate () ;
74+ private final AbiUtils .TrampolineTemplate trampolineTemplate ;
6975 private final EconomicMap <NativeEntryPointInfo , FunctionPointerHolder > downcallStubs = EconomicMap .create ();
7076 private final EconomicMap <DirectMethodHandleDesc , FunctionPointerHolder > directUpcallStubs = EconomicMap .create ();
7177 private final EconomicMap <JavaEntryPointInfo , FunctionPointerHolder > upcallStubs = EconomicMap .create ();
@@ -77,7 +83,8 @@ public static ForeignFunctionsRuntime singleton() {
7783 private BiConsumer <Long , DirectMethodHandleDesc > usingSpecializedUpcallListener ;
7884
7985 @ Platforms (Platform .HOSTED_ONLY .class )
80- public ForeignFunctionsRuntime () {
86+ public ForeignFunctionsRuntime (AbiUtils abiUtils ) {
87+ this .trampolineTemplate = abiUtils .generateTrampolineTemplate ();
8188 }
8289
8390 public static boolean areFunctionCallsSupported () {
@@ -224,6 +231,60 @@ private static String generateMessage(JavaEntryPointInfo jep) {
224231 }
225232 }
226233
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+
227288 /**
228289 * Workaround for CapturableState.mask() being interruptible.
229290 */
@@ -276,3 +337,8 @@ public static void captureCallState(int statesToCapture, CIntPointer captureBuff
276337 public static final SnippetRuntime .SubstrateForeignCallDescriptor CAPTURE_CALL_STATE = SnippetRuntime .findForeignCall (ForeignFunctionsRuntime .class ,
277338 "captureCallState" , HAS_SIDE_EFFECT , LocationIdentity .any ());
278339}
340+
341+ interface StubPointer extends CFunctionPointer {
342+ @ InvokeJavaFunctionPointer
343+ Object invoke (Object ... args );
344+ }
0 commit comments