package com.oracle.svm.truffle.nfi;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.ObjectHandle;
import org.graalvm.nativeimage.ObjectHandles;
import org.graalvm.nativeimage.c.type.CCharPointer;
import org.graalvm.nativeimage.c.type.CTypeConversion;
import org.graalvm.word.SignedWord;
import org.graalvm.word.UnsignedWord;
import org.graalvm.word.WordFactory;
import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.threadlocal.FastThreadLocalFactory;
import com.oracle.svm.core.threadlocal.FastThreadLocalObject;
import com.oracle.svm.truffle.nfi.NativeAPI.TruffleContextHandle;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
public abstract class TruffleNFISupport {
static final Charset UTF8 = Charset.forName("utf8");
private static final FastThreadLocalObject<LocalNativeScope> currentScope = FastThreadLocalFactory.createObject(LocalNativeScope.class);
private final ObjectHandles globalHandles;
private final ObjectHandles closureHandles;
private final ObjectHandles contextHandles;
public final String errnoGetterFunctionName;
protected TruffleNFISupport(String errnoLocation) {
errnoGetterFunctionName = errnoLocation;
globalHandles = ObjectHandles.create();
closureHandles = ObjectHandles.create();
contextHandles = ObjectHandles.create();
}
public static LocalNativeScope createLocalScope(int pinCount) {
LocalNativeScope parent = currentScope.get();
LocalNativeScope ret = new LocalNativeScope(parent, pinCount);
currentScope.set(ret);
return ret;
}
public static void closeLocalScope(LocalNativeScope current, LocalNativeScope parent) {
assert currentScope.get() == current;
currentScope.set(parent);
}
public static TruffleObjectHandle createLocalHandle(Object obj) {
return currentScope.get().createLocalHandle(obj);
}
public TruffleObjectHandle createGlobalHandle(Object obj) {
return (TruffleObjectHandle) globalHandles.create(obj);
}
public void destroyGlobalHandle(TruffleObjectHandle handle) {
SignedWord word = (SignedWord) handle;
if (word.greaterThan(0)) {
globalHandles.destroy((ObjectHandle) word);
}
}
public Object resolveHandle(TruffleObjectHandle handle) {
SignedWord word = (SignedWord) handle;
if (word.equal(0)) {
return null;
} else if (word.greaterThan(0)) {
return globalHandles.get((ObjectHandle) word);
} else {
return currentScope.get().resolveLocalHandle(handle);
}
}
public LibFFI.NativeClosureHandle createClosureHandle(NativeClosure closure) {
return (LibFFI.NativeClosureHandle) closureHandles.create(closure);
}
public NativeClosure resolveClosureHandle(LibFFI.NativeClosureHandle handle) {
return (NativeClosure) closureHandles.get((ObjectHandle) handle);
}
public void destroyClosureHandle(LibFFI.NativeClosureHandle handle) {
closureHandles.destroy((ObjectHandle) handle);
}
public TruffleContextHandle createContextHandle(Target_com_oracle_truffle_nfi_impl_NFIContext context) {
return (TruffleContextHandle) contextHandles.create(context);
}
public Target_com_oracle_truffle_nfi_impl_NFIContext resolveContextHandle(TruffleContextHandle handle) {
return (Target_com_oracle_truffle_nfi_impl_NFIContext) contextHandles.get((ObjectHandle) handle);
}
public void destroyContextHandle(TruffleContextHandle handle) {
contextHandles.destroy((ObjectHandle) handle);
}
@TruffleBoundary
public static String utf8ToJavaString(CCharPointer str) {
if (str.equal(WordFactory.zero())) {
return null;
} else {
UnsignedWord len = SubstrateUtil.strlen(str);
ByteBuffer buffer = CTypeConversion.asByteBuffer(str, (int) len.rawValue());
return UTF8.decode(buffer).toString();
}
}
private static final class ZeroTerminatedCharSequence implements CharSequence {
private CharSequence seq;
ZeroTerminatedCharSequence(CharSequence seq) {
this.seq = seq;
}
@Override
public int length() {
return seq.length() + 1;
}
@Override
public char charAt(int index) {
if (index == seq.length()) {
return '\0';
} else {
return seq.charAt(index);
}
}
@Override
public CharSequence subSequence(int start, int end) {
if (end == length()) {
return new ZeroTerminatedCharSequence(seq.subSequence(start, end - 1));
} else {
return seq.subSequence(start, end);
}
}
}
@TruffleBoundary
public static byte[] javaStringToUtf8(String str) {
CharBuffer input = CharBuffer.wrap(new ZeroTerminatedCharSequence(str));
return UTF8.encode(input).array();
}
protected abstract CCharPointer strdupImpl(CCharPointer src);
protected abstract long loadLibraryImpl(long nativeContext, String name, int flags);
protected abstract void freeLibraryImpl(long library);
protected abstract long lookupImpl(long nativeContext, long library, String name);
public static CCharPointer strdup(CCharPointer src) {
TruffleNFISupport truffleNFISupport = ImageSingletons.lookup(TruffleNFISupport.class);
return truffleNFISupport.strdupImpl(src);
}
public static long loadLibrary(long nativeContext, String name, int flags) {
TruffleNFISupport truffleNFISupport = ImageSingletons.lookup(TruffleNFISupport.class);
return truffleNFISupport.loadLibraryImpl(nativeContext, name, flags);
}
public static void freeLibrary(long library) {
TruffleNFISupport truffleNFISupport = ImageSingletons.lookup(TruffleNFISupport.class);
truffleNFISupport.freeLibraryImpl(library);
}
public static long lookup(long nativeContext, long library, String name) {
TruffleNFISupport truffleNFISupport = ImageSingletons.lookup(TruffleNFISupport.class);
return truffleNFISupport.lookupImpl(nativeContext, library, name);
}
protected static Target_com_oracle_truffle_nfi_impl_NFIContext getContext(long nativeContext) {
TruffleNFISupport truffleNFISupport = ImageSingletons.lookup(TruffleNFISupport.class);
NativeAPI.NativeTruffleContext ctx = WordFactory.pointer(nativeContext);
return truffleNFISupport.resolveContextHandle(ctx.contextHandle());
}
}