changeset 18776:c0fb70634640

Truffle-DSL: support for frame types Frame, MaterializedFrame. Added validation for frame type consistency. Some refactorings along the way.
author Christian Humer <christian.humer@gmail.com>
date Mon, 05 Jan 2015 01:31:08 +0100
parents a069a87b9a02
children 76cbf5f33f82
files graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/Log.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ProcessorContext.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeBaseFactory.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemNodeFactory.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeMethodParser.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java
diffstat 16 files changed, 710 insertions(+), 337 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java	Mon Jan 05 01:31:08 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java	Mon Jan 05 01:31:08 2015 +0100
@@ -147,6 +147,11 @@
 
     abstract static class TestEvaluatedVarArgs0 extends ChildrenNode {
 
+        @Override
+        public final Object execute(VirtualFrame frame) {
+            return execute1(frame);
+        }
+
         public abstract Object execute1(VirtualFrame frame, Object... value);
 
         @Specialization
@@ -247,6 +252,11 @@
 
     abstract static class TestEvaluatedVarArgs5 extends ValueNode {
 
+        @Override
+        public final Object execute(VirtualFrame frame) {
+            return execute1(frame);
+        }
+
         public abstract Object execute1(VirtualFrame frame, Object... value);
 
         @Specialization
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java	Mon Jan 05 01:31:08 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java	Mon Jan 05 01:31:08 2015 +0100
@@ -23,26 +23,28 @@
 package com.oracle.truffle.api.dsl.test;
 
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.dsl.internal.*;
+import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 
 public class ExecuteMethodTest {
 
-    private static final String NO_EXECUTE = "No accessible and overridable generic execute method found. Generic execute methods usually have the signature 'public abstract {Type} "
-                    + "executeGeneric(VirtualFrame)' and must not throw any checked exceptions.";
+    private static final String ERROR_NO_EXECUTE = "No accessible and overridable generic execute method found. Generic execute methods usually have the signature 'public abstract {Type} "
+                    + "execute(VirtualFrame)' and must not throw any checked exceptions.";
 
-    @TypeSystem({int.class, Object[].class})
-    static class ExecuteTypeSystem {
-
+    @TypeSystem({int.class})
+    @DSLOptions(useNewLayout = true)
+    static class ExecuteMethodTypes {
     }
 
-    @TypeSystemReference(ExecuteTypeSystem.class)
-    abstract static class ValidChildNode extends Node {
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    abstract static class ChildNoFrame extends Node {
         abstract Object execute();
     }
 
-    @TypeSystemReference(ExecuteTypeSystem.class)
-    @NodeChild(value = "a", type = ValidChildNode.class)
-    @ExpectError(NO_EXECUTE)
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    @ExpectError(ERROR_NO_EXECUTE)
     abstract static class ExecuteThis1 extends Node {
 
         @Specialization
@@ -51,9 +53,9 @@
         }
     }
 
-    @TypeSystemReference(ExecuteTypeSystem.class)
-    @NodeChild(value = "a", type = ValidChildNode.class)
-    @ExpectError(NO_EXECUTE)
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    @ExpectError(ERROR_NO_EXECUTE)
     abstract static class ExecuteThis2 extends Node {
 
         abstract Object execute() throws UnexpectedResultException;
@@ -64,9 +66,9 @@
         }
     }
 
-    @TypeSystemReference(ExecuteTypeSystem.class)
-    @NodeChild(value = "a", type = ValidChildNode.class)
-    @ExpectError(NO_EXECUTE)
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    @ExpectError(ERROR_NO_EXECUTE)
     abstract static class ExecuteThis3 extends Node {
 
         abstract int execute() throws UnexpectedResultException;
@@ -77,8 +79,8 @@
         }
     }
 
-    @TypeSystemReference(ExecuteTypeSystem.class)
-    @NodeChild(value = "a", type = ValidChildNode.class)
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
     abstract static class ExecuteThis4 extends Node {
 
         protected abstract Object execute();
@@ -89,8 +91,8 @@
         }
     }
 
-    @TypeSystemReference(ExecuteTypeSystem.class)
-    @NodeChild(value = "a", type = ValidChildNode.class)
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
     abstract static class ExecuteThis5 extends Node {
 
         public abstract Object execute();
@@ -101,9 +103,9 @@
         }
     }
 
-    @TypeSystemReference(ExecuteTypeSystem.class)
-    @NodeChild(value = "a", type = ValidChildNode.class)
-    @ExpectError(NO_EXECUTE)
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    @ExpectError(ERROR_NO_EXECUTE)
     abstract static class ExecuteThis6 extends Node {
 
         @SuppressWarnings({"unused", "static-method"})
@@ -117,9 +119,9 @@
         }
     }
 
-    @TypeSystemReference(ExecuteTypeSystem.class)
-    @NodeChild(value = "a", type = ValidChildNode.class)
-    @ExpectError(NO_EXECUTE)
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    @ExpectError(ERROR_NO_EXECUTE)
     abstract static class ExecuteThis7 extends Node {
 
         @SuppressWarnings("static-method")
@@ -133,8 +135,8 @@
         }
     }
 
-    @TypeSystemReference(ExecuteTypeSystem.class)
-    @NodeChild(value = "a", type = ValidChildNode.class)
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
     @ExpectError("Multiple accessible and overridable generic execute methods found [executeInt(), executeObject()]. Remove all but one or mark all but one as final.")
     abstract static class ExecuteThis8 extends Node {
 
@@ -149,8 +151,8 @@
 
     }
 
