package com.oracle.truffle.llvm.tests.interop.nfi;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import com.oracle.truffle.llvm.runtime.NativeContextExtension;
import com.oracle.truffle.llvm.tests.interop.InteropTestBase;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.interop.InteropException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.llvm.tests.options.TestOptions;
import com.oracle.truffle.tck.TruffleRunner;
public class NFIAPITest {
@ClassRule public static TruffleRunner.RunWithPolyglotRule runWithPolyglot = new TruffleRunner.RunWithPolyglotRule(InteropTestBase.getContextBuilder());
private static final Path TEST_DIR = Paths.get(TestOptions.TEST_SUITE_PATH, "nfi");
private static final String SULONG_FILENAME = "O1." + NativeContextExtension.getNativeLibrarySuffix();
public static Object sulongObject;
public static CallTarget lookupAndBind;
@BeforeClass
public static void initialize() {
sulongObject = loadLibrary("basicTest.c.dir", SULONG_FILENAME);
lookupAndBind = lookupAndBind();
}
private static CallTarget lookupAndBind() {
return Truffle.getRuntime().createCallTarget(new LookupAndBindNode());
}
private static Object loadLibrary(String lib, String filename) {
File file = new File(TEST_DIR.toFile(), lib + "/" + filename);
String loadLib = "with llvm load '" + file.getAbsolutePath() + "'";
Source source = Source.newBuilder("nfi", loadLib, "loadLibrary").internal(true).build();
CallTarget target = runWithPolyglot.getTruffleTestEnv().parseInternal(source);
return target.call();
}
private static final class LookupAndBindNode extends RootNode {
@Child private InteropLibrary lookupSymbol = InteropLibrary.getFactory().createDispatched(3);
@Child private InteropLibrary bind = InteropLibrary.getFactory().createDispatched(3);
private LookupAndBindNode() {
super(null);
}
@Override
public Object execute(VirtualFrame frame) {
Object library = frame.getArguments()[0];
String symbolName = (String) frame.getArguments()[1];
String signature = (String) frame.getArguments()[2];
try {
Object symbol = lookupSymbol.readMember(library, symbolName);
return bind.invokeMember(symbol, "bind", signature);
} catch (InteropException e) {
CompilerDirectives.transferToInterpreter();
throw new AssertionError(e);
}
}
}
protected abstract static class TestRootNode extends RootNode {
protected TestRootNode() {
super(null);
}
@TruffleBoundary
protected static void assertEquals(Object expected, Object actual) {
Assert.assertEquals(expected, actual);
}
@Override
public final Object execute(VirtualFrame frame) {
try {
return executeTest(frame);
} catch (InteropException e) {
CompilerDirectives.transferToInterpreter();
throw new AssertionError(e);
}
}
public abstract Object executeTest(VirtualFrame frame) throws InteropException;
}
protected static class SendExecuteNode extends TestRootNode {
private final Object receiver;
@Child private InteropLibrary interop;
protected SendExecuteNode(Object library, String symbol, String signature) {
this(lookupAndBind(library, symbol, signature));
}
protected SendExecuteNode(Object receiver) {
this.receiver = receiver;
this.interop = InteropLibrary.getFactory().create(receiver);
}
@Override
public Object executeTest(VirtualFrame frame) throws InteropException {
return interop.execute(receiver, frame.getArguments());
}
}
protected static Object lookupAndBind(Object lib, String name, String signature) {
return lookupAndBind.call(lib, name, signature);
}
}