package com.oracle.truffle.nfi;
import com.oracle.truffle.api.dsl.Fallback;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import com.oracle.truffle.nfi.api.SignatureLibrary;
final class NFIType {
final TypeCachedState cachedState;
final Object backendType;
final Object runtimeData;
NFIType(TypeCachedState cachedState, Object backendType) {
this(cachedState, backendType, null);
}
NFIType(TypeCachedState cachedState, Object backendType, Object runtimeData) {
this.cachedState = cachedState;
this.backendType = backendType;
this.runtimeData = runtimeData;
}
abstract static class TypeCachedState {
final int managedArgCount;
TypeCachedState(int managedArgCount) {
this.managedArgCount = managedArgCount;
}
}
static final TypeCachedState SIMPLE = new SimpleTypeCachedState();
static final TypeCachedState CLOSURE = new ClosureTypeCachedState();
static final TypeCachedState INJECTED = new InjectedTypeCachedState();
@ExportLibrary(NFITypeLibrary.class)
static final class SimpleTypeCachedState extends TypeCachedState {
private SimpleTypeCachedState() {
super(1);
}
@ExportMessage
Object convertToNative(NFIType type, Object value) {
assert type.cachedState == this;
return value;
}
@ExportMessage
Object convertFromNative(NFIType type, Object value) {
assert type.cachedState == this;
return value;
}
}
@ExportLibrary(NFITypeLibrary.class)
static final class ClosureTypeCachedState extends TypeCachedState {
private ClosureTypeCachedState() {
super(1);
}
@ExportMessage
static class ConvertToNative {
@Specialization(limit = "3", guards = "interop.isExecutable(value)")
static Object convertToNative(ClosureTypeCachedState state, NFIType type, Object value,
@SuppressWarnings("unused") @CachedLibrary("value") InteropLibrary interop,
@CachedLibrary("type.runtimeData") SignatureLibrary library) {
assert type.cachedState == state;
return library.createClosure(type.runtimeData, value);
}
@Fallback
static Object convertToNative(ClosureTypeCachedState state, NFIType type, Object value) {
assert type.cachedState == state;
return value;
}
}
@ExportMessage
static class ConvertFromNative {
@Specialization(limit = "3", guards = "interop.isNull(nullValue)")
static Object doNull(ClosureTypeCachedState state, NFIType type, Object nullValue,
@SuppressWarnings("unused") @CachedLibrary("nullValue") InteropLibrary interop) {
assert type.cachedState == state;
return nullValue;
}
@Specialization(limit = "3", guards = "!interop.isNull(value)")
static Object doBind(ClosureTypeCachedState state, NFIType type, Object value,
@SuppressWarnings("unused") @CachedLibrary("value") InteropLibrary interop,
@CachedLibrary("type.runtimeData") SignatureLibrary library) {
assert type.cachedState == state;
return library.bind(type.runtimeData, value);
}
}
}
@ExportLibrary(NFITypeLibrary.class)
static final class InjectedTypeCachedState extends TypeCachedState {
private InjectedTypeCachedState() {
super(0);
}
@ExportMessage
Object convertFromNative(NFIType type, @SuppressWarnings("unused") Object value) {
assert type.cachedState == this;
return null;
}
@ExportMessage
Object convertToNative(NFIType type, Object value) {
assert type.cachedState == this && value == null;
return type.runtimeData;
}
}
}