All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oracle.truffle.api.dsl.test.ImplicitCastTest Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
package com.oracle.truffle.api.dsl.test;

import static com.oracle.truffle.api.dsl.test.examples.ExampleNode.createArguments;

import java.util.concurrent.locks.ReentrantLock;

import org.junit.Assert;
import org.junit.Test;

import com.oracle.truffle.api.CallTarget;
import com.oracle.truffle.api.Truffle;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.ImplicitCast;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.dsl.TypeSystem;
import com.oracle.truffle.api.dsl.TypeSystemReference;
import com.oracle.truffle.api.dsl.UnsupportedSpecializationException;
import com.oracle.truffle.api.dsl.test.ImplicitCastTestFactory.ExecuteChildWithImplicitCast1NodeGen;
import com.oracle.truffle.api.dsl.test.ImplicitCastTestFactory.ImplicitCast0NodeFactory;
import com.oracle.truffle.api.dsl.test.ImplicitCastTestFactory.ImplicitCast1NodeFactory;
import com.oracle.truffle.api.dsl.test.ImplicitCastTestFactory.ImplicitCast2NodeFactory;
import com.oracle.truffle.api.dsl.test.ImplicitCastTestFactory.ImplicitCast3NodeGen;
import com.oracle.truffle.api.dsl.test.ImplicitCastTestFactory.ImplicitCast4NodeFactory;
import com.oracle.truffle.api.dsl.test.ImplicitCastTestFactory.ImplicitCast5NodeFactory;
import com.oracle.truffle.api.dsl.test.ImplicitCastTestFactory.ImplicitCastExecuteNodeGen;
import com.oracle.truffle.api.dsl.test.ImplicitCastTestFactory.StringEquals1NodeGen;
import com.oracle.truffle.api.dsl.test.ImplicitCastTestFactory.StringEquals2NodeGen;
import com.oracle.truffle.api.dsl.test.ImplicitCastTestFactory.StringEquals3NodeGen;
import com.oracle.truffle.api.dsl.test.ImplicitCastTestFactory.TestImplicitCastWithCacheNodeGen;
import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode;
import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode;
import com.oracle.truffle.api.dsl.test.examples.ExampleNode;
import com.oracle.truffle.api.dsl.test.examples.ExampleNode.ExampleArgumentNode;
import com.oracle.truffle.api.frame.FrameDescriptor;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.UnexpectedResultException;

public class ImplicitCastTest {

    @TypeSystem({int.class, String.class, boolean.class})
    static class ImplicitCast0Types {

        @ImplicitCast
        static boolean castInt(int intvalue) {
            return intvalue == 1 ? true : false;
        }

        @ImplicitCast
        static boolean castString(String strvalue) {
            return strvalue.equals("1");
        }

    }

    private static int charSequenceCast;

    @TypeSystem
    static class ImplicitCast1Types {

        @ImplicitCast
        static CharSequence castCharSequence(String strvalue) {
            charSequenceCast++;
            return strvalue;
        }

    }

    @TypeSystemReference(ImplicitCast0Types.class)
    @NodeChild(value = "operand", type = ImplicitCast0Node.class)
    abstract static class ImplicitCast0Node extends ValueNode {

        public abstract Object executeEvaluated(VirtualFrame frame, Object value2);

        @Specialization
        public String op1(String value) {
            return value;
        }

        @Specialization
        public boolean op1(boolean value) {
            return value;
        }

    }

    @Test
    public void testImplicitCast0() {
        ImplicitCast0Node node = ImplicitCast0NodeFactory.create(null);
        TestRootNode root = new TestRootNode<>(node);
        root.adoptChildren();
        Assert.assertEquals("2", root.getNode().executeEvaluated(null, "2"));
        Assert.assertEquals(true, root.getNode().executeEvaluated(null, 1));
        Assert.assertEquals("1", root.getNode().executeEvaluated(null, "1"));
        Assert.assertEquals(true, root.getNode().executeEvaluated(null, 1));
        Assert.assertEquals(true, root.getNode().executeEvaluated(null, true));
    }

