changeset 13861:28479abd1a69

Truffle-DSL: implemented support for UnsupportedSpecializationException#getSuppliedNodes().
author Christian Humer <christian.humer@gmail.com>
date Mon, 03 Feb 2014 20:59:57 +0100
parents 6b91134526a7
children f9b934e1e172
files graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/UnsupportedSpecializationTest.java graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/UnsupportedSpecializationException.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java
diffstat 4 files changed, 123 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/UnsupportedSpecializationTest.java	Mon Feb 03 15:49:58 2014 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/UnsupportedSpecializationTest.java	Mon Feb 03 20:59:57 2014 +0100
@@ -22,18 +22,22 @@
  */
 package com.oracle.truffle.api.dsl.test;
 
+import java.util.*;
+
 import org.junit.*;
 
 import com.oracle.truffle.api.dsl.*;
 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.UnsupportedSpecializationTestFactory.Undefined1Factory;
+import com.oracle.truffle.api.dsl.test.UnsupportedSpecializationTestFactory.Unsupported1Factory;
+import com.oracle.truffle.api.dsl.test.UnsupportedSpecializationTestFactory.Unsupported2Factory;
+import com.oracle.truffle.api.nodes.*;
 
 public class UnsupportedSpecializationTest {
 
     @Test
-    public void testUndefined1() {
-        TestRootNode<Undefined1> root = TestHelper.createRoot(Undefined1Factory.getInstance());
+    public void testUnsupported1() {
+        TestRootNode<Unsupported1> root = TestHelper.createRoot(Unsupported1Factory.getInstance());
         try {
             TestHelper.executeWith(root, "");
             Assert.fail();
@@ -41,12 +45,13 @@
             Assert.assertNotNull(e.getSuppliedValues());
             Assert.assertEquals(1, e.getSuppliedValues().length);
             Assert.assertEquals("", e.getSuppliedValues()[0]);
+            Assert.assertSame(root.getNode().getChildren().iterator().next(), e.getSuppliedNodes()[0]);
             Assert.assertEquals(root.getNode(), e.getNode());
         }
     }
 
     @NodeChild("a")
-    abstract static class Undefined1 extends ValueNode {
+    abstract static class Unsupported1 extends ValueNode {
 
         @Specialization
         public int doInteger(@SuppressWarnings("unused") int a) {
@@ -54,5 +59,41 @@
         }
     }
 
-    // TODO more tests required
+    @Test
+    public void testUnsupported2() {
+        TestRootNode<Unsupported2> root = TestHelper.createRoot(Unsupported2Factory.getInstance());
+        try {
+            TestHelper.executeWith(root, "", 1);
+            Assert.fail();
+        } catch (UnsupportedSpecializationException e) {
+            Assert.assertNotNull(e.getSuppliedValues());
+            Assert.assertNotNull(e.getSuppliedNodes());
+            Assert.assertEquals(3, e.getSuppliedValues().length);
+            Assert.assertEquals(3, e.getSuppliedNodes().length);
+            Assert.assertEquals("", e.getSuppliedValues()[0]);
+            Assert.assertEquals(false, e.getSuppliedValues()[1]);
+            Assert.assertEquals(null, e.getSuppliedValues()[2]);
+            List<Node> children = NodeUtil.findNodeChildren(root.getNode());
+            Assert.assertSame(children.get(0), e.getSuppliedNodes()[0]);
+            Assert.assertNull(e.getSuppliedNodes()[1]);
+            Assert.assertSame(children.get(1), e.getSuppliedNodes()[2]);
+            Assert.assertEquals(root.getNode(), e.getNode());
+        }
+    }
+
+    @SuppressWarnings("unused")
+    @NodeChildren({@NodeChild("a"), @NodeChild("b")})
+    abstract static class Unsupported2 extends ValueNode {
+
+        @ShortCircuit("b")
+        public boolean needsB(Object a) {
+            return false;
+        }
+
+        @Specialization
+        public int doInteger(int a, boolean hasB, int b) {
+            throw new AssertionError();
+        }
+    }
+
 }
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/UnsupportedSpecializationException.java	Mon Feb 03 15:49:58 2014 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/UnsupportedSpecializationException.java	Mon Feb 03 20:59:57 2014 +0100
@@ -37,11 +37,17 @@
     private static final long serialVersionUID = -2122892028296836269L;
 
     private final Node node;
+    private final Node[] suppliedNodes;
     private final Object[] suppliedValues;
 
-    public UnsupportedSpecializationException(Node node, Object... suppliedValues) {
+    public UnsupportedSpecializationException(Node node, Node[] suppliedNodes, Object... suppliedValues) {
         super("Unexpected values provided for " + node + ": " + Arrays.toString(suppliedValues));
+        Objects.requireNonNull(suppliedNodes, "The suppliedNodes parameter must not be null.");
+        if (suppliedNodes.length != suppliedValues.length) {
+            throw new IllegalArgumentException("The length of suppliedNodes must match the length of suppliedValues.");
+        }
         this.node = node;
+        this.suppliedNodes = suppliedNodes;
         this.suppliedValues = suppliedValues;
     }
 
@@ -53,7 +59,19 @@
     }
 
     /**
-     * Returns the dynamic values that were supplied to the node.
+     * Returns the children of the {@link Node} returned by {@link #getNode()} which produced the
+     * values returned by {@link #getSuppliedValues()}. The array returned by
+     * {@link #getSuppliedNodes()} has the same length as the array returned by
+     * {@link #getSuppliedValues()}. Never returns null.
+     */
+    public Node[] getSuppliedNodes() {
+        return suppliedNodes;
+    }
+
+    /**
+     * Returns the dynamic values that were supplied to the node.The array returned by
+     * {@link #getSuppliedNodes()} has the same length as the array returned by
+     * {@link #getSuppliedValues()}. Never returns null.
      */
     public Object[] getSuppliedValues() {
         return suppliedValues;
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java	Mon Feb 03 15:49:58 2014 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java	Mon Feb 03 20:59:57 2014 +0100
@@ -43,8 +43,8 @@
 
     public static final String OPTION_DETAILED_REWRITE_REASONS = "DetailedRewriteReasons";
 
-    private final TypeMirror node;
-    private final TypeMirror nodeArray;
+    private final DeclaredType node;
+    private final ArrayType nodeArray;
     private final TypeMirror unexpectedValueException;
     private final TypeMirror frame;
     private final TypeMirror assumption;
@@ -131,11 +131,11 @@
         return compilerDirectives;
     }
 
-    public TypeMirror getNode() {
+    public DeclaredType getNode() {
         return node;
     }
 
-    public TypeMirror getNodeArray() {
+    public ArrayType getNodeArray() {
         return nodeArray;
     }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Mon Feb 03 15:49:58 2014 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Mon Feb 03 20:59:57 2014 +0100
@@ -99,6 +99,22 @@
         return param.getLocalName();
     }
 
+    private static CodeTree createAccessChild(NodeExecutionData targetExecution) {
+        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
+        Element accessElement = targetExecution.getChild().getAccessElement();
+        if (accessElement == null || accessElement.getKind() == ElementKind.METHOD) {
+            builder.string("this.").string(targetExecution.getChild().getName());
+        } else if (accessElement.getKind() == ElementKind.FIELD) {
+            builder.string("this.").string(accessElement.getSimpleName().toString());
+        } else {
+            throw new AssertionError();
+        }
+        if (targetExecution.isIndexed()) {
+            builder.string("[" + targetExecution.getIndex() + "]");
+        }
+        return builder.getRoot();
+    }
+
     private static String castValueName(ActualParameter parameter) {
         return valueName(parameter) + "Cast";
     }
@@ -155,18 +171,14 @@
     }
 
     private String valueName(ActualParameter sourceParameter, ActualParameter targetParameter) {
-        if (sourceParameter != null) {
-            if (!sourceParameter.getSpecification().isSignature()) {
-                return valueName(targetParameter);
-            } else if (sourceParameter.getTypeSystemType() != null && targetParameter.getTypeSystemType() != null) {
-                if (sourceParameter.getTypeSystemType().needsCastTo(getContext(), targetParameter.getTypeSystemType())) {
-                    return castValueName(targetParameter);
-                }
+        if (!sourceParameter.getSpecification().isSignature()) {
+            return valueName(targetParameter);
+        } else if (sourceParameter.getTypeSystemType() != null && targetParameter.getTypeSystemType() != null) {
+            if (sourceParameter.getTypeSystemType().needsCastTo(getContext(), targetParameter.getTypeSystemType())) {
+                return castValueName(targetParameter);
             }
-            return valueName(targetParameter);
-        } else {
-            return valueName(targetParameter);
         }
+        return valueName(targetParameter);
     }
 
     private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, CodeTree target, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName,
@@ -331,9 +343,35 @@
     }
 
     protected void emitEncounteredSynthetic(CodeTreeBuilder builder, TemplateMethod current) {
+        CodeTreeBuilder nodes = builder.create();
+        CodeTreeBuilder arguments = builder.create();
+        nodes.startCommaGroup();
+        arguments.startCommaGroup();
+        boolean empty = true;
+        for (ActualParameter parameter : current.getParameters()) {
+            NodeExecutionData executionData = parameter.getSpecification().getExecution();
+            if (executionData != null) {
+                if (executionData.isShortCircuit()) {
+                    nodes.nullLiteral();
+                    arguments.string(valueName(parameter.getPreviousParameter()));
+                }
+                nodes.tree(createAccessChild(executionData));
+                arguments.string(valueName(parameter));
+                empty = false;
+            }
+        }
+        nodes.end();
+        arguments.end();
+
         builder.startThrow().startNew(getContext().getType(UnsupportedSpecializationException.class));
         builder.string("this");
-        addInternalValueParameterNames(builder, current, current, null, false, null);
+        builder.startNewArray(getContext().getTruffleTypes().getNodeArray(), null);
+
+        builder.tree(nodes.getRoot());
+        builder.end();
+        if (!empty) {
+            builder.tree(arguments.getRoot());
+        }
         builder.end().end();
     }
 
@@ -965,16 +1003,12 @@
             for (ActualParameter param : getModel().getSignatureParameters()) {
                 NodeExecutionData execution = param.getSpecification().getExecution();
 
-                CodeTreeBuilder access = builder.create();
-                access.string("this.").string(execution.getChild().getName());
-                if (execution.isIndexed()) {
-                    access.string("[").string(String.valueOf(execution.getIndex())).string("]");
-                }
+                CodeTree access = createAccessChild(execution);
 
                 String oldName = "old" + Utils.firstLetterUpperCase(param.getLocalName());
                 oldBuilder.declaration(execution.getChild().getNodeData().getNodeType(), oldName, access);
-                nullBuilder.startStatement().tree(access.getRoot()).string(" = null").end();
-                resetBuilder.startStatement().tree(access.getRoot()).string(" = ").string(oldName).end();
+                nullBuilder.startStatement().tree(access).string(" = null").end();
+                resetBuilder.startStatement().tree(access).string(" = ").string(oldName).end();
             }
 
             builder.tree(oldBuilder.getRoot());
@@ -2274,7 +2308,7 @@
         private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeExecutionData targetExecution, ExecutableTypeData targetExecutable, ActualParameter unexpectedParameter) {
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             if (targetExecution != null) {
-                builder.tree(createAccessChild(builder, targetExecution));
+                builder.tree(createAccessChild(targetExecution));
                 builder.string(".");
             }
 
@@ -2328,22 +2362,6 @@
             return builder.getRoot();
         }
 
-        private CodeTree createAccessChild(CodeTreeBuilder parent, NodeExecutionData targetExecution) throws AssertionError {
-            CodeTreeBuilder builder = parent.create();
-            Element accessElement = targetExecution.getChild().getAccessElement();
-            if (accessElement == null || accessElement.getKind() == ElementKind.METHOD) {
-                builder.string("this.").string(targetExecution.getChild().getName());
-            } else if (accessElement.getKind() == ElementKind.FIELD) {
-                builder.string("this.").string(accessElement.getSimpleName().toString());
-            } else {
-                throw new AssertionError();
-            }
-            if (targetExecution.isIndexed()) {
-                builder.string("[" + targetExecution.getIndex() + "]");
-            }
-            return builder.getRoot();
-        }
-
         private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, SpecializationData specialization, ActualParameter parameter, ActualParameter exceptionParam) {
             NodeExecutionData execution = parameter.getSpecification().getExecution();
             if (execution == null || !execution.isShortCircuit()) {