Skip to content

Commit 18ad31a

Browse files
committed
Support conditions in foreign configuration files
1 parent c6fd7c7 commit 18ad31a

File tree

6 files changed

+273
-172
lines changed

6 files changed

+273
-172
lines changed

docs/reference-manual/native-image/assets/foreign-config-schema-v0.1.0.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
"default": [],
77
"items": {
88
"properties": {
9+
"condition": {
10+
"$ref": "config-condition-schema-v1.0.0.json",
11+
"title": "Condition under which the downcall stub should be registered"
12+
},
913
"returnType": {
1014
"type": "string",
1115
"title": "A memory layout definition (allows canonical layouts; see 'java.lang.foreign.Linker')"
@@ -56,6 +60,10 @@
5660
"default": [],
5761
"items": {
5862
"properties": {
63+
"condition": {
64+
"$ref": "config-condition-schema-v1.0.0.json",
65+
"title": "Condition under which the upcall stub should be registered"
66+
},
5967
"returnType": {
6068
"type": "string",
6169
"title": "A memory layout definition (allows canonical layouts; see 'java.lang.foreign.Linker')"
@@ -88,6 +96,10 @@
8896
"default": [],
8997
"items": {
9098
"properties": {
99+
"condition": {
100+
"$ref": "config-condition-schema-v1.0.0.json",
101+
"title": "Condition under which the direct upcall stub should be registered"
102+
},
91103
"class": {
92104
"type": "string",
93105
"title": "Full-qualified class name (e.g. 'org.package.OuterClass$InnerClass')"

substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/ForeignConfigurationParser.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,14 @@
2929
import java.util.List;
3030

3131
import org.graalvm.collections.EconomicMap;
32-
import org.graalvm.nativeimage.impl.ConfigurationCondition;
3332

3433
/**
3534
* A base class for parsing FFM API configurations.
3635
*
3736
* @param <FD> the type of the function descriptor
3837
* @param <LO> the type of the linker options
3938
*/
40-
public abstract class ForeignConfigurationParser<FD, LO> extends ConfigurationParser {
39+
public abstract class ForeignConfigurationParser<FD, LO> extends ConditionalConfigurationParser {
4140
private static final String PARAMETER_TYPES = "parameterTypes";
4241
private static final String RETURN_TYPE = "returnType";
4342

@@ -68,20 +67,21 @@ public void parseAndRegister(Object json, URI origin) {
6867

6968
private void parseAndRegisterForeignCall(Object call, boolean forUpcall) {
7069
var map = asMap(call, "a foreign call must be a map");
71-
checkAttributes(map, "foreign call", List.of(RETURN_TYPE, PARAMETER_TYPES), List.of("options"));
70+
checkAttributes(map, "foreign call", List.of(RETURN_TYPE, PARAMETER_TYPES), List.of(CONDITIONAL_KEY, "options"));
71+
var condition = parseCondition(map, true);
7272
var descriptor = createFunctionDescriptor(map);
7373
var optionsMap = asMap(map.get("options", EconomicMap.emptyMap()), "options must be a map");
7474
if (forUpcall) {
7575
LO upcallOptions = createUpcallOptions(optionsMap, descriptor);
7676
try {
77-
registerUpcall(ConfigurationCondition.alwaysTrue(), descriptor, upcallOptions);
77+
registerUpcall(condition, descriptor, upcallOptions);
7878
} catch (Exception e) {
7979
handleRegistrationError(e, map);
8080
}
8181
} else {
8282
LO downcallOptions = createDowncallOptions(optionsMap, descriptor);
8383
try {
84-
registerDowncall(ConfigurationCondition.alwaysTrue(), descriptor, downcallOptions);
84+
registerDowncall(condition, descriptor, downcallOptions);
8585
} catch (Exception e) {
8686
handleRegistrationError(e, map);
8787
}
@@ -90,8 +90,9 @@ private void parseAndRegisterForeignCall(Object call, boolean forUpcall) {
9090

9191
private void parseAndRegisterDirectUpcall(Object call) {
9292
var map = asMap(call, "a foreign call must be a map");
93-
checkAttributes(map, "foreign call", List.of("class", "method"), List.of(RETURN_TYPE, PARAMETER_TYPES, "options"));
93+
checkAttributes(map, "foreign call", List.of("class", "method"), List.of(CONDITIONAL_KEY, RETURN_TYPE, PARAMETER_TYPES, "options"));
9494

95+
var condition = parseCondition(map, true);
9596
String className = asString(map.get("class"), "class");
9697
String methodName = asString(map.get("method"), "method");
9798
Object returnTypeInput = map.get(RETURN_TYPE);
@@ -102,13 +103,13 @@ private void parseAndRegisterDirectUpcall(Object call) {
102103
FD descriptor = createFunctionDescriptor(map);
103104
LO upcallOptions = createUpcallOptions(optionsMap, descriptor);
104105
try {
105-
registerDirectUpcallWithDescriptor(className, methodName, descriptor, upcallOptions);
106+
registerDirectUpcallWithDescriptor(condition, className, methodName, descriptor, upcallOptions);
106107
} catch (Exception e) {
107108
handleRegistrationError(e, map);
108109
}
109110
} else {
110111
try {
111-
registerDirectUpcallWithoutDescriptor(className, methodName, optionsMap);
112+
registerDirectUpcallWithoutDescriptor(condition, className, methodName, optionsMap);
112113
} catch (Exception e) {
113114
handleRegistrationError(e, map);
114115
}
@@ -141,13 +142,13 @@ private FD createFunctionDescriptor(EconomicMap<String, Object> map) {
141142
/** Parses the options allowed for upcalls. */
142143
protected abstract LO createUpcallOptions(EconomicMap<String, Object> map, FD desc);
143144

144-
protected abstract void registerDowncall(ConfigurationCondition configurationCondition, FD descriptor, LO options);
145+
protected abstract void registerDowncall(UnresolvedConfigurationCondition configurationCondition, FD descriptor, LO options);
145146

146-
protected abstract void registerUpcall(ConfigurationCondition configurationCondition, FD descriptor, LO options);
147+
protected abstract void registerUpcall(UnresolvedConfigurationCondition configurationCondition, FD descriptor, LO options);
147148

148-
protected abstract void registerDirectUpcallWithoutDescriptor(String className, String methodName, EconomicMap<String, Object> optionsMap);
149+
protected abstract void registerDirectUpcallWithoutDescriptor(UnresolvedConfigurationCondition configurationCondition, String className, String methodName, EconomicMap<String, Object> optionsMap);
149150

150-
protected abstract void registerDirectUpcallWithDescriptor(String className, String methodName, FD descriptor, LO options);
151+
protected abstract void registerDirectUpcallWithDescriptor(UnresolvedConfigurationCondition configurationCondition, String className, String methodName, FD descriptor, LO options);
151152

152153
protected abstract void handleRegistrationError(Exception e, EconomicMap<String, Object> map);
153154
}

substratevm/src/com.oracle.svm.configure/src/com/oracle/svm/configure/config/ForeignConfiguration.java

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737

3838
import org.graalvm.collections.EconomicMap;
3939
import org.graalvm.collections.MapCursor;
40-
import org.graalvm.nativeimage.impl.ConfigurationCondition;
4140

4241
import com.oracle.svm.configure.ConfigurationBase;
4342
import com.oracle.svm.configure.ConfigurationParser;
@@ -57,7 +56,7 @@ public void printJson(JsonWriter writer) throws IOException {
5756
}
5857
}
5958

60-
private record StubDesc(ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions) implements JsonPrintable {
59+
private record StubDesc(UnresolvedConfigurationCondition condition, ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions) implements JsonPrintable {
6160
@Override
6261
public void printJson(JsonWriter writer) throws IOException {
6362
writer.appendObjectStart();
@@ -69,7 +68,8 @@ public void printJson(JsonWriter writer) throws IOException {
6968
}
7069
}
7170

72-
private record DirectStubDesc(String clazz, String method, ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions) implements JsonPrintable {
71+
private record DirectStubDesc(UnresolvedConfigurationCondition condition, String clazz, String method, ConfigurationFunctionDescriptor desc,
72+
Map<String, Object> linkerOptions) implements JsonPrintable {
7373
@Override
7474
public void printJson(JsonWriter writer) throws IOException {
7575
writer.appendObjectStart()
@@ -88,7 +88,7 @@ public DirectStubDesc withoutFD() {
8888
if (desc == null) {
8989
return this;
9090
}
91-
return new DirectStubDesc(clazz, method, null, linkerOptions);
91+
return new DirectStubDesc(condition, clazz, method, null, linkerOptions);
9292
}
9393
}
9494

@@ -216,48 +216,48 @@ public void mergeConditional(UnresolvedConfigurationCondition condition, Foreign
216216
public void addDowncall(String returnType, List<String> parameterTypes, Map<String, Object> linkerOptions) {
217217
Objects.requireNonNull(returnType);
218218
Objects.requireNonNull(parameterTypes);
219-
addDowncall(new ConfigurationFunctionDescriptor(returnType, parameterTypes), Map.copyOf(linkerOptions));
219+
addDowncall(UnresolvedConfigurationCondition.alwaysTrue(), new ConfigurationFunctionDescriptor(returnType, parameterTypes), Map.copyOf(linkerOptions));
220220
}
221221

222222
public void addUpcall(String returnType, List<String> parameterTypes, Map<String, Object> linkerOptions) {
223223
Objects.requireNonNull(returnType);
224224
Objects.requireNonNull(parameterTypes);
225-
addUpcall(new ConfigurationFunctionDescriptor(returnType, parameterTypes), Map.copyOf(linkerOptions));
225+
addUpcall(UnresolvedConfigurationCondition.alwaysTrue(), new ConfigurationFunctionDescriptor(returnType, parameterTypes), Map.copyOf(linkerOptions));
226226
}
227227

228228
public void addDirectUpcall(String returnType, List<String> parameterTypes, Map<String, Object> linkerOptions, String clazz, String method) {
229229
Objects.requireNonNull(returnType);
230230
Objects.requireNonNull(parameterTypes);
231231
Objects.requireNonNull(clazz);
232232
Objects.requireNonNull(method);
233-
addDirectUpcall(new ConfigurationFunctionDescriptor(returnType, parameterTypes), Map.copyOf(linkerOptions), clazz, method);
233+
addDirectUpcall(UnresolvedConfigurationCondition.alwaysTrue(), new ConfigurationFunctionDescriptor(returnType, parameterTypes), Map.copyOf(linkerOptions), clazz, method);
234234
}
235235

236-
public void addDowncall(ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions) {
236+
public void addDowncall(UnresolvedConfigurationCondition configurationCondition, ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions) {
237237
Objects.requireNonNull(desc);
238-
downcallStubs.add(new StubDesc(desc, Map.copyOf(linkerOptions)));
238+
downcallStubs.add(new StubDesc(configurationCondition, desc, Map.copyOf(linkerOptions)));
239239
}
240240

241-
public void addUpcall(ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions) {
241+
public void addUpcall(UnresolvedConfigurationCondition configurationCondition, ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions) {
242242
Objects.requireNonNull(desc);
243-
upcallStubs.add(new StubDesc(desc, Map.copyOf(linkerOptions)));
243+
upcallStubs.add(new StubDesc(configurationCondition, desc, Map.copyOf(linkerOptions)));
244244
}
245245

246-
public void addDirectUpcall(ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions, String clazz, String method) {
246+
public void addDirectUpcall(UnresolvedConfigurationCondition configurationCondition, ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions, String clazz, String method) {
247247
Objects.requireNonNull(desc);
248248
Objects.requireNonNull(clazz);
249249
Objects.requireNonNull(method);
250-
DirectStubDesc candidate = new DirectStubDesc(clazz, method, desc, Map.copyOf(linkerOptions));
250+
DirectStubDesc candidate = new DirectStubDesc(configurationCondition, clazz, method, desc, Map.copyOf(linkerOptions));
251251
// only add the new descriptor if it is not subsumed by an existing one
252252
if (!directUpcallStubs.contains(candidate.withoutFD())) {
253253
directUpcallStubs.add(candidate);
254254
}
255255
}
256256

257-
public void addDirectUpcall(Map<String, Object> linkerOptions, String clazz, String method) {
257+
public void addDirectUpcall(UnresolvedConfigurationCondition configurationCondition, Map<String, Object> linkerOptions, String clazz, String method) {
258258
Objects.requireNonNull(clazz);
259259
Objects.requireNonNull(method);
260-
DirectStubDesc directStubDesc = new DirectStubDesc(clazz, method, null, Map.copyOf(linkerOptions));
260+
DirectStubDesc directStubDesc = new DirectStubDesc(configurationCondition, clazz, method, null, Map.copyOf(linkerOptions));
261261
// remove all existing descriptors if they are subsumed by the new descriptor
262262
directUpcallStubs.removeIf(existing -> directStubDesc.equals(existing.withoutFD()));
263263
directUpcallStubs.add(directStubDesc);
@@ -337,24 +337,25 @@ private UnresolvedForeignConfigurationParser(EnumSet<ConfigurationParserOption>
337337
}
338338

339339
@Override
340-
protected void registerDowncall(ConfigurationCondition configurationCondition, ConfigurationFunctionDescriptor descriptor, Map<String, Object> options) {
341-
ForeignConfiguration.this.addDowncall(descriptor, options);
340+
protected void registerDowncall(UnresolvedConfigurationCondition configurationCondition, ConfigurationFunctionDescriptor descriptor, Map<String, Object> options) {
341+
ForeignConfiguration.this.addDowncall(configurationCondition, descriptor, options);
342342

343343
}
344344

345345
@Override
346-
protected void registerUpcall(ConfigurationCondition configurationCondition, ConfigurationFunctionDescriptor descriptor, Map<String, Object> options) {
347-
ForeignConfiguration.this.addUpcall(descriptor, options);
346+
protected void registerUpcall(UnresolvedConfigurationCondition configurationCondition, ConfigurationFunctionDescriptor descriptor, Map<String, Object> options) {
347+
ForeignConfiguration.this.addUpcall(configurationCondition, descriptor, options);
348348
}
349349

350350
@Override
351-
protected void registerDirectUpcallWithoutDescriptor(String className, String methodName, EconomicMap<String, Object> optionsMap) {
352-
ForeignConfiguration.this.addDirectUpcall(economicMapToJavaMap(optionsMap), className, methodName);
351+
protected void registerDirectUpcallWithoutDescriptor(UnresolvedConfigurationCondition configurationCondition, String className, String methodName, EconomicMap<String, Object> optionsMap) {
352+
ForeignConfiguration.this.addDirectUpcall(configurationCondition, economicMapToJavaMap(optionsMap), className, methodName);
353353
}
354354

355355
@Override
356-
protected void registerDirectUpcallWithDescriptor(String className, String methodName, ConfigurationFunctionDescriptor descriptor, Map<String, Object> options) {
357-
ForeignConfiguration.this.addDirectUpcall(descriptor, options, className, methodName);
356+
protected void registerDirectUpcallWithDescriptor(UnresolvedConfigurationCondition configurationCondition, String className, String methodName, ConfigurationFunctionDescriptor descriptor,
357+
Map<String, Object> options) {
358+
ForeignConfiguration.this.addDirectUpcall(configurationCondition, descriptor, options, className, methodName);
358359
}
359360

360361
@Override

substratevm/src/com.oracle.svm.core.foreign/src/com/oracle/svm/core/foreign/ForeignFunctionsRuntime.java

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import java.util.Map;
3737
import java.util.function.BiConsumer;
3838

39+
import com.oracle.svm.core.util.ImageHeapMap;
3940
import org.graalvm.collections.EconomicMap;
4041
import org.graalvm.collections.Pair;
4142
import org.graalvm.nativeimage.ImageSingletons;
@@ -75,9 +76,10 @@ public static ForeignFunctionsRuntime singleton() {
7576
}
7677

7778
private final AbiUtils.TrampolineTemplate trampolineTemplate;
78-
private final EconomicMap<NativeEntryPointInfo, FunctionPointerHolder> downcallStubs = EconomicMap.create();
79-
private final EconomicMap<Pair<DirectMethodHandleDesc, JavaEntryPointInfo>, FunctionPointerHolder> directUpcallStubs = EconomicMap.create();
80-
private final EconomicMap<JavaEntryPointInfo, FunctionPointerHolder> upcallStubs = EconomicMap.create();
79+
80+
private final EconomicMap<NativeEntryPointInfo, FunctionPointerHolder> downcallStubs = ImageHeapMap.create("downcallStubs");
81+
private final EconomicMap<Pair<DirectMethodHandleDesc, JavaEntryPointInfo>, FunctionPointerHolder> directUpcallStubs = ImageHeapMap.create("directUpcallStubs");
82+
private final EconomicMap<JavaEntryPointInfo, FunctionPointerHolder> upcallStubs = ImageHeapMap.create("upcallStubs");
8183

8284
private final Map<Long, TrampolineSet> trampolines = new HashMap<>();
8385
private TrampolineSet currentTrampolineSet;
@@ -104,22 +106,49 @@ public static RuntimeException functionCallsUnsupported() {
104106
}
105107

106108
@Platforms(Platform.HOSTED_ONLY.class)
107-
public void addDowncallStubPointer(NativeEntryPointInfo nep, CFunctionPointer ptr) {
108-
VMError.guarantee(!downcallStubs.containsKey(nep), "Seems like multiple stubs were generated for %s", nep);
109-
VMError.guarantee(downcallStubs.put(nep, new FunctionPointerHolder(ptr)) == null);
109+
public boolean downcallStubExists(NativeEntryPointInfo nep) {
110+
return downcallStubs.containsKey(nep);
111+
}
112+
113+
@Platforms(Platform.HOSTED_ONLY.class)
114+
public int getDowncallStubsCount() {
115+
return downcallStubs.size();
116+
}
117+
118+
@Platforms(Platform.HOSTED_ONLY.class)
119+
public boolean upcallStubExists(JavaEntryPointInfo jep) {
120+
return upcallStubs.containsKey(jep);
121+
}
122+
123+
@Platforms(Platform.HOSTED_ONLY.class)
124+
public int getUpcallStubsCount() {
125+
return upcallStubs.size();
126+
}
127+
128+
@Platforms(Platform.HOSTED_ONLY.class)
129+
public boolean directUpcallStubExists(DirectMethodHandleDesc desc, JavaEntryPointInfo jep) {
130+
return directUpcallStubs.containsKey(Pair.create(desc, jep));
131+
}
132+
133+
@Platforms(Platform.HOSTED_ONLY.class)
134+
public int getDirectUpcallStubsCount() {
135+
return directUpcallStubs.size();
136+
}
137+
138+
@Platforms(Platform.HOSTED_ONLY.class)
139+
public boolean addDowncallStubPointer(NativeEntryPointInfo nep, CFunctionPointer ptr) {
140+
return downcallStubs.putIfAbsent(nep, new FunctionPointerHolder(ptr)) == null;
110141
}
111142

112143
@Platforms(Platform.HOSTED_ONLY.class)
113-
public void addUpcallStubPointer(JavaEntryPointInfo jep, CFunctionPointer ptr) {
114-
VMError.guarantee(!upcallStubs.containsKey(jep), "Seems like multiple stubs were generated for %s", jep);
115-
VMError.guarantee(upcallStubs.put(jep, new FunctionPointerHolder(ptr)) == null);
144+
public boolean addUpcallStubPointer(JavaEntryPointInfo jep, CFunctionPointer ptr) {
145+
return upcallStubs.putIfAbsent(jep, new FunctionPointerHolder(ptr)) == null;
116146
}
117147

118148
@Platforms(Platform.HOSTED_ONLY.class)
119-
public void addDirectUpcallStubPointer(DirectMethodHandleDesc desc, JavaEntryPointInfo jep, CFunctionPointer ptr) {
149+
public boolean addDirectUpcallStubPointer(DirectMethodHandleDesc desc, JavaEntryPointInfo jep, CFunctionPointer ptr) {
120150
var key = Pair.create(desc, jep);
121-
VMError.guarantee(!directUpcallStubs.containsKey(key), "Seems like multiple stubs were generated for %s", desc);
122-
VMError.guarantee(directUpcallStubs.put(key, new FunctionPointerHolder(ptr)) == null);
151+
return directUpcallStubs.putIfAbsent(key, new FunctionPointerHolder(ptr)) == null;
123152
}
124153

125154
/**

0 commit comments

Comments
 (0)