    @TypeSystemReference(ImplicitCast0Types.class)
    @NodeChild(value = "operand", type = ImplicitCast1Node.class)
    abstract static class ImplicitCast1Node extends ValueNode {

        public abstract Object executeEvaluated(VirtualFrame frame, Object operand);

        @Specialization
        public String op0(String value) {
            return value;
        }

        @Specialization(rewriteOn = RuntimeException.class)
        public boolean op1(@SuppressWarnings("unused") boolean value) throws RuntimeException {
            throw new RuntimeException();
        }

        @Specialization(replaces = "op1")
        public boolean op2(boolean value) {
            return value;
        }

    }

    @Test
    public void testImplicitCast1() {
        ImplicitCast1Node node = ImplicitCast1NodeFactory.create(null);
        TestRootNode root = new TestRootNode<>(node);
        root.adoptChildren();
        Assert.assertEquals("2", root.getNode().executeEvaluated(null, "2"));
        Assert.assertEquals(true, root.getNode().executeEvaluated(null, 1));
        Assert.assertEquals("1", root.getNode().executeEvaluated(null, "1"));
        Assert.assertEquals(true, root.getNode().executeEvaluated(null, 1));
        Assert.assertEquals(true, root.getNode().executeEvaluated(null, true));
    }

    @TypeSystemReference(ImplicitCast0Types.class)
    @NodeChildren({@NodeChild(value = "operand0", type = ImplicitCast2Node.class), @NodeChild(value = "operand1", type = ImplicitCast2Node.class, executeWith = "operand0")})
    // TODO temporary workaround
    abstract static class ImplicitCast2Node extends ValueNode {

        @Specialization
        public String op0(String v0, String v1) {
            return v0 + v1;
        }

        @SuppressWarnings("unused")
        @Specialization(rewriteOn = RuntimeException.class)
        public boolean op1(boolean v0, boolean v1) throws RuntimeException {
            throw new RuntimeException();
        }

        @Specialization(replaces = "op1")
        public boolean op2(boolean v0, boolean v1) {
            return v0 && v1;
        }

        public abstract Object executeEvaluated(VirtualFrame frame, Object v1);

        public abstract Object executeEvaluated(VirtualFrame frame, Object v1, Object v2);

        public abstract Object executeEvaluated(VirtualFrame frame, boolean v1, boolean v2);

    }

    @Test
    public void testImplicitCast2() {
        ImplicitCast2Node node = ImplicitCast2NodeFactory.create(null, null);
        TestRootNode root = new TestRootNode<>(node);
        root.adoptChildren();
        Assert.assertEquals("42", root.getNode().executeEvaluated(null, "4", "2"));
        Assert.assertEquals(true, root.getNode().executeEvaluated(null, 1, 1));
        Assert.assertEquals("42", root.getNode().executeEvaluated(null, "4", "2"));
        Assert.assertEquals(true, root.getNode().executeEvaluated(null, 1, 1));
        Assert.assertEquals(true, root.getNode().executeEvaluated(null, true, true));
    }

    @TypeSystemReference(ImplicitCast1Types.class)
    abstract static class ImplicitCast3Node extends Node {

        @Specialization
        public CharSequence op0(CharSequence v0, @SuppressWarnings("unused") CharSequence v1) {
            return v0;
        }

        public abstract Object executeEvaluated(CharSequence v1, CharSequence v2);

    }

    @Test
    public void testImplicitCast3() {
        ImplicitCast3Node node = ImplicitCast3NodeGen.create();
        CharSequence seq1 = "foo";
        CharSequence seq2 = "bar";
        charSequenceCast = 0;
        node.executeEvaluated(seq1, seq2);
        Assert.assertEquals(2, charSequenceCast);
    }

    @TypeSystem
    static class ImplicitCast3Types {

