Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
"default": [],
"items": {
"properties": {
"condition": {
"$ref": "config-condition-schema-v1.0.0.json",
"title": "Condition under which the downcall stub should be registered"
},
"returnType": {
"type": "string",
"title": "A memory layout definition (allows canonical layouts; see 'java.lang.foreign.Linker')"
Expand Down Expand Up @@ -56,6 +60,10 @@
"default": [],
"items": {
"properties": {
"condition": {
"$ref": "config-condition-schema-v1.0.0.json",
"title": "Condition under which the upcall stub should be registered"
},
"returnType": {
"type": "string",
"title": "A memory layout definition (allows canonical layouts; see 'java.lang.foreign.Linker')"
Expand Down Expand Up @@ -88,6 +96,10 @@
"default": [],
"items": {
"properties": {
"condition": {
"$ref": "config-condition-schema-v1.0.0.json",
"title": "Condition under which the direct upcall stub should be registered"
},
"class": {
"type": "string",
"title": "Full-qualified class name (e.g. 'org.package.OuterClass$InnerClass')"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,14 @@
import java.util.List;

import org.graalvm.collections.EconomicMap;
import org.graalvm.nativeimage.impl.ConfigurationCondition;

/**
* A base class for parsing FFM API configurations.
*
* @param <FD> the type of the function descriptor
* @param <LO> the type of the linker options
*/
public abstract class ForeignConfigurationParser<FD, LO> extends ConfigurationParser {
public abstract class ForeignConfigurationParser<FD, LO> extends ConditionalConfigurationParser {
private static final String PARAMETER_TYPES = "parameterTypes";
private static final String RETURN_TYPE = "returnType";

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

private void parseAndRegisterForeignCall(Object call, boolean forUpcall) {
var map = asMap(call, "a foreign call must be a map");
checkAttributes(map, "foreign call", List.of(RETURN_TYPE, PARAMETER_TYPES), List.of("options"));
checkAttributes(map, "foreign call", List.of(RETURN_TYPE, PARAMETER_TYPES), List.of(CONDITIONAL_KEY, "options"));
var condition = parseCondition(map, true);
var descriptor = createFunctionDescriptor(map);
var optionsMap = asMap(map.get("options", EconomicMap.emptyMap()), "options must be a map");
if (forUpcall) {
LO upcallOptions = createUpcallOptions(optionsMap, descriptor);
try {
registerUpcall(ConfigurationCondition.alwaysTrue(), descriptor, upcallOptions);
registerUpcall(condition, descriptor, upcallOptions);
} catch (Exception e) {
handleRegistrationError(e, map);
}
} else {
LO downcallOptions = createDowncallOptions(optionsMap, descriptor);
try {
registerDowncall(ConfigurationCondition.alwaysTrue(), descriptor, downcallOptions);
registerDowncall(condition, descriptor, downcallOptions);
} catch (Exception e) {
handleRegistrationError(e, map);
}
Expand All @@ -90,8 +90,9 @@ private void parseAndRegisterForeignCall(Object call, boolean forUpcall) {

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

var condition = parseCondition(map, true);
String className = asString(map.get("class"), "class");
String methodName = asString(map.get("method"), "method");
Object returnTypeInput = map.get(RETURN_TYPE);
Expand All @@ -102,13 +103,13 @@ private void parseAndRegisterDirectUpcall(Object call) {
FD descriptor = createFunctionDescriptor(map);
LO upcallOptions = createUpcallOptions(optionsMap, descriptor);
try {
registerDirectUpcallWithDescriptor(className, methodName, descriptor, upcallOptions);
registerDirectUpcallWithDescriptor(condition, className, methodName, descriptor, upcallOptions);
} catch (Exception e) {
handleRegistrationError(e, map);
}
} else {
try {
registerDirectUpcallWithoutDescriptor(className, methodName, optionsMap);
registerDirectUpcallWithoutDescriptor(condition, className, methodName, optionsMap);
} catch (Exception e) {
handleRegistrationError(e, map);
}
Expand Down Expand Up @@ -141,13 +142,13 @@ private FD createFunctionDescriptor(EconomicMap<String, Object> map) {
/** Parses the options allowed for upcalls. */
protected abstract LO createUpcallOptions(EconomicMap<String, Object> map, FD desc);

protected abstract void registerDowncall(ConfigurationCondition configurationCondition, FD descriptor, LO options);
protected abstract void registerDowncall(UnresolvedConfigurationCondition configurationCondition, FD descriptor, LO options);

protected abstract void registerUpcall(ConfigurationCondition configurationCondition, FD descriptor, LO options);
protected abstract void registerUpcall(UnresolvedConfigurationCondition configurationCondition, FD descriptor, LO options);

protected abstract void registerDirectUpcallWithoutDescriptor(String className, String methodName, EconomicMap<String, Object> optionsMap);
protected abstract void registerDirectUpcallWithoutDescriptor(UnresolvedConfigurationCondition configurationCondition, String className, String methodName, EconomicMap<String, Object> optionsMap);

protected abstract void registerDirectUpcallWithDescriptor(String className, String methodName, FD descriptor, LO options);
protected abstract void registerDirectUpcallWithDescriptor(UnresolvedConfigurationCondition configurationCondition, String className, String methodName, FD descriptor, LO options);

protected abstract void handleRegistrationError(Exception e, EconomicMap<String, Object> map);
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@

import org.graalvm.collections.EconomicMap;
import org.graalvm.collections.MapCursor;
import org.graalvm.nativeimage.impl.ConfigurationCondition;

import com.oracle.svm.configure.ConfigurationBase;
import com.oracle.svm.configure.ConfigurationParser;
Expand All @@ -57,7 +56,7 @@ public void printJson(JsonWriter writer) throws IOException {
}
}

private record StubDesc(ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions) implements JsonPrintable {
private record StubDesc(UnresolvedConfigurationCondition condition, ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions) implements JsonPrintable {
@Override
public void printJson(JsonWriter writer) throws IOException {
writer.appendObjectStart();
Expand All @@ -69,7 +68,8 @@ public void printJson(JsonWriter writer) throws IOException {
}
}

private record DirectStubDesc(String clazz, String method, ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions) implements JsonPrintable {
private record DirectStubDesc(UnresolvedConfigurationCondition condition, String clazz, String method, ConfigurationFunctionDescriptor desc,
Map<String, Object> linkerOptions) implements JsonPrintable {
@Override
public void printJson(JsonWriter writer) throws IOException {
writer.appendObjectStart()
Expand All @@ -88,7 +88,7 @@ public DirectStubDesc withoutFD() {
if (desc == null) {
return this;
}
return new DirectStubDesc(clazz, method, null, linkerOptions);
return new DirectStubDesc(condition, clazz, method, null, linkerOptions);
}
}

Expand Down Expand Up @@ -216,48 +216,48 @@ public void mergeConditional(UnresolvedConfigurationCondition condition, Foreign
public void addDowncall(String returnType, List<String> parameterTypes, Map<String, Object> linkerOptions) {
Objects.requireNonNull(returnType);
Objects.requireNonNull(parameterTypes);
addDowncall(new ConfigurationFunctionDescriptor(returnType, parameterTypes), Map.copyOf(linkerOptions));
addDowncall(UnresolvedConfigurationCondition.alwaysTrue(), new ConfigurationFunctionDescriptor(returnType, parameterTypes), Map.copyOf(linkerOptions));
}

public void addUpcall(String returnType, List<String> parameterTypes, Map<String, Object> linkerOptions) {
Objects.requireNonNull(returnType);
Objects.requireNonNull(parameterTypes);
addUpcall(new ConfigurationFunctionDescriptor(returnType, parameterTypes), Map.copyOf(linkerOptions));
addUpcall(UnresolvedConfigurationCondition.alwaysTrue(), new ConfigurationFunctionDescriptor(returnType, parameterTypes), Map.copyOf(linkerOptions));
}

public void addDirectUpcall(String returnType, List<String> parameterTypes, Map<String, Object> linkerOptions, String clazz, String method) {
Objects.requireNonNull(returnType);
Objects.requireNonNull(parameterTypes);
Objects.requireNonNull(clazz);
Objects.requireNonNull(method);
addDirectUpcall(new ConfigurationFunctionDescriptor(returnType, parameterTypes), Map.copyOf(linkerOptions), clazz, method);
addDirectUpcall(UnresolvedConfigurationCondition.alwaysTrue(), new ConfigurationFunctionDescriptor(returnType, parameterTypes), Map.copyOf(linkerOptions), clazz, method);
}

public void addDowncall(ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions) {
public void addDowncall(UnresolvedConfigurationCondition configurationCondition, ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions) {
Objects.requireNonNull(desc);
downcallStubs.add(new StubDesc(desc, Map.copyOf(linkerOptions)));
downcallStubs.add(new StubDesc(configurationCondition, desc, Map.copyOf(linkerOptions)));
}

public void addUpcall(ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions) {
public void addUpcall(UnresolvedConfigurationCondition configurationCondition, ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions) {
Objects.requireNonNull(desc);
upcallStubs.add(new StubDesc(desc, Map.copyOf(linkerOptions)));
upcallStubs.add(new StubDesc(configurationCondition, desc, Map.copyOf(linkerOptions)));
}

public void addDirectUpcall(ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions, String clazz, String method) {
public void addDirectUpcall(UnresolvedConfigurationCondition configurationCondition, ConfigurationFunctionDescriptor desc, Map<String, Object> linkerOptions, String clazz, String method) {
Objects.requireNonNull(desc);
Objects.requireNonNull(clazz);
Objects.requireNonNull(method);
DirectStubDesc candidate = new DirectStubDesc(clazz, method, desc, Map.copyOf(linkerOptions));
DirectStubDesc candidate = new DirectStubDesc(configurationCondition, clazz, method, desc, Map.copyOf(linkerOptions));
// only add the new descriptor if it is not subsumed by an existing one
if (!directUpcallStubs.contains(candidate.withoutFD())) {
directUpcallStubs.add(candidate);
}
}

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

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

}

@Override
protected void registerUpcall(ConfigurationCondition configurationCondition, ConfigurationFunctionDescriptor descriptor, Map<String, Object> options) {
ForeignConfiguration.this.addUpcall(descriptor, options);
protected void registerUpcall(UnresolvedConfigurationCondition configurationCondition, ConfigurationFunctionDescriptor descriptor, Map<String, Object> options) {
ForeignConfiguration.this.addUpcall(configurationCondition, descriptor, options);
}

@Override
protected void registerDirectUpcallWithoutDescriptor(String className, String methodName, EconomicMap<String, Object> optionsMap) {
ForeignConfiguration.this.addDirectUpcall(economicMapToJavaMap(optionsMap), className, methodName);
protected void registerDirectUpcallWithoutDescriptor(UnresolvedConfigurationCondition configurationCondition, String className, String methodName, EconomicMap<String, Object> optionsMap) {
ForeignConfiguration.this.addDirectUpcall(configurationCondition, economicMapToJavaMap(optionsMap), className, methodName);
}

@Override
protected void registerDirectUpcallWithDescriptor(String className, String methodName, ConfigurationFunctionDescriptor descriptor, Map<String, Object> options) {
ForeignConfiguration.this.addDirectUpcall(descriptor, options, className, methodName);
protected void registerDirectUpcallWithDescriptor(UnresolvedConfigurationCondition configurationCondition, String className, String methodName, ConfigurationFunctionDescriptor descriptor,
Map<String, Object> options) {
ForeignConfiguration.this.addDirectUpcall(configurationCondition, descriptor, options, className, methodName);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import java.util.Map;
import java.util.function.BiConsumer;

import com.oracle.svm.core.util.ImageHeapMap;
import org.graalvm.collections.EconomicMap;
import org.graalvm.collections.Pair;
import org.graalvm.nativeimage.ImageSingletons;
Expand Down Expand Up @@ -75,9 +76,10 @@ public static ForeignFunctionsRuntime singleton() {
}

private final AbiUtils.TrampolineTemplate trampolineTemplate;
private final EconomicMap<NativeEntryPointInfo, FunctionPointerHolder> downcallStubs = EconomicMap.create();
private final EconomicMap<Pair<DirectMethodHandleDesc, JavaEntryPointInfo>, FunctionPointerHolder> directUpcallStubs = EconomicMap.create();
private final EconomicMap<JavaEntryPointInfo, FunctionPointerHolder> upcallStubs = EconomicMap.create();

private final EconomicMap<NativeEntryPointInfo, FunctionPointerHolder> downcallStubs = ImageHeapMap.create("downcallStubs");
private final EconomicMap<Pair<DirectMethodHandleDesc, JavaEntryPointInfo>, FunctionPointerHolder> directUpcallStubs = ImageHeapMap.create("directUpcallStubs");
private final EconomicMap<JavaEntryPointInfo, FunctionPointerHolder> upcallStubs = ImageHeapMap.create("upcallStubs");

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

@Platforms(Platform.HOSTED_ONLY.class)
public void addDowncallStubPointer(NativeEntryPointInfo nep, CFunctionPointer ptr) {
VMError.guarantee(!downcallStubs.containsKey(nep), "Seems like multiple stubs were generated for %s", nep);
VMError.guarantee(downcallStubs.put(nep, new FunctionPointerHolder(ptr)) == null);
public boolean downcallStubExists(NativeEntryPointInfo nep) {
return downcallStubs.containsKey(nep);
}

@Platforms(Platform.HOSTED_ONLY.class)
public int getDowncallStubsCount() {
return downcallStubs.size();
}

@Platforms(Platform.HOSTED_ONLY.class)
public boolean upcallStubExists(JavaEntryPointInfo jep) {
return upcallStubs.containsKey(jep);
}

@Platforms(Platform.HOSTED_ONLY.class)
public int getUpcallStubsCount() {
return upcallStubs.size();
}

@Platforms(Platform.HOSTED_ONLY.class)
public boolean directUpcallStubExists(DirectMethodHandleDesc desc, JavaEntryPointInfo jep) {
return directUpcallStubs.containsKey(Pair.create(desc, jep));
}

@Platforms(Platform.HOSTED_ONLY.class)
public int getDirectUpcallStubsCount() {
return directUpcallStubs.size();
}

@Platforms(Platform.HOSTED_ONLY.class)
public boolean addDowncallStubPointer(NativeEntryPointInfo nep, CFunctionPointer ptr) {
return downcallStubs.putIfAbsent(nep, new FunctionPointerHolder(ptr)) == null;
}

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

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

/**
Expand Down
Loading