changeset 9287:8e3a1635cc9e

Implemented @NodeChild(executeWith={...}).
author Christian Humer <christian.humer@gmail.com>
date Wed, 24 Apr 2013 21:50:03 +0200
parents 39f08ef7b5d8
children cadb3702cb8f
files graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/AssumptionsTest.java graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryNodeTest.java graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/ExecuteEvaluatedTest.java graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MessageContainer.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java
diffstat 16 files changed, 338 insertions(+), 113 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/AssumptionsTest.java	Wed Apr 24 18:39:41 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/AssumptionsTest.java	Wed Apr 24 21:50:03 2013 +0200
@@ -38,7 +38,7 @@
     @Test
     public void testSingleAssumption() {
         Assumption assumption = Truffle.getRuntime().createAssumption();
-        TestRootNode<?> root = TestHelper.create(SingleAssumptionNodeFactory.getInstance(), assumption);
+        TestRootNode<?> root = TestHelper.createRoot(SingleAssumptionNodeFactory.getInstance(), assumption);
 
         Assert.assertEquals(42, TestHelper.executeWith(root));
         assumption.invalidate();
@@ -63,7 +63,7 @@
     public void testMultipleAssumption() {
         Assumption assumption1 = Truffle.getRuntime().createAssumption();
         Assumption assumption2 = Truffle.getRuntime().createAssumption();
-        TestRootNode<?> root = TestHelper.create(MultipleAssumptionsNodeFactory.getInstance(), assumption1, assumption2);
+        TestRootNode<?> root = TestHelper.createRoot(MultipleAssumptionsNodeFactory.getInstance(), assumption1, assumption2);
 
         Assert.assertEquals(42, TestHelper.executeWith(root));
         assumption2.invalidate();
@@ -95,7 +95,7 @@
     public void testDerivedAssumption() {
         Assumption additionalAssumption = Truffle.getRuntime().createAssumption();
         Assumption assumption = Truffle.getRuntime().createAssumption();
-        TestRootNode<?> root = TestHelper.create(DerivedAssumptionNodeFactory.getInstance(), assumption, additionalAssumption);
+        TestRootNode<?> root = TestHelper.createRoot(DerivedAssumptionNodeFactory.getInstance(), assumption, additionalAssumption);
 
         Assert.assertEquals(42, TestHelper.executeWith(root));
         assumption.invalidate();
@@ -117,7 +117,7 @@
     public void testDerivedAssumptionRedeclared() {
         Assumption additionalAssumption = Truffle.getRuntime().createAssumption();
         Assumption assumption = Truffle.getRuntime().createAssumption();
-        TestRootNode<?> root = TestHelper.create(DerivedAssumptionRedeclaredNodeFactory.getInstance(), additionalAssumption, assumption);
+        TestRootNode<?> root = TestHelper.createRoot(DerivedAssumptionRedeclaredNodeFactory.getInstance(), additionalAssumption, assumption);
 
         Assert.assertEquals(42, TestHelper.executeWith(root));
         assumption.invalidate();
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryNodeTest.java	Wed Apr 24 18:39:41 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryNodeTest.java	Wed Apr 24 21:50:03 2013 +0200
@@ -36,7 +36,7 @@
 
     @Test
     public void testAdd() {
-        TestRootNode<AddNode> node = create(AddNodeFactory.getInstance());
+        TestRootNode<AddNode> node = createRoot(AddNodeFactory.getInstance());
         assertEquals(42, executeWith(node, 19, 23));
         assertEquals(42d, executeWith(node, 19d, 23d));
         assertEquals(42d, executeWith(node, "19", "23"));
@@ -45,7 +45,7 @@
 
     @Test(expected = RuntimeException.class)
     public void testAddUnsupported() {
-        TestRootNode<AddNode> node = create(AddNodeFactory.getInstance());
+        TestRootNode<AddNode> node = createRoot(AddNodeFactory.getInstance());
         executeWith(node, new Object(), new Object());
     }
 
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java	Wed Apr 24 18:39:41 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java	Wed Apr 24 21:50:03 2013 +0200
@@ -39,7 +39,7 @@
 
     @Test
     public void testConcat() {
-        TestRootNode<BuiltinNode> node = create(StrConcatFactory.getInstance(), new Context());
+        TestRootNode<BuiltinNode> node = createRoot(StrConcatFactory.getInstance(), new Context());
         Str str1 = new Str("42");
         Str str2 = new Str(" is the number.");
         assertEquals(str1.concat(str2), executeWith(node, str1, str2));
@@ -47,13 +47,13 @@
 
     @Test(expected = UnsupportedOperationException.class)
     public void testConcatUnsupported() {
-        TestRootNode<BuiltinNode> node = create(StrConcatFactory.getInstance(), new Context());
+        TestRootNode<BuiltinNode> node = createRoot(StrConcatFactory.getInstance(), new Context());
         executeWith(node, 42, new Str(" is the number."));
     }
 
     @Test
     public void testSubstrSpecialized() {
-        TestRootNode<BuiltinNode> node = create(StrSubstrFactory.getInstance(), new Context());
+        TestRootNode<BuiltinNode> node = createRoot(StrSubstrFactory.getInstance(), new Context());
         Str str = new Str("test 42");
 
         assertEquals(str.substr(5, 7), executeWith(node, str, 5, 7));
@@ -61,7 +61,7 @@
 
     @Test
     public void testSubstrGeneric() {
-        TestRootNode<BuiltinNode> node = create(StrSubstrFactory.getInstance(), new Context());
+        TestRootNode<BuiltinNode> node = createRoot(StrSubstrFactory.getInstance(), new Context());
         Str str = new Str("test 42");
 
         assertEquals(Str.substr(str, "5", "7"), executeWith(node, str, "5", "7"));
@@ -69,27 +69,27 @@
 
     @Test(expected = UnsupportedOperationException.class)
     public void testSubstrUnsupported() {
-        TestRootNode<BuiltinNode> node = create(StrSubstrFactory.getInstance(), new Context());
+        TestRootNode<BuiltinNode> node = createRoot(StrSubstrFactory.getInstance(), new Context());
         executeWith(node, new Object(), "5", "7");
     }
 
     @Test
     public void testLength() {
-        TestRootNode<BuiltinNode> node = create(StrLengthFactory.getInstance(), new Context());
+        TestRootNode<BuiltinNode> node = createRoot(StrLengthFactory.getInstance(), new Context());
         Str testStr = new Str("test 42");
         assertEquals(testStr.length(), executeWith(node, testStr));
     }
 
     @Test(expected = UnsupportedOperationException.class)
     public void testLengthUnsupported() {
-        TestRootNode<BuiltinNode> node = create(StrLengthFactory.getInstance(), new Context());
+        TestRootNode<BuiltinNode> node = createRoot(StrLengthFactory.getInstance(), new Context());
         executeWith(node, new Object());
     }
 
     @Test
     public void testAccessContext() {
         Context context = new Context();
-        TestRootNode<BuiltinNode> node = create(StrAccessContextFactory.getInstance(), context);
+        TestRootNode<BuiltinNode> node = createRoot(StrAccessContextFactory.getInstance(), context);
         // accessible by node
         assertSame(context, node.getNode().getContext());
         // accessible by execution
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/ExecuteEvaluatedTest.java	Wed Apr 24 18:39:41 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/ExecuteEvaluatedTest.java	Wed Apr 24 21:50:03 2013 +0200
@@ -22,48 +22,86 @@
  */
 package com.oracle.truffle.api.codegen.test;
 
+import org.junit.*;
+
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.codegen.*;
+import com.oracle.truffle.api.codegen.test.ExecuteEvaluatedTestFactory.DoubleEvaluatedNodeFactory;
+import com.oracle.truffle.api.codegen.test.ExecuteEvaluatedTestFactory.EvaluatedNodeFactory;
+import com.oracle.truffle.api.codegen.test.ExecuteEvaluatedTestFactory.UseDoubleEvaluatedNodeFactory;
+import com.oracle.truffle.api.codegen.test.ExecuteEvaluatedTestFactory.UseEvaluatedNodeFactory;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.ArgumentNode;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestArguments;
 import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode;
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 
 public class ExecuteEvaluatedTest {
 
-    /* Represents target[element] */
-    @NodeChildren({@NodeChild("target"), @NodeChild("element")})
-    abstract static class ReadElementNode extends ValueNode {
+    @Test
+    public void testSingleEvaluated() {
+        ArgumentNode arg0 = new ArgumentNode(0);
+        CallTarget callTarget = TestHelper.createCallTarget(UseEvaluatedNodeFactory.create(arg0, EvaluatedNodeFactory.create(null)));
+
+        Assert.assertEquals(43, callTarget.call(new TestArguments(42)));
+        Assert.assertEquals(1, arg0.getInvocationCount());
+    }
+
+    @NodeChild("exp")
+    abstract static class EvaluatedNode extends ValueNode {
 
         @Specialization
-        int getInt(Object[] target, int element) {
-            return (int) target[element];
+        int doExecuteWith(int exp) {
+            return exp + 1;
         }
 
-        public abstract Object executeWith(VirtualFrame frame, Object targetValue);
+        public abstract Object executeEvaluated(VirtualFrame frame, Object targetValue);
+
+        public abstract int executeIntEvaluated(VirtualFrame frame, Object targetValue) throws UnexpectedResultException;
     }
 
-    /* Represents target[element]() */
-    @NodeChildren({@NodeChild("target"), @NodeChild(value = "element", type = ReadElementNode.class, executeWith = "target")})
-    abstract static class ElementCallNode extends ValueNode {
+    @NodeChildren({@NodeChild("exp0"), @NodeChild(value = "exp1", type = EvaluatedNode.class, executeWith = "exp0")})
+    abstract static class UseEvaluatedNode extends ValueNode {
 
         @Specialization
-        Object call(Object receiver, Object callTarget) {
-            return ((CallTarget) callTarget).call(new TestArguments(receiver));
+        int call(int exp0, int exp1) {
+            Assert.assertEquals(exp0 + 1, exp1);
+            return exp1;
         }
+    }
 
+    @Test
+    public void testDoubleEvaluated() {
+        ArgumentNode arg0 = new ArgumentNode(0);
+        ArgumentNode arg1 = new ArgumentNode(1);
+        CallTarget callTarget = TestHelper.createCallTarget(UseDoubleEvaluatedNodeFactory.create(arg0, arg1, DoubleEvaluatedNodeFactory.create(null, null)));
+
+        Assert.assertEquals(85, callTarget.call(new TestArguments(42, 43)));
+        Assert.assertEquals(1, arg0.getInvocationCount());
+        Assert.assertEquals(1, arg1.getInvocationCount());
     }
 
-    public static class TestArguments extends Arguments {
+    @NodeChildren({@NodeChild("exp0"), @NodeChild("exp1")})
+    abstract static class DoubleEvaluatedNode extends ValueNode {
 
-        private final Object receiver;
-
-        public TestArguments(Object receiver) {
-            this.receiver = receiver;
+        @Specialization
+        int doExecuteWith(int exp0, int exp1) {
+            return exp0 + exp1;
         }
 
-        public Object getReceiver() {
-            return receiver;
+        public abstract Object executeEvaluated(VirtualFrame frame, Object exp0, Object exp1);
+
+        public abstract int executeIntEvaluated(VirtualFrame frame, Object exp0, Object exp1) throws UnexpectedResultException;
+    }
+
+    @NodeChildren({@NodeChild("exp0"), @NodeChild("exp1"), @NodeChild(value = "exp2", type = DoubleEvaluatedNode.class, executeWith = {"exp0", "exp1"})})
+    abstract static class UseDoubleEvaluatedNode extends ValueNode {
+
+        @Specialization
+        int call(int exp0, int exp1, int exp2) {
+            Assert.assertEquals(exp0 + exp1, exp2);
+            return exp2;
         }
-
     }
 
 }
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java	Wed Apr 24 18:39:41 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java	Wed Apr 24 21:50:03 2013 +0200
@@ -40,7 +40,7 @@
 
     @Test
     public void testGuardInvocations() {
-        TestRootNode<InvocationGuard> root = create(InvocationGuardFactory.getInstance());
+        TestRootNode<InvocationGuard> root = createRoot(InvocationGuardFactory.getInstance());
 
         assertEquals(Integer.MAX_VALUE, executeWith(root, Integer.MAX_VALUE - 1, 1));
         assertEquals(1, InvocationGuard.specializedInvocations);
@@ -76,7 +76,7 @@
 
     @Test
     public void testGuardGlobal() {
-        TestRootNode<GlobalFlagGuard> root = create(GlobalFlagGuardFactory.getInstance());
+        TestRootNode<GlobalFlagGuard> root = createRoot(GlobalFlagGuardFactory.getInstance());
 
         assertEquals(42, executeWith(root, NULL));
 
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java	Wed Apr 24 18:39:41 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java	Wed Apr 24 21:50:03 2013 +0200
@@ -42,7 +42,7 @@
         return nodes;
     }
 
-    static <E extends ValueNode> TestRootNode<E> create(NodeFactory<E> factory, Object... constants) {
+    static <E extends ValueNode> E createNode(NodeFactory<E> factory, Object... constants) {
         ArgumentNode[] argumentNodes = arguments(factory.getExecutionSignature().size());
 
         List<Object> argumentList = new ArrayList<>();
@@ -52,11 +52,23 @@
         } else {
             argumentList.addAll(Arrays.asList(argumentNodes));
         }
-        return new TestRootNode<>(factory.createNode(argumentList.toArray(new Object[argumentList.size()])));
+        return factory.createNode(argumentList.toArray(new Object[argumentList.size()]));
+    }
+
+    static <E extends ValueNode> TestRootNode<E> createRoot(NodeFactory<E> factory, Object... constants) {
+        return new TestRootNode<>(createNode(factory, constants));
+    }
+
+    static CallTarget createCallTarget(ValueNode node) {
+        return createCallTarget(new TestRootNode<>(node));
+    }
+
+    static CallTarget createCallTarget(TestRootNode<? extends ValueNode> node) {
+        return Truffle.getRuntime().createCallTarget(node);
     }
 
     static <E> Object executeWith(TestRootNode<? extends ValueNode> node, Object... values) {
-        return Truffle.getRuntime().createCallTarget(node).call(new TestArguments(values));
+        return createCallTarget(node).call(new TestArguments(values));
     }
 
 }
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java	Wed Apr 24 18:39:41 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java	Wed Apr 24 21:50:03 2013 +0200
@@ -101,14 +101,20 @@
 
     public static class ArgumentNode extends ValueNode {
 
+        private int invocationCount;
         final int index;
 
         public ArgumentNode(int index) {
             this.index = index;
         }
 
+        public int getInvocationCount() {
+            return invocationCount;
+        }
+
         @Override
         public Object execute(VirtualFrame frame) {
+            invocationCount++;
             return ((TestArguments) frame.getArguments()).get(index);
         }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Wed Apr 24 18:39:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Wed Apr 24 21:50:03 2013 +0200
@@ -44,8 +44,8 @@
     }
 
     @Override
-    protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData) {
-        List<ExecutableTypeData> execTypes = nodeData.findGenericExecutableTypes(getContext());
+    protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData, int evaluatedCount) {
+        List<ExecutableTypeData> execTypes = nodeData.findGenericExecutableTypes(getContext(), evaluatedCount);
         List<TypeMirror> types = new ArrayList<>();
         for (ExecutableTypeData type : execTypes) {
             types.add(type.getType().getPrimitiveType());
@@ -57,7 +57,7 @@
 
     @Override
     protected ParameterSpec createReturnParameterSpec() {
-        return super.createValueParameterSpec("returnValue", getNode());
+        return super.createValueParameterSpec("returnValue", getNode(), 0);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java	Wed Apr 24 18:39:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java	Wed Apr 24 21:50:03 2013 +0200
@@ -22,10 +22,14 @@
  */
 package com.oracle.truffle.codegen.processor.node;
 
+import java.util.*;
+
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
 
+import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
+import com.oracle.truffle.codegen.processor.typesystem.*;
 
 public class NodeChildData extends MessageContainer {
 
@@ -54,6 +58,9 @@
 
     private final Cardinality cardinality;
     private final ExecutionKind executionKind;
+
+    private List<NodeChildData> executeWith = Collections.emptyList();
+
     private NodeData nodeData;
 
     public NodeChildData(Element sourceElement, AnnotationMirror sourceMirror, String name, TypeMirror nodeType, Element accessElement, Cardinality cardinality, ExecutionKind executionKind) {
@@ -66,6 +73,34 @@
         this.executionKind = executionKind;
     }
 
+    public List<NodeChildData> getExecuteWith() {
+        return executeWith;
+    }
+
+    void setExecuteWith(List<NodeChildData> executeWith) {
+        this.executeWith = executeWith;
+    }
+
+    public ExecutableTypeData findExecutableType(ProcessorContext context, TypeData targetType) {
+        ExecutableTypeData executableType = nodeData.findExecutableType(targetType, getExecuteWith().size());
+        if (executableType == null) {
+            executableType = findAnyGenericExecutableType(context);
+        }
+        return executableType;
+    }
+
+    public List<ExecutableTypeData> findGenericExecutableTypes(ProcessorContext context) {
+        return nodeData.findGenericExecutableTypes(context, getExecuteWith().size());
+    }
+
+    public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context) {
+        return nodeData.findAnyGenericExecutableType(context, getExecuteWith().size());
+    }
+
+    public List<ExecutableTypeData> findExecutableTypes() {
+        return nodeData.getExecutableTypes(getExecuteWith().size());
+    }
+
     @Override
     public Element getMessageElement() {
         return sourceElement;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Wed Apr 24 18:39:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Wed Apr 24 21:50:03 2013 +0200
@@ -141,7 +141,7 @@
         }
     }
 
-    private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) {
+    private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, CodeTree target, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) {
         CodeTreeBuilder builder = parent.create();
 
         boolean castedValues = sourceMethod != targetMethod;
@@ -154,43 +154,47 @@
         TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement());
         NodeData node = (NodeData) targetMethod.getTemplate();
 
-        boolean accessible = targetMethod.canBeAccessedByInstanceOf(getContext(), node.getNodeType());
-        if (accessible) {
-            if (builder.findMethod().getModifiers().contains(STATIC)) {
+        if (target == null) {
+            boolean accessible = targetMethod.canBeAccessedByInstanceOf(getContext(), node.getNodeType());
+            if (accessible) {
+                if (builder.findMethod().getModifiers().contains(STATIC)) {
+                    if (method.getModifiers().contains(STATIC)) {
+                        builder.type(targetClass.asType());
+                    } else {
+                        builder.string(THIS_NODE_LOCAL_VAR_NAME);
+                    }
+                } else {
+                    if (targetMethod instanceof ExecutableTypeData) {
+                        builder.string("this");
+                    } else {
+                        builder.string("super");
+                    }
+                }
+            } else {
                 if (method.getModifiers().contains(STATIC)) {
                     builder.type(targetClass.asType());
                 } else {
-                    builder.string(THIS_NODE_LOCAL_VAR_NAME);
-                }
-            } else {
-                if (targetMethod instanceof ExecutableTypeData) {
-                    builder.string("this");
-                } else {
-                    builder.string("super");
+                    ActualParameter parameter = null;
+                    for (ActualParameter searchParameter : targetMethod.getParameters()) {
+                        if (searchParameter.getSpecification().isSignature()) {
+                            parameter = searchParameter;
+                            break;
+                        }
+                    }
+                    ActualParameter sourceParameter = sourceMethod.findParameter(parameter.getLocalName());
+                    assert parameter != null;
+
+                    if (castedValues && sourceParameter != null) {
+                        builder.string(valueName(sourceParameter, parameter));
+                    } else {
+                        builder.string(valueName(parameter));
+                    }
                 }
             }
+            builder.string(".");
         } else {
-            if (method.getModifiers().contains(STATIC)) {
-                builder.type(targetClass.asType());
-            } else {
-                ActualParameter parameter = null;
-                for (ActualParameter searchParameter : targetMethod.getParameters()) {
-                    if (searchParameter.getSpecification().isSignature()) {
-                        parameter = searchParameter;
-                        break;
-                    }
-                }
-                ActualParameter sourceParameter = sourceMethod.findParameter(parameter.getLocalName());
-                assert parameter != null;
-
-                if (castedValues && sourceParameter != null) {
-                    builder.string(valueName(sourceParameter, parameter));
-                } else {
-                    builder.string(valueName(parameter));
-                }
-            }
+            builder.tree(target);
         }
-        builder.string(".");
         builder.startCall(method.getSimpleName().toString());
 
         for (ActualParameter targetParameter : targetMethod.getParameters()) {
@@ -370,7 +374,7 @@
             // Explicitly specified guards
             for (GuardData guard : guardedSpecialization.getGuards()) {
                 builder.string(andOperator);
-                builder.tree(createTemplateMethodCall(parent, valueSpecialization, guard, null));
+                builder.tree(createTemplateMethodCall(parent, null, valueSpecialization, guard, null));
                 andOperator = " && ";
             }
         }
@@ -1273,7 +1277,7 @@
                 emitEncounteredSynthetic(builder);
             } else {
                 builder.startReturn();
-                builder.tree(createTemplateMethodCall(builder, specialization.getNode().getGenericSpecialization(), specialization, null));
+                builder.tree(createTemplateMethodCall(builder, null, specialization.getNode().getGenericSpecialization(), specialization, null));
                 builder.end(); // return
             }
 
@@ -1429,7 +1433,7 @@
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             NodeData node = specialization.getNode();
 
-            ExecutableTypeData castedType = node.findExecutableType(type);
+            ExecutableTypeData castedType = node.findExecutableType(type, 0);
             TypeData primaryType = castExecutable.getType();
 
             boolean needsTry = castExecutable.hasUnexpectedValue(getContext());
@@ -1450,7 +1454,7 @@
 
             builder.tree(createExecuteChildren(builder, executable, specialization, executeParameters, null, true));
 
-            CodeTree primaryExecuteCall = createTemplateMethodCall(builder, executable, castExecutable, null);
+            CodeTree primaryExecuteCall = createTemplateMethodCall(builder, null, executable, castExecutable, null);
             if (needsTry) {
                 if (!returnVoid) {
                     builder.declaration(primaryType.getPrimitiveType(), "value");
@@ -1517,6 +1521,24 @@
             return builder.getRoot();
         }
 
+        private CodeTree createExpectType(NodeData node, TypeData castedType, CodeTree value) {
+            if (castedType == null) {
+                return value;
+            } else if (castedType.isVoid()) {
+                return value;
+            } else if (castedType.isGeneric()) {
+                return value;
+            }
+
+            CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
+            String targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(castedType);
+            startCallTypeSystemMethod(getContext(), builder, node, targetMethodName);
+
+            builder.tree(value);
+            builder.end().end();
+            return builder.getRoot();
+        }
+
         private CodeTree createFunctionalExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable) {
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             if (specialization.isUninitialized()) {
@@ -1606,7 +1628,7 @@
                 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true);
                 returnBuilder.end();
             } else {
-                returnBuilder.tree(createTemplateMethodCall(returnBuilder, specialization, specialization, null));
+                returnBuilder.tree(createTemplateMethodCall(returnBuilder, null, specialization, specialization, null));
             }
 
             if (!returnBuilder.isEmpty()) {
@@ -1654,7 +1676,7 @@
                 }
                 TypeData targetType = targetParameter.getTypeSystemType();
 
-                ExecutableTypeData targetExecutable = field.getNodeData().findExecutableType(targetType);
+                ExecutableTypeData targetExecutable = field.findExecutableType(getContext(), targetType);
 
                 ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName());
 
@@ -1675,7 +1697,7 @@
                         executionExpression = createExpectType(sourceNode, targetExecutable, CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter)));
                     }
                 } else if (sourceParameter == null) {
-                    executionExpression = createExecuteChildExpression(builder, field, targetParameter);
+                    executionExpression = createExecuteChildExpression(builder, field, targetParameter, unexpectedParameter);
                 }
 
                 if (executionExpression != null) {
@@ -1694,7 +1716,7 @@
         private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) {
             for (TemplateMethod listener : node.getSpecializationListeners()) {
                 builder.startStatement();
-                builder.tree(createTemplateMethodCall(builder, listener, listener, null));
+                builder.tree(createTemplateMethodCall(builder, null, listener, listener, null));
                 builder.end(); // statement
             }
         }
@@ -1703,6 +1725,12 @@
                         ExecutableTypeData targetExecutable, ActualParameter param, boolean shortCircuit) {
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             boolean unexpected = targetExecutable.hasUnexpectedValue(getContext());
+            boolean cast = false;
+            if (targetExecutable.getType().needsCastTo(param.getTypeSystemType())) {
+                unexpected = true;
+                cast = true;
+            }
+
             builder.startStatement();
 
             if (!shortCircuit) {
@@ -1721,7 +1749,11 @@
                 builder.string(targetVariableName);
             }
             builder.string(" = ");
-            builder.tree(body);
+            if (cast) {
+                builder.tree(createExpectType(specialization.getNode(), specialization.getReturnSignature(), body));
+            } else {
+                builder.tree(body);
+            }
             builder.end();
 
             if (unexpected) {
@@ -1738,9 +1770,9 @@
             return builder.getRoot();
         }
 
-        private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData targetField, ActualParameter sourceParameter) {
+        private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData targetField, ActualParameter sourceParameter, ActualParameter unexpectedParameter) {
             TypeData type = sourceParameter.getTypeSystemType();
-            ExecutableTypeData execType = targetField.getNodeData().findExecutableType(type);
+            ExecutableTypeData execType = targetField.findExecutableType(getContext(), type);
 
             /*
              * FIXME Temporary deactivated due to partial evaluation failure else if
@@ -1762,11 +1794,42 @@
                 }
                 builder.string(".");
             }
+
             builder.startCall(execType.getMethodName());
-            if (execType.getParameters().size() == 1) {
-                builder.string("frameValue");
+
+            List<ActualParameter> signatureParameters = getModel().getSignatureParameters();
+            int index = 0;
+            for (ActualParameter parameter : execType.getParameters()) {
+
+                if (!parameter.getSpecification().isSignature()) {
+                    builder.string(parameter.getLocalName());
+                } else {
+                    if (index < signatureParameters.size()) {
+                        ActualParameter specializationParam = signatureParameters.get(index);
+
+                        String localName = specializationParam.getLocalName();
+                        if (unexpectedParameter != null && unexpectedParameter.getLocalName().equals(specializationParam.getLocalName())) {
+                            localName = "ex.getResult()";
+                        }
+
+                        TypeData sourceType = specializationParam.getTypeSystemType();
+                        TypeData targetType = parameter.getTypeSystemType();
+
+                        CodeTree value = CodeTreeBuilder.singleString(localName);
+
+                        if (sourceType.needsCastTo(targetType)) {
+                            value = createCallTypeSystemMethod(getContext(), builder, getModel().getNode(), TypeSystemCodeGenerator.asTypeMethodName(targetType), value);
+                        }
+                        builder.tree(value);
+                    } else {
+                        builder.defaultValue(parameter.getType());
+                    }
+                    index++;
+                }
             }
+
             builder.end();
+
             return builder.getRoot();
         }
 
@@ -1810,7 +1873,7 @@
 
             builder.startStatement().type(shortCircuitParam.getType()).string(" ").string(valueName(shortCircuitParam)).string(" = ");
             ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex);
-            builder.tree(createTemplateMethodCall(builder, specialization, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null));
+            builder.tree(createTemplateMethodCall(builder, null, specialization, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null));
             builder.end(); // statement
 
             return builder.getRoot();
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Wed Apr 24 18:39:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Wed Apr 24 21:50:03 2013 +0200
@@ -224,8 +224,8 @@
         return methods;
     }
 
-    public ExecutableTypeData findGenericExecutableType(ProcessorContext context, TypeData type) {
-        List<ExecutableTypeData> types = findGenericExecutableTypes(context);
+    public ExecutableTypeData findGenericExecutableType(ProcessorContext context, TypeData type, int evaluatedCount) {
+        List<ExecutableTypeData> types = findGenericExecutableTypes(context, evaluatedCount);
         for (ExecutableTypeData availableType : types) {
             if (Utils.typeEquals(availableType.getType().getBoxedType(), type.getBoxedType())) {
                 return availableType;
@@ -234,8 +234,8 @@
         return null;
     }
 
-    public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context) {
-        List<ExecutableTypeData> types = findGenericExecutableTypes(context);
+    public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context, int evaluatedCount) {
+        List<ExecutableTypeData> types = findGenericExecutableTypes(context, evaluatedCount);
         for (ExecutableTypeData type : types) {
             if (type.getType().isGeneric()) {
                 return type;
@@ -261,13 +261,17 @@
             }
             return typeData;
         } else {
-            return executableTypes.get(evaluatedCount);
+            List<ExecutableTypeData> types = executableTypes.get(evaluatedCount);
+            if (types == null) {
+                return Collections.emptyList();
+            }
+            return types;
         }
     }
 
-    public List<ExecutableTypeData> findGenericExecutableTypes(ProcessorContext context) {
+    public List<ExecutableTypeData> findGenericExecutableTypes(ProcessorContext context, int evaluatedCount) {
         List<ExecutableTypeData> types = new ArrayList<>();
-        for (ExecutableTypeData type : getExecutableTypes(0)) {
+        for (ExecutableTypeData type : getExecutableTypes(evaluatedCount)) {
             if (!type.hasUnexpectedValue(context)) {
                 types.add(type);
             }
@@ -275,8 +279,8 @@
         return types;
     }
 
-    public ExecutableTypeData findExecutableType(TypeData prmitiveType) {
-        for (ExecutableTypeData type : getExecutableTypes(0)) {
+    public ExecutableTypeData findExecutableType(TypeData prmitiveType, int evaluatedCount) {
+        for (ExecutableTypeData type : getExecutableTypes(evaluatedCount)) {
             if (Utils.typeEquals(type.getType().getPrimitiveType(), prmitiveType.getPrimitiveType())) {
                 return type;
             }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java	Wed Apr 24 18:39:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java	Wed Apr 24 21:50:03 2013 +0200
@@ -42,7 +42,8 @@
         return template;
     }
 
-    protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData) {
+    @SuppressWarnings("unused")
+    protected ParameterSpec createValueParameterSpec(String valueName, NodeData nodeData, int evaluatedCount) {
         ParameterSpec spec = new ParameterSpec(valueName, nodeTypeMirrors(nodeData));
         spec.setSignature(true);
         return spec;
@@ -61,7 +62,7 @@
     }
 
     protected ParameterSpec createReturnParameterSpec() {
-        return createValueParameterSpec("returnValue", getNode());
+        return createValueParameterSpec("returnValue", getNode(), 0);
     }
 
     @Override
@@ -95,7 +96,7 @@
         if (getNode().getChildren() != null) {
             for (NodeChildData child : getNode().getChildren()) {
                 if (child.getExecutionKind() == ExecutionKind.DEFAULT) {
-                    ParameterSpec spec = createValueParameterSpec(child.getName(), child.getNodeData());
+                    ParameterSpec spec = createValueParameterSpec(child.getName(), child.getNodeData(), child.getExecuteWith().size());
                     if (child.getCardinality().isMany()) {
                         spec.setCardinality(Cardinality.MANY);
                         spec.setIndexed(true);
@@ -110,7 +111,7 @@
                     if (shortCircuitsEnabled) {
                         methodSpec.addRequired(new ParameterSpec(shortCircuitValueName(valueName), getContext().getType(boolean.class)));
                     }
-                    methodSpec.addRequired(createValueParameterSpec(valueName, child.getNodeData()));
+                    methodSpec.addRequired(createValueParameterSpec(valueName, child.getNodeData(), child.getExecuteWith().size()));
                 } else {
                     assert false;
                 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Wed Apr 24 18:39:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Wed Apr 24 21:50:03 2013 +0200
@@ -310,7 +310,7 @@
             GenericParser parser = new GenericParser(context, node);
             MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, true, null);
 
-            ExecutableTypeData anyGenericReturnType = node.findAnyGenericExecutableType(context);
+            ExecutableTypeData anyGenericReturnType = node.findAnyGenericExecutableType(context, 0);
             assert anyGenericReturnType != null;
 
             ActualParameter returnType = new ActualParameter(specification.getReturnType(), anyGenericReturnType.getType(), 0, false);
@@ -322,7 +322,7 @@
                 if (child == null) {
                     actualType = specializationParameter.getTypeSystemType();
                 } else {
-                    ExecutableTypeData paramType = child.getNodeData().findAnyGenericExecutableType(context);
+                    ExecutableTypeData paramType = child.findAnyGenericExecutableType(context);
                     assert paramType != null;
                     actualType = paramType.getType();
                 }
@@ -584,7 +584,7 @@
         nodeData.setFields(parseFields(elements));
         parsedNodes.put(Utils.getQualifiedName(templateType), nodeData);
         // parseChildren invokes cyclic parsing.
-        nodeData.setChildren(parseChildren(templateType, elements, lookupTypes));
+        nodeData.setChildren(parseChildren(elements, lookupTypes));
         nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements)));
 
         return nodeData;
@@ -722,7 +722,7 @@
         return fields;
     }
 
-    private List<NodeChildData> parseChildren(TypeElement templateType, List<? extends Element> elements, final List<TypeElement> typeHierarchy) {
+    private List<NodeChildData> parseChildren(List<? extends Element> elements, final List<TypeElement> typeHierarchy) {
         Set<String> shortCircuits = new HashSet<>();
         for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
             AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class);
@@ -765,7 +765,7 @@
                     kind = ExecutionKind.SHORT_CIRCUIT;
                 }
 
-                NodeChildData nodeChild = new NodeChildData(templateType, childMirror, name, childType, getter, cardinality, kind);
+                NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, getter, cardinality, kind);
 
                 parsedChildren.add(nodeChild);
 
@@ -778,8 +778,6 @@
                 nodeChild.setNode(fieldNodeData);
                 if (fieldNodeData == null) {
                     nodeChild.addError("Node type '%s' is invalid or not a valid Node.", Utils.getQualifiedName(childType));
-                } else if (fieldNodeData.findGenericExecutableTypes(context).isEmpty()) {
-                    nodeChild.addError("No executable generic types found for node '%s'.", Utils.getQualifiedName(type));
                 }
             }
         }
@@ -793,6 +791,53 @@
                 encounteredNames.add(child.getName());
             }
         }
+
+        for (NodeChildData child : filteredChildren) {
+            List<String> executeWithStrings = Utils.getAnnotationValueList(String.class, child.getMessageAnnotation(), "executeWith");
+            AnnotationValue executeWithValue = Utils.getAnnotationValue(child.getMessageAnnotation(), "executeWith");
+            List<NodeChildData> executeWith = new ArrayList<>();
+            for (String executeWithString : executeWithStrings) {
+
+                if (child.getName().equals(executeWithString)) {
+                    child.addError(executeWithValue, "The child node '%s' cannot be executed with itself.", executeWithString);
+                    continue;
+                }
+
+                NodeChildData found = null;
+                boolean before = true;
+                for (NodeChildData resolveChild : filteredChildren) {
+                    if (resolveChild == child) {
+                        before = false;
+                        continue;
+                    }
+                    if (resolveChild.getName().equals(executeWithString)) {
+                        found = resolveChild;
+                        break;
+                    }
+                }
+
+                if (found == null) {
+                    child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The child node was not found.", child.getName(), executeWithString);
+                    continue;
+                } else if (!before) {
+                    child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The node %s is executed after the current node.", child.getName(), executeWithString,
+                                    executeWithString);
+                    continue;
+                }
+                executeWith.add(found);
+            }
+            child.setExecuteWith(executeWith);
+            if (child.getNodeData() == null) {
+                continue;
+            }
+
+            List<ExecutableTypeData> types = child.findGenericExecutableTypes(context);
+            if (types.isEmpty()) {
+                child.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s.", executeWith.size(), Utils.getSimpleName(child.getNodeType()));
+                continue;
+            }
+        }
+
         return filteredChildren;
     }
 
@@ -930,7 +975,7 @@
                 continue;
             }
             ExecutableTypeData found = null;
-            List<ExecutableTypeData> executableElements = field.getNodeData().findGenericExecutableTypes(context);
+            List<ExecutableTypeData> executableElements = field.findGenericExecutableTypes(context);
             for (ExecutableTypeData executable : executableElements) {
                 if (executable.getType().equalsType(parameter.getTypeSystemType())) {
                     found = executable;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Wed Apr 24 18:39:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Wed Apr 24 21:50:03 2013 +0200
@@ -85,11 +85,11 @@
             return true;
         }
         for (ActualParameter parameter : getParameters()) {
-            NodeChildData field = getNode().findChild(parameter.getSpecification().getName());
-            if (field == null) {
+            NodeChildData child = getNode().findChild(parameter.getSpecification().getName());
+            if (child == null) {
                 continue;
             }
-            ExecutableTypeData type = field.getNodeData().findExecutableType(parameter.getTypeSystemType());
+            ExecutableTypeData type = child.findExecutableType(context, parameter.getTypeSystemType());
             if (type.hasUnexpectedValue(context)) {
                 return true;
             }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MessageContainer.java	Wed Apr 24 18:39:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MessageContainer.java	Wed Apr 24 21:50:03 2013 +0200
@@ -34,11 +34,15 @@
     private final List<Message> messages = new ArrayList<>();
 
     public final void addWarning(String text, Object... params) {
-        getMessages().add(new Message(this, String.format(text, params), Kind.WARNING));
+        getMessages().add(new Message(null, this, String.format(text, params), Kind.WARNING));
     }
 
     public final void addError(String text, Object... params) {
-        getMessages().add(new Message(this, String.format(text, params), Kind.ERROR));
+        addError(null, text, params);
+    }
+
+    public final void addError(AnnotationValue value, String text, Object... params) {
+        getMessages().add(new Message(value, this, String.format(text, params), Kind.ERROR));
     }
 
     protected List<MessageContainer> findChildContainers() {
@@ -150,15 +154,21 @@
     public static final class Message {
 
         private final MessageContainer originalContainer;
+        private final AnnotationValue annotationValue;
         private final String text;
         private final Kind kind;
 
-        public Message(MessageContainer originalContainer, String text, Kind kind) {
+        public Message(AnnotationValue annotationValue, MessageContainer originalContainer, String text, Kind kind) {
+            this.annotationValue = annotationValue;
             this.originalContainer = originalContainer;
             this.text = text;
             this.kind = kind;
         }
 
+        public AnnotationValue getAnnotationValue() {
+            return annotationValue;
+        }
+
         public MessageContainer getOriginalContainer() {
             return originalContainer;
         }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Wed Apr 24 18:39:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Wed Apr 24 21:50:03 2013 +0200
@@ -206,6 +206,17 @@
         return types;
     }
 
+    public List<ActualParameter> getSignatureParameters() {
+        List<ActualParameter> types = new ArrayList<>();
+        for (ActualParameter parameter : getParameters()) {
+            if (!parameter.getSpecification().isSignature()) {
+                continue;
+            }
+            types.add(parameter);
+        }
+        return types;
+    }
+
     @Override
     public int compareTo(TemplateMethod o) {
         if (this == o) {