changeset 12392:4e26955b6da2

Truffle-DSL: new implicit cast code generation layout supports now executeWith.
author Christian Humer <christian.humer@gmail.com>
date Thu, 03 Oct 2013 18:07:59 +0200
parents 7aa2a8c69ba3
children 7cce548b0b60
files graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java
diffstat 2 files changed, 123 insertions(+), 64 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java	Thu Oct 03 16:31:09 2013 +0200
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java	Thu Oct 03 18:07:59 2013 +0200
@@ -26,6 +26,8 @@
 
 import com.oracle.truffle.api.dsl.*;
 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.NodeContainerTest.Str;
 import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode;
 import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode;
@@ -54,12 +56,12 @@
 
         public abstract Object executeEvaluated(VirtualFrame frame, Object value2);
 
-        @Specialization
+        @Specialization(order = 1)
         public String op1(String value) {
             return value;
         }
 
-        @Specialization
+        @Specialization(order = 2)
         public boolean op1(boolean value) {
             return value;
         }
@@ -77,40 +79,81 @@
         Assert.assertEquals(true, root.getNode().executeEvaluated(null, true));
     }
 
-// @TypeSystemReference(ImplicitCast0Types.class)
-// @NodeChild(value = "operand", type = ImplicitCast0Node.class)
-// abstract static class ImplicitCast1Node extends ValueNode {
-//
-// @Specialization
-// public String op0(String value) {
-// return value;
-// }
-//
-// @Specialization(order = 1, rewriteOn = RuntimeException.class)
-// public boolean op1(@SuppressWarnings("unused") boolean value) throws RuntimeException {
-// throw new RuntimeException();
-// }
-//
-// @Specialization(order = 2)
-// public boolean op2(boolean value) {
-// return value;
-// }
-//
-// }
-//
-// @Test
-// public void testImplicitCast1() {
-// ImplicitCast0Node node = ImplicitCast0NodeFactory.create(null);
-// TestRootNode<ImplicitCast0Node> root = new TestRootNode<>(node);
-// 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)
+    // TODO temporary workaround
+    @PolymorphicLimit(1)
+    abstract static class ImplicitCast1Node extends ValueNode {
+
+        public abstract Object executeEvaluated(VirtualFrame frame, Object operand);
+
+        @Specialization(order = 0)
+        public String op0(String value) {
+            return value;
+        }
+
+        @Specialization(order = 1, rewriteOn = RuntimeException.class)
+        public boolean op1(@SuppressWarnings("unused") boolean value) throws RuntimeException {
+            throw new RuntimeException();
+        }
+
+        @Specialization(order = 2)
+        public boolean op2(boolean value) {
+            return value;
+        }
+
+    }
+
+    @Test
+    public void testImplicitCast1() {
+        ImplicitCast1Node node = ImplicitCast1NodeFactory.create(null);
+        TestRootNode<ImplicitCast1Node> root = new TestRootNode<>(node);
+        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));
+    }
 
-    // TODO assert implicit casts only in one direction
+    @TypeSystemReference(ImplicitCast0Types.class)
+    @NodeChildren({@NodeChild(value = "operand0", type = ImplicitCast2Node.class), @NodeChild(value = "operand1", type = ImplicitCast2Node.class, executeWith = "operand0")})
+    // TODO temporary workaround
+    @PolymorphicLimit(1)
+    abstract static class ImplicitCast2Node extends ValueNode {
+
+        @Specialization(order = 0)
+        public String op0(String v0, String v1) {
+            return v0 + v1;
+        }
+
+        @SuppressWarnings("unused")
+        @Specialization(order = 1, rewriteOn = RuntimeException.class)
+        public boolean op1(boolean v0, boolean v1) throws RuntimeException {
+            throw new RuntimeException();
+        }
 
-    // test example that covers the most cases
+        @Specialization(order = 2)
+        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<ImplicitCast2Node> root = new TestRootNode<>(node);
+        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));
+    }
 
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Thu Oct 03 16:31:09 2013 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Thu Oct 03 18:07:59 2013 +0200
@@ -42,7 +42,6 @@
 import com.oracle.truffle.dsl.processor.template.*;
 import com.oracle.truffle.dsl.processor.template.TemplateMethod.Signature;
 import com.oracle.truffle.dsl.processor.typesystem.*;
-import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBaseIterators.*;
 
 public class NodeCodeGenerator extends CompilationUnitFactory<NodeData> {
 
@@ -954,7 +953,7 @@
                     }
                 }
 
-                for (CodeExecutableElement method : createImplicitChildrenAccessors(node, clazz)) {
+                for (CodeExecutableElement method : createImplicitChildrenAccessors()) {
                     clazz.add(method);
                 }
 
@@ -967,7 +966,8 @@
             }
         }
 