-    @TypeSystemReference(ExecuteTypeSystem.class)
-    @NodeChild(value = "a", type = ValidChildNode.class)
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
     abstract static class ExecuteThis9 extends Node {
 
         abstract int executeInt();
@@ -166,4 +168,270 @@
         }
     }
 
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    abstract static class ExecuteThisVoid1 extends Node {
+
+        abstract void executeVoid();
+
+        @Specialization
+        int doInt(int a) {
+            return a;
+        }
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    abstract static class ExecuteThisVoid2 extends Node {
+
+        // allow one execute void
+        abstract void executeVoid();
+
+        abstract Object executeObject();
+
+        @Specialization
+        int doInt(int a) {
+            return a;
+        }
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    @ExpectError("Multiple accessible and overridable generic execute methods found [executeObject(), executeVoid1(), executeVoid2()]. Remove all but one or mark all but one as final.")
+    abstract static class ExecuteThisVoid3 extends Node {
+
+        // allow only one execute void
+        abstract void executeVoid1();
+
+        abstract void executeVoid2();
+
+        abstract Object executeObject();
+
+        @Specialization
+        int doInt(int a) {
+            return a;
+        }
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    abstract static class ExecuteWithFrame1 extends Node {
+
+        // no frame in execute. no parameter in specializations
+        abstract Object executeNoFrame();
+
+        @Specialization
+        int doInt(int a) {
+            return a;
+        }
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    abstract static class ExecuteWithFrame2 extends Node {
+
+        // frame in execute also usable in specialization
+        abstract Object executeWithFrame(VirtualFrame frame);
+
+        @Specialization
+        int doInt(@SuppressWarnings("unused") VirtualFrame frame, int a) {
+            return a;
+        }
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    abstract static class ExecuteWithFrame3 extends Node {
+
+        abstract Object executeWithFrame(Frame frame);
+
+        @Specialization
+        int doInt(@SuppressWarnings("unused") Frame frame, int a) {
+            return a;
+        }
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ExecuteWithFrame4.class)
+    abstract static class ExecuteWithFrame4 extends Node {
+
+        abstract Object executeWithFrame(MaterializedFrame frame);
+
+        @Specialization
+        int doInt(@SuppressWarnings("unused") MaterializedFrame frame, int a) {
+            return a;
+        }
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    abstract static class ExecuteWithFrameError1 extends Node {
+
+        abstract Object executeNoFrame();
+
+        @Specialization
+        @ExpectError("Method signature (VirtualFrame, int) does not match to the expected signature:%")
+        int doInt(@SuppressWarnings("unused") VirtualFrame frame, int a) {
+            return a;
+        }
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    abstract static class ExecuteWithFrameError2 extends Node {
+
+        abstract Object executeFrame(MaterializedFrame frame);
+
+        @Specialization
+        @ExpectError("Method signature (VirtualFrame, int) does not match to the expected signature:%")
+        int doInt(@SuppressWarnings("unused") VirtualFrame frame, int a) {
+            return a;
+        }
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    abstract static class ExecuteWithFrameError3 extends Node {
+
+        abstract Object executeFrame(VirtualFrame frame);
+
+        @Specialization
+        @ExpectError("Method signature (MaterializedFrame, int) does not match to the expected signature:%")
+        int doInt(@SuppressWarnings("unused") MaterializedFrame frame, int a) {
+            return a;
+        }
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    @ExpectError("Invalid inconsistent frame types [MaterializedFrame, VirtualFrame] found for the declared execute methods.%")
+    abstract static class ExecuteWithFrameError4 extends Node {
+
+        abstract Object execute(VirtualFrame frame);
+
+        abstract int executeInt(MaterializedFrame frame) throws UnexpectedResultException;
+
+        @Specialization
+        int doInt(int a) {
+            return a;
+        }
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    @ExpectError("Invalid inconsistent frame types [MaterializedFrame, void] found for the declared execute methods.%")
+    abstract static class ExecuteWithFrameError5 extends Node {
+
+        abstract Object execute();
+
+        abstract int executeInt(MaterializedFrame frame) throws UnexpectedResultException;
+
+        @Specialization
+        int doInt(int a) {
+            return a;
+        }
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    abstract static class ChildVirtualFrame extends Node {
+        abstract Object execute(VirtualFrame frame);
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    abstract static class ChildMaterializedFrame extends Node {
+        abstract Object execute(MaterializedFrame frame);
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    abstract static class ChildFrame extends Node {
+        abstract Object execute(Frame frame);
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildNoFrame.class)
+    abstract static class ExecuteChildFrame1 extends Node {
+
+        abstract Object execute(VirtualFrame frame);
+
+        @Specialization
+        int doInt(int a) {
+            return a;
+        }
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildFrame.class)
+    abstract static class ExecuteChildFrame2 extends Node {
+
+        abstract Object execute(VirtualFrame frame);
+
+        @Specialization
+        int doInt(int a) {
+            return a;
+        }
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildFrame.class)
+    abstract static class ExecuteChildFrame3 extends Node {
+
+        abstract Object execute(MaterializedFrame frame);
+
+        @Specialization
+        int doInt(int a) {
+            return a;
+        }
+    }
+
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildFrame.class)
+    abstract static class ExecuteChildFrame4 extends Node {
+
+        abstract Object execute(Frame frame);
+
+        @Specialization
+        int doInt(int a) {
+            return a;
+        }
+    }
+
+    @ExpectError("No generic execute method found with 0 evaluated arguments for node type ChildVirtualFrame and frame types [com.oracle.truffle.api.frame.Frame].")
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildVirtualFrame.class)
+    abstract static class ExecuteChildFrameError1 extends Node {
+
+        abstract Object execute(Frame frame);
+
+        @Specialization
+        int doInt(int a) {
+            return a;
+        }
+    }
+
+    @ExpectError("No generic execute method found with 0 evaluated arguments for node type ChildFrame and frame types [].")
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildFrame.class)
+    abstract static class ExecuteChildFrameError2 extends Node {
+
+        abstract Object execute();
+
+        @Specialization
+        int doInt(int a) {
+            return a;
+        }
+    }
+
+    @ExpectError("No generic execute method found with 0 evaluated arguments for node type ChildVirtualFrame and frame types [].")
+    @TypeSystemReference(ExecuteMethodTypes.class)
+    @NodeChild(value = "a", type = ChildVirtualFrame.class)
+    abstract static class ExecuteChildFrameError3 extends Node {
+
+        abstract Object execute();
+
+        @Specialization
+        int doInt(int a) {
+            return a;
+        }
+    }
+
 }
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java	Mon Jan 05 01:31:08 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java	Mon Jan 05 01:31:08 2015 +0100
@@ -175,27 +175,27 @@
         return start;
     }
 
-    public Object acceptAndExecute(VirtualFrame frame) {
+    public Object acceptAndExecute(Frame frame) {
         throw new UnsupportedOperationException();
     }
 
-    public Object acceptAndExecute(VirtualFrame frame, Object o1) {
+    public Object acceptAndExecute(Frame frame, Object o1) {
         throw new UnsupportedOperationException();
     }
 
-    public Object acceptAndExecute(VirtualFrame frame, Object o1, Object o2) {
+    public Object acceptAndExecute(Frame frame, Object o1, Object o2) {
         throw new UnsupportedOperationException();
     }
 
-    public Object acceptAndExecute(VirtualFrame frame, Object o1, Object o2, Object o3) {
+    public Object acceptAndExecute(Frame frame, Object o1, Object o2, Object o3) {
         throw new UnsupportedOperationException();
     }
 
-    public Object acceptAndExecute(VirtualFrame frame, Object o1, Object o2, Object o3, Object o4) {
+    public Object acceptAndExecute(Frame frame, Object o1, Object o2, Object o3, Object o4) {
         throw new UnsupportedOperationException();
     }
 
-    public Object acceptAndExecute(VirtualFrame frame, Object... args) {
+    public Object acceptAndExecute(Frame frame, Object... args) {
         throw new UnsupportedOperationException();
     }
 
@@ -207,31 +207,31 @@
         return null;
     }
 
-    protected SpecializationNode createNext(VirtualFrame frame) {
+    protected SpecializationNode createNext(Frame frame) {
         throw new UnsupportedOperationException();
     }
 
-    protected SpecializationNode createNext(VirtualFrame frame, Object o1) {
+    protected SpecializationNode createNext(Frame frame, Object o1) {
         throw new UnsupportedOperationException();
     }
 
-    protected SpecializationNode createNext(VirtualFrame frame, Object o1, Object o2) {
+    protected SpecializationNode createNext(Frame frame, Object o1, Object o2) {
         throw new UnsupportedOperationException();
     }
 
-    protected SpecializationNode createNext(VirtualFrame frame, Object o1, Object o2, Object o3) {
+    protected SpecializationNode createNext(Frame frame, Object o1, Object o2, Object o3) {
         throw new UnsupportedOperationException();
     }
 
-    protected SpecializationNode createNext(VirtualFrame frame, Object o1, Object o2, Object o3, Object o4) {
+    protected SpecializationNode createNext(Frame frame, Object o1, Object o2, Object o3, Object o4) {
         throw new UnsupportedOperationException();
     }
 
-    protected SpecializationNode createNext(VirtualFrame frame, Object... args) {
+    protected SpecializationNode createNext(Frame frame, Object... args) {
         throw new UnsupportedOperationException();
     }
 
-    protected final Object uninitialized(VirtualFrame frame) {
+    protected final Object uninitialized(Frame frame) {
         CompilerDirectives.transferToInterpreterAndInvalidate();
         SpecializationNode nextSpecialization = createNext(frame);
         if (nextSpecialization == null) {
@@ -243,7 +243,7 @@
         return insertSpecialization(nextSpecialization, new RewriteEvent0(findParentNode(), "inserted new specialization")).acceptAndExecute(frame);
     }
 
-    protected final Object uninitialized(VirtualFrame frame, Object o1) {
+    protected final Object uninitialized(Frame frame, Object o1) {
         CompilerDirectives.transferToInterpreterAndInvalidate();
         SpecializationNode nextSpecialization = createNext(frame, o1);
         if (nextSpecialization == null) {
@@ -255,7 +255,7 @@
         return insertSpecialization(nextSpecialization, new RewriteEvent1(findParentNode(), "inserted new specialization", o1)).acceptAndExecute(frame, o1);
     }
 
-    protected final Object uninitialized(VirtualFrame frame, Object o1, Object o2) {
+    protected final Object uninitialized(Frame frame, Object o1, Object o2) {
         CompilerDirectives.transferToInterpreterAndInvalidate();
         SpecializationNode nextSpecialization = createNext(frame, o1, o2);
         if (nextSpecialization == null) {
@@ -267,7 +267,7 @@
         return insertSpecialization(nextSpecialization, new RewriteEvent2(findParentNode(), "inserted new specialization", o1, o2)).acceptAndExecute(frame, o1, o2);
     }
 
-    protected final Object uninitialized(VirtualFrame frame, Object o1, Object o2, Object o3) {
+    protected final Object uninitialized(Frame frame, Object o1, Object o2, Object o3) {
         CompilerDirectives.transferToInterpreterAndInvalidate();
         SpecializationNode nextSpecialization = createNext(frame, o1, o2, o3);
         if (nextSpecialization == null) {
@@ -279,7 +279,7 @@
         return insertSpecialization(nextSpecialization, new RewriteEvent3(findParentNode(), "inserted new specialization", o1, o2, o3)).acceptAndExecute(frame, o1, o2, o3);
     }
 
-    protected final Object uninitialized(VirtualFrame frame, Object o1, Object o2, Object o3, Object o4) {
+    protected final Object uninitialized(Frame frame, Object o1, Object o2, Object o3, Object o4) {
         CompilerDirectives.transferToInterpreterAndInvalidate();
         SpecializationNode nextSpecialization = createNext(frame, o1, o2, o3, o4);
         if (nextSpecialization == null) {
@@ -291,7 +291,7 @@
         return insertSpecialization(nextSpecialization, new RewriteEvent4(findParentNode(), "inserts new specialization", o1, o2, o3, o4)).acceptAndExecute(frame, o1, o2, o3, o4);
     }
 
-    protected final Object uninitialized(VirtualFrame frame, Object... args) {
+    protected final Object uninitialized(Frame frame, Object... args) {
         CompilerDirectives.transferToInterpreterAndInvalidate();
         SpecializationNode nextSpecialization = createNext(frame, args);
         if (nextSpecialization == null) {
@@ -307,51 +307,51 @@
         return findStart().count() == 2;
     }
 
-    protected final Object remove(String reason, VirtualFrame frame) {
+    protected final Object remove(String reason, Frame frame) {
         return removeSame(new RewriteEvent0(findParentNode(), reason)).acceptAndExecute(frame);
     }
 
-    protected final Object remove(String reason, VirtualFrame frame, Object o1) {
+    protected final Object remove(String reason, Frame frame, Object o1) {
         return removeSame(new RewriteEvent1(findParentNode(), reason, o1)).acceptAndExecute(frame, o1);
     }
 
-    protected final Object remove(String reason, VirtualFrame frame, Object o1, Object o2) {
+    protected final Object remove(String reason, Frame frame, Object o1, Object o2) {
         return removeSame(new RewriteEvent2(findParentNode(), reason, o1, o2)).acceptAndExecute(frame, o1, o2);
     }
 
-    protected final Object remove(String reason, VirtualFrame frame, Object o1, Object o2, Object o3) {
+    protected final Object remove(String reason, Frame frame, Object o1, Object o2, Object o3) {
         return removeSame(new RewriteEvent3(findParentNode(), reason, o1, o2, o3)).acceptAndExecute(frame, o1, o2, o3);
     }
 
-    protected final Object remove(String reason, VirtualFrame frame, Object o1, Object o2, Object o3, Object o4) {
+    protected final Object remove(String reason, Frame frame, Object o1, Object o2, Object o3, Object o4) {
         return removeSame(new RewriteEvent4(findParentNode(), reason, o1, o2, o3, o4)).acceptAndExecute(frame, o1, o2, o3, o4);
     }
 
-    protected final Object remove(String reason, VirtualFrame frame, Object... args) {
+    protected final Object remove(String reason, Frame frame, Object... args) {
         return removeSame(new RewriteEventN(findParentNode(), reason, args)).acceptAndExecute(frame, args);
     }
 
-    protected Object unsupported(VirtualFrame frame) {
+    protected Object unsupported(Frame frame) {
         throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren());
     }
 
-    protected Object unsupported(VirtualFrame frame, Object o1) {
+    protected Object unsupported(Frame frame, Object o1) {
         throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1);
     }
 
-    protected Object unsupported(VirtualFrame frame, Object o1, Object o2) {
+    protected Object unsupported(Frame frame, Object o1, Object o2) {
         throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1, o2);
     }
 
-    protected Object unsupported(VirtualFrame frame, Object o1, Object o2, Object o3) {
+    protected Object unsupported(Frame frame, Object o1, Object o2, Object o3) {
         throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1, o2, o3);
     }
 
-    protected Object unsupported(VirtualFrame frame, Object o1, Object o2, Object o3, Object o4) {
+    protected Object unsupported(Frame frame, Object o1, Object o2, Object o3, Object o4) {
         throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1, o2, o3, o4);
     }
 
-    protected Object unsupported(VirtualFrame frame, Object... args) {
+    protected Object unsupported(Frame frame, Object... args) {
         throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), args);
     }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/Log.java	Mon Jan 05 01:31:08 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/Log.java	Mon Jan 05 01:31:08 2015 +0100
@@ -33,7 +33,9 @@
  */
 public class Log {
 
-    public static final boolean DEBUG = false;
+    public static boolean isDebug() {
+        return false;
+    }
 
     private final ProcessingEnvironment processingEnv;
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ProcessorContext.java	Mon Jan 05 01:31:08 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ProcessorContext.java	Mon Jan 05 01:31:08 2015 +0100
@@ -29,6 +29,7 @@
 import javax.lang.model.type.*;
 import javax.lang.model.util.*;
 
+import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.dsl.processor.java.*;
 import com.oracle.truffle.dsl.processor.java.model.*;
 import com.oracle.truffle.dsl.processor.model.*;
@@ -137,4 +138,8 @@
     public static ProcessorContext getInstance() {
         return instance.get();
     }
+
+    public List<TypeMirror> getFrameTypes() {
+        return Arrays.asList(getType(VirtualFrame.class), getType(MaterializedFrame.class), getType(Frame.class));
+    }
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeBaseFactory.java	Mon Jan 05 01:31:08 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeBaseFactory.java	Mon Jan 05 01:31:08 2015 +0100
@@ -559,7 +559,7 @@
         addInternalValueParameters(method, generic, true, false, false);
         CodeTreeBuilder builder = method.createBuilder();
 
-        boolean needsFrame = node.isFrameUsedByAnyGuard(context);
+        boolean needsFrame = node.isFrameUsedByAnyGuard();
         CodeTreeBuilder createSpecializationCall = builder.create();
         createSpecializationCall.startCall(SPECIALIZE);
         addInternalValueParameterNames(createSpecializationCall, generic, generic, null, needsFrame, !needsFrame, null);
@@ -607,7 +607,7 @@
         addInternalValueParameters(method, generic, true, false, false);
         method.addParameter(new CodeVariableElement(context.getType(String.class), "reason"));
 
-        boolean needsFrame = node.isFrameUsedByAnyGuard(context);
+        boolean needsFrame = node.isFrameUsedByAnyGuard();
         CodeTreeBuilder builder = method.createBuilder();
 
         builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerAsserts(), "neverPartOfCompilation").end().end();
@@ -669,7 +669,7 @@
         CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), new GeneratedTypeMirror(ElementUtils.getPackageName(node.getTemplateType()), baseClassName(node)),
                         SPECIALIZE);
 
-        final boolean needsFrame = node.isFrameUsedByAnyGuard(context);
+        final boolean needsFrame = node.isFrameUsedByAnyGuard();
 
         if (!needsFrame) {
             method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getTruffleTypes().getTruffleBoundary()));
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Mon Jan 05 01:31:08 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Mon Jan 05 01:31:08 2015 +0100
@@ -169,7 +169,7 @@
         }
 
         for (NodeExecutionData execution : node.getChildExecutions()) {
-            if (findSpecializedExecutables(execution, node.findSpecializedTypes(execution), options.polymorphicTypeBoxingElimination()).isEmpty()) {
+            if (resolveSpecializedExecutables(execution, node.findSpecializedTypes(execution), options.polymorphicTypeBoxingElimination()).isEmpty()) {
                 continue;
             }
             clazz.add(createNodeField(PRIVATE, getType(Class.class), polymorphicTypeProfileFieldName(execution), CompilationFinal.class));
@@ -225,7 +225,7 @@
                     CodeTree nameTree = CodeTreeBuilder.singleString(name);
                     CodeTreeBuilder callBuilder = builder.create();
                     callBuilder.string(name).string(" != null ? ");
-                    callBuilder.tree(callTemplateMethod(builder, null, createCast, nameTree));
+                    callBuilder.tree(callTemplateMethod(null, createCast, nameTree));
                     callBuilder.string(" : null");
                     name += "_";
                     builder.declaration(child.getNodeType(), name, callBuilder.build());
@@ -251,7 +251,7 @@
             CodeTree accessor = accessorBuilder.build();
 
             if (createCast != null && execution.getChild().getCardinality().isOne()) {
-                accessor = callTemplateMethod(builder, null, createCast, accessor);
+                accessor = callTemplateMethod(null, createCast, accessor);
             }
 
             if (execution.isIndexed()) {
@@ -282,7 +282,7 @@
             clazz.add(createSingleSpecialization(single));
             return single;
         } else {
-            CodeTypeElement baseSpecialization = clazz.add(createBaseSpecialization(clazz));
+            CodeTypeElement baseSpecialization = clazz.add(createBaseSpecialization());
             TypeMirror baseSpecializationType = baseSpecialization.asType();
 
             Map<SpecializationData, CodeTypeElement> generated = new LinkedHashMap<>();
@@ -308,7 +308,7 @@
 
     // create specialization
 
-    private CodeTypeElement createBaseSpecialization(CodeTypeElement parentClass) {
+    private CodeTypeElement createBaseSpecialization() {
         CodeTypeElement clazz = createClass(node, null, modifiers(PRIVATE, ABSTRACT, STATIC), "BaseNode_", TypeSystemNodeFactory.nodeType(typeSystem));
 
         clazz.addOptional(createSpecializationConstructor(clazz, null, null));
@@ -330,11 +330,7 @@
             specializedTypes.add(genericType);
             for (TypeData specializedType : specializedTypes) {
                 if (isExecuteChildShared(execution, specializedType)) {
-                    if (specializedType.isGeneric()) {
-                        parentClass.add(createExecuteChildMethod(execution, specializedType));
-                    } else {
-                        clazz.add(createExecuteChildMethod(execution, specializedType));
-                    }
+                    clazz.add(createExecuteChildMethod(execution, specializedType));
                 }
             }
         }
@@ -495,7 +491,7 @@
 
     private Element createFastPathWrapVoidMethod(TypeData wrap) {
         CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), typeSystem.getVoidType().getPrimitiveType(), TypeSystemNodeFactory.executeName(typeSystem.getVoidType()));
-        executable.addParameter(new CodeVariableElement(getType(VirtualFrame.class), FRAME_VALUE));
+        executable.addParameter(new CodeVariableElement(getType(Frame.class), FRAME_VALUE));
         executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
         CodeTreeBuilder builder = executable.createBuilder();
         builder.startStatement();
@@ -509,7 +505,7 @@
 
     private Element createFastPathWrapExecuteMethod(TypeData override, TypeData wrap) {
         CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), override.getPrimitiveType(), TypeSystemNodeFactory.executeName(override));
-        executable.addParameter(new CodeVariableElement(getType(VirtualFrame.class), FRAME_VALUE));
+        executable.addParameter(new CodeVariableElement(getType(Frame.class), FRAME_VALUE));
         executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
         CodeTreeBuilder builder = executable.createBuilder();
         if (wrap != null) {
@@ -605,7 +601,7 @@
     }
 
     private CodeExecutableElement createFallbackGuardMethod() {
-        boolean frameUsed = node.isFrameUsedByAnyGuard(context);
+        boolean frameUsed = node.isFrameUsedByAnyGuard();
         LocalContext locals = LocalContext.load(this);
 
         if (!frameUsed) {
@@ -701,7 +697,7 @@
 
         CodeTreeBuilder builder = method.createBuilder();
         builder.startReturn();
-        builder.tree(callTemplateMethod(builder, accessParent(null), fallback, locals));
+        builder.tree(callTemplateMethod(accessParent(null), fallback, locals));
         builder.end();
 
         return method;
@@ -860,9 +856,11 @@
         return childField;
     }
 
-    private static List<ExecutableTypeData> findSpecializedExecutables(NodeExecutionData execution, Collection<TypeData> types, TypeBoxingOptimization optimization) {
+    private static List<ExecutableTypeData> resolveSpecializedExecutables(NodeExecutionData execution, Collection<TypeData> types, TypeBoxingOptimization optimization) {
         if (optimization == TypeBoxingOptimization.NONE) {
             return Collections.emptyList();
+        } else if (types.isEmpty()) {
+            return Collections.emptyList();
         }
 
         List<ExecutableTypeData> executables = new ArrayList<>();
@@ -878,8 +876,8 @@
         return executables;
     }
 
-    private static CodeTree callTemplateMethod(CodeTreeBuilder parent, CodeTree receiver, TemplateMethod method, CodeTree... boundValues) {
-        CodeTreeBuilder builder = parent.create();
+    private static CodeTree callTemplateMethod(CodeTree receiver, TemplateMethod method, CodeTree... boundValues) {
+        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
         if (method.getMethod().getModifiers().contains(STATIC)) {
             builder.startStaticCall(method.getMethod().getEnclosingElement().asType(), method.getMethodName());
         } else {
@@ -901,25 +899,33 @@
         return builder.build();
     }
 
-    private static CodeTree callTemplateMethod(CodeTreeBuilder parent, CodeTree receiver, TemplateMethod method, LocalContext currentValues) {
+    private static CodeTree callTemplateMethod(CodeTree receiver, TemplateMethod method, LocalContext currentValues) {
         CodeTree[] bindings = new CodeTree[method.getParameters().size()];
 
         int signatureIndex = 0;
         for (int i = 0; i < bindings.length; i++) {
             Parameter parameter = method.getParameters().get(i);
+
             LocalVariable var = currentValues.get(parameter, signatureIndex);
+            if (var == null) {
+                var = currentValues.get(parameter.getLocalName());
+            }
+
             if (var != null) {
-                CodeTree valueReference = bindings[i] = var.createReference();
+                CodeTree valueReference = var.createReference();
                 if (parameter.getTypeSystemType() != null && var.getType() != null && var.getType().needsCastTo(parameter.getTypeSystemType())) {
                     valueReference = TypeSystemCodeGenerator.cast(parameter.getTypeSystemType(), valueReference);
+                } else if (ElementUtils.needsCastTo(var.getTypeMirror(), parameter.getType())) {
+                    valueReference = CodeTreeBuilder.createBuilder().cast(parameter.getType(), valueReference).build();
                 }
                 bindings[i] = valueReference;
             }
+
             if (parameter.getSpecification().isSignature()) {
                 signatureIndex++;
             }
         }
-        return callTemplateMethod(parent, receiver, method, bindings);
+        return callTemplateMethod(receiver, method, bindings);
     }
 
     private SpecializationGroup createSpecializationGroups() {
@@ -931,7 +937,7 @@
         if (specialization.isFallback()) {
             return builder.returnNull().build();
         }
-        if (node.isFrameUsedByAnyGuard(context)) {
+        if (node.isFrameUsedByAnyGuard()) {
             builder.tree(createTransferToInterpreterAndInvalidate());
         }
         for (SpecializationData otherSpeciailzation : node.getSpecializations()) {
@@ -1154,24 +1160,27 @@
         return TypeSystemCodeGenerator.expect(executedType, forType, builder.build());
     }
 
-    private static ExecutableTypeData findSpecializedExecutableType(NodeExecutionData execution, TypeData type) {
-        NodeChildData child = execution.getChild();
+    private Set<ExecutableTypeData> findSpecializedExecutableTypes(NodeExecutionData execution, TypeData type) {
+        ExecutableTypeData executableType = resolveExecutableType(execution.getChild(), type);
+        Set<ExecutableTypeData> executedTypes = new HashSet<>();
+        executedTypes.add(executableType);
+        if (type.hasImplicitSourceTypes()) {
+            executedTypes.addAll(resolveSpecializedExecutables(execution, type.getImplicitSourceTypes(), options.implicitTypeBoxingOptimization()));
+        }
+        return executedTypes;
+    }
+
+    private ExecutableTypeData resolveExecutableType(NodeChildData child, TypeData type) {
         int executeWithCount = child.getExecuteWith().size();
-        return child.getNodeData().findExecutableType(type, executeWithCount);
+        ExecutableTypeData executableType = child.getNodeData().findExecutableType(type, executeWithCount);
+        if (executableType == null) {
+            executableType = child.getNodeData().findAnyGenericExecutableType(context, executeWithCount);
+        }
+        return executableType;
     }
 
     private boolean hasUnexpectedResult(NodeExecutionData execution, TypeData type) {
-        if (type.isGeneric() || type.isVoid()) {
-            return false;
-        }
-        List<ExecutableTypeData> executableTypes = new ArrayList<>();
-        executableTypes.add(findSpecializedExecutableType(execution, type));
-
-        if (!options.implicitCastOptimization().isNone()) {
-            executableTypes.addAll(findSpecializedExecutables(execution, type.getImplicitSourceTypes(), options.implicitTypeBoxingOptimization()));
-        }
-
-        for (ExecutableTypeData executableType : executableTypes) {
+        for (ExecutableTypeData executableType : findSpecializedExecutableTypes(execution, type)) {
             if (executableType != null && executableType.hasUnexpectedValue(context)) {
                 return true;
             }
@@ -1245,7 +1254,7 @@
 
         if (execution.isShortCircuit()) {
             ShortCircuitData shortCircuitData = resolvedSpecialization.getShortCircuits().get(calculateShortCircuitIndex(execution));
-            CodeTree access = callTemplateMethod(CodeTreeBuilder.createBuilder(), accessParent(null), shortCircuitData, currentLocals);
+            CodeTree access = callTemplateMethod(accessParent(null), shortCircuitData, currentLocals);
             shortCircuit = currentLocals.createShortCircuitValue(execution).accessWith(access);
         }
         return shortCircuit;
@@ -1269,7 +1278,7 @@
         int ifCount = 0;
         if (specialization.isFallback()) {
             builder.startIf().startCall("guardFallback");
-            if (node.isFrameUsedByAnyGuard(context)) {
+            if (node.isFrameUsedByAnyGuard()) {
                 builder.string(FRAME_VALUE);
             }
             currentValues.addReferencesTo(builder);
@@ -1286,7 +1295,7 @@
             currentValues.addReferencesTo(execute, FRAME_VALUE);
             execute.end();
         } else {
-            execute.tree(callTemplateMethod(execute, accessParent(null), specialization, currentValues));
+            execute.tree(callTemplateMethod(accessParent(null), specialization, currentValues));
         }
         execute.end();
         builder.tree(createFastPathTryCatchRewriteException(specialization, forType, currentValues, execute.build()));
@@ -1454,7 +1463,7 @@
         }
 
         CodeTreeBuilder builder = method.createBuilder();
-        CodeTree executeChild = createExecuteChild(execution, targetType, locals.createValue(execution, targetType), locals, true);
+        CodeTree executeChild = createExecuteChild(execution, locals.createValue(execution, targetType), locals, true);
         if (executeChild.isSingleLine()) {
             builder.statement(executeChild);
         } else {
@@ -1484,7 +1493,7 @@
             if (isSingleSpecializable(getReachableSpecializations())) {
                 return false;
             }
-            return findSpecializedExecutables(execution, node.findSpecializedTypes(execution), options.polymorphicTypeBoxingElimination()).size() >= 1;
+            return resolveSpecializedExecutables(execution, node.findSpecializedTypes(execution), options.polymorphicTypeBoxingElimination()).size() >= 1;
         } else {
             if (!isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), targetType)) {
                 return false;
@@ -1503,7 +1512,7 @@
                 }
             }
             if (uses > 1) {
-                return findSpecializedExecutables(execution, targetType.getImplicitSourceTypes(), options.implicitTypeBoxingOptimization()).size() > 1;
+                return resolveSpecializedExecutables(execution, targetType.getImplicitSourceTypes(), options.implicitTypeBoxingOptimization()).size() > 1;
             } else {
                 return false;
             }
@@ -1518,7 +1527,7 @@
         if (isExecuteChildShared(execution, targetValue.getType())) {
             executeChild = createCallSharedExecuteChild(execution, targetValue, currentValues);
         } else {
-            executeChild = createExecuteChild(execution, targetValue.getType(), targetValue, currentValues, false);
+            executeChild = createExecuteChild(execution, targetValue, currentValues, false);
         }
 
         builder.tree(createTryExecuteChild(targetValue, executeChild, shortCircuit == null, hasUnexpected));
@@ -1605,11 +1614,7 @@
 
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
         builder.tree(targetValue.createReference()).string(" = ");
-        if (targetValue.getType().isGeneric()) {
-            builder.startCall("root", executeChildMethodName(execution, targetValue.getType()));
-        } else {
-            builder.startCall(executeChildMethodName(execution, targetValue.getType()));
-        }
+        builder.startCall(executeChildMethodName(execution, targetValue.getType()));
         builder.string(FRAME_VALUE);
 
         CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetValue.getType());
@@ -1623,171 +1628,149 @@
         return builder.build();
     }
 
-    private CodeTree createExecuteChild(NodeExecutionData execution, TypeData returnType, LocalVariable target, LocalContext currentValues, boolean shared) {
+    private CodeTree createExecuteChild(NodeExecutionData execution, LocalVariable target, LocalContext currentValues, boolean shared) {
         final CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        final ExecutableTypeData executableType = findSpecializedExecutableType(execution, target.getType());
 
-        CodeTree assignment = createAssignmentStart(target, shared, false);
+        CodeTree assignment = createAssignmentStart(target, shared);
 
-        if (executableType == null) {
-            if (target.getType().isGeneric()) {
-                throw new AssertionError("Should be caught by the parser.");
-            }
-            CodeTree genericExecute = createExecuteChild(execution, returnType, target.makeGeneric(), currentValues, shared);
-            builder.tree(genericExecute);
-        } else {
+        final Set<ExecutableTypeData> executableTypes = findSpecializedExecutableTypes(execution, target.getType());
+        if (executableTypes.isEmpty()) {
+            throw new AssertionError(); // cannot execute child
+        } else if (executableTypes.size() == 1) {
+            ExecutableTypeData executableType = executableTypes.iterator().next();
             if (target.getType().isGeneric() && executableType.getEvaluatedCount() == 0) {
                 return createPolymorphicExecuteChild(execution, target, currentValues, shared);
-            } else if (target.getType().hasImplicitSourceTypes()) {
-                if (options.implicitCastOptimization().isNone()) {
-                    CodeTree execute = createCallSharedExecuteChild(execution, target.makeGeneric(), currentValues);
-                    return TypeSystemCodeGenerator.implicitExpect(target.getType(), execute, null);
-                } else if (options.implicitCastOptimization().isDuplicateTail()) {
-                    builder.tree(createExecuteChildDuplicateTail(builder, execution, assignment, target, currentValues));
-                } else if (options.implicitCastOptimization().isMergeCasts()) {
-                    // TODO
-                } else {
-                    throw new AssertionError();
-                }
             } else {
                 builder.tree(assignment);
-
-                CodeTree accessChild;
-                if (shared && target.getType().isGeneric()) {
-                    accessChild = CodeTreeBuilder.singleString(nodeFieldName(execution));
-                } else {
-                    accessChild = accessParent(nodeFieldName(execution));
-                }
-
-                CodeTree execute = callTemplateMethod(builder, accessChild, executableType, currentValues);
-                CodeTree expect = TypeSystemCodeGenerator.expect(executableType.getType(), returnType, execute);
-                builder.tree(expect);
+                builder.tree(createSingleExecute(execution, target, currentValues, executableType));
+            }
+        } else {
+            if (options.implicitCastOptimization().isNone()) {
+                throw new AssertionError("findSpecializedExecutableTypes is always 1 if implicit cast opt is disabled");
+            } else if (options.implicitCastOptimization().isDuplicateTail()) {
+                builder.tree(createExecuteChildDuplicateTail(builder, execution, assignment, target, currentValues));
+            } else if (options.implicitCastOptimization().isMergeCasts()) {
+                // TODO
+                throw new UnsupportedOperationException();
+            } else {
+                throw new AssertionError();
             }
         }
         return builder.build();
     }
 
+    private static CodeTree createSingleExecute(NodeExecutionData execution, LocalVariable target, LocalContext currentValues, ExecutableTypeData executableType) {
+        CodeTree accessChild = accessParent(nodeFieldName(execution));
+        CodeTree execute = callTemplateMethod(accessChild, executableType, currentValues);
+        return TypeSystemCodeGenerator.expect(executableType.getType(), target.getType(), execute);
+    }
+
     private CodeTree createPolymorphicExecuteChild(NodeExecutionData execution, LocalVariable target, LocalContext currentValues, boolean shared) throws AssertionError {
         ExecutableTypeData genericExecutableType = execution.getChild().getNodeData().findAnyGenericExecutableType(context, execution.getChild().getExecuteWith().size());
         if (genericExecutableType == null) {
-            throw new AssertionError("error should be caught by the parser");
+            throw new AssertionError("At least one generic executable method must be available.");
         }
 
-        CodeTree assignment = createAssignmentStart(target, shared, true);
-
-        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        CodeTreeBuilder polyChainBuilder = builder.create();
-        boolean hasUnexpectedResult = false;
-
         Set<TypeData> specializedTypes = new HashSet<>();
         for (TypeData type : node.findSpecializedTypes(execution)) {
             specializedTypes.addAll(type.getImplicitSourceTypes());
         }
 
-        List<ExecutableTypeData> specializedExecutables = findSpecializedExecutables(execution, specializedTypes, options.polymorphicTypeBoxingElimination());
-
+        List<ExecutableTypeData> specializedExecutables = resolveSpecializedExecutables(execution, specializedTypes, options.polymorphicTypeBoxingElimination());
         Collections.sort(specializedExecutables, new Comparator<ExecutableTypeData>() {
             public int compare(ExecutableTypeData o1, ExecutableTypeData o2) {
                 return o1.getType().compareTo(o2.getType());
             }
         });
 
-        if (isSingleSpecializable(getReachableSpecializations())) {
-            specializedExecutables = Collections.emptyList();
-        }
+        CodeTree assignment = createAssignmentStart(target, shared);
+        CodeTree executeGeneric = createSingleExecute(execution, target, currentValues, genericExecutableType);
 
-        boolean hasSpecializedTypes = false;
-        for (ExecutableTypeData executableType : specializedExecutables) {
-            hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes);
-            polyChainBuilder.tree(createAccessPolymorphicField(execution, shared));
-            polyChainBuilder.string(" == ").typeLiteral(executableType.getType().getPrimitiveType());
-            polyChainBuilder.end();
-            polyChainBuilder.startBlock();
-            polyChainBuilder.startStatement();
-            polyChainBuilder.tree(assignment);
-            polyChainBuilder.tree(callTemplateMethod(polyChainBuilder, CodeTreeBuilder.singleString(nodeFieldName(execution)), executableType, currentValues)).end();
-            polyChainBuilder.end();
-            hasUnexpectedResult |= executableType.hasUnexpectedValue(context);
-        }
-
-        CodeTree executeGeneric = callTemplateMethod(polyChainBuilder, CodeTreeBuilder.singleString(nodeFieldName(execution)), genericExecutableType, currentValues);
-
-        if (specializedExecutables.isEmpty()) {
+        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
+        if (specializedExecutables.isEmpty() || isSingleSpecializable(getReachableSpecializations())) {
             builder.tree(assignment);
             builder.tree(executeGeneric);
         } else {
-            CodeTree accessPolymorphicProfile = createAccessPolymorphicField(execution, shared);
-            polyChainBuilder.startElseIf().tree(accessPolymorphicProfile).string(" == null").end();
+            final CodeTreeBuilder polyChainBuilder = builder.create();
+            final String profileField = polymorphicTypeProfileFieldName(execution);
+            final String valueFieldName = "_value";
+
+            builder.declaration(getType(Class.class), profileField, accessParent(profileField));
+
+            boolean encounteredUnexpectedResult = false;
+            boolean hasSpecializedTypes = false;
+            for (ExecutableTypeData executableType : specializedExecutables) {
+                hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes);
+                polyChainBuilder.string(profileField);
+                polyChainBuilder.string(" == ").typeLiteral(executableType.getType().getPrimitiveType());
+                polyChainBuilder.end();
+                polyChainBuilder.startBlock();
+                polyChainBuilder.startStatement();
+                polyChainBuilder.tree(assignment);
+                polyChainBuilder.tree(createSingleExecute(execution, target, currentValues, executableType)).end();
+                polyChainBuilder.end();
+                encounteredUnexpectedResult |= executableType.hasUnexpectedValue(context);
+            }
+
+            // else if null -> specialize
+            polyChainBuilder.startElseIf().string(profileField).string(" == null").end();
             polyChainBuilder.startBlock();
             polyChainBuilder.tree(createTransferToInterpreterAndInvalidate());
-            polyChainBuilder.declaration(genericExecutableType.getType().getPrimitiveType(), "value_", executeGeneric);
+            polyChainBuilder.declaration(genericExecutableType.getType().getPrimitiveType(), valueFieldName, executeGeneric);
 
             hasSpecializedTypes = false;
             for (ExecutableTypeData executableType : specializedExecutables) {
                 hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes);
-                polyChainBuilder.tree(TypeSystemCodeGenerator.check(executableType.getType(), CodeTreeBuilder.singleString("value_")));
+                polyChainBuilder.tree(TypeSystemCodeGenerator.check(executableType.getType(), CodeTreeBuilder.singleString(valueFieldName)));
                 polyChainBuilder.end();
                 polyChainBuilder.startBlock();
-                polyChainBuilder.startStatement().tree(accessPolymorphicProfile).string(" = ").typeLiteral(executableType.getType().getPrimitiveType()).end();
+                polyChainBuilder.startStatement().string(profileField).string(" = ").typeLiteral(executableType.getType().getPrimitiveType()).end();
                 polyChainBuilder.end();
             }
 
             polyChainBuilder.startElseBlock();
-            polyChainBuilder.startStatement().tree(accessPolymorphicProfile).string(" = ").typeLiteral(genericType.getPrimitiveType()).end();
+            polyChainBuilder.startStatement().string(profileField).string(" = ").typeLiteral(genericType.getPrimitiveType()).end();
+            polyChainBuilder.end();
+            polyChainBuilder.startReturn().string(valueFieldName).end();
             polyChainBuilder.end();
 
-            polyChainBuilder.startReturn().string("value_").end();
-
-            polyChainBuilder.end();
+            // else -> execute generic
             polyChainBuilder.startElseBlock();
             polyChainBuilder.startStatement().tree(assignment).tree(executeGeneric).end();
             polyChainBuilder.end();
 
-            if (hasUnexpectedResult) {
+            CodeTree executePolymorphic = polyChainBuilder.build();
+            if (encounteredUnexpectedResult) {
                 builder.startTryBlock();
-            }
-
-            builder.tree(polyChainBuilder.build());
-
-            if (hasUnexpectedResult) {
+                builder.tree(executePolymorphic);
                 builder.end();
                 builder.startCatchBlock(getType(UnexpectedResultException.class), "ex");
-                builder.startStatement().tree(accessPolymorphicProfile).string(" = ").typeLiteral(genericType.getPrimitiveType()).end();
+                builder.startStatement().string(profileField).string(" = ").typeLiteral(genericType.getPrimitiveType()).end();
                 builder.startReturn().string("ex.getResult()").end();
                 builder.end();
+            } else {
+                builder.tree(executePolymorphic);
             }
         }
         return builder.build();
     }
 
-    private static CodeTree createAssignmentStart(LocalVariable target, boolean shared, boolean accessParent) {
+    private static CodeTree createAssignmentStart(LocalVariable target, boolean shared) {
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
         if (shared) {
             builder.string("return ");
         } else {
             builder.string(target.getName()).string(" = ");
-            if (accessParent) {
-                builder.tree(accessParent(null)).string(".");
-            }
         }
         return builder.build();
     }
 
-    private static CodeTree createAccessPolymorphicField(NodeExecutionData execution, boolean shared) {
-        String name = polymorphicTypeProfileFieldName(execution);
-        if (shared) {
-            return CodeTreeBuilder.singleString(name);
-        } else {
-            return accessParent(name);
-        }
-    }
-
     private CodeTree createExecuteChildDuplicateTail(CodeTreeBuilder parent, NodeExecutionData execution, CodeTree assignment, LocalVariable target, LocalContext currentValues) {
         CodeTreeBuilder builder = parent.create();
         List<TypeData> sourceTypes = target.getType().getImplicitSourceTypes();
         String implicitClassFieldName = implicitClassFieldName(execution);
         String nodeFieldName = nodeFieldName(execution);
-        List<ExecutableTypeData> executableTypes = findSpecializedExecutables(execution, sourceTypes, options.implicitTypeBoxingOptimization());
+        List<ExecutableTypeData> executableTypes = resolveSpecializedExecutables(execution, sourceTypes, options.implicitTypeBoxingOptimization());
 
         boolean elseIf = false;
         for (ExecutableTypeData executableType : executableTypes) {
@@ -1797,10 +1780,10 @@
             builder.startBlock();
             builder.startStatement().tree(assignment);
 
-            CodeTree execute = callTemplateMethod(builder, accessParent(nodeFieldName), executableType, currentValues);
+            CodeTree execute = callTemplateMethod(accessParent(nodeFieldName), executableType, currentValues);
             ImplicitCastData cast = typeSystem.lookupCast(executableType.getType(), target.getType());
             if (cast != null) {
-                execute = callTemplateMethod(builder, null, cast, execute);
+                execute = callTemplateMethod(null, cast, execute);
             }
             builder.tree(execute);
             builder.end();
@@ -1857,7 +1840,7 @@
             if (guard.isNegated()) {
                 builder.string("!");
             }
-            builder.tree(callTemplateMethod(builder, accessParent(null), guard.getResolvedGuard(), currentValues));
+            builder.tree(callTemplateMethod(accessParent(null), guard.getResolvedGuard(), currentValues));
             and = " && ";
         }
         return builder.build();
@@ -2039,7 +2022,7 @@
         }
 
         private void loadValues(int evaluatedArguments) {
-            values.put(FRAME_VALUE, new LocalVariable(null, factory.getType(VirtualFrame.class), FRAME_VALUE, null));
+            values.put(FRAME_VALUE, new LocalVariable(null, factory.getType(Frame.class), FRAME_VALUE, null));
 
             for (NodeFieldData field : factory.node.getFields()) {
                 String fieldName = fieldValueName(field);
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java	Mon Jan 05 01:31:08 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java	Mon Jan 05 01:31:08 2015 +0100
@@ -118,6 +118,14 @@
         return builder.build();
     }
 
+    public static CodeTree cast(TypeData sourceType, TypeData targetType, CodeTree content) {
+        if (sourceType != null && !sourceType.needsCastTo(targetType)) {
+            return content;
+        } else {
+            return cast(targetType, content);
+        }
+    }
+
     public static CodeTree expect(TypeData type, CodeTree content) {
         if (type.isGeneric() || type.isVoid()) {
             return content;
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemNodeFactory.java	Mon Jan 05 01:31:08 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemNodeFactory.java	Mon Jan 05 01:31:08 2015 +0100
@@ -98,7 +98,7 @@
         TypeData voidType = typeSystem.getVoidType();
         String methodName = voidBoxingExecuteName(type);
         CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), voidType.getPrimitiveType(), methodName);
-        method.addParameter(new CodeVariableElement(context.getType(VirtualFrame.class), "frame"));
+        method.addParameter(new CodeVariableElement(context.getType(Frame.class), "frame"));
 
         CodeTreeBuilder builder = method.createBuilder();
         builder.startTryBlock();
@@ -114,7 +114,7 @@
         TypeData genericType = typeSystem.getGenericTypeData();
         String methodName = executeName(type);
         CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), type.getPrimitiveType(), methodName);
-        method.addParameter(new CodeVariableElement(context.getType(VirtualFrame.class), "frame"));
+        method.addParameter(new CodeVariableElement(context.getType(Frame.class), "frame"));
 
         if (type.isGeneric()) {
             method.getModifiers().add(ABSTRACT);
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java	Mon Jan 05 01:31:08 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java	Mon Jan 05 01:31:08 2015 +0100
@@ -954,6 +954,14 @@
         }
     }
 
+    public static List<String> getUniqueIdentifiers(List<TypeMirror> typeMirror) {
+        List<String> ids = new ArrayList<>();
+        for (TypeMirror type : typeMirror) {
+            ids.add(getUniqueIdentifier(type));
+        }
+        return ids;
+    }
+
     public static String getUniqueIdentifier(TypeMirror typeMirror) {
         if (typeMirror.getKind() == TypeKind.ARRAY) {
             return getUniqueIdentifier(((ArrayType) typeMirror).getComponentType()) + "[]";
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java	Mon Jan 05 01:31:08 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java	Mon Jan 05 01:31:08 2015 +0100
@@ -54,23 +54,24 @@
     private final NodeExecutionData thisExecution;
     private final boolean generateFactory;
 
-    public NodeData(ProcessorContext context, TypeElement type, String shortName, TypeSystemData typeSystem, List<NodeChildData> children, List<NodeExecutionData> executions,
-                    List<NodeFieldData> fields, List<String> assumptions, boolean generateFactory) {
+    private TypeMirror frameType;
+
+    public NodeData(ProcessorContext context, TypeElement type, String shortName, TypeSystemData typeSystem, boolean generateFactory) {
         super(context, type, null);
-        this.nodeId = type.getSimpleName().toString();
+        this.nodeId = ElementUtils.getSimpleName(type);
         this.shortName = shortName;
         this.typeSystem = typeSystem;
-        this.fields = fields;
-        this.children = children;
-        this.childExecutions = executions;
-        this.assumptions = assumptions;
+        this.fields = new ArrayList<>();
+        this.children = new ArrayList<>();
+        this.childExecutions = new ArrayList<>();
+        this.assumptions = new ArrayList<>();
         this.thisExecution = new NodeExecutionData(new NodeChildData(null, null, "this", getNodeType(), getNodeType(), null, Cardinality.ONE), -1, false);
         this.thisExecution.getChild().setNode(this);
         this.generateFactory = generateFactory;
     }
 
     public NodeData(ProcessorContext context, TypeElement type) {
-        this(context, type, null, null, null, null, null, null, false);
+        this(context, type, null, null, false);
     }
 
     public boolean isGenerateFactory() {
@@ -89,6 +90,14 @@
         return false;
     }
 
+    public void setFrameType(TypeMirror frameType) {
+        this.frameType = frameType;
+    }
+
+    public TypeMirror getFrameType() {
+        return frameType;
+    }
+
     public void addEnclosedNode(NodeData node) {
         this.enclosingNodes.add(node);
         node.declaringNode = this;
@@ -134,12 +143,12 @@
         return 0;
     }
 
-    public boolean isFrameUsedByAnyGuard(ProcessorContext context) {
+    public boolean isFrameUsedByAnyGuard() {
         for (SpecializationData specialization : specializations) {
             if (!specialization.isReachable()) {
                 continue;
             }
-            if (specialization.isFrameUsedByGuard(context)) {
+            if (specialization.isFrameUsedByGuard()) {
                 return true;
             }
         }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java	Mon Jan 05 01:31:08 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java	Mon Jan 05 01:31:08 2015 +0100
@@ -49,6 +49,16 @@
         this.allowedTypesIdentifier = typeIdentifiers;
     }
 
+    public ParameterSpec(String name, List<TypeMirror> allowedTypes) {
+        this.name = name;
+        this.allowedTypes = allowedTypes;
+        Set<String> typeIdentifiers = new HashSet<>();
+        for (TypeMirror type : allowedTypes) {
+            typeIdentifiers.add(ElementUtils.getUniqueIdentifier(type));
+        }
+        this.allowedTypesIdentifier = typeIdentifiers;
+    }
+
     public ParameterSpec(String name, TypeMirror type) {
         this(name, Arrays.asList(type), new HashSet<>(Arrays.asList(ElementUtils.getUniqueIdentifier(type))));
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java	Mon Jan 05 01:31:08 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java	Mon Jan 05 01:31:08 2015 +0100
@@ -284,14 +284,14 @@
         return String.format("%s [id = %s, method = %s, guards = %s, signature = %s]", getClass().getSimpleName(), getId(), getMethod(), getGuards(), getTypeSignature());
     }
 
-    public boolean isFrameUsedByGuard(ProcessorContext context) {
+    public boolean isFrameUsedByGuard() {
         for (GuardExpression guard : getGuards()) {
             if (guard.getResolvedGuard() == null) {
                 continue;
             }
 
             for (Parameter param : guard.getResolvedGuard().getParameters()) {
-                if (ElementUtils.typeEquals(param.getType(), context.getTruffleTypes().getFrame())) {
+                if (ElementUtils.typeEquals(param.getType(), getNode().getFrameType())) {
                     return true;
                 }
             }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java	Mon Jan 05 01:31:08 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java	Mon Jan 05 01:31:08 2015 +0100
@@ -35,8 +35,11 @@
 
 public class ExecutableTypeMethodParser extends NodeMethodParser<ExecutableTypeData> {
 
-    public ExecutableTypeMethodParser(ProcessorContext context, NodeData node) {
+    private final List<TypeMirror> frameTypes;
+
+    public ExecutableTypeMethodParser(ProcessorContext context, NodeData node, List<TypeMirror> frameTypes) {
         super(context, node);
+        this.frameTypes = frameTypes;
         setParseNullOnError(false);
         getParser().setEmitErrors(false);
         getParser().setUseVarArgs(true);
@@ -48,8 +51,9 @@
         List<ParameterSpec> requiredSpecs = new ArrayList<>(spec.getRequired());
         spec.getRequired().clear();
 
-        List<TypeMirror> allowedTypes = getNode().getTypeSystem().getPrimitiveTypeMirrors();
-        Set<String> allowedIdentifiers = getNode().getTypeSystem().getTypeIdentifiers();
+        TypeSystemData typeSystem = getNode().getTypeSystem();
+        List<TypeMirror> allowedTypes = typeSystem.getPrimitiveTypeMirrors();
+        Set<String> allowedIdentifiers = typeSystem.getTypeIdentifiers();
         for (ParameterSpec originalSpec : requiredSpecs) {
             spec.addRequired(new ParameterSpec(originalSpec, allowedTypes, allowedIdentifiers));
         }
@@ -64,6 +68,11 @@
     }
 
     @Override
+    protected void addDefaultFrame(MethodSpec methodSpec) {
+        methodSpec.addOptional(new ParameterSpec("frame", frameTypes));
+    }
+
+    @Override
     protected List<TypeMirror> nodeTypeMirrors(NodeData nodeData) {
         return getNode().getTypeSystem().getPrimitiveTypeMirrors();
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeMethodParser.java	Mon Jan 05 01:31:08 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeMethodParser.java	Mon Jan 05 01:31:08 2015 +0100
@@ -100,9 +100,9 @@
         }
     }
 
-    private void addDefaultFrame(MethodSpec methodSpec) {
+    protected void addDefaultFrame(MethodSpec methodSpec) {
         if (getNode().supportsFrame()) {
-            methodSpec.addOptional(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame()));
+            methodSpec.addOptional(new ParameterSpec("frame", getNode().getFrameType()));
         }
     }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java	Mon Jan 05 01:31:08 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java	Mon Jan 05 01:31:08 2015 +0100
@@ -45,25 +45,13 @@
     public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Fallback.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, NodeChild.class,
                     NodeChildren.class);
 
-    private Map<String, NodeData> parsedNodes;
-
     @Override
     protected NodeData parse(Element element, AnnotationMirror mirror) {
-        NodeData node = null;
-        try {
-            parsedNodes = new HashMap<>();
-            node = resolveNode((TypeElement) element);
-            if (Log.DEBUG) {
-                NodeData parsed = parsedNodes.get(ElementUtils.getQualifiedName((TypeElement) element));
-                if (node != null) {
-                    String dump = parsed.dump();
-                    log.message(Kind.ERROR, null, null, null, dump);
-                }
-            }
-        } finally {
-            parsedNodes = null;
+        NodeData node = parseRootType((TypeElement) element);
+        if (Log.isDebug() && node != null) {
+            String dump = node.dump();
+            log.message(Kind.ERROR, null, null, null, dump);
         }
-
         return node;
     }
 
@@ -96,20 +84,14 @@
         return ANNOTATIONS;
     }
 
-    private NodeData resolveNode(TypeElement rootType) {
-        String typeName = ElementUtils.getQualifiedName(rootType);
-        if (parsedNodes.containsKey(typeName)) {
-            return parsedNodes.get(typeName);
-        }
-
+    private NodeData parseRootType(TypeElement rootType) {
         List<NodeData> enclosedNodes = new ArrayList<>();
         for (TypeElement enclosedType : ElementFilter.typesIn(rootType.getEnclosedElements())) {
-            NodeData enclosedChild = resolveNode(enclosedType);
+            NodeData enclosedChild = parseRootType(enclosedType);
             if (enclosedChild != null) {
                 enclosedNodes.add(enclosedChild);
             }
         }
-
         NodeData node = parseNode(rootType);
         if (node == null && !enclosedNodes.isEmpty()) {
             node = new NodeData(context, rootType);
@@ -120,8 +102,6 @@
                 node.addEnclosedNode(enclosedNode);
             }
         }
-
-        parsedNodes.put(typeName, node);
         return node;
     }
 
@@ -134,24 +114,64 @@
             return null;
         }
 
-        List<TypeElement> lookupTypes = collectSuperClasses(new ArrayList<TypeElement>(), templateType);
         if (!ElementUtils.isAssignable(templateType.asType(), context.getTruffleTypes().getNode())) {
             return null;
         }
-        List<Element> elements = new ArrayList<>(CompilerFactory.getCompiler(templateType).getAllMembersInDeclarationOrder(context.getEnvironment(), templateType));
+
+        List<TypeElement> lookupTypes = collectSuperClasses(new ArrayList<TypeElement>(), templateType);
+        List<Element> members = loadMembers(templateType);
+        // ensure the processed element has at least one @Specialization annotation.
+        if (!containsSpecializations(members)) {
+            return null;
+        }
 
-        NodeData node = parseNodeData(templateType, elements, lookupTypes);
+        NodeData node = parseNodeData(templateType, lookupTypes);
 
-        parseImportGuards(node, lookupTypes, elements);
+        node.getAssumptions().addAll(parseAssumptions(lookupTypes));
+        node.getFields().addAll(parseFields(lookupTypes, members));
+        node.getChildren().addAll(parseChildren(lookupTypes, members));
+        node.getChildExecutions().addAll(parseExecutions(node.getChildren(), members));
+        node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node, context.getFrameTypes()).parse(members)));
+
+        initializeExecutableTypes(node);
+        initializeImportGuards(node, lookupTypes, members);
 
         if (node.hasErrors()) {
             return node; // error sync point
         }
 
-        initializeExecutableTypes(elements, node);
         initializeChildren(node);
 
-        // ensure the processed element has at least one @Specialization annotation.
+        if (node.hasErrors()) {
+            return node; // error sync point
+        }
+
+        node.getSpecializations().addAll(new SpecializationMethodParser(context, node).parse(members));
+        node.getSpecializations().addAll(new GenericParser(context, node).parse(members));
+        node.getCasts().addAll(new CreateCastParser(context, node).parse(members));
+        node.getShortCircuits().addAll(new ShortCircuitParser(context, node).parse(members));
+
+        if (node.hasErrors()) {
+            return node;  // error sync point
+        }
+
+        verifySpecializationSameLength(node);
+        initializeSpecializations(members, node);
+        initializeShortCircuits(node); // requires specializations and polymorphic specializations
+
+        verifyVisibilities(node);
+        verifyMissingAbstractMethods(node, members);
+        verifyConstructors(node);
+        verifyNamingConvention(node.getShortCircuits(), "needs");
+        verifySpecializationThrows(node);
+        return node;
+    }
+
+    private ArrayList<Element> loadMembers(TypeElement templateType) {
+        return new ArrayList<>(CompilerFactory.getCompiler(templateType).getAllMembersInDeclarationOrder(context.getEnvironment(), templateType));
+    }
+
+    private boolean containsSpecializations(List<Element> elements) {
         boolean foundSpecialization = false;
         for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
             if (ElementUtils.findAnnotationMirror(processingEnv, method, Specialization.class) != null) {
@@ -159,36 +179,10 @@
                 break;
             }
         }
-        if (!foundSpecialization) {
-            return node;
-        }
-
-        if (node.hasErrors()) {
-            return node; // error sync point
-        }
-
-        node.getSpecializations().addAll(new SpecializationMethodParser(context, node).parse(elements));
-        node.getSpecializations().addAll(new GenericParser(context, node).parse(elements));
-        node.getCasts().addAll(new CreateCastParser(context, node).parse(elements));
-        node.getShortCircuits().addAll(new ShortCircuitParser(context, node).parse(elements));
-
-        if (node.hasErrors()) {
-            return node;  // error sync point
-        }
-
-        verifySpecializationSameLength(node);
-        initializeSpecializations(elements, node);
-        initializeShortCircuits(node); // requires specializations and polymorphic specializations
-
-        verifyVisibilities(node);
-        verifyMissingAbstractMethods(node, elements);
-        verifyConstructors(node);
-        verifyNamingConvention(node.getShortCircuits(), "needs");
-        verifySpecializationThrows(node);
-        return node;
+        return foundSpecialization;
     }
 
-    private void parseImportGuards(NodeData node, List<TypeElement> lookupTypes, List<Element> elements) {
+    private void initializeImportGuards(NodeData node, List<TypeElement> lookupTypes, List<Element> elements) {
         for (TypeElement lookupType : lookupTypes) {
             AnnotationMirror importAnnotation = ElementUtils.findAnnotationMirror(processingEnv, lookupType, ImportGuards.class);
             if (importAnnotation == null) {
@@ -228,7 +222,7 @@
         }
     }
 
-    private NodeData parseNodeData(TypeElement templateType, List<? extends Element> elements, List<TypeElement> typeHierarchy) {
+    private NodeData parseNodeData(TypeElement templateType, List<TypeElement> typeHierarchy) {
         AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class);
         if (typeSystemMirror == null) {
             NodeData nodeData = new NodeData(context, templateType);
@@ -244,6 +238,17 @@
             return nodeData;
         }
 
+        AnnotationMirror nodeInfoMirror = findFirstAnnotation(typeHierarchy, NodeInfo.class);
+        String shortName = null;
+        if (nodeInfoMirror != null) {
+            shortName = ElementUtils.getAnnotationValue(String.class, nodeInfoMirror, "shortName");
+        }
+        boolean useNodeFactory = findFirstAnnotation(typeHierarchy, GenerateNodeFactory.class) != null;
+        return new NodeData(context, templateType, shortName, typeSystem, useNodeFactory);
+
+    }
+
+    private List<String> parseAssumptions(List<TypeElement> typeHierarchy) {
         List<String> assumptionsList = new ArrayList<>();
         for (int i = typeHierarchy.size() - 1; i >= 0; i--) {
             TypeElement type = typeHierarchy.get(i);
@@ -258,22 +263,7 @@
                 }
             }
         }
-        AnnotationMirror nodeInfoMirror = findFirstAnnotation(typeHierarchy, NodeInfo.class);
-        String shortName = null;
-        if (nodeInfoMirror != null) {
-            shortName = ElementUtils.getAnnotationValue(String.class, nodeInfoMirror, "shortName");
-        }
-
-        List<NodeFieldData> fields = parseFields(typeHierarchy, elements);
-        List<NodeChildData> children = parseChildren(typeHierarchy, elements);
-        List<NodeExecutionData> executions = parseExecutions(children, elements);
-        boolean useNodeFactory = findFirstAnnotation(typeHierarchy, GenerateNodeFactory.class) != null;
-
-        NodeData nodeData = new NodeData(context, templateType, shortName, typeSystem, children, executions, fields, assumptionsList, useNodeFactory);
-
-        parsedNodes.put(ElementUtils.getQualifiedName(templateType), nodeData);
-
-        return nodeData;
+        return assumptionsList;
     }
 
     private List<NodeFieldData> parseFields(List<TypeElement> typeHierarchy, List<? extends Element> elements) {
@@ -469,31 +459,33 @@
             }
         }
 
-        // pre-parse specializations
+        List<TypeMirror> frameTypes = context.getFrameTypes();
+        // pre-parse specializations to find signature size
         for (ExecutableElement method : methods) {
             AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, Specialization.class);
             if (mirror == null) {
                 continue;
             }
 
-            int currentArgumentCount = 0;
+            int currentArgumentIndex = 0;
             boolean skipShortCircuit = false;
-            for (VariableElement var : method.getParameters()) {
+            outer: for (VariableElement var : method.getParameters()) {
                 TypeMirror type = var.asType();
-                if (currentArgumentCount == 0) {
+                if (currentArgumentIndex == 0) {
                     // skip optionals
-                    if (ElementUtils.typeEquals(type, context.getTruffleTypes().getFrame())) {
-                        continue;
+                    for (TypeMirror frameType : frameTypes) {
+                        if (ElementUtils.typeEquals(type, frameType)) {
+                            continue outer;
+                        }
                     }
-                    // TODO skip optional fields?
                 }
-                int childIndex = currentArgumentCount < children.size() ? currentArgumentCount : children.size() - 1;
+                int childIndex = currentArgumentIndex < children.size() ? currentArgumentIndex : children.size() - 1;
                 if (childIndex == -1) {
                     continue;
                 }
                 if (!skipShortCircuit) {
                     NodeChildData child = children.get(childIndex);
-                    if (shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, currentArgumentCount - childIndex))) {
+                    if (shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, currentArgumentIndex - childIndex))) {
                         skipShortCircuit = true;
                         continue;
                     }
@@ -501,9 +493,9 @@
                     skipShortCircuit = false;
                 }
 
-                currentArgumentCount++;
+                currentArgumentIndex++;
             }
-            maxSignatureSize = Math.max(maxSignatureSize, currentArgumentCount);
+            maxSignatureSize = Math.max(maxSignatureSize, currentArgumentIndex);
         }
 
         List<NodeExecutionData> executions = new ArrayList<>();
@@ -526,25 +518,63 @@
         return executions;
     }
 
-    private void initializeExecutableTypes(List<Element> elements, NodeData node) {
-        node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node).parse(elements)));
-        List<ExecutableTypeData> genericExecutes = node.getThisExecution().getChild().findGenericExecutableTypes(context);
+    private void initializeExecutableTypes(NodeData node) {
+        List<ExecutableTypeData> genericExecutes = node.findGenericExecutableTypes(context, 0);
+        List<ExecutableTypeData> allExecutes = node.getExecutableTypes();
+
+        Set<String> inconsistentFrameTypes = new HashSet<>();
+        TypeMirror frameType = null;
+        Set<Integer> evaluatedCounts = new HashSet<>();
+        for (ExecutableTypeData execute : allExecutes) {
+            evaluatedCounts.add(execute.getEvaluatedCount());
+
+            Parameter frame = execute.getFrame();
+            TypeMirror resolvedFrameType;
+            if (frame == null) {
+                resolvedFrameType = node.getTypeSystem().getVoidType().getPrimitiveType();
+            } else {
+                resolvedFrameType = frame.getType();
+            }
 
-        List<ExecutableTypeData> overridableGenericExecutes = new ArrayList<>();
+            if (frameType == null) {
+                frameType = resolvedFrameType;
+            } else {
+                if (!ElementUtils.typeEquals(frameType, resolvedFrameType)) {
+                    // found inconsistent frame types
+                    inconsistentFrameTypes.add(ElementUtils.getSimpleName(frameType));
+                    inconsistentFrameTypes.add(ElementUtils.getSimpleName(resolvedFrameType));
+                }
+            }
+        }
+        if (!inconsistentFrameTypes.isEmpty()) {
+            // ensure they are sorted somehow
+            List<String> inconsistentFrameTypesList = new ArrayList<>(inconsistentFrameTypes);
+            Collections.sort(inconsistentFrameTypesList);
+            node.addError("Invalid inconsistent frame types %s found for the declared execute methods. The frame type must be identical for all execute methods.", inconsistentFrameTypesList);
+        }
+        node.setFrameType(frameType);
+
+        int nonFinalCount = 0;
+        int voidCount = 0;
         for (ExecutableTypeData executableTypeData : genericExecutes) {
             if (!executableTypeData.getMethod().getModifiers().contains(Modifier.FINAL)) {
-                overridableGenericExecutes.add(executableTypeData);
+                nonFinalCount++;
+            }
+            if (ElementUtils.isVoid(executableTypeData.getReturnType().getType())) {
+                voidCount++;
             }
         }
 
-        if (overridableGenericExecutes.isEmpty()) {
+        // no generic executes
+        if (nonFinalCount == 0 && voidCount == 0) {
             node.addError("No accessible and overridable generic execute method found. Generic execute methods usually have the "
-                            + "signature 'public abstract {Type} executeGeneric(VirtualFrame)' and must not throw any checked exceptions.");
+                            + "signature 'public abstract {Type} execute(VirtualFrame)' and must not throw any checked exceptions.");
         }
 
-        if (overridableGenericExecutes.size() > 1) {
+        // multiple generic execute
+        if (voidCount > 1 || (nonFinalCount - voidCount) > 1) {
             List<String> methodSignatures = new ArrayList<>();
-            for (ExecutableTypeData type : overridableGenericExecutes) {
+            for (ExecutableTypeData type : genericExecutes) {
                 methodSignatures.add(type.createReferenceName());
             }
             node.addWarning("Multiple accessible and overridable generic execute methods found %s. Remove all but one or mark all but one as final.", methodSignatures);
@@ -571,30 +601,61 @@
     }
 
     private void initializeChildren(NodeData node) {
-        for (NodeChildData nodeChild : node.getChildren()) {
-            NodeData fieldNodeData = resolveNode(ElementUtils.fromTypeMirror(nodeChild.getNodeType()));
-            nodeChild.setNode(fieldNodeData);
-            if (fieldNodeData == null) {
-                nodeChild.addError("Node type '%s' is invalid or not a valid Node.", ElementUtils.getQualifiedName(nodeChild.getNodeType()));
+        for (NodeChildData child : node.getChildren()) {
+            TypeMirror nodeType = child.getNodeType();
+            NodeData fieldNodeData = parseChildNodeData(node, ElementUtils.fromTypeMirror(nodeType));
+
+            child.setNode(fieldNodeData);
+            if (fieldNodeData == null || fieldNodeData.hasErrors()) {
+                child.addError("Node type '%s' is invalid or not a subclass of Node.", ElementUtils.getQualifiedName(nodeType));
             } else if (!ElementUtils.typeEquals(fieldNodeData.getTypeSystem().getTemplateType().asType(), (node.getTypeSystem().getTemplateType().asType()))) {
-                nodeChild.addError("The @%s of the node and the @%s of the @%s does not match. %s != %s. ", TypeSystem.class.getSimpleName(), TypeSystem.class.getSimpleName(),
+                child.addError("The @%s of the node and the @%s of the @%s does not match. %s != %s. ", TypeSystem.class.getSimpleName(), TypeSystem.class.getSimpleName(),
                                 NodeChild.class.getSimpleName(), ElementUtils.getSimpleName(node.getTypeSystem().getTemplateType()),
                                 ElementUtils.getSimpleName(fieldNodeData.getTypeSystem().getTemplateType()));
-            } else if (nodeChild.findAnyGenericExecutableType(context) == null) {
-                nodeChild.addError("No generic execute method found for child type %s. Generic execute methods usually have the signature 'Object executeGeneric(VirtualFrame)'.",
-                                ElementUtils.getQualifiedName(nodeChild.getNodeType()));
-            }
-            if (fieldNodeData != null) {
-                List<ExecutableTypeData> types = nodeChild.findGenericExecutableTypes(context);
+            } else {
+                List<ExecutableTypeData> types = child.findGenericExecutableTypes(context);
                 if (types.isEmpty()) {
-                    AnnotationValue executeWithValue = ElementUtils.getAnnotationValue(nodeChild.getMessageAnnotation(), "executeWith");
-                    nodeChild.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s.", nodeChild.getExecuteWith().size(),
-                                    ElementUtils.getSimpleName(nodeChild.getNodeType()));
+                    AnnotationValue executeWithValue = ElementUtils.getAnnotationValue(child.getMessageAnnotation(), "executeWith");
+                    child.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s and frame types %s.", child.getExecuteWith().size(),
+                                    ElementUtils.getSimpleName(nodeType), ElementUtils.getUniqueIdentifiers(createAllowedChildFrameTypes(node)));
                 }
             }
         }
     }
 
+    private NodeData parseChildNodeData(NodeData parentNode, TypeElement originalTemplateType) {
+        TypeElement templateType = ElementUtils.fromTypeMirror(context.reloadTypeElement(originalTemplateType));
+
+        if (ElementUtils.findAnnotationMirror(processingEnv, originalTemplateType, GeneratedBy.class) != null) {
+            // generated nodes should not get called again.
+            return null;
+        }
+
+        if (!ElementUtils.isAssignable(templateType.asType(), context.getTruffleTypes().getNode())) {
+            return null;
+        }
+
+        List<TypeElement> lookupTypes = collectSuperClasses(new ArrayList<TypeElement>(), templateType);
+
+        // Declaration order is not required for child nodes.
+        List<? extends Element> members = processingEnv.getElementUtils().getAllMembers(templateType);
+        NodeData node = parseNodeData(templateType, lookupTypes);
+
+        node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node, createAllowedChildFrameTypes(parentNode)).parse(members)));
+        node.setFrameType(parentNode.getFrameType());
+        return node;
+    }
+
+    private List<TypeMirror> createAllowedChildFrameTypes(NodeData parentNode) {
+        List<TypeMirror> allowedFrameTypes = new ArrayList<>();
+        for (TypeMirror frameType : context.getFrameTypes()) {
+            if (ElementUtils.isAssignable(parentNode.getFrameType(), frameType)) {
+                allowedFrameTypes.add(frameType);
+            }
+        }
+        return allowedFrameTypes;
+    }
+
     private void initializeSpecializations(List<? extends Element> elements, final NodeData node) {
         if (node.getSpecializations().isEmpty()) {
             return;