26
26
27
27
import java .lang .foreign .FunctionDescriptor ;
28
28
import java .lang .foreign .Linker ;
29
+ import java .lang .foreign .Linker .Option ;
29
30
import java .net .URI ;
30
31
import java .util .ArrayList ;
31
32
import java .util .List ;
32
33
import java .util .function .BiConsumer ;
34
+ import java .util .function .Function ;
33
35
34
36
import org .graalvm .collections .EconomicMap ;
35
37
import org .graalvm .nativeimage .Platform ;
38
40
import org .graalvm .nativeimage .impl .RuntimeForeignAccessSupport ;
39
41
40
42
import com .oracle .svm .core .configure .ConfigurationParser ;
43
+ import com .oracle .svm .core .util .BasedOnJDKFile ;
41
44
42
45
import jdk .graal .compiler .util .json .JsonParserException ;
43
46
47
+ @ BasedOnJDKFile ("https://github.com/openjdk/jdk/blob/jdk-24+23/src/java.base/share/classes/jdk/internal/foreign/abi/LinkerOptions.java" )
44
48
@ Platforms (Platform .HOSTED_ONLY .class )
45
49
public class ForeignFunctionsConfigurationParser extends ConfigurationParser {
46
50
private static final String DOWNCALL_OPTION_CAPTURE_CALL_STATE = "captureCallState" ;
@@ -58,41 +62,41 @@ public ForeignFunctionsConfigurationParser(RuntimeForeignAccessSupport access) {
58
62
@ Override
59
63
public void parseAndRegister (Object json , URI origin ) {
60
64
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" ));
62
66
63
67
var downcalls = asList (topLevel .get ("downcalls" , List .of ()), "downcalls must be an array of method signatures" );
64
68
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 ));
66
70
}
67
71
68
72
var upcalls = asList (topLevel .get ("upcalls" , List .of ()), "upcalls must be an array of method signatures" );
69
73
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 ));
71
75
}
72
76
}
73
77
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 ) {
75
79
var map = asMap (call , "a foreign call must be a map" );
76
80
checkAttributes (map , "foreign call" , List .of ("descriptor" ), List .of ("options" ));
77
81
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 ());
80
85
}
81
86
82
87
private FunctionDescriptor parseDescriptor (Object signature ) {
83
88
String input = asString (signature , "a function descriptor must be a string" );
84
89
return FunctionDescriptorParser .parse (input );
85
90
}
86
91
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 ) {
94
97
checkAttributes (map , "options" , List .of (), List .of (DOWNCALL_OPTION_FIRST_VARIADIC_ARG , DOWNCALL_OPTION_CAPTURE_CALL_STATE , DOWNCALL_OPTION_CRITICAL ));
95
98
99
+ ArrayList <Linker .Option > res = new ArrayList <>();
96
100
if (map .containsKey (DOWNCALL_OPTION_FIRST_VARIADIC_ARG )) {
97
101
int firstVariadic = (int ) asLong (map .get (DOWNCALL_OPTION_FIRST_VARIADIC_ARG ), "" );
98
102
res .add (Linker .Option .firstVariadicArg (firstVariadic ));
@@ -128,4 +132,13 @@ private List<Linker.Option> parseOptions(Object options) {
128
132
129
133
return res ;
130
134
}
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
+ }
131
144
}
0 commit comments