        @ImplicitCast
        static long castLong(int intValue) {
            return intValue;
        }

        @ImplicitCast
        static long castLong(boolean intValue) {
            return intValue ? 1 : 0;
        }

    }

    @NodeChild
    @TypeSystemReference(ImplicitCast3Types.class)
    abstract static class ImplicitCast4Node extends ValueNode {

        @Specialization(guards = "value != 1")
        public int doInt(int value) {
            return value;
        }

        @Specialization(guards = "value != 42")
        public long doLong(long value) {
            return -value;
        }

        protected abstract Object executeEvaluated(Object operand);

    }

    @NodeChildren({@NodeChild, @NodeChild})
    @TypeSystemReference(ImplicitCast3Types.class)
    @SuppressWarnings("unused")
    abstract static class ImplicitCast5Node extends ValueNode {

        @Specialization(guards = "value != 1")
        public int doInt(int a, int value) {
            return value;
        }

        @Specialization(guards = "value != 42")
        public long doLong(long a, long value) {
            return -value;
        }

    }

    static class Test4Input extends ValueNode {

        int n = 0;

        @Override
        public Object execute(VirtualFrame frame) {
            n++;
            if (n == 1) {
                return 1;
            } else if (n == 2) {
                return 42;
            } else {
                throw new AssertionError();
            }
        }

    }

    @Test
    public void testUseUncastedValuesForSlowPath1() {
        ImplicitCast4Node node = ImplicitCast4NodeFactory.create(new Test4Input());
        Assert.assertEquals(-1L, node.execute(null));
        Assert.assertEquals(42, node.execute(null));
    }

    @Test
    public void testUseUncastedValuesForSlowPath2() {
        ImplicitCast5Node node = ImplicitCast5NodeFactory.create(new Test4Input(), new Test4Input());
        Assert.assertEquals(-1L, node.execute(null));
        Assert.assertEquals(42, node.execute(null));
    }

    @TypeSystem({String.class, boolean.class})
    static class ImplicitCastError1 {

        @ImplicitCast
        @ExpectError("Target type and source type of an @ImplicitCast must not be the same type.")
        static String castInvalid(@SuppressWarnings("unused") String value) {
            throw new AssertionError();
        }

    }

    @TypeSystem({String.class, boolean.class})
    static class ImplicitCastError2 {

        @ImplicitCast
        @ExpectError("Target type and source type of an @ImplicitCast must not be the same type.")
        static String castInvalid(@SuppressWarnings("unused") String value) {
            throw new AssertionError();
        }

    }

    @TypeSystem
    static class ImplicitCast2Types {
        @ImplicitCast
        static String castString(CharSequence str) {
            return str.toString();
        }
    }

    @Test
    public void testStringEquals1() {
        StringEquals1Node node = StringEquals1NodeGen.create();
        Assert.assertTrue(node.executeBoolean("foo", "foo"));
        Assert.assertFalse(node.executeBoolean("foo", "bar"));
    }

    @TypeSystemReference(ImplicitCast2Types.class)
    abstract static class StringEquals1Node extends Node {
        protected abstract boolean executeBoolean(String arg1, String arg2);

        @SuppressWarnings("unused")
        @Specialization(guards = {"cachedArg1.equals(arg1)", "cachedArg2.equals(arg2)"}, limit = "1")
        protected static boolean doCached(String arg1, String arg2,
                        @Cached("arg1") String cachedArg1,
                        @Cached("arg2") String cachedArg2,
                        @Cached("arg1.equals(arg2)") boolean result) {
            return result;
        }

        @Specialization
        protected static boolean doUncached(String arg1, String arg2) {
            return arg1.equals(arg2);
        }
    }

    @Test
    public void testStringEquals2() {
        StringEquals2Node node = StringEquals2NodeGen.create();
        Assert.assertTrue(node.executeBoolean("foo", "foo"));
        Assert.assertFalse(node.executeBoolean("foo", "bar"));
    }

