changeset 20984:6361fa2e3321

Truffle-DSL: further fixes for polymorphic execute signatures.
author Christian Humer <christian.humer@oracle.com>
date Wed, 15 Apr 2015 21:13:43 +0200
parents b99da6d86cfe
children eebb05f2d1e8
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/ExecuteGroupingTest.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/java/ElementUtils.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/AnnotatedParameterSpec.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.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/model/TemplateMethod.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java
diffstat 11 files changed, 398 insertions(+), 213 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java	Wed Apr 15 21:35:51 2015 +0200
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java	Wed Apr 15 21:13:43 2015 +0200
@@ -287,4 +287,51 @@
         }
     }
 
+    @SuppressWarnings("unused")
+    @NodeChildren({@NodeChild(value = "a", type = ValueNode.class), @NodeChild(value = "b", type = ValueNode.class)})
+    abstract static class TestEvaluatedShortCircuit1 extends Node {
+
+        public abstract Object execute1(VirtualFrame frame, Object value);
+
+        public abstract Object execute2(VirtualFrame frame, Object value, boolean hasB);
+
+        public abstract Object execute3(VirtualFrame frame, Object value, boolean hasB, Object b);
+
+        @ShortCircuit("b")
+        public boolean needsB(Object a) {
+            return true;
+        }
+
+        @Specialization
+        int call(Object a, boolean hasB, Object b) {
+            return 42;
+        }
+    }
+
+    @SuppressWarnings("unused")
+    @NodeChildren({@NodeChild(value = "a", type = ValueNode.class), @NodeChild(value = "b", type = ValueNode.class)})
+    abstract static class TestEvaluatedShortCircuit2 extends Node {
+
+        public abstract Object execute1(VirtualFrame frame, Object value);
+
+        public abstract Object execute2(VirtualFrame frame, Object value, boolean hasB);
+
+        public abstract Object execute3(VirtualFrame frame, Object value, boolean hasB, Object b);
+
+        @ShortCircuit("b")
+        public boolean needsB(Object a) {
+            return true;
+        }
+
+        @Specialization
+        int call(int a, boolean hasB, int b) {
+            return 42;
+        }
+
+        @Specialization
+        int call(Object a, boolean hasB, Object b) {
+            return 42;
+        }
+    }
+
 }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteGroupingTest.java	Wed Apr 15 21:35:51 2015 +0200
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteGroupingTest.java	Wed Apr 15 21:13:43 2015 +0200
@@ -144,18 +144,18 @@
         }
 
         @Specialization(rewriteOn = RuntimeException.class)
-        int s1() {
+        double s1() {
             return 42;
         }
 
         @Specialization
-        int s2() {
+        double s2() {
             return 42;
         }
 
     }
 
-    @ExpectError("Incompatible abstract execute methods found [executeDouble(), executeInt()].%")
+    @ExpectError("Incompatible abstract execute methods found %")
     abstract static class IncompatibleAbstract1 extends Node {
 
         // we don't know how to implement executeDouble
@@ -164,7 +164,7 @@
         abstract int executeInt();
 
         @Specialization
-        int s1() {
+        double s1() {
             return 42;
         }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Wed Apr 15 21:35:51 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Wed Apr 15 21:13:43 2015 +0200
@@ -66,7 +66,9 @@
     private final boolean singleSpecializable;
     private final int varArgsThreshold;
     private final Set<TypeMirror> expectedTypes = new HashSet<>();
+    private final Set<NodeExecutionData> usedExecuteChildMethods = new HashSet<>();
     private boolean nextUsed;
+
     private List<ExecutableTypeData> usedTypes;
     private List<SpecializationData> reachableSpecializations;
 
@@ -210,7 +212,7 @@
         }
 
         for (ExecutableTypeData execType : usedTypes) {
-            if (execType.getMethod() == null) {
+            if (!singleSpecializable && execType.getMethod() == null) {
                 continue;
             }
             clazz.add(createExecutableTypeOverride(usedTypes, execType));
@@ -273,7 +275,7 @@
 
     private Element createUnsupportedMethod() {
         LocalContext locals = LocalContext.load(this);
-        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED), getType(UnsupportedSpecializationException.class), "unsupported");
+        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED), getType(UnsupportedSpecializationException.class), "unsupported", varArgsThreshold);
 
         CodeTreeBuilder builder = method.createBuilder();
         builder.startReturn();
@@ -380,6 +382,16 @@
         baseSpecialization.addOptional(createCreatePolymorphic(generated));
         baseSpecialization.addOptional(createGetNext(baseSpecialization));
 
+        for (NodeExecutionData execution : node.getChildExecutions()) {
+            Collection<TypeMirror> specializedTypes = node.findSpecializedTypes(execution);
+            specializedTypes.add(genericType);
+            for (TypeMirror specializedType : specializedTypes) {
+                if (isExecuteChildShared(execution, specializedType)) {
+                    baseSpecialization.addOptional(createExecuteChildMethod(execution, specializedType));
+                }
+            }
+        }
+
         return node.getUninitializedSpecialization();
     }
 
@@ -418,28 +430,13 @@
             clazz.add(createFastPathExecuteMethod(null, type, usedTypes));
         }
 
-        for (NodeExecutionData execution : node.getChildExecutions()) {
-            Collection<TypeMirror> specializedTypes = node.findSpecializedTypes(execution);
-            specializedTypes.add(genericType);
-            for (TypeMirror specializedType : specializedTypes) {
-                if (isExecuteChildShared(execution, specializedType)) {
-                    clazz.add(createExecuteChildMethod(execution, specializedType));
-                }
-            }
-        }
-
         return clazz;
     }
 
     private Element createAcceptAndExecute() {
-
-        TypeMirror[] parameters = new TypeMirror[node.getSignatureSize()];
-        Arrays.fill(parameters, genericType);
-
-        ExecutableTypeData executableElement = new ExecutableTypeData(genericType, "acceptAndExecute", context.getType(Frame.class), Arrays.asList(parameters));
-
-        LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold);
-        CodeExecutableElement executable = createExecuteMethod(null, executableElement, currentLocals, false);
+        ExecutableTypeData executableElement = createSpecializationNodeSignature(node.getSignatureSize());
+        LocalContext currentLocals = LocalContext.load(this, executableElement, varArgsThreshold);
+        CodeExecutableElement executable = createExecuteMethod(null, executableElement, currentLocals, false, varArgsThreshold);
 
         executable.getModifiers().add(FINAL);
         CodeTreeBuilder builder = executable.createBuilder();
