Skip to content

Commit

Permalink
Unit tests for pointer arithmetic with foreign objects.
Browse files Browse the repository at this point in the history
  • Loading branch information
rschatz committed Jul 15, 2019
1 parent 35763d0 commit b8a9e52
Show file tree
Hide file tree
Showing 5 changed files with 403 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.oracle.truffle.llvm.test.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.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import com.oracle.truffle.llvm.test.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 TruffleObject testLibrary;

@BeforeClass
public static void loadLibrary() {
testLibrary = InteropTestBase.loadTestBitcodeInternal("pointerArithmetic");
}

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);
// 0 - (p ^ -1) == p + 1
obj.verify(1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.oracle.truffle.llvm.test.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.llvm.test.interop.values.NativeValue;
import com.oracle.truffle.llvm.test.interop.values.NullValue;
import com.oracle.truffle.tck.TruffleRunner;
import com.oracle.truffle.tck.TruffleRunner.Inject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.LongBinaryOperator;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized.UseParametersRunnerFactory;

@RunWith(Parameterized.class)
@UseParametersRunnerFactory(TruffleRunner.ParametersFactory.class)
public final class PointerArithmeticTest extends InteropTestBase {

static TruffleObject testLibrary;

@BeforeClass
public static void loadLibrary() {
testLibrary = InteropTestBase.loadTestBitcodeInternal("pointerArithmetic");
}

private static void addTest(ArrayList<Object[]> tests, String method, LongBinaryOperator op) {
tests.add(new Object[]{method, 15L, 37L, op.applyAsLong(15, 37)});
tests.add(new Object[]{method, new NullValue(), 42L, op.applyAsLong(0, 42)});
tests.add(new Object[]{method, 42L, new NullValue(), op.applyAsLong(42, 0)});
tests.add(new Object[]{method, new NativeValue(81), 17L, op.applyAsLong(81, 17)});
tests.add(new Object[]{method, 18L, new NativeValue(27), op.applyAsLong(18, 27)});
}

@Parameters(name = "{0}({1},{2})")
public static Collection<Object[]> data() {
ArrayList<Object[]> tests = new ArrayList<>();
addTest(tests, "test_pointer_add", (a, b) -> a + b);
addTest(tests, "test_pointer_sub", (a, b) -> a - b);
addTest(tests, "test_pointer_mul", (a, b) -> a * b);
addTest(tests, "test_pointer_xor", (a, b) -> a ^ b);
return tests;
}

@Parameter(0) public String name;
@Parameter(1) public Object a;
@Parameter(2) public Object b;
@Parameter(3) public long expected;

public class PointerArithmeticNode extends SulongTestNode {

public PointerArithmeticNode() {
super(testLibrary, name);
}
}

@Test
public void test(@Inject(PointerArithmeticNode.class) CallTarget function) {
Object ret = function.call(a, b);
try {
InteropLibrary lib = InteropLibrary.getFactory().getUncached(ret);
lib.toNative(ret);
Assert.assertEquals("ret", expected, lib.asPointer(ret));
} catch (UnsupportedMessageException ex) {
throw new AssertionError("ret is not a pointer", ex);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.oracle.truffle.llvm.test.interop.values;

import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;

@ExportLibrary(InteropLibrary.class)
@SuppressWarnings("static-method")
public final class NativeValue implements TruffleObject {

final long ptrValue;

public NativeValue(long ptrValue) {
this.ptrValue = ptrValue;
}

@ExportMessage
boolean isPointer() {
return true;
}

@ExportMessage
long asPointer() {
return ptrValue;
}

@Override
public String toString() {
return "native:" + ptrValue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,13 @@
@SuppressWarnings("static-method")
public final class NullValue implements TruffleObject {

static boolean isInstance(TruffleObject object) {
return object instanceof NullValue;
}

@ExportMessage
boolean isNull() {
return true;
}

@ExportMessage
boolean isPointer() {
return true;
}

@ExportMessage
long asPointer() {
return 0;
@Override
public String toString() {
return "null";
}
}
Loading

0 comments on commit b8a9e52

Please sign in to comment.