    @TypeSystemReference(ImplicitCast2Types.class)
    abstract static class StringEquals2Node extends Node {
        protected abstract boolean executeBoolean(CharSequence arg1, CharSequence arg2);

        @SuppressWarnings("unused")
        @Specialization(guards = {"cachedArg1.equals(arg1)", "cachedArg2.equals(arg2)"}, limit = "2")
        protected static boolean doCached(String arg1, String arg2,
                        @Cached("arg1") String cachedArg1,
                        @Cached("arg2") String cachedArg2,
                        @Cached("arg1.equals(arg2)") boolean result) {
            return result;
        }

        @Specialization
        protected static boolean doUncached(String arg1, String arg2) {
            return arg1.equals(arg2);
        }
    }

    @Test
    public void testStringEquals3() {
        StringEquals3Node node = StringEquals3NodeGen.create();
        Assert.assertTrue(node.executeBoolean("foo"));
        try {
            Assert.assertTrue(node.executeBoolean("bar"));
            Assert.fail();
        } catch (UnsupportedSpecializationException e) {
        }
    }

    @TypeSystemReference(ImplicitCast2Types.class)
    abstract static class StringEquals3Node extends Node {
        protected abstract boolean executeBoolean(CharSequence arg1);

        @SuppressWarnings("unused")
        @Specialization(guards = {"cachedArg1.equals(arg1)"}, limit = "1")
        protected static boolean doCached(String arg1,
                        @Cached("arg1") String cachedArg1,
                        @Cached("arg1.equals(arg1)") boolean result) {
            return result;
        }

    }

    @TypeSystem
    static class ImplicitCast4Types {
        @ImplicitCast
        static long castLong(int value) {
            return value;
        }
    }

    @Test
    public void testExecuteChildWithImplicitCast1() throws UnexpectedResultException {
        ExecuteChildWithImplicitCast1Node node = ExecuteChildWithImplicitCast1NodeGen.create(createArguments(1));
        /*
         * if executeLong is used for the initial execution of the node and the uninitialized case
         * is not checked then this executeLong method might return 0L instead of 2L. This test
         * verifies that this particular case does not happen.
         */
        Assert.assertEquals(2L, node.executeLong(Truffle.getRuntime().createVirtualFrame(new Object[]{2L}, new FrameDescriptor())));
    }

    @TypeSystemReference(ImplicitCast4Types.class)
    public abstract static class ExecuteChildWithImplicitCast1Node extends ExampleNode {

        @Specialization
        public long sleep(long duration) {
            return duration;
        }

    }

    @Test
    public void testImplicitCastExecute() {
        CallTarget target = ExampleNode.createTarget(ImplicitCastExecuteNodeGen.create(ExampleNode.createArguments(2)));
        Assert.assertEquals("s1", target.call(1, 2D));
        Assert.assertEquals("s0", target.call(1, 1));

        target = ExampleNode.createTarget(ImplicitCastExecuteNodeGen.create(ExampleNode.createArguments(2)));
        Assert.assertEquals("s0", target.call(1, 1));
        Assert.assertEquals("s1", target.call(1, 2D));

        target = ExampleNode.createTarget(ImplicitCastExecuteNodeGen.create(ExampleNode.createArguments(2)));
        Assert.assertEquals("s0", target.call(1, 1));
        Assert.assertEquals("s2", target.call(1, 2L));

        target = ExampleNode.createTarget(ImplicitCastExecuteNodeGen.create(ExampleNode.createArguments(2)));
        Assert.assertEquals("s2", target.call(1, 2L));
        Assert.assertEquals("s0", target.call(1, 1));
    }

    @TypeSystem
    public static class TS {
        @ImplicitCast
        public static int promoteToInt(byte value) {
            return value;
        }

        @ImplicitCast
        public static int promoteToInt(short value) {
            return value;
        }

        @ImplicitCast
        public static long promoteToLong(byte value) {
            return value;
        }