@@ -451,6 +448,12 @@
         return executable;
     }
 
+    private ExecutableTypeData createSpecializationNodeSignature(int argumentCount) {
+        TypeMirror[] parameters = new TypeMirror[argumentCount];
+        Arrays.fill(parameters, genericType);
+        return new ExecutableTypeData(node, genericType, "acceptAndExecute", context.getType(Frame.class), Arrays.asList(parameters));
+    }
+
     private boolean shouldImplementExecutableType(SpecializationData specialization, ExecutableTypeData executableType) {
         // always implement the root execute method. they are declared abstract in the base node.
         if (executableType.getDelegatedTo() == null) {
@@ -458,7 +461,7 @@
         }
 
         // specializations with more parameters are just ignored
-        if (executableType.getEvaluatedCount() > node.getSignatureSize()) {
+        if (executableType.getEvaluatedCount() > node.getExecutionCount()) {
             return false;
         }
 
@@ -468,8 +471,9 @@
 
         // the evaluated signature might be compatible to the specialization
         boolean specializationCompatible = true;
-        for (int i = 0; i < executableType.getEvaluatedCount(); i++) {
-            TypeMirror evaluatedType = executableType.getEvaluatedParameters().get(i);
+        List<TypeMirror> signatureParameters = executableType.getSignatureParameters();
+        for (int i = 0; i < signatureParameters.size(); i++) {
+            TypeMirror evaluatedType = signatureParameters.get(i);
             TypeMirror specializedType = specialization.findParameterOrDie(node.getChildExecutions().get(i)).getType();
 
             if (!isSubtypeBoxed(context, evaluatedType, specializedType) && !isSubtypeBoxed(context, specializedType, evaluatedType)) {
@@ -489,7 +493,7 @@
         }
 
         // trigger type boxing elimination for unevaluated arguments
-        for (int i = executableType.getEvaluatedCount(); i < node.getSignatureSize(); i++) {
+        for (int i = executableType.getEvaluatedCount(); i < node.getExecutionCount(); i++) {
             NodeExecutionData execution = node.getChildExecutions().get(i);
             TypeMirror specializedType = specialization.findParameterOrDie(execution).getType();
             if (isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), specializedType)) {
@@ -512,8 +516,8 @@
         }
 
         // trigger generation for evaluated assignable type matches other than generic
-        for (int i = 0; i < executableType.getEvaluatedCount(); i++) {
-            TypeMirror evaluatedType = executableType.getEvaluatedParameters().get(i);
+        for (int i = 0; i < signatureParameters.size(); i++) {
+            TypeMirror evaluatedType = signatureParameters.get(i);
             NodeExecutionData execution = node.getChildExecutions().get(i);
             TypeMirror specializedType = specialization.findParameterOrDie(execution).getType();
 
@@ -664,12 +668,12 @@
             return null;
         }
 
-        LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold);
+        LocalContext currentLocals = LocalContext.load(this, createSpecializationNodeSignature(node.getSignatureSize()), varArgsThreshold);
         currentLocals.loadFastPathState(specialization);
 
         CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(boolean.class), "isIdentical");
         method.addParameter(new CodeVariableElement(getType(SpecializationNode.class), "other"));
-        currentLocals.addParametersTo(method, FRAME_VALUE);
+        currentLocals.addParametersTo(method, varArgsThreshold, FRAME_VALUE);
         method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
         final CodeTreeBuilder builder = method.createBuilder();
 
@@ -729,11 +733,11 @@
             return null;
         }
         TypeMirror specializationNodeType = getType(SpecializationNode.class);
-        LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold);
+        LocalContext currentLocals = LocalContext.load(this, createSpecializationNodeSignature(node.getSignatureSize()), varArgsThreshold);
 
         CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), specializationNodeType, "merge");
         executable.addParameter(new CodeVariableElement(specializationNodeType, "newNode"));
-        currentLocals.addParametersTo(executable, FRAME_VALUE);
+        currentLocals.addParametersTo(executable, varArgsThreshold, FRAME_VALUE);
         executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
         CodeTreeBuilder builder = executable.createBuilder();
 
@@ -802,7 +806,7 @@
     private CodeExecutableElement createCreateNext(final Map<SpecializationData, CodeTypeElement> specializationClasses) {
         final LocalContext locals = LocalContext.load(this);
 
-        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), getType(SpecializationNode.class), "createNext", FRAME_VALUE);
+        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), getType(SpecializationNode.class), "createNext", varArgsThreshold, FRAME_VALUE);
         method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
 
         CodeTreeBuilder builder = method.createBuilder();
@@ -834,7 +838,7 @@
             locals.removeValue(FRAME_VALUE);
         }
 
-        CodeExecutableElement boundaryMethod = locals.createMethod(modifiers(PRIVATE), getType(boolean.class), "guardFallback", FRAME_VALUE);
+        CodeExecutableElement boundaryMethod = locals.createMethod(modifiers(PRIVATE), getType(boolean.class), "guardFallback", varArgsThreshold, FRAME_VALUE);
         if (!frameUsed) {
             boundaryMethod.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(TruffleBoundary.class)));
         }
@@ -887,7 +891,7 @@
         }
         LocalContext locals = LocalContext.load(this);
 
-        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType, "unsupported", FRAME_VALUE);
+        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType, "unsupported", varArgsThreshold, FRAME_VALUE);
         method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
 
         CodeTreeBuilder builder = method.createBuilder();
@@ -950,8 +954,8 @@
     }
 
     private CodeExecutableElement createExecutableTypeOverride(List<ExecutableTypeData> usedExecutables, ExecutableTypeData execType) {
-        LocalContext locals = LocalContext.load(this, execType.getEvaluatedCount(), Integer.MAX_VALUE);
-        CodeExecutableElement method = createExecuteMethod(null, execType, locals, true);
+        LocalContext locals = LocalContext.load(this, execType, Integer.MAX_VALUE);
+        CodeExecutableElement method = createExecuteMethod(null, execType, locals, true, Integer.MAX_VALUE);
 
         CodeTreeBuilder builder = method.createBuilder();
         if (singleSpecializable) {
@@ -1043,17 +1047,38 @@
                 values.add(createTypeSafeReference(frameLocal, method.getFrameParameter()));
             }
         }
-        for (int parameterIndex = 0; parameterIndex < method.getEvaluatedCount(); parameterIndex++) {
-            TypeMirror targetParameter = method.getEvaluatedParameters().get(parameterIndex);
-            LocalVariable variable;
-            if (executeWith != null && parameterIndex < executeWith.size()) {
-                variable = currentValues.getValue(executeWith.get(parameterIndex));
+
+        int evaluatedIndex = 0;
+        for (int executionIndex = 0; executionIndex < node.getExecutionCount(); executionIndex++) {
+            NodeExecutionData parameterExecution;
+            if (executeWith != null && executionIndex < executeWith.size()) {
+                parameterExecution = executeWith.get(executionIndex);
             } else {
-                variable = currentValues.getValue(parameterIndex);
+                parameterExecution = node.getChildExecutions().get(executionIndex);
             }
-            values.add(createTypeSafeReference(variable, targetParameter));
+            if (parameterExecution.isShortCircuit()) {
+                if (evaluatedIndex < method.getEvaluatedCount()) {
+                    TypeMirror targetType = method.getEvaluatedParameters().get(evaluatedIndex);
+                    LocalVariable shortCircuit = currentValues.getShortCircuit(parameterExecution);
+                    if (shortCircuit != null) {
+                        values.add(createTypeSafeReference(shortCircuit, targetType));
+                    } else {
+                        values.add(CodeTreeBuilder.createBuilder().defaultValue(targetType).build());
+                    }
+                    evaluatedIndex++;
+                }
+            }
+            if (evaluatedIndex < method.getEvaluatedCount()) {
+                TypeMirror targetType = method.getEvaluatedParameters().get(evaluatedIndex);
+                LocalVariable value = currentValues.getValue(parameterExecution);
+                if (value != null) {
+                    values.add(createTypeSafeReference(value, targetType));
+                } else {
+                    values.add(CodeTreeBuilder.createBuilder().defaultValue(targetType).build());
+                }
+                evaluatedIndex++;
+            }
         }
-
         return values.toArray(new CodeTree[values.size()]);
     }
 
@@ -1518,8 +1543,11 @@
     }
 
     private CodeTree expect(TypeMirror sourceType, TypeMirror forType, CodeTree tree) {
-        expectedTypes.add(forType);
-        return TypeSystemCodeGenerator.expect(typeSystem, sourceType, forType, tree);
+        if (sourceType == null || ElementUtils.needsCastTo(sourceType, forType)) {
+            expectedTypes.add(forType);
+            return TypeSystemCodeGenerator.expect(typeSystem, forType, tree);
+        }
+        return tree;
     }
 
     private Set<ExecutableTypeData> findSpecializedExecutableTypes(NodeExecutionData execution, TypeMirror type) {
@@ -1554,8 +1582,8 @@
     }
 
     private Element createFastPathExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, List<ExecutableTypeData> allTypes) {
-        LocalContext currentLocals = LocalContext.load(this, executedType.getEvaluatedCount(), varArgsThreshold);
-        CodeExecutableElement executable = createExecuteMethod(specialization, executedType, currentLocals, false);
+        LocalContext currentLocals = LocalContext.load(this, executedType, Integer.MAX_VALUE);
+        CodeExecutableElement executable = createExecuteMethod(specialization, executedType, currentLocals, false, Integer.MAX_VALUE);
         CodeTreeBuilder builder = executable.createBuilder();
         if (specialization == null) {
             if (executedType.getDelegatedTo() == null) {
@@ -1569,28 +1597,17 @@
         return executable;
     }
 
-    private CodeExecutableElement createExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, LocalContext currentLocals, boolean originalOverride) {
+    private static final String VARARGS_NAME = "args";
+
+    private CodeExecutableElement createExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, LocalContext currentLocals, boolean originalOverride, int varArgs) {
         TypeMirror returnType = executedType.getReturnType();
-        TypeMirror frame = executedType.getFrameParameter();
-        List<TypeMirror> evaluatedParameters = executedType.getEvaluatedParameters();
 
         if (specialization != null) {
             currentLocals.loadFastPathState(specialization);
         }
 
-        if (frame == null) {
-            currentLocals.removeValue(FRAME_VALUE);
-        } else {
-            currentLocals.set(FRAME_VALUE, currentLocals.get(FRAME_VALUE).newType(frame));
-        }
-
-        for (int i = 0; i < Math.min(node.getChildExecutions().size(), evaluatedParameters.size()); i++) {
-            NodeExecutionData execution = node.getChildExecutions().get(i);
-            currentLocals.setValue(execution, currentLocals.getValue(execution).newType(evaluatedParameters.get(i)));
-        }
-
         String methodName;
-        if (originalOverride) {
+        if (originalOverride && executedType.getMethod() != null) {
             methodName = executedType.getMethod().getSimpleName().toString();
         } else {
             methodName = executedType.getUniqueName();
@@ -1608,32 +1625,13 @@
                 ((CodeVariableElement) executable.getParameters().get(0)).setName(FRAME_VALUE);
             }
 
-            final String varArgsName = "args";
             if (executable.isVarArgs()) {
-                ((CodeVariableElement) executable.getParameters().get(executable.getParameters().size() - 1)).setName(varArgsName);
+                ((CodeVariableElement) executable.getParameters().get(executable.getParameters().size() - 1)).setName(VARARGS_NAME);
             }
 
-            // rename varargs parameter
-            int signatureIndex = 0;
-            for (TypeMirror parameter : executedType.getEvaluatedParameters()) {
-                LocalVariable var = currentLocals.getValue(signatureIndex);
-                if (var != null) {
-                    int varArgsIndex = executedType.getVarArgsIndex(executedType.getParameterIndex(signatureIndex));
-                    if (varArgsIndex >= 0) {
-                        var = var.accessWith(CodeTreeBuilder.singleString(varArgsName + "[" + varArgsIndex + "]"));
-                    } else {
-                        ((CodeVariableElement) executable.getParameters().get(executedType.getParameterIndex(signatureIndex))).setName(var.getName());
-                    }
-                    if (!isObject(parameter)) {
-                        var = var.newType(parameter);
-                    }
-                    currentLocals.setValue(node.getChildExecutions().get(signatureIndex), var);
-                }
-
-                signatureIndex++;
-            }
+            renameOriginalParameters(executedType, executable, currentLocals);
         } else {
-            executable = currentLocals.createMethod(modifiers(PUBLIC), returnType, methodName, FRAME_VALUE);
+            executable = currentLocals.createMethod(modifiers(PUBLIC), returnType, methodName, varArgs, FRAME_VALUE);
         }
         executable.getThrownTypes().clear();
 
@@ -1644,6 +1642,47 @@
         return executable;
     }
 
+    private void renameOriginalParameters(ExecutableTypeData executedType, CodeExecutableElement executable, LocalContext currentLocals) {
+        // rename varargs parameter
+        int evaluatedIndex = 0;
+        for (int executionIndex = 0; executionIndex < node.getExecutionCount(); executionIndex++) {
+            NodeExecutionData execution = node.getChildExecutions().get(executionIndex);
+            if (execution.isShortCircuit()) {
+                if (evaluatedIndex < executedType.getEvaluatedCount()) {
+                    TypeMirror evaluatedType = executedType.getEvaluatedParameters().get(evaluatedIndex);
+                    LocalVariable shortCircuit = currentLocals.getShortCircuit(execution);
+                    if (shortCircuit != null) {
+                        currentLocals.setShortCircuitValue(execution, renameExecutableTypeParameter(executable, executedType, evaluatedIndex, evaluatedType, shortCircuit));
+                    }
+                    evaluatedIndex++;
+                }
+            }
+            if (evaluatedIndex < executedType.getEvaluatedCount()) {
+                TypeMirror evaluatedType = executedType.getEvaluatedParameters().get(evaluatedIndex);
+                LocalVariable value = currentLocals.getValue(execution);
+                if (value != null) {
+                    currentLocals.setValue(execution, renameExecutableTypeParameter(executable, executedType, evaluatedIndex, evaluatedType, value));
+                }
+                evaluatedIndex++;
+            }
+        }
+    }
+
+    private static LocalVariable renameExecutableTypeParameter(CodeExecutableElement method, ExecutableTypeData executedType, int evaluatedIndex, TypeMirror targetType, LocalVariable var) {
+        int parameterIndex = executedType.getParameterIndex(evaluatedIndex);
+        int varArgsIndex = executedType.getVarArgsIndex(parameterIndex);
+        LocalVariable returnVar = var;
+        if (varArgsIndex >= 0) {
+            returnVar = returnVar.accessWith(CodeTreeBuilder.singleString(VARARGS_NAME + "[" + varArgsIndex + "]"));
+        } else {
+            ((CodeVariableElement) method.getParameters().get(parameterIndex)).setName(returnVar.getName());
+        }
+        if (!isObject(targetType)) {
+            returnVar = returnVar.newType(targetType);
+        }
+        return returnVar;
+    }
+
     private boolean needsUnexpectedResultException(ExecutableTypeData executedType) {
         if (!executedType.hasUnexpectedValue(context)) {
             return false;
@@ -1670,8 +1709,9 @@
             delegate = findFastPathDelegate((specialization != null ? specialization.getReturnType().getType() : genericType), executableType, allTypes);
         }
 
+        int delegateSignatureCount = delegate != null ? delegate.getSignatureParameters().size() : 0;
         for (NodeExecutionData execution : node.getChildExecutions()) {
-            if (specialization == null && delegate != null && execution.getIndex() >= delegate.getEvaluatedCount()) {
+            if (specialization == null && delegate != null && execution.getIndex() >= delegateSignatureCount) {
                 // we just evaluate children for the next delegate
                 continue;
             } else if (specialization != null && delegate != null) {
@@ -1794,15 +1834,21 @@
 
     private LocalVariable resolveShortCircuit(SpecializationData specialization, NodeExecutionData execution, LocalContext currentLocals) {
         LocalVariable shortCircuit = null;
-        SpecializationData resolvedSpecialization = specialization;
-        if (specialization == null) {
-            resolvedSpecialization = node.getGenericSpecialization();
-        }
-
         if (execution.isShortCircuit()) {
-            ShortCircuitData shortCircuitData = resolvedSpecialization.getShortCircuits().get(calculateShortCircuitIndex(execution));
-            CodeTree access = callTemplateMethod(accessParent(null), shortCircuitData, currentLocals);
-            shortCircuit = currentLocals.createShortCircuitValue(execution).accessWith(access);
+            shortCircuit = currentLocals.getShortCircuit(execution);
+
+            if (shortCircuit == null) {
+                SpecializationData resolvedSpecialization = specialization;
+                if (specialization == null) {
+                    resolvedSpecialization = node.getGenericSpecialization();
+                }
+                ShortCircuitData shortCircuitData = resolvedSpecialization.getShortCircuits().get(calculateShortCircuitIndex(execution));
+                CodeTree access = callTemplateMethod(accessParent(null), shortCircuitData, currentLocals);
+                shortCircuit = currentLocals.createShortCircuitValue(execution).accessWith(access);
+            } else {
+                CodeTree access = shortCircuit.createReference();
+                shortCircuit = shortCircuit.nextName().accessWith(access);
+            }
         }
         return shortCircuit;
     }
@@ -2016,9 +2062,13 @@
     }
 
     private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeMirror targetType) {
-        LocalContext locals = LocalContext.load(this, 0, varArgsThreshold);
-
-        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType, executeChildMethodName(execution, targetType), FRAME_VALUE);
+        if (!usedExecuteChildMethods.contains(execution)) {
+            return null;
+        }
+
+        LocalContext locals = LocalContext.load(this, createSpecializationNodeSignature(0), Integer.MAX_VALUE);
+
+        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType, executeChildMethodName(execution, targetType), Integer.MAX_VALUE, FRAME_VALUE);
         if (hasChildUnexpectedResult(execution, targetType)) {
             method.getThrownTypes().add(getType(UnexpectedResultException.class));
         }
@@ -2047,6 +2097,10 @@
 
     private CodeVariableElement createImplicitProfileParameter(NodeExecutionData execution, TypeMirror targetType) {
         if (typeSystem.hasImplicitSourceTypes(targetType)) {
+            if (typeEquals(node.getGenericType(execution), targetType)) {
+                return null;
+            }
+
             switch (options.implicitCastOptimization()) {
                 case NONE:
                     return null;
@@ -2185,6 +2239,7 @@
         if (!isExecuteChildShared(execution, targetValue.getTypeMirror())) {
             throw new AssertionError("Execute child not shared with method but called.");
         }
+        usedExecuteChildMethods.add(execution);
 
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
         builder.tree(targetValue.createReference()).string(" = ");
@@ -2594,20 +2649,59 @@
             }
         }
 
-        public CodeExecutableElement createMethod(Set<Modifier> modifiers, TypeMirror returnType, String name, String... optionalArguments) {
+        public CodeExecutableElement createMethod(Set<Modifier> modifiers, TypeMirror returnType, String name, int varArgsThreshold, String... optionalArguments) {
             CodeExecutableElement method = new CodeExecutableElement(modifiers, returnType, name);
-            addParametersTo(method, optionalArguments);
+            addParametersTo(method, varArgsThreshold, optionalArguments);
             return method;
         }
 
-        public static LocalContext load(NodeGenFactory factory, int signatureSize, int varargsThreshold) {
+        public static LocalContext load(NodeGenFactory factory, ExecutableTypeData type, int varargsThreshold) {
             LocalContext context = new LocalContext(factory);
-            context.loadValues(signatureSize, varargsThreshold);
+            context.loadEvaluatedValues(type, varargsThreshold);
             return context;
         }
 
+        private void loadEvaluatedValues(ExecutableTypeData executedType, int varargsThreshold) {
+            TypeMirror frame = executedType.getFrameParameter();
+            if (frame == null) {
+                removeValue(FRAME_VALUE);
+            } else {
+                set(FRAME_VALUE, new LocalVariable(frame, FRAME_VALUE, null, null));
+            }
+            for (NodeFieldData field : factory.node.getFields()) {
+                String fieldName = fieldValueName(field);
+                values.put(fieldName, new LocalVariable(field.getType(), fieldName, factory.accessParent(field.getName()), null));
+            }
+            boolean varargs = needsVarargs(false, varargsThreshold);
+            List<TypeMirror> evaluatedParameter = executedType.getEvaluatedParameters();
+            int evaluatedIndex = 0;
+            for (int executionIndex = 0; executionIndex < factory.node.getExecutionCount(); executionIndex++) {
+                NodeExecutionData execution = factory.node.getChildExecutions().get(executionIndex);
+                if (execution.isShortCircuit()) {
+                    if (evaluatedIndex < executedType.getEvaluatedCount()) {
+                        TypeMirror evaluatedType = evaluatedParameter.get(evaluatedIndex);
+                        LocalVariable shortCircuit = createShortCircuitValue(execution).newType(evaluatedType);
+                        if (varargs) {
+                            shortCircuit = shortCircuit.accessWith(createReadVarargs(evaluatedIndex));
+                        }
+                        values.put(shortCircuit.getName(), shortCircuit.makeOriginal());
+                        evaluatedIndex++;
+                    }
+                }
+                if (evaluatedIndex < executedType.getEvaluatedCount()) {
+                    TypeMirror evaluatedType = evaluatedParameter.get(evaluatedIndex);
+                    LocalVariable value = createValue(execution, evaluatedType);
+                    if (varargs) {
+                        value = value.accessWith(createReadVarargs(evaluatedIndex));
+                    }
+                    values.put(value.getName(), value.makeOriginal());
+                    evaluatedIndex++;
+                }
+            }
+        }
+
         public static LocalContext load(NodeGenFactory factory) {
-            return load(factory, factory.node.getSignatureSize(), factory.varArgsThreshold);
+            return load(factory, factory.createSpecializationNodeSignature(factory.node.getSignatureSize()), factory.varArgsThreshold);
         }
 
         public LocalContext copy() {
@@ -2701,36 +2795,6 @@
             return size >= varArgsThreshold;
         }
 
-        private void loadValues(int evaluatedArguments, int varargsThreshold) {
-            values.put(FRAME_VALUE, new LocalVariable(factory.getType(Frame.class), FRAME_VALUE, null, null));
-
-            for (NodeFieldData field : factory.node.getFields()) {
-                String fieldName = fieldValueName(field);
-                values.put(fieldName, new LocalVariable(field.getType(), fieldName, factory.accessParent(field.getName()), null));
-            }
-
-            boolean varargs = needsVarargs(false, varargsThreshold);
-            for (int i = 0; i < evaluatedArguments; i++) {
-                List<NodeExecutionData> childExecutions = factory.node.getChildExecutions();
-                if (i >= childExecutions.size()) {
-                    break;
-                }
-                NodeExecutionData execution = childExecutions.get(i);
-                if (execution.isShortCircuit()) {
-                    LocalVariable shortCircuit = createShortCircuitValue(execution).makeGeneric(factory.context);
-                    if (varargs) {
-                        shortCircuit = shortCircuit.accessWith(createReadVarargs(i));
-                    }
-                    values.put(shortCircuit.getName(), shortCircuit.makeOriginal());
-                }
-                LocalVariable value = createValue(execution, factory.genericType);
-                if (varargs) {
-                    value = value.accessWith(createReadVarargs(i));
-                }
-                values.put(value.getName(), value.makeOriginal());
-            }
-        }
-
         private static CodeTree createReadVarargs(int i) {
             return CodeTreeBuilder.createBuilder().string("args_[").string(String.valueOf(i)).string("]").build();
         }
@@ -2766,14 +2830,14 @@
             }
         }
 
-        public void addParametersTo(CodeExecutableElement method, String... optionalNames) {
+        public void addParametersTo(CodeExecutableElement method, int varArgsThreshold, String... optionalNames) {
             for (String var : optionalNames) {
                 LocalVariable local = values.get(var);
                 if (local != null) {
                     method.addParameter(local.createParameter());
                 }
             }
-            if (needsVarargs(true, factory.varArgsThreshold)) {
+            if (needsVarargs(true, varArgsThreshold)) {
                 method.addParameter(new CodeVariableElement(factory.getType(Object[].class), "args_"));
                 method.setVarArgs(true);
             } else {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java	Wed Apr 15 21:35:51 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java	Wed Apr 15 21:13:43 2015 +0200
@@ -163,21 +163,36 @@
         if (typeEquals(type1, type2)) {
             return type1;
         }
-        TypeElement element1 = fromTypeMirror(type1);
-        TypeElement element2 = fromTypeMirror(type2);
-        if (element1 == null || element2 == null) {
-            if (element1 != null) {
-                return type1;
-            } else if (element2 != null) {
-                return type2;
-            }
+        if (isVoid(type1)) {
+            return type2;
+        } else if (isVoid(type2)) {
+            return type1;
+        }
+        if (isObject(type1)) {
+            return type1;
+        } else if (isObject(type2)) {
+            return type2;
+        }
+
+        if (isPrimitive(type1) || isPrimitive(type2)) {
             return context.getType(Object.class);
         }
 
-        List<TypeElement> element1Types = getDirectSuperTypes(element1);
-        element1Types.add(0, element1);
-        List<TypeElement> element2Types = getDirectSuperTypes(element2);
-        element2Types.add(0, element2);
+        if (isSubtype(type1, type2)) {
+            return type2;
+        } else if (isSubtype(type2, type1)) {
+            return type1;
+        }
+
+        TypeElement element1 = fromTypeMirror(type1);
+        TypeElement element2 = fromTypeMirror(type2);
+
+        if (element1 == null || element2 == null) {
+            return context.getType(Object.class);
+        }
+
+        List<TypeElement> element1Types = getSuperTypes(element1);
+        List<TypeElement> element2Types = getSuperTypes(element2);
 
         for (TypeElement superType1 : element1Types) {
             for (TypeElement superType2 : element2Types) {
@@ -186,6 +201,7 @@
                 }
             }
         }
+
         return context.getType(Object.class);
     }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/AnnotatedParameterSpec.java	Wed Apr 15 21:35:51 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/AnnotatedParameterSpec.java	Wed Apr 15 21:13:43 2015 +0200
@@ -43,6 +43,11 @@
     }
 
     @Override
+    public boolean isAnnotated() {
+        return true;
+    }
+
+    @Override
     public boolean matches(VariableElement variable) {
         if (ElementUtils.findAnnotationMirror(variable.getAnnotationMirrors(), annotationType) != null) {
             return true;
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java	Wed Apr 15 21:35:51 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java	Wed Apr 15 21:13:43 2015 +0200
@@ -35,6 +35,7 @@
 
 public class ExecutableTypeData extends MessageContainer implements Comparable<ExecutableTypeData> {
 
+    private final NodeData node;
     private final ExecutableElement method;
     private final TypeMirror returnType;
     private final TypeMirror frameParameter;
@@ -44,7 +45,8 @@
 
     private String uniqueName;
 
-    public ExecutableTypeData(TypeMirror returnType, String uniqueName, TypeMirror frameParameter, List<TypeMirror> evaluatedParameters) {
+    public ExecutableTypeData(NodeData node, TypeMirror returnType, String uniqueName, TypeMirror frameParameter, List<TypeMirror> evaluatedParameters) {
+        this.node = node;
         this.returnType = returnType;
         this.frameParameter = frameParameter;
         this.evaluatedParameters = evaluatedParameters;
@@ -52,7 +54,8 @@
         this.method = null;
     }
 
-    public ExecutableTypeData(ExecutableElement method, int signatureSize, List<TypeMirror> frameTypes) {
+    public ExecutableTypeData(NodeData node, ExecutableElement method, int signatureSize, List<TypeMirror> frameTypes) {
+        this.node = node;
         this.method = method;
         this.returnType = method.getReturnType();
         TypeMirror foundFrameParameter = null;
@@ -123,6 +126,21 @@
         return evaluatedParameters;
     }
 
+    public List<TypeMirror> getSignatureParameters() {
+        List<TypeMirror> signaturetypes = new ArrayList<>();
+        int index = 0;
+        for (NodeExecutionData execution : node.getChildExecutions()) {
+            if (execution.isShortCircuit()) {
+                index++;
+            }
+            if (index < getEvaluatedCount()) {
+                signaturetypes.add(getEvaluatedParameters().get(index));
+            }
+            index++;
+        }
+        return signaturetypes;
+    }
+
     public int getVarArgsIndex(int parameterIndex) {
         if (method.isVarArgs()) {
             int index = parameterIndex - (method.getParameters().size() - 1);
@@ -159,7 +177,7 @@
         return evaluatedParameters.size();
     }
 
-    public boolean canDelegateTo(NodeData node, ExecutableTypeData to) {
+    public boolean canDelegateTo(ExecutableTypeData to) {
         ExecutableTypeData from = this;
         if (to.getEvaluatedCount() < from.getEvaluatedCount()) {
             return false;
@@ -189,8 +207,10 @@
             }
         }
 
-        for (int i = from.getEvaluatedCount(); i < to.getEvaluatedCount(); i++) {
-            TypeMirror delegateToParameter = to.getEvaluatedParameters().get(i);
+        List<TypeMirror> fromSignatureParameters = from.getSignatureParameters();
+        List<TypeMirror> toSignatureParameters = to.getSignatureParameters();
+        for (int i = fromSignatureParameters.size(); i < toSignatureParameters.size(); i++) {
+            TypeMirror delegateToParameter = toSignatureParameters.get(i);
             if (i < node.getChildExecutions().size()) {
                 TypeMirror genericType = node.getGenericType(node.getChildExecutions().get(i));
                 if (!isSubtypeBoxed(context, genericType, delegateToParameter)) {
@@ -206,6 +226,14 @@
         ExecutableTypeData o1 = this;
         ProcessorContext context = ProcessorContext.getInstance();
 
+        if (canDelegateTo(o2)) {
+            if (!o2.canDelegateTo(this)) {
+                return 1;
+            }
+        } else if (o2.canDelegateTo(this)) {
+            return -1;
+        }
+
         int result = Integer.compare(o2.getEvaluatedCount(), o1.getEvaluatedCount());
         if (result != 0) {
             return result;
@@ -282,9 +310,22 @@
         }
     }
 
+    public String getName() {
+        if (method != null) {
+            return method.getSimpleName().toString();
+        } else {
+            return getUniqueName();
+        }
+
+    }
+
+    private static String formatType(TypeMirror type) {
+        return type == null ? "null" : ElementUtils.getSimpleName(type);
+    }
+
     @Override
     public String toString() {
-        return method != null ? ElementUtils.createReferenceName(method) : getUniqueName() + evaluatedParameters.toString();
+        return String.format("%s %s(%s,%s)", formatType(getReturnType()), getName(), formatType(getFrameParameter()), getEvaluatedParameters());
     }
 
     public boolean sameParameters(ExecutableTypeData other) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java	Wed Apr 15 21:35:51 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java	Wed Apr 15 21:13:43 2015 +0200
@@ -134,8 +134,19 @@
         return types;
     }
 
+    public int getExecutionCount() {
+        return getChildExecutions().size();
+    }
+
     public int getSignatureSize() {
-        return getChildExecutions().size();
+        int count = 0;
+        for (NodeExecutionData execution : getChildExecutions()) {
+            if (execution.isShortCircuit()) {
+                count++;
+            }
+            count++;
+        }
+        return count;
     }
 
     public boolean isFrameUsedByAnyGuard() {
@@ -567,20 +578,17 @@
                 if (executable.hasUnexpectedValue(getContext())) {
                     continue;
                 }
-                if (!typeSystem.hasImplicitSourceTypes(executable.getReturnType())) {
-                    types.add(executable.getReturnType());
-                }
+                types.add(executable.getReturnType());
             }
         }
 
         int executionIndex = execution.getIndex();
         if (executionIndex >= 0) {
             for (ExecutableTypeData typeData : getExecutableTypes()) {
-                if (executionIndex < typeData.getEvaluatedCount()) {
-                    TypeMirror genericType = typeData.getEvaluatedParameters().get(executionIndex);
-                    if (!typeSystem.hasImplicitSourceTypes(genericType)) {
-                        types.add(genericType);
-                    }
+                List<TypeMirror> signatureParameters = typeData.getSignatureParameters();
+                if (executionIndex < signatureParameters.size()) {
+                    TypeMirror genericType = signatureParameters.get(executionIndex);
+                    types.add(genericType);
                 }
             }
         }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java	Wed Apr 15 21:35:51 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java	Wed Apr 15 21:13:43 2015 +0200
@@ -59,6 +59,10 @@
         this.anyType = anyTypeTemp;
     }
 
+    public boolean isAnnotated() {
+        return false;
+    }
+
     public ParameterSpec(ParameterSpec original, TypeMirror newType) {
         this(original.name, newType);
         this.local = original.local;
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java	Wed Apr 15 21:35:51 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java	Wed Apr 15 21:13:43 2015 +0200
@@ -167,14 +167,6 @@
         return kind == SpecializationKind.POLYMORPHIC;
     }
 
-    public List<Parameter> getDynamicParameters() {
-        List<Parameter> uncachedParameters = new ArrayList<>(getParameters());
-        for (CacheExpression cacheExpression : getCaches()) {
-            uncachedParameters.remove(cacheExpression.getParameter());
-        }
-        return uncachedParameters;
-    }
-
     @Override
     protected List<MessageContainer> findChildContainers() {
         List<MessageContainer> sinks = new ArrayList<>();
@@ -304,7 +296,7 @@
 
     @Override
     public String toString() {
-        return String.format("%s [id = %s, method = %s, guards = %s, signature = %s]", getClass().getSimpleName(), getId(), getMethod(), getGuards(), getTypeSignature());
+        return String.format("%s [id = %s, method = %s, guards = %s, signature = %s]", getClass().getSimpleName(), getId(), getMethod(), getGuards(), getDynamicTypes());
     }
 
     public boolean isFrameUsed() {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java	Wed Apr 15 21:35:51 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java	Wed Apr 15 21:13:43 2015 +0200
@@ -153,6 +153,14 @@
         newParameter.setMethod(this);
     }
 
+    public Iterable<Parameter> getDynamicParameters() {
+        return new FilteredIterable<>(getParameters(), new Predicate<Parameter>() {
+            public boolean evaluate(Parameter value) {
+                return !value.getSpecification().isLocal() && !value.getSpecification().isAnnotated();
+            }
+        });
+    }
+
     public Iterable<Parameter> getSignatureParameters() {
         return new FilteredIterable<>(getParameters(), new Predicate<Parameter>() {
             public boolean evaluate(Parameter value) {
@@ -291,8 +299,8 @@
     }
 
     public int compareBySignature(TemplateMethod compareMethod) {
-        List<TypeMirror> signature1 = getSignatureTypes(this);
-        List<TypeMirror> signature2 = getSignatureTypes(compareMethod);
+        List<TypeMirror> signature1 = getDynamicTypes();
+        List<TypeMirror> signature2 = compareMethod.getDynamicTypes();
 
         int result = 0;
         for (int i = 0; i < Math.max(signature1.size(), signature2.size()); i++) {
@@ -307,9 +315,9 @@
         return result;
     }
 
-    public static List<TypeMirror> getSignatureTypes(TemplateMethod method) {
+    public List<TypeMirror> getDynamicTypes() {
         List<TypeMirror> types = new ArrayList<>();
-        for (Parameter param : method.getSignatureParameters()) {
+        for (Parameter param : getDynamicParameters()) {
             types.add(param.getType());
         }
         return types;
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java	Wed Apr 15 21:35:51 2015 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java	Wed Apr 15 21:13:43 2015 +0200
@@ -148,7 +148,7 @@
         node.getFields().addAll(parseFields(lookupTypes, members));
         node.getChildren().addAll(parseChildren(lookupTypes, members));
         node.getChildExecutions().addAll(parseExecutions(node.getFields(), node.getChildren(), members));
-        node.getExecutableTypes().addAll(parseExecutableTypeData(members, node.getChildExecutions().size(), context.getFrameTypes(), false));
+        node.getExecutableTypes().addAll(parseExecutableTypeData(node, members, node.getSignatureSize(), context.getFrameTypes(), false));
 
         initializeExecutableTypes(node);
         initializeImportGuards(node, lookupTypes, members);
@@ -188,8 +188,13 @@
         SpecializationData polymorphic = node.getPolymorphicSpecialization();
         if (polymorphic != null) {
             boolean polymorphicSignatureFound = false;
-            TypeMirror frame = polymorphic.getFrame() != null ? polymorphic.getFrame().getType() : null;
-            ExecutableTypeData polymorphicType = new ExecutableTypeData(polymorphic.getReturnType().getType(), "execute", frame, TemplateMethod.getSignatureTypes(polymorphic));
+            List<TypeMirror> dynamicTypes = polymorphic.getDynamicTypes();
+            TypeMirror frame = null;
+            if (polymorphic.getFrame() != null) {
+                frame = dynamicTypes.remove(0);
+            }
+
+            ExecutableTypeData polymorphicType = new ExecutableTypeData(node, polymorphic.getReturnType().getType(), "execute", frame, dynamicTypes);
             for (ExecutableTypeData type : node.getExecutableTypes()) {
                 if (polymorphicType.sameSignature(type)) {
                     polymorphicSignatureFound = true;
@@ -214,9 +219,11 @@
             }
         }
         if (!additionalAbstractRootTypes.isEmpty()) {
-            node.addError("Incompatible abstract execute methods found %s.", rootTypes);
+            node.addError("Incompatible abstract execute methods found %s.", additionalAbstractRootTypes);
         }
 
+        namesUnique(node.getExecutableTypes());
+
     }
 
     private static List<ExecutableTypeData> buildExecutableHierarchy(NodeData node) {
@@ -235,7 +242,7 @@
     private static void buildExecutableHierarchy(NodeData node, ExecutableTypeData parent, ListIterator<ExecutableTypeData> executesIterator) {
         while (executesIterator.hasNext()) {
             ExecutableTypeData other = executesIterator.next();
-            if (other.canDelegateTo(node, parent)) {
+            if (other.canDelegateTo(parent)) {
                 parent.addDelegatedFrom(other);
                 executesIterator.remove();
             }
@@ -574,7 +581,7 @@
         return executions;
     }
 
-    private List<ExecutableTypeData> parseExecutableTypeData(List<? extends Element> elements, int signatureSize, List<TypeMirror> frameTypes, boolean includeFinals) {
+    private List<ExecutableTypeData> parseExecutableTypeData(NodeData node, List<? extends Element> elements, int signatureSize, List<TypeMirror> frameTypes, boolean includeFinals) {
         List<ExecutableTypeData> typeData = new ArrayList<>();
         for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
             Set<Modifier> modifiers = method.getModifiers();
@@ -592,7 +599,7 @@
                 continue;
             }
 
-            ExecutableTypeData executableType = new ExecutableTypeData(method, signatureSize, context.getFrameTypes());
+            ExecutableTypeData executableType = new ExecutableTypeData(node, method, signatureSize, context.getFrameTypes());
 
             if (executableType.getFrameParameter() != null) {
                 boolean supportedType = false;
@@ -610,8 +617,12 @@
             typeData.add(executableType);
         }
 
-        Collections.sort(typeData);
+        namesUnique(typeData);
 
+        return typeData;
+    }
+
+    private static void namesUnique(List<ExecutableTypeData> typeData) {
         List<String> names = new ArrayList<>();
         for (ExecutableTypeData type : typeData) {
             names.add(type.getUniqueName());
@@ -623,8 +634,6 @@
         for (int i = 0; i < typeData.size(); i++) {
             typeData.get(i).setUniqueName(names.get(i));
         }
-
-        return typeData;
     }
 
     private void initializeExecutableTypes(NodeData node) {
@@ -632,9 +641,7 @@
 
         Set<String> inconsistentFrameTypes = new HashSet<>();
         TypeMirror frameType = null;
-        Set<Integer> evaluatedCounts = new HashSet<>();
         for (ExecutableTypeData execute : allExecutes) {
-            evaluatedCounts.add(execute.getEvaluatedCount());
 
             TypeMirror frame = execute.getFrameParameter();
             TypeMirror resolvedFrameType;
@@ -788,7 +795,7 @@
         if (parentNode.getFrameType() != null) {
             frameTypes = Arrays.asList(parentNode.getFrameType());
         }
-        node.getExecutableTypes().addAll(parseExecutableTypeData(members, child.getExecuteWith().size(), frameTypes, true));
+        node.getExecutableTypes().addAll(parseExecutableTypeData(node, members, child.getExecuteWith().size(), frameTypes, true));
         node.setFrameType(parentNode.getFrameType());
         return node;
     }
@@ -1297,26 +1304,11 @@
         }
     }
 
-    private void initializeUninitialized(final NodeData node) {
+    private static void initializeUninitialized(final NodeData node) {
         SpecializationData generic = node.getGenericSpecialization();
         if (generic == null) {
             return;
         }
-        for (Parameter parameter : generic.getReturnTypeAndParameters()) {
-            if (ElementUtils.isObject(parameter.getType())) {
-                continue;
-            }
-            Set<String> types = new HashSet<>();
-            for (SpecializationData specialization : node.getSpecializations()) {
-                Parameter actualParameter = specialization.findParameter(parameter.getLocalName());
-                if (actualParameter != null) {
-                    types.add(ElementUtils.getQualifiedName(actualParameter.getType()));
-                }
-            }
-            if (types.size() > 1) {
-                generic.replaceParameter(parameter.getLocalName(), new Parameter(parameter, context.getType(Object.class)));
-            }
-        }
         TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", -1, node, generic.getSpecification(), null, null, generic.getReturnType(), generic.getParameters());
         // should not use messages from generic specialization
         uninializedMethod.getMessages().clear();
@@ -1329,7 +1321,6 @@
         }
 
         SpecializationData generic = node.getGenericSpecialization();
-
         List<VariableElement> types = new ArrayList<>();
 
         Collection<TypeMirror> frameTypes = new HashSet<>();
@@ -1338,6 +1329,10 @@
                 frameTypes.add(specialization.getFrame().getType());
             }
         }
+        if (node.supportsFrame()) {
+            frameTypes.add(node.getFrameType());
+        }
+
         if (!frameTypes.isEmpty()) {
             frameTypes = ElementUtils.uniqueSortedTypes(frameTypes);
             TypeMirror frameType;
@@ -1378,13 +1373,15 @@
 
                 if (usedTypes.size() == 1) {
                     polymorphicType = usedTypes.iterator().next();
+                } else {
+                    polymorphicType = ElementUtils.getCommonSuperType(context, usedTypes);
+                }
 
-                    if (!isReturnParameter && node.getTypeSystem().hasImplicitSourceTypes(polymorphicType)) {
-                        polymorphicType = context.getType(Object.class);
-                    }
-                } else {
-                    polymorphicType = context.getType(Object.class);
+                NodeExecutionData execution = genericParameter.getSpecification().getExecution();
+                if (execution != null && !ElementUtils.isSubtypeBoxed(context, polymorphicType, node.getGenericType(execution))) {
+                    throw new AssertionError(String.format("Polymorphic types %s not compatible to generic type %s.", polymorphicType, node.getGenericType(execution)));
                 }
+
             }
             if (isReturnParameter) {
                 returnType = polymorphicType;
@@ -1395,8 +1392,11 @@
         }
 
         SpecializationMethodParser parser = new SpecializationMethodParser(context, node);
+        SpecializationData polymorphic = parser.create("Polymorphic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, types);
+        if (polymorphic == null) {
+            throw new AssertionError("Failed to parse polymorphic signature. " + parser.createDefaultMethodSpec(null, null, false, null) + " Types: " + returnType + " - " + types);
+        }
 
-        SpecializationData polymorphic = parser.create("Polymorphic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, types);
         polymorphic.setKind(SpecializationKind.POLYMORPHIC);
         node.getSpecializations().add(polymorphic);
     }