package com.oracle.truffle.llvm.tests.interop;
import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import com.oracle.truffle.llvm.tests.interop.values.NativeValue;
import com.oracle.truffle.tck.TruffleRunner;
import com.oracle.truffle.tck.TruffleRunner.Inject;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(TruffleRunner.class)
public class PointerArithmeticDerefTest extends InteropTestBase {
static Object testLibrary;
@BeforeClass
public static void loadLibrary() {
testLibrary = loadTestBitcodeInternal("pointerArithmetic.c");
}
public static class DerefPointerNode extends SulongTestNode {
public DerefPointerNode() {
super(testLibrary, "deref_pointer");
}
}
public static class TestPointerAddNode extends SulongTestNode {
public TestPointerAddNode() {
super(testLibrary, "test_pointer_add");
}
}
public static class TestPointerSubNode extends SulongTestNode {
public TestPointerSubNode() {
super(testLibrary, "test_pointer_sub");
}
}
public static class TestPointerMulNode extends SulongTestNode {
public TestPointerMulNode() {
super(testLibrary, "test_pointer_mul");
}
}
public static class TestPointerXorNode extends SulongTestNode {
public TestPointerXorNode() {
super(testLibrary, "test_pointer_xor");
}
}
@ExportLibrary(InteropLibrary.class)
static class DerefableObject implements TruffleObject {
boolean access = false;
long lastAccessOffset;
@ExportMessage
boolean hasArrayElements() {
return true;
}
@ExportMessage
long getArraySize() {
return Long.MAX_VALUE;
}
@ExportMessage
boolean isArrayElementReadable(@SuppressWarnings("unused") long offset) {
return true;
}
@ExportMessage
byte readArrayElement(long offset) {
access = true;
lastAccessOffset = offset;
return 42;
}
@ExportMessage
void toNative() {
Assert.fail("unexpected toNative");
}
void verify(int expectedOffset) {
Assert.assertTrue("access", access);
Assert.assertEquals("offset", expectedOffset, lastAccessOffset);
}
}
private static Object ptr(long v) {
return new NativeValue(v);
}
@Test
public void testSimple(@Inject(DerefPointerNode.class) CallTarget derefPointer) {
DerefableObject obj = new DerefableObject();
derefPointer.call(obj);
obj.verify(0);
}
@Test
public void testOffset(
@Inject(DerefPointerNode.class) CallTarget derefPointer,
@Inject(TestPointerAddNode.class) CallTarget testPointerAdd) {
DerefableObject obj = new DerefableObject();
Object offsetPtr = testPointerAdd.call(obj, ptr(42));
derefPointer.call(offsetPtr);
obj.verify(42);
}
@Test
public void testNegativeOffset(
@Inject(DerefPointerNode.class) CallTarget derefPointer,
@Inject(TestPointerSubNode.class) CallTarget testPointerSub) {
DerefableObject obj = new DerefableObject();
Object offsetPtr = testPointerSub.call(obj, ptr(42));
derefPointer.call(offsetPtr);
obj.verify(-42);
}
@Test
public void testNegativePointer(
@Inject(DerefPointerNode.class) CallTarget derefPointer,
@Inject(TestPointerAddNode.class) CallTarget testPointerAdd,
@Inject(TestPointerSubNode.class) CallTarget testPointerSub,
@Inject(TestPointerMulNode.class) CallTarget testPointerMul) {
DerefableObject obj = new DerefableObject();
Object negative = testPointerSub.call(ptr(5), obj);
Object negOffset = testPointerAdd.call(negative, ptr(3));
Object posOffset = testPointerMul.call(negOffset, ptr(-1));
derefPointer.call(posOffset);
obj.verify(-8);
}
@Test
public void testXorPointer(
@Inject(DerefPointerNode.class) CallTarget derefPointer,
@Inject(TestPointerXorNode.class) CallTarget testPointerXor,
@Inject(TestPointerSubNode.class) CallTarget testPointerSub) {
DerefableObject obj = new DerefableObject();
Object xored = testPointerXor.call(obj, ptr(-1));
Object neg = testPointerSub.call(ptr(0), xored);
derefPointer.call(neg);
obj.verify(1);
}
@Test
public void testSubtractCancel(
@Inject(TestPointerAddNode.class) CallTarget testPointerAdd,
@Inject(TestPointerSubNode.class) CallTarget testPointerSub) throws UnsupportedMessageException {
DerefableObject obj = new DerefableObject();
Object ptr1 = testPointerAdd.call(obj, ptr(27));
Object ptr2 = testPointerAdd.call(obj, ptr(12));
Object diff = testPointerSub.call(ptr1, ptr2);
Assert.assertEquals("diff", 15, InteropLibrary.getFactory().getUncached().asPointer(diff));
}
}