-        private List<CodeExecutableElement> createImplicitChildrenAccessors(NodeData node, CodeTypeElement clazz) {
+        private List<CodeExecutableElement> createImplicitChildrenAccessors() {
+            NodeData node = getModel().getNode();
             List<CodeExecutableElement> methods = new ArrayList<>();
             Map<NodeChildData, Set<TypeData>> expectTypes = new HashMap<>();
             for (ExecutableTypeData executableType : node.getExecutableTypes()) {
@@ -2018,14 +2018,22 @@
 
                 builder.end();
             } else {
+                List<TypeData> sourceTypes = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
                 TypeData expectType = sourceParameter != null ? sourceParameter.getTypeSystemType() : null;
-                builder.tree(createExecuteExpression(parent, child, expectType, targetExecutable, param, unexpectedParameter, null));
+                if (sourceTypes.size() > 1) {
+                    builder.tree(createExecuteExpressions(parent, param, expectType));
+                } else {
+                    builder.tree(createExecuteExpression(parent, child, expectType, targetExecutable, param, unexpectedParameter, null));
+                }
             }
             return builder.getRoot();
         }
 
         private String createExecuteChildMethodName(ActualParameter param, boolean expect) {
             NodeChildData child = getModel().getNode().findChild(param.getSpecification().getName());
+            if (child.getExecuteWith().size() > 0) {
+                return null;
+            }
             List<TypeData> sourceTypes = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
             if (sourceTypes.size() <= 1) {
                 return null;
@@ -2057,53 +2065,56 @@
                 return null;
             }
 
-            NodeData node = getModel().getNode();
-            NodeChildData child = node.findChild(param.getSpecification().getName());
-            List<TypeData> sourceTypes = node.getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
-            assert sourceTypes.size() >= 1;
-
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, expectType != null ? STATIC : FINAL), param.getType(), childExecuteName);
-
+            method.getThrownTypes().add(getContext().getTruffleTypes().getUnexpectedValueException());
             method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue"));
             if (expectType != null) {
                 method.addParameter(new CodeVariableElement(expectType.getPrimitiveType(), valueNameEvaluated(param)));
             }
             method.addParameter(new CodeVariableElement(getContext().getType(Class.class), typeName(param)));
+
             CodeTreeBuilder builder = method.createBuilder();
-
             builder.declaration(param.getType(), valueName(param));
-
-            boolean unexpected = false;
+            builder.tree(createExecuteExpressions(builder, param, expectType));
+            builder.startReturn().string(valueName(param)).end();
+
+            return method;
+        }
+
+        private CodeTree createExecuteExpressions(CodeTreeBuilder parent, ActualParameter param, TypeData expectType) {
+            CodeTreeBuilder builder = parent.create();
+            NodeData node = getModel().getNode();
+            NodeChildData child = node.findChild(param.getSpecification().getName());
+            List<TypeData> sourceTypes = node.getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
             boolean elseIf = false;
             int index = 0;
-            for (TypeData typeData : sourceTypes) {
+            for (TypeData sourceType : sourceTypes) {
                 if (index < sourceTypes.size() - 1) {
                     elseIf = builder.startIf(elseIf);
-                    builder.string(typeName(param)).string(" == ").typeLiteral(typeData.getPrimitiveType());
+                    builder.string(typeName(param)).string(" == ").typeLiteral(sourceType.getPrimitiveType());
                     builder.end();
                     builder.startBlock();
                 } else {
                     builder.startElseBlock();
                 }
 
-                ExecutableTypeData implictExecutableTypeData = child.getNodeData().findExecutableType(typeData, child.getExecuteWith().size());
-                if (!unexpected && implictExecutableTypeData.hasUnexpectedValue(getContext())) {
-                    unexpected = true;
+                ExecutableTypeData implictExecutableTypeData = child.getNodeData().findExecutableType(sourceType, child.getExecuteWith().size());
+                if (implictExecutableTypeData == null) {
+                    /*
+                     * For children with executeWith.size() > 0 an executable type may not exist so
+                     * use the generic executable type which is guaranteed to exist. An expect call
+                     * is inserted automatically by #createExecuteExpression.
+                     */
+                    implictExecutableTypeData = child.getNodeData().findExecutableType(node.getTypeSystem().getGenericTypeData(), child.getExecuteWith().size());
                 }
-                ImplicitCastData cast = child.getNodeData().getTypeSystem().lookupCast(typeData, param.getTypeSystemType());
+
+                ImplicitCastData cast = child.getNodeData().getTypeSystem().lookupCast(sourceType, param.getTypeSystemType());
                 CodeTree execute = createExecuteExpression(builder, child, expectType, implictExecutableTypeData, param, null, cast);
                 builder.statement(execute);
                 builder.end();
                 index++;
             }
-
-            builder.startReturn().string(valueName(param)).end();
-
-            if (unexpected) {
-                method.getThrownTypes().add(getContext().getTruffleTypes().getUnexpectedValueException());
-            }
-
-            return method;
+            return builder.getRoot();
         }
 
         private CodeTree createExecuteExpression(CodeTreeBuilder parent, NodeChildData child, TypeData expectType, ExecutableTypeData targetExecutable, ActualParameter targetParameter,
@@ -2115,8 +2126,13 @@
                 startCallTypeSystemMethod(getContext(), builder, child.getNodeData(), cast.getMethodName());
             }
 
-            if (targetExecutable.getType().needsCastTo(context, targetParameter.getTypeSystemType()) && cast == null) {
-                startCallTypeSystemMethod(getContext(), builder, child.getNodeData(), TypeSystemCodeGenerator.expectTypeMethodName(targetParameter.getTypeSystemType()));
+            TypeData expectTarget = targetParameter.getTypeSystemType();
+            if (cast != null) {
+                expectTarget = cast.getSourceType();
+            }
+
+            if (targetExecutable.getType().needsCastTo(context, expectTarget)) {
+                startCallTypeSystemMethod(getContext(), builder, child.getNodeData(), TypeSystemCodeGenerator.expectTypeMethodName(expectTarget));
             }
 
             NodeData node = getModel().getNode();