Skip to content

Commit 2b69a66

Browse files
committed
[GR-59353] FFM API: Allow upcalls in configuration files.
PullRequest: graal/19130
2 parents 1be285c + f7ae49c commit 2b69a66

File tree

1 file changed

+26
-13
lines changed

1 file changed

+26
-13
lines changed

substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignFunctionsConfigurationParser.java

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@
2626

2727
import java.lang.foreign.FunctionDescriptor;
2828
import java.lang.foreign.Linker;
29+
import java.lang.foreign.Linker.Option;
2930
import java.net.URI;
3031
import java.util.ArrayList;
3132
import java.util.List;
3233
import java.util.function.BiConsumer;
34+
import java.util.function.Function;
3335

3436
import org.graalvm.collections.EconomicMap;
3537
import org.graalvm.nativeimage.Platform;
@@ -38,9 +40,11 @@
3840
import org.graalvm.nativeimage.impl.RuntimeForeignAccessSupport;
3941

4042
import com.oracle.svm.core.configure.ConfigurationParser;
43+
import com.oracle.svm.core.util.BasedOnJDKFile;
4144

4245
import jdk.graal.compiler.util.json.JsonParserException;
4346

47+
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+23/src/java.base/share/classes/jdk/internal/foreign/abi/LinkerOptions.java")
4448
@Platforms(Platform.HOSTED_ONLY.class)
4549
public class ForeignFunctionsConfigurationParser extends ConfigurationParser {
4650
private static final String DOWNCALL_OPTION_CAPTURE_CALL_STATE = "captureCallState";
@@ -58,41 +62,41 @@ public ForeignFunctionsConfigurationParser(RuntimeForeignAccessSupport access) {
5862
@Override
5963
public void parseAndRegister(Object json, URI origin) {
6064
var topLevel = asMap(json, "first level of document must be a map");
61-
checkAttributes(topLevel, "foreign methods categories", List.of(), List.of("downcalls"));
65+
checkAttributes(topLevel, "foreign methods categories", List.of(), List.of("downcalls", "upcalls"));
6266

6367
var downcalls = asList(topLevel.get("downcalls", List.of()), "downcalls must be an array of method signatures");
6468
for (Object downcall : downcalls) {
65-
parseAndRegisterForeignCall(downcall, (descriptor, options) -> accessSupport.registerForDowncall(ConfigurationCondition.alwaysTrue(), descriptor, options));
69+
parseAndRegisterForeignCall(downcall, this::parseDowncallOptions, (descriptor, options) -> accessSupport.registerForDowncall(ConfigurationCondition.alwaysTrue(), descriptor, options));
6670
}
6771

6872
var upcalls = asList(topLevel.get("upcalls", List.of()), "upcalls must be an array of method signatures");
6973
for (Object upcall : upcalls) {
70-
parseAndRegisterForeignCall(upcall, (descriptor, options) -> accessSupport.registerForUpcall(ConfigurationCondition.alwaysTrue(), descriptor, options));
74+
parseAndRegisterForeignCall(upcall, this::parseUpcallOptions, (descriptor, options) -> accessSupport.registerForUpcall(ConfigurationCondition.alwaysTrue(), descriptor, options));
7175
}
7276
}
7377

74-
private void parseAndRegisterForeignCall(Object call, BiConsumer<Object, Object[]> register) {
78+
private void parseAndRegisterForeignCall(Object call, Function<EconomicMap<String, Object>, List<Option>> optionsParser, BiConsumer<Object, Object[]> register) {
7579
var map = asMap(call, "a foreign call must be a map");
7680
checkAttributes(map, "foreign call", List.of("descriptor"), List.of("options"));
7781
var descriptor = parseDescriptor(map.get("descriptor"));
78-
var options = parseOptions(map.get("options", null));
79-
register.accept(descriptor, options.toArray());
82+
var options = map.get("options", EconomicMap.create());
83+
List<Option> parsedOptions = optionsParser.apply(asMap(options, "options must be a map"));
84+
register.accept(descriptor, parsedOptions.toArray());
8085
}
8186

8287
private FunctionDescriptor parseDescriptor(Object signature) {
8388
String input = asString(signature, "a function descriptor must be a string");
8489
return FunctionDescriptorParser.parse(input);
8590
}
8691

87-
private List<Linker.Option> parseOptions(Object options) {
88-
if (options == null) {
89-
return List.of();
90-
}
91-
92-
ArrayList<Linker.Option> res = new ArrayList<>();
93-
var map = asMap(options, "options must be a map");
92+
/**
93+
* Parses the options allowed for downcalls. This needs to be consistent with
94+
* 'jdk.internal.foreign.abi.LinkerOptions.forDowncall'.
95+
*/
96+
private List<Linker.Option> parseDowncallOptions(EconomicMap<String, Object> map) {
9497
checkAttributes(map, "options", List.of(), List.of(DOWNCALL_OPTION_FIRST_VARIADIC_ARG, DOWNCALL_OPTION_CAPTURE_CALL_STATE, DOWNCALL_OPTION_CRITICAL));
9598

99+
ArrayList<Linker.Option> res = new ArrayList<>();
96100
if (map.containsKey(DOWNCALL_OPTION_FIRST_VARIADIC_ARG)) {
97101
int firstVariadic = (int) asLong(map.get(DOWNCALL_OPTION_FIRST_VARIADIC_ARG), "");
98102
res.add(Linker.Option.firstVariadicArg(firstVariadic));
@@ -128,4 +132,13 @@ private List<Linker.Option> parseOptions(Object options) {
128132

129133
return res;
130134
}
135+
136+
/**
137+
* Parses the options allowed for upcalls (currently, no options are allowed). This needs to be
138+
* consistent with 'jdk.internal.foreign.abi.LinkerOptions.forUpcall'.
139+
*/
140+
private List<Linker.Option> parseUpcallOptions(EconomicMap<String, Object> map) {
141+
checkAttributes(map, "options", List.of(), List.of());
142+
return List.of();
143+
}
131144
}

0 commit comments

Comments
 (0)