        @ImplicitCast
        public static long promoteToLong(short value) {
            return value;
        }

        @ImplicitCast
        public static long promoteToLong(int value) {
            return value;
        }

        @ImplicitCast
        public static double promoteToDouble(float value) {
            return value;
        }
    }

    @TypeSystemReference(TS.class)
    @SuppressWarnings("unused")
    public abstract static class ImplicitCastExecuteNode extends ExampleNode {

        @Specialization
        public String s0(int a, int b) {
            return "s0";
        }

        @Specialization
        public String s1(long a, double b) {
            return "s1";
        }

        @Specialization
        public String s2(long a, long b) {
            return "s2";
        }

    }

    @Test
    public void testImplicitCastExecute2() {
        ExampleArgumentNode[] args = ExampleNode.createArguments(2);
        CallTarget target = ExampleNode.createTarget(ImplicitCastExecuteNodeGen.create(args));

        Assert.assertEquals("s2", target.call(1L, 1L));
        Assert.assertEquals(0, args[0].longInvocationCount);
        Assert.assertEquals(0, args[1].longInvocationCount);
        Assert.assertEquals(1, args[0].genericInvocationCount);
        Assert.assertEquals(1, args[1].genericInvocationCount);

        Assert.assertEquals("s2", target.call(1L, 1L));

        Assert.assertEquals(1, args[0].longInvocationCount);
        Assert.assertEquals(1, args[1].longInvocationCount);
        Assert.assertEquals(2, args[0].genericInvocationCount);
        Assert.assertEquals(2, args[1].genericInvocationCount);

        Assert.assertEquals("s2", target.call(1L, 1L));

        Assert.assertEquals(2, args[0].longInvocationCount);
        Assert.assertEquals(2, args[1].longInvocationCount);
        Assert.assertEquals(3, args[0].genericInvocationCount);
        Assert.assertEquals(3, args[1].genericInvocationCount);

        Assert.assertEquals(0, args[0].doubleInvocationCount);
        Assert.assertEquals(0, args[1].doubleInvocationCount);
        Assert.assertEquals(0, args[0].intInvocationCount);
        Assert.assertEquals(0, args[1].intInvocationCount);

    }

    @Test
    public void testImplicitCastWithCache() {
        TestImplicitCastWithCacheNode node = TestImplicitCastWithCacheNodeGen.create();

        Assert.assertEquals(0, node.specializeCalls);

        ConcreteString concrete = new ConcreteString();
        node.execute("a", true);
        Assert.assertEquals(1, node.specializeCalls);
        node.execute(concrete, true);
        Assert.assertEquals(2, node.specializeCalls);
        node.execute(concrete, true);
        node.execute(concrete, true);
        node.execute(concrete, true);

        // ensure we stabilize
        Assert.assertEquals(2, node.specializeCalls);
    }

    interface AbstractString {
    }

    static class ConcreteString implements AbstractString {
    }

    @TypeSystem
    static class TestTypeSystem {
        @ImplicitCast
        public static AbstractString toAbstractStringVector(@SuppressWarnings("unused") String vector) {
            return new ConcreteString();
        }
    }

    @TypeSystemReference(TestTypeSystem.class)
    abstract static class TestImplicitCastWithCacheNode extends Node {

        int specializeCalls;

        public abstract int execute(Object arg, boolean flag);

        @Specialization(guards = {"specializeCall(flag)", "cachedFlag == flag"})
        @SuppressWarnings("unused")
        protected static int test(AbstractString arg, boolean flag,
                        @Cached("flag") boolean cachedFlag) {
            return flag ? 100 : -100;
        }

        boolean specializeCall(@SuppressWarnings("unused") boolean flag) {
            ReentrantLock lock = (ReentrantLock) getLock();
            if (lock.isHeldByCurrentThread()) {
                // the lock is held for guards executed in executeAndSpecialize
                specializeCalls++;
            }
            return true;
        }

    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy