11/*
2- * Copyright (c) 2023, 2025 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2023, 2026 , 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
7272import com .oracle .svm .core .snippets .SnippetRuntime ;
7373import com .oracle .svm .core .snippets .SubstrateForeignCallTarget ;
7474import com .oracle .svm .core .util .ImageHeapMap ;
75+ import com .oracle .svm .shared .AlwaysInline ;
7576import com .oracle .svm .shared .Uninterruptible ;
7677import com .oracle .svm .shared .singletons .traits .BuiltinTraits .AllAccess ;
7778import com .oracle .svm .shared .singletons .traits .BuiltinTraits .NoLayeredCallbacks ;
@@ -102,6 +103,7 @@ public static ForeignFunctionsRuntime singleton() {
102103 private final AbiUtils .TrampolineTemplate trampolineTemplate ;
103104
104105 private final EconomicMap <NativeEntryPointInfo , FunctionPointerHolder > downcallStubs = ImageHeapMap .create ("downcallStubs" );
106+ private final EconomicMap <MethodType , FunctionPointerHolder > downcallStubInvokers = ImageHeapMap .create ("downcallStubInvokers" );
105107 private final EconomicMap <Pair <DirectMethodHandleDesc , JavaEntryPointInfo >, FunctionPointerHolder > directUpcallStubs = ImageHeapMap .create ("directUpcallStubs" );
106108 private final EconomicMap <JavaEntryPointInfo , FunctionPointerHolder > upcallStubs = ImageHeapMap .create ("upcallStubs" );
107109 private final EconomicSet <ResolvedJavaType > neverAccessesSharedArenaTypes = EconomicSet .create ();
@@ -161,6 +163,11 @@ public boolean downcallStubExists(NativeEntryPointInfo nep) {
161163 return downcallStubs .containsKey (nep );
162164 }
163165
166+ @ Platforms (Platform .HOSTED_ONLY .class )
167+ public boolean downcallStubInvokerExists (MethodType methodType ) {
168+ return downcallStubInvokers .containsKey (methodType );
169+ }
170+
164171 @ Platforms (Platform .HOSTED_ONLY .class )
165172 public int getDowncallStubsCount () {
166173 return downcallStubs .size ();
@@ -171,6 +178,11 @@ public boolean upcallStubExists(JavaEntryPointInfo jep) {
171178 return upcallStubs .containsKey (jep );
172179 }
173180
181+ @ Platforms (Platform .HOSTED_ONLY .class )
182+ public boolean addDowncallStubInvokerPointer (MethodType methodType , CFunctionPointer ptr ) {
183+ return downcallStubInvokers .putIfAbsent (methodType , new FunctionPointerHolder (ptr )) == null ;
184+ }
185+
174186 @ Platforms (Platform .HOSTED_ONLY .class )
175187 public int getUpcallStubsCount () {
176188 return upcallStubs .size ();
@@ -212,14 +224,22 @@ public void registerSafeArenaAccessorMethod(ResolvedJavaMethod method) {
212224 neverAccessesSharedArenaMethods .add (method );
213225 }
214226
215- CFunctionPointer getDowncallStubPointer (NativeEntryPointInfo nep ) {
227+ public CFunctionPointer getDowncallStubPointer (NativeEntryPointInfo nep ) {
216228 FunctionPointerHolder holder = downcallStubs .get (nep );
217229 if (holder == null ) {
218230 throw reportMissingDowncall (nep );
219231 }
220232 return holder .functionPointer ;
221233 }
222234
235+ CFunctionPointer getDowncallStubInvokerPointer (MethodType methodType ) {
236+ FunctionPointerHolder holder = downcallStubInvokers .get (methodType );
237+ if (holder == null ) {
238+ throw reportMissingDowncall (methodType );
239+ }
240+ return holder .functionPointer ;
241+ }
242+
223243 CFunctionPointer getUpcallStubPointer (JavaEntryPointInfo jep ) {
224244 FunctionPointerHolder holder = upcallStubs .get (jep );
225245 if (holder == null ) {
@@ -307,6 +327,9 @@ void freeTrampoline(long addr) {
307327 private MissingForeignRegistrationError reportMissingDowncall (NativeEntryPointInfo nep ) {
308328 LinkRequest currentLinkRequest = null ;
309329 for (LinkRequest linkRequest : currentLinkRequests ) {
330+ if (!Thread .currentThread ().equals (linkRequest .requester )) {
331+ continue ;
332+ }
310333 NativeEntryPointInfo nativeEntryPointInfo = abiUtils .makeNativeEntrypoint (linkRequest .functionDescriptor , linkRequest .linkerOptions );
311334 if (nep .equals (nativeEntryPointInfo )) {
312335 currentLinkRequest = linkRequest ;
@@ -316,6 +339,21 @@ private MissingForeignRegistrationError reportMissingDowncall(NativeEntryPointIn
316339 throw MissingForeignRegistrationUtils .report (false , currentLinkRequest , nep .methodType ());
317340 }
318341
342+ /**
343+ * Similar to {@link #reportMissingDowncall(NativeEntryPointInfo)} but only matches the
344+ * requested {@link MethodType}.
345+ */
346+ private MissingForeignRegistrationError reportMissingDowncall (MethodType methodType ) {
347+ LinkRequest currentLinkRequest = null ;
348+ for (LinkRequest linkRequest : currentLinkRequests ) {
349+ if (methodType .equals (linkRequest .functionDescriptor .toMethodType ())) {
350+ currentLinkRequest = linkRequest ;
351+ break ;
352+ }
353+ }
354+ throw MissingForeignRegistrationUtils .report (false , currentLinkRequest , methodType );
355+ }
356+
319357 /**
320358 * Similar to {@link #reportMissingDowncall} but for upcalls.
321359 */
@@ -352,10 +390,10 @@ private static MissingForeignRegistrationError report(boolean upcall, LinkReques
352390 "upcallStub" ));
353391 }
354392
355- record LinkRequest (boolean upcall , FunctionDescriptor functionDescriptor , LinkerOptions linkerOptions ) implements AutoCloseable , JsonPrintable {
393+ record LinkRequest (boolean upcall , FunctionDescriptor functionDescriptor , LinkerOptions linkerOptions , Thread requester ) implements AutoCloseable , JsonPrintable {
356394
357395 static LinkRequest create (boolean upcall , FunctionDescriptor functionDescriptor , LinkerOptions linkerOptions ) {
358- LinkRequest linkRequest = new LinkRequest (upcall , functionDescriptor , linkerOptions );
396+ LinkRequest linkRequest = new LinkRequest (upcall , functionDescriptor , linkerOptions , Thread . currentThread () );
359397 ForeignFunctionsRuntime .singleton ().currentLinkRequests .push (linkRequest );
360398 return linkRequest ;
361399 }
@@ -399,9 +437,10 @@ public void printJson(JsonWriter writer) throws IOException {
399437 @ Override
400438 public Object linkToNative (Object ... args ) throws Throwable {
401439 Target_jdk_internal_foreign_abi_NativeEntryPoint nep = (Target_jdk_internal_foreign_abi_NativeEntryPoint ) args [args .length - 1 ];
402- StubPointer pointer = Word .pointer (nep .downcallStubAddress );
403- /* The nep argument will be dropped in the invoked function */
404- return pointer .invoke (args );
440+ StubInvokerPointer invoker = (StubInvokerPointer ) nep .downcallInvokerPointer ;
441+ CFunctionPointer stub = nep .downcallStubPointer ;
442+ /* The nep argument will be dropped in the invoked downcall stub */
443+ return invoker .invoke (stub , args );
405444 }
406445
407446 @ Override
@@ -437,6 +476,12 @@ public void onScopeReachable(Object scopeObj, DisallowedObjectReporter reporter)
437476 }
438477 }
439478
479+ @ AlwaysInline ("method handle interpreter performance" )
480+ @ Override
481+ public MethodType getMethodTypeFromNativeEntryPoint (Object nativeEntryPoint ) {
482+ return ((Target_jdk_internal_foreign_abi_NativeEntryPoint ) nativeEntryPoint ).type ();
483+ }
484+
440485 /**
441486 * Workaround for CapturableState.maskFromName(String) being interruptible.
442487 */
@@ -502,7 +547,8 @@ public boolean isSafeCallee(ResolvedJavaMethod method) {
502547 }
503548}
504549
505- interface StubPointer extends CFunctionPointer {
550+ /** Invoke interface for {@code com.oracle.svm.hosted.foreign.DowncallStubInvoker}. */
551+ interface StubInvokerPointer extends CFunctionPointer {
506552 @ InvokeJavaFunctionPointer
507- Object invoke (Object ... args );
553+ Object invoke (CFunctionPointer downcallStub , Object ... args );
508554}
0 commit comments