package com.oracle.truffle.llvm.runtime.interop.nfi;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.llvm.runtime.interop.nfi.LLVMNativeConvertNodeFactory.I1FromNativeToLLVMNodeGen;
import com.oracle.truffle.llvm.runtime.interop.nfi.LLVMNativeConvertNodeFactory.IdNodeGen;
import com.oracle.truffle.llvm.runtime.interop.nfi.LLVMNativeConvertNodeFactory.NativeToAddressNodeGen;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMNode;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMToNativeNode;
import com.oracle.truffle.llvm.runtime.pointer.LLVMManagedPointer;
import com.oracle.truffle.llvm.runtime.pointer.LLVMNativePointer;
import com.oracle.truffle.llvm.runtime.pointer.LLVMPointer;
import com.oracle.truffle.llvm.runtime.types.FunctionType;
import com.oracle.truffle.llvm.runtime.types.PointerType;
import com.oracle.truffle.llvm.runtime.types.PrimitiveType;
import com.oracle.truffle.llvm.runtime.types.PrimitiveType.PrimitiveKind;
import com.oracle.truffle.llvm.runtime.types.Type;
import com.oracle.truffle.llvm.runtime.types.VoidType;
public abstract class LLVMNativeConvertNode extends LLVMNode {
public abstract Object executeConvert(Object arg);
public static LLVMNativeConvertNode createToNative(Type argType) {
if (argType instanceof PointerType || argType instanceof FunctionType) {
return new AddressToNative();
} else if (argType instanceof VoidType) {
return new VoidToNative();
} else if (argType instanceof PrimitiveType) {
if (((PrimitiveType) argType).getPrimitiveKind() == PrimitiveKind.I64) {
return new AddressToNative();
}
}
return IdNodeGen.create();
}
public static LLVMNativeConvertNode createFromNative(Type retType) {
if (retType instanceof PointerType) {
return NativeToAddressNodeGen.create();
} else if (retType instanceof PrimitiveType && ((PrimitiveType) retType).getPrimitiveKind() == PrimitiveKind.I1) {
return I1FromNativeToLLVMNodeGen.create();
}
return IdNodeGen.create();
}
protected static class VoidToNative extends LLVMNativeConvertNode {
@Override
public Object executeConvert(Object arg) {
assert LLVMPointer.isInstance(arg) && LLVMPointer.cast(arg).isNull();
return LLVMNativePointer.createNull();
}
}
protected static class AddressToNative extends LLVMNativeConvertNode {
@Child LLVMToNativeNode toNative = LLVMToNativeNode.createToNativeWithTarget();
@Override
public Object executeConvert(Object arg) {
return toNative.executeWithTarget(arg).asNative();
}
}
protected abstract static class NativeToAddress extends LLVMNativeConvertNode {
@Specialization
protected LLVMNativePointer doLong(long pointer) {
return LLVMNativePointer.create(pointer);
}
@Specialization(guards = "interop.isPointer(address)", limit = "3", rewriteOn = UnsupportedMessageException.class)
protected LLVMNativePointer doPointer(Object address,
@CachedLibrary("address") InteropLibrary interop) throws UnsupportedMessageException {
return LLVMNativePointer.create(interop.asPointer(address));
}
@Specialization(guards = "!interop.isPointer(address)", limit = "3")
protected LLVMManagedPointer doFunction(Object address,
@CachedLibrary("address") @SuppressWarnings("unused") InteropLibrary interop) {
return LLVMManagedPointer.create(address);
}
@Specialization(limit = "3", replaces = {"doPointer", "doFunction"})
protected LLVMPointer doGeneric(Object address,
@CachedLibrary("address") InteropLibrary interop) {
if (interop.isPointer(address)) {
try {
return doPointer(address, interop);
} catch (UnsupportedMessageException ex) {
}
}
return doFunction(address, interop);
}
}
protected abstract static class Id extends LLVMNativeConvertNode {
@Specialization
protected Object doConvert(Object arg) {
return arg;
}
}
abstract static class I1FromNativeToLLVMNode extends LLVMNativeConvertNode {
@Specialization
protected Object convert(byte value) {
return value != 0;
}
@Specialization
protected Object convert(boolean value) {
return value;
}
}
}