changeset 9217:61ba6fc21ba4

Sourcegen can now generate execute methods of signature execute(frame, evaluatedValue).
author Christian Humer <christian.humer@gmail.com>
date Mon, 15 Apr 2013 18:50:19 +0200
parents 8b9ea2f5c36e
children 797bb88bf004
files graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeVariable.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java
diffstat 24 files changed, 562 insertions(+), 287 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java	Mon Apr 15 18:50:19 2013 +0200
@@ -46,6 +46,11 @@
         this.parent = parent;
     }
 
+    @Override
+    public String toString() {
+        return root.toString();
+    }
+
     public int getTreeCount() {
         return treeCount;
     }
@@ -277,7 +282,13 @@
     }
 
     public CodeTreeBuilder tree(CodeTree treeToAdd) {
-        return push((BuilderCodeTree) treeToAdd).end();
+        if (treeToAdd instanceof BuilderCodeTree) {
+            return push((BuilderCodeTree) treeToAdd).end();
+        } else {
+            BuilderCodeTree tree = new BuilderCodeTree(GROUP, null, null);
+            tree.add(treeToAdd);
+            return push(tree).end();
+        }
     }
 
     public CodeTreeBuilder string(String chunk1, String chunk2, String chunk3, String chunk4, String... chunks) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeVariable.java	Mon Apr 15 18:50:19 2013 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.codegen.processor.ast;
+
+public class CodeTreeVariable extends CodeTree {
+
+    private final String name;
+
+    private CodeTree value;
+
+    public CodeTreeVariable() {
+        super(CodeTreeKind.GROUP, null, null);
+        this.name = "";
+    }
+
+    public CodeTreeVariable(String name) {
+        super(CodeTreeKind.GROUP, null, null);
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void set(CodeTree tree) {
+        if (value == tree) {
+            return;
+        }
+        if (this.value != null) {
+            remove(this.value);
+        }
+        this.value = tree;
+        add(tree);
+    }
+
+    public CodeTree get() {
+        return value;
+    }
+
+}
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeData.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeData.java	Mon Apr 15 18:50:19 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.codegen.processor.node;
 
+import java.util.*;
+
 import javax.lang.model.element.*;
 
 import com.oracle.truffle.codegen.processor.*;
@@ -63,6 +65,43 @@
         return getMethod().getModifiers().contains(Modifier.ABSTRACT);
     }
 
+    public int getEvaluatedCount() {
+        int count = 0;
+        for (ActualParameter parameter : getParameters()) {
+            if (parameter.getSpecification().isSignature()) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    public boolean startsWithSignature(TemplateMethod method) {
+        for (ActualParameter param : getParameters()) {
+            if (!param.getSpecification().isSignature()) {
+                continue;
+            }
+            ActualParameter foundParam = method.findParameter(param.getLocalName());
+            if (foundParam != null) {
+                TypeData actualType = param.getTypeSystemType();
+                TypeData foundType = foundParam.getTypeSystemType();
+                if (actualType == null || foundType == null || !actualType.equalsType(foundType)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    public boolean hasGenericSignature() {
+        List<TypeData> types = getSignature();
+        for (TypeData typeData : types) {
+            if (!typeData.isGeneric()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     @Override
     public int hashCode() {
         return type.hashCode();
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java	Mon Apr 15 18:50:19 2013 +0200
@@ -30,6 +30,7 @@
 
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
+import com.oracle.truffle.codegen.processor.template.ParameterSpec.*;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
 public class ExecutableTypeMethodParser extends NodeMethodParser<ExecutableTypeData> {
@@ -42,27 +43,37 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-
-        List<TypeMirror> types = new ArrayList<>();
-        types.addAll(getNode().getTypeSystem().getPrimitiveTypeMirrors());
-        types.add(getContext().getType(void.class));
-
-        ParameterSpec returnTypeSpec = new ParameterSpec("executedValue", types);
-        returnTypeSpec.setSignature(true);
-        MethodSpec spec = new MethodSpec(returnTypeSpec);
-        spec.addOptional(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame()));
+        MethodSpec spec = createDefaultMethodSpec(method, mirror, false, null);
+        spec.setVariableRequiredArguments(true);
+        ParameterSpec other = new ParameterSpec("other", nodeTypeMirrors(getNode()));
+        other.setCardinality(Cardinality.MULTIPLE);
+        other.setSignature(true);
+        other.setIndexed(true);
+        spec.addRequired(other);
         return spec;
     }
 
     @Override
     public final boolean isParsable(ExecutableElement method) {
-        boolean parsable = method.getSimpleName().toString().startsWith("execute");
-        return parsable;
+        if (method.getModifiers().contains(Modifier.STATIC)) {
+            return false;
+        } else if (method.getModifiers().contains(Modifier.NATIVE)) {
+            return false;
+        }
+        return method.getSimpleName().toString().startsWith("execute");
+    }
+
+    @Override
+    protected List<TypeMirror> nodeTypeMirrors(NodeData nodeData) {
+        // executable types not yet available
+        List<TypeMirror> types = new ArrayList<>(nodeData.getTypeSystem().getPrimitiveTypeMirrors());
+        types.add(nodeData.getTypeSystem().getVoidType().getPrimitiveType());
+        return types;
     }
 
     @Override
     public ExecutableTypeData create(TemplateMethod method) {
-        TypeData resolvedType = method.getReturnType().getActualTypeData(getNode().getTypeSystem());
+        TypeData resolvedType = method.getReturnType().getTypeSystemType();
         return new ExecutableTypeData(method, getNode().getTypeSystem(), resolvedType);
     }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Mon Apr 15 18:50:19 2013 +0200
@@ -40,7 +40,7 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        return createDefaultMethodSpec(method, mirror, null);
+        return createDefaultMethodSpec(method, mirror, true, null);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Mon Apr 15 18:50:19 2013 +0200
@@ -88,11 +88,12 @@
                 continue;
             }
 
-            method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(parameter)));
+            method.addParameter(new CodeVariableElement(parameter.getType(), valueName(parameter)));
         }
     }
 
-    private static void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, boolean includeImplicit) {
+    private static void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame,
+                    boolean includeImplicit) {
         if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) {
             builder.string("frameValue");
         }
@@ -109,14 +110,33 @@
                 continue;
             }
 
+            ActualParameter sourceParameter = source.findParameter(parameter.getLocalName());
+
             if (unexpectedValueName != null && parameter.getLocalName().equals(unexpectedValueName)) {
-                builder.cast(parameter.getActualType(), CodeTreeBuilder.singleString("ex.getResult()"));
+                builder.cast(parameter.getType(), CodeTreeBuilder.singleString("ex.getResult()"));
+            } else if (sourceParameter != null) {
+                builder.string(valueName(sourceParameter, parameter));
             } else {
                 builder.string(valueName(parameter));
             }
         }
     }
 
+    private static String valueName(ActualParameter sourceParameter, ActualParameter targetParameter) {
+        if (sourceParameter != null) {
+            if (!sourceParameter.getSpecification().isSignature()) {
+                return valueName(targetParameter);
+            } else if (sourceParameter.getTypeSystemType() != null && targetParameter.getTypeSystemType() != null) {
+                if (sourceParameter.getTypeSystemType().needsCastTo(targetParameter.getTypeSystemType())) {
+                    return castValueName(targetParameter);
+                }
+            }
+            return valueName(targetParameter);
+        } else {
+            return valueName(targetParameter);
+        }
+    }
+
     private static CodeTree createTemplateMethodCall(CodeTreeBuilder parent, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) {
         CodeTreeBuilder builder = parent.create();
 
@@ -129,7 +149,6 @@
         }
         TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement());
         NodeData node = (NodeData) targetMethod.getTemplate();
-        TypeSystemData typeSystem = node.getTypeSystem();
 
         boolean accessible = targetMethod.canBeAccessedByInstanceOf(node.getNodeType());
         if (accessible) {
@@ -140,7 +159,11 @@
                     builder.string(THIS_NODE_LOCAL_VAR_NAME);
                 }
             } else {
-                builder.string("super");
+                if (targetMethod instanceof ExecutableTypeData) {
+                    builder.string("this");
+                } else {
+                    builder.string("super");
+                }
             }
         } else {
             if (method.getModifiers().contains(STATIC)) {
@@ -156,17 +179,8 @@
                 ActualParameter sourceParameter = sourceMethod.findParameter(parameter.getLocalName());
                 assert parameter != null;
 
-                if (castedValues) {
-                    NodeFieldData field = node.findField(parameter.getSpecification().getName());
-                    if (field == null) {
-                        builder.string(valueName(parameter));
-                    } else {
-                        if (Utils.typeEquals(sourceParameter.getActualType(), parameter.getActualType())) {
-                            builder.string(valueName(parameter));
-                        } else {
-                            builder.string(castValueName(parameter));
-                        }
-                    }
+                if (castedValues && sourceParameter != null) {
+                    builder.string(valueName(sourceParameter, parameter));
                 } else {
                     builder.string(valueName(parameter));
                 }
@@ -180,7 +194,7 @@
             if (valueParameter == null) {
                 valueParameter = targetParameter;
             }
-            TypeData targetType = targetParameter.getActualTypeData(typeSystem);
+            TypeData targetType = targetParameter.getTypeSystemType();
 
             if (targetParameter.isImplicit() || valueParameter.isImplicit()) {
                 continue;
@@ -188,7 +202,7 @@
 
             TypeData valueType = null;
             if (valueParameter != null) {
-                valueType = valueParameter.getActualTypeData(typeSystem);
+                valueType = valueParameter.getTypeSystemType();
             }
 
             if (targetParameter.getSpecification().isLocal()) {
@@ -203,7 +217,15 @@
             } else if (unexpectedValueName != null && targetParameter.getLocalName().equals(unexpectedValueName)) {
                 builder.string("ex.getResult()");
             } else if (targetType == null || targetType.isGeneric() || (valueType != null && valueType.equalsType(targetType))) {
+                builder.startGroup();
+
+                if (valueType != null && sourceMethod.getMethodName().equals(targetMethod.getMethodName()) && !valueType.isGeneric() && targetType.isGeneric()) {
+                    builder.string("(");
+                    builder.type(targetType.getPrimitiveType());
+                    builder.string(") ");
+                }
                 builder.string(valueName(targetParameter));
+                builder.end();
             } else {
                 builder.string(castValueName(targetParameter));
             }
@@ -243,10 +265,10 @@
         return prefix;
     }
 
-    private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, String value) {
+    private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, CodeTree value) {
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
         startCallTypeSystemMethod(context, builder, node, methodName);
-        builder.string(value);
+        builder.tree(value);
         builder.end().end();
         return builder.getRoot();
     }
@@ -281,7 +303,7 @@
                     if (field == null) {
                         continue;
                     }
-                    TypeData typeData = parameter.getActualTypeData(node.getTypeSystem());
+                    TypeData typeData = parameter.getTypeSystemType();
                     if (typeData != null && !typeData.isGeneric()) {
                         valuesNeedsCast.add(parameter.getLocalName());
                     }
@@ -345,7 +367,7 @@
         // Implict guards based on method signature
         for (ActualParameter guardedParam : guardedSpecialization.getParameters()) {
             NodeFieldData field = guardedSpecialization.getNode().findField(guardedParam.getSpecification().getName());
-            if (field == null || field.getKind() == FieldKind.FIELD) {
+            if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
                 continue;
             }
             ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName());
@@ -370,7 +392,7 @@
         String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
         for (ActualParameter guardedParam : guardedSpecialization.getParameters()) {
             NodeFieldData field = guardedSpecialization.getNode().findField(guardedParam.getSpecification().getName());
-            if (field == null || field.getKind() == FieldKind.FIELD) {
+            if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
                 continue;
             }
             ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName());
@@ -392,8 +414,8 @@
         NodeData node = field.getNodeData();
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
 
-        TypeData targetType = target.getActualTypeData(node.getTypeSystem());
-        TypeData sourceType = source.getActualTypeData(node.getTypeSystem());
+        TypeData targetType = target.getTypeSystemType();
+        TypeData sourceType = source.getTypeSystemType();
 
         if (targetType.equalsType(sourceType) || targetType.isGeneric()) {
             return null;
@@ -409,7 +431,7 @@
             builder.string(" || ");
         }
 
-        startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(target.getActualTypeData(node.getTypeSystem())));
+        startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(target.getTypeSystemType()));
         builder.string(valueName(source));
         builder.end().end(); // call
 
@@ -424,12 +446,10 @@
 
     private CodeTree createCast(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) {
         NodeData node = field.getNodeData();
-        TypeSystemData typeSystem = node.getTypeSystem();
+        TypeData sourceType = source.getTypeSystemType();
+        TypeData targetType = target.getTypeSystemType();
 
-        TypeData sourceType = source.getActualTypeData(typeSystem);
-        TypeData targetType = target.getActualTypeData(typeSystem);
-
-        if (targetType.equalsType(sourceType) || targetType.isGeneric()) {
+        if (!sourceType.needsCastTo(targetType)) {
             return null;
         }
 
@@ -440,9 +460,9 @@
             condition = CodeTreeBuilder.singleString(valueName(shortCircuit));
         }
 
-        CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), valueName(target));
+        CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), CodeTreeBuilder.singleString(valueName(target)));
 
-        return createLazyAssignment(parent, castValueName(target), target.getActualType(), condition, value);
+        return createLazyAssignment(parent, castValueName(target), target.getType(), condition, value);
     }
 
     /**
@@ -668,7 +688,7 @@
             for (ActualParameter parameter : data.getParameters()) {
                 ParameterSpec spec = parameter.getSpecification();
                 NodeFieldData field = node.findField(spec.getName());
-                if (field == null || field.getKind() == FieldKind.FIELD) {
+                if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
                     continue;
                 }
 
@@ -992,7 +1012,7 @@
         }
 
         private List<CodeExecutableElement> createGeneratedGenericMethod(NodeData node) {
-            TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getActualType();
+            TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType();
             if (node.needsRewrites(context)) {
                 List<CodeExecutableElement> methods = new ArrayList<>();
 
@@ -1037,7 +1057,7 @@
 
                 nextBuilder.startReturn().startCall(generatedGenericMethodName(next));
                 nextBuilder.string(THIS_NODE_LOCAL_VAR_NAME);
-                addInternalValueParameterNames(nextBuilder, next, null, true, true);
+                addInternalValueParameterNames(nextBuilder, next, next, null, true, true);
                 nextBuilder.end().end();
 
                 invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, true, invokeMethod, nextBuilder.getRoot());
@@ -1069,7 +1089,7 @@
 
                     builder.startReturn().startCall(generatedGenericMethodName(exception.getTransitionTo()));
                     builder.string(THIS_NODE_LOCAL_VAR_NAME);
-                    addInternalValueParameterNames(builder, exception.getTransitionTo(), null, true, true);
+                    addInternalValueParameterNames(builder, exception.getTransitionTo(), exception.getTransitionTo(), null, true, true);
                     builder.end().end();
                 }
                 builder.end();
@@ -1104,23 +1124,19 @@
                 }
             }
 
-            TypeData primaryType = specialization.getReturnType().getActualTypeData(node.getTypeSystem());
-
             for (ExecutableTypeData execType : node.getExecutableTypes()) {
                 if (execType.isFinal()) {
                     continue;
                 }
-
-                if (primaryType == execType.getType()) {
-                    CodeExecutableElement executeMethod = createExecutableTypeOverride(execType);
-                    clazz.add(executeMethod);
-                    executeMethod.setBodyTree(createFunctionalExecute(executeMethod.createBuilder(), specialization));
-                } else if (needsCastingExecuteMethod(execType, primaryType)) {
-                    CodeExecutableElement executeMethod = createExecutableTypeOverride(execType);
-                    clazz.add(executeMethod);
-                    executeMethod.setBodyTree(createCastingExecute(executeMethod.createBuilder(), specialization, execType.getType()));
+                CodeExecutableElement executeMethod = createExecutableTypeOverride(execType);
+                clazz.add(executeMethod);
+                CodeTreeBuilder builder = executeMethod.createBuilder();
+                CodeTree result = createExecuteBody(builder, specialization, execType);
+                if (result != null) {
+                    builder.tree(result);
+                } else {
+                    clazz.remove(executeMethod);
                 }
-
             }
 
             if (node.needsRewrites(getContext()) && !specialization.isGeneric() && !specialization.isUninitialized()) {
@@ -1128,13 +1144,36 @@
             }
         }
 
+        private CodeTree createExecuteBody(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData execType) {
+            TypeData primaryType = specialization.getReturnType().getTypeSystemType();
+
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+
+            ExecutableTypeData foundEvaluatedPrimaryType = findFunctionalExecutableType(specialization, execType.getEvaluatedCount());
+
+            if (execType == foundEvaluatedPrimaryType || foundEvaluatedPrimaryType == null) {
+                builder.tree(createFunctionalExecute(builder, specialization, execType));
+            } else if (needsCastingExecuteMethod(execType, primaryType)) {
+                builder.tree(createCastingExecute(builder, specialization, execType, foundEvaluatedPrimaryType));
+            } else {
+                return null;
+            }
+
+            return builder.getRoot();
+        }
+
         private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType) {
             CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod());
-            if (method.getParameters().size() == 1) {
-                CodeVariableElement var = CodeVariableElement.clone(method.getParameters().get(0));
-                var.setName("frameValue");
-                method.getParameters().set(0, var);
+
+            int i = 0;
+            for (VariableElement param : method.getParameters()) {
+                CodeVariableElement var = CodeVariableElement.clone(param);
+                var.setName(valueName(execType.getParameters().get(i)));
+                method.getParameters().set(i, var);
+                i++;
             }
+
+            method.getAnnotationMirrors().clear();
             method.getModifiers().remove(Modifier.ABSTRACT);
             return method;
         }
@@ -1152,24 +1191,64 @@
             return false;
         }
 
-        private CodeTree createCastingExecute(CodeTreeBuilder parent, SpecializationData specialization, TypeData type) {
+        private ExecutableTypeData findFunctionalExecutableType(SpecializationData specialization, int evaluatedCount) {
+            TypeData primaryType = specialization.getReturnType().getTypeSystemType();
+            List<ExecutableTypeData> otherTypes = specialization.getNode().getExecutableTypes(evaluatedCount);
+
+            List<ExecutableTypeData> filteredTypes = new ArrayList<>();
+            for (ExecutableTypeData compareType : otherTypes) {
+                if (!Utils.typeEquals(compareType.getType().getPrimitiveType(), primaryType.getPrimitiveType())) {
+                    continue;
+                }
+                filteredTypes.add(compareType);
+            }
+
+            for (ExecutableTypeData compareType : filteredTypes) {
+                if (compareType.startsWithSignature(specialization)) {
+                    return compareType;
+                }
+            }
+
+            for (ExecutableTypeData compareType : otherTypes) {
+                if (compareType.startsWithSignature(specialization)) {
+                    return compareType;
+                }
+            }
+
+            return null;
+        }
+
+        private CodeTree createCastingExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable, ExecutableTypeData castExecutable) {
+            TypeData type = executable.getType();
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             NodeData node = specialization.getNode();
-            TypeSystemData typeSystem = node.getTypeSystem();
 
             ExecutableTypeData castedType = node.findExecutableType(type);
-            TypeData primaryType = specialization.getReturnType().getActualTypeData(typeSystem);
-            ExecutableTypeData execType = specialization.getNode().findExecutableType(primaryType);
+            TypeData primaryType = castExecutable.getType();
 
-            boolean needsTry = execType.hasUnexpectedValue(getContext());
+            boolean needsTry = castExecutable.hasUnexpectedValue(getContext());
             boolean returnVoid = type.isVoid();
 
-            CodeTree primaryExecuteCall = null;
+            List<ActualParameter> executeParameters = new ArrayList<>();
+            for (ActualParameter sourceParameter : executable.getParameters()) {
+                NodeFieldData field = specialization.getNode().findField(sourceParameter.getSpecification().getName());
+                if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
+                    continue;
+                }
 
-            CodeTreeBuilder executeBuilder = new CodeTreeBuilder(builder);
-            buildExecute(executeBuilder, null, null, execType);
-            primaryExecuteCall = executeBuilder.getRoot();
+                ActualParameter targetParameter = castExecutable.findParameter(sourceParameter.getLocalName());
+                if (targetParameter != null) {
+                    TypeData sourceType = sourceParameter.getTypeSystemType();
+                    TypeData targetType = targetParameter.getTypeSystemType();
+                    if (sourceType.needsCastTo(targetType)) {
+                        executeParameters.add(targetParameter);
+                    }
+                }
+            }
 
+            builder.tree(createExecuteChildren(builder, executable, specialization, executeParameters, null, true));
+
+            CodeTree primaryExecuteCall = createTemplateMethodCall(builder, executable, castExecutable, null);
             if (needsTry) {
                 if (!returnVoid) {
                     builder.declaration(primaryType.getPrimitiveType(), "value");
@@ -1236,24 +1315,24 @@
             return builder.getRoot();
         }
 
-        private CodeTree createFunctionalExecute(CodeTreeBuilder parent, SpecializationData specialization) {
+        private CodeTree createFunctionalExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable) {
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             if (specialization.isUninitialized()) {
                 builder.tree(createDeoptimize(builder));
             }
 
-            builder.tree(createExecuteChildren(builder, specialization));
+            builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null, false));
 
             CodeTree executeNode;
             if (specialization.isUninitialized()) {
-                builder.tree(createSpecializeCall(builder, specialization));
+                builder.tree(createSpecializeCall(builder, executable, specialization));
             }
-            executeNode = createExecute(builder, specialization);
+            executeNode = createExecute(builder, executable, specialization);
 
             SpecializationData next = specialization.findNextSpecialization();
             CodeTree returnSpecialized = null;
             if (next != null) {
-                returnSpecialized = createReturnSpecializeAndExecute(builder, next, null);
+                returnSpecialized = createReturnSpecializeAndExecute(builder, executable, next, null);
             }
             builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized));
 
@@ -1268,7 +1347,7 @@
             return builder.getRoot();
         }
 
-        private CodeTree createSpecializeCall(CodeTreeBuilder parent, SpecializationData specialization) {
+        private CodeTree createSpecializeCall(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) {
             NodeData node = specialization.getNode();
 
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
@@ -1280,7 +1359,7 @@
                 builder.startCall(factoryClassName(node), "specialize");
                 builder.string("this");
                 builder.typeLiteral(builder.findMethod().getEnclosingElement().asType());
-                addInternalValueParameterNames(builder, specialization, null, true, true);
+                addInternalValueParameterNames(builder, executable, specialization, null, true, true);
                 builder.end(); // call replace, call specialize
             } else {
                 builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end();
@@ -1289,19 +1368,20 @@
             return builder.getRoot();
         }
 
-        private CodeTree createExecute(CodeTreeBuilder parent, SpecializationData specialization) {
+        private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) {
             NodeData node = specialization.getNode();
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             if (!specialization.getExceptions().isEmpty()) {
                 builder.startTryBlock();
             }
 
+            CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent);
             if (specialization.isUninitialized()) {
                 String genericMethodName = generatedGenericMethodName(null);
-                builder.startReturn().startCall(factoryClassName(node), genericMethodName);
-                builder.string("this");
-                addInternalValueParameterNames(builder, specialization, null, true, true);
-                builder.end().end();
+                returnBuilder.startCall(factoryClassName(node), genericMethodName);
+                returnBuilder.string("this");
+                addInternalValueParameterNames(returnBuilder, executable, specialization, null, true, true);
+                returnBuilder.end();
             } else if (specialization.getMethod() == null && !node.needsRewrites(context)) {
                 emitEncounteredSynthetic(builder);
             } else if (specialization.isGeneric()) {
@@ -1312,36 +1392,82 @@
                     genericMethodName = generatedGenericMethodName(null);
                 }
 
-                builder.startReturn().startCall(factoryClassName(node), genericMethodName);
-                builder.string("this");
-                addInternalValueParameterNames(builder, specialization, null, true, true);
-                builder.end().end();
+                returnBuilder.startCall(factoryClassName(node), genericMethodName);
+                returnBuilder.string("this");
+                addInternalValueParameterNames(returnBuilder, executable, specialization, null, true, true);
+                returnBuilder.end();
             } else {
+                returnBuilder.tree(createTemplateMethodCall(returnBuilder, executable, specialization, null));
+            }
+
+            if (!returnBuilder.isEmpty()) {
                 builder.startReturn();
-                builder.tree(createTemplateMethodCall(builder, specialization, specialization, null));
-                builder.end(); // return
+
+                TypeData targetType = node.getTypeSystem().findTypeData(builder.findMethod().getReturnType());
+                TypeData sourceType = specialization.getReturnType().getTypeSystemType();
+
+                if (targetType == null || sourceType == null) {
+                    builder.tree(returnBuilder.getRoot());
+                } else if (sourceType.needsCastTo(targetType)) {
+                    builder.tree(createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.expectTypeMethodName(targetType), returnBuilder.getRoot()));
+                } else {
+                    builder.tree(returnBuilder.getRoot());
+                }
+                builder.end();
             }
 
             if (!specialization.getExceptions().isEmpty()) {
                 for (SpecializationThrowsData exception : specialization.getExceptions()) {
                     builder.end().startCatchBlock(exception.getJavaClass(), "ex");
-                    builder.tree(createReturnSpecializeAndExecute(parent, exception.getTransitionTo(), null));
+                    builder.tree(createReturnSpecializeAndExecute(parent, executable, exception.getTransitionTo(), null));
                 }
                 builder.end();
             }
             return builder.getRoot();
         }
 
-        private CodeTree createExecuteChildren(CodeTreeBuilder parent, SpecializationData specialization) {
+        private CodeTree createExecuteChildren(CodeTreeBuilder parent, ExecutableTypeData sourceExecutable, SpecializationData specialization, List<ActualParameter> targetParameters,
+                        ActualParameter unexpectedParameter, boolean cast) {
+            NodeData sourceNode = specialization.getNode();
+
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
 
-            for (ActualParameter parameter : specialization.getParameters()) {
-                NodeFieldData field = specialization.getNode().findField(parameter.getSpecification().getName());
-                if (field == null || field.getKind() == FieldKind.FIELD) {
+            for (ActualParameter targetParameter : targetParameters) {
+                NodeFieldData field = sourceNode.findField(targetParameter.getSpecification().getName());
+                if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
                     continue;
                 }
+                TypeData targetType = targetParameter.getTypeSystemType();
 
-                buildFieldExecute(builder, specialization, parameter, field, null);
+                ExecutableTypeData targetExecutable = field.getNodeData().findExecutableType(targetType);
+
+                ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName());
+
+                String targetVariableName;
+                CodeTree executionExpression;
+                if (cast || sourceParameter != null) {
+                    TypeData sourceType = sourceParameter.getTypeSystemType();
+                    if (!sourceType.needsCastTo(targetType)) {
+                        continue;
+                    }
+                    executionExpression = createExpectType(sourceNode, targetExecutable, CodeTreeBuilder.singleString(valueName(targetParameter)));
+                    targetVariableName = castValueName(targetParameter);
+                } else {
+                    if (sourceExecutable.findParameter(targetParameter.getLocalName()) == null) {
+                        executionExpression = createExecuteChildExpression(builder, field, targetParameter);
+                        targetVariableName = valueName(targetParameter);
+                    } else {
+                        continue;
+                    }
+                }
+
+                CodeTreeVariable executionVar = new CodeTreeVariable();
+                CodeTree shortCircuitTree = createShortCircuitTree(builder, executionVar, targetVariableName, sourceExecutable, specialization, targetParameter, unexpectedParameter);
+                CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpression, targetVariableName, specialization, sourceExecutable, targetExecutable, targetParameter,
+                                shortCircuitTree != executionVar);
+
+                executionVar.set(unexpectedTree);
+                builder.tree(shortCircuitTree);
             }
             return builder.getRoot();
         }
@@ -1354,53 +1480,52 @@
             }
         }
 
-        private void buildFieldExecute(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter param, NodeFieldData field, ActualParameter exceptionParam) {
-            boolean shortCircuit = startShortCircuit(builder, specialization, param, exceptionParam);
-            ExecutableTypeData execType = field.getNodeData().findExecutableType(param.getActualTypeData(field.getNodeData().getTypeSystem()));
-            boolean unexpected = execType.hasUnexpectedValue(getContext());
+        private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ExecutableTypeData currentExecutable,
+                        ExecutableTypeData targetExecutable, ActualParameter param, boolean shortCircuit) {
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+            boolean unexpected = targetExecutable.hasUnexpectedValue(getContext());
+            builder.startStatement();
 
-            if (!shortCircuit && unexpected) {
-                builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).end();
+            if (!shortCircuit) {
+                builder.type(param.getType()).string(" ").string(targetVariableName);
             }
 
             if (unexpected) {
+                if (!shortCircuit) {
+                    builder.end();
+                }
                 builder.startTryBlock();
+                builder.startStatement();
+                builder.string(targetVariableName);
+            } else if (shortCircuit) {
+                builder.startStatement();
+                builder.string(targetVariableName);
             }
-
-            if (!shortCircuit && !unexpected) {
-                builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).string(" = ");
-            } else {
-                builder.startStatement().string(valueName(param)).string(" = ");
-            }
-            buildExecute(builder, param, field, execType);
+            builder.string(" = ");
+            builder.tree(body);
             builder.end();
 
             if (unexpected) {
                 builder.end().startCatchBlock(getUnexpectedValueException(), "ex");
                 SpecializationData generic = specialization.getNode().getGenericSpecialization();
-                boolean execute = false;
-                for (ActualParameter exParam : generic.getParameters()) {
-                    NodeFieldData exField = generic.getNode().findField(exParam.getSpecification().getName());
-                    if (exField == null || field.getKind() == FieldKind.FIELD) {
-                        continue;
-                    }
-                    if (execute) {
-                        buildFieldExecute(builder, specialization.getNode().getGenericSpecialization(), exParam, exField, param);
-                    } else if (exParam.getLocalName().equals(param.getLocalName())) {
-                        execute = true;
-                    }
-                }
-                builder.tree(createReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param));
+                ActualParameter genericParameter = generic.findParameter(param.getLocalName());
+
+                List<ActualParameter> genericParameters = generic.getParametersAfter(genericParameter);
+                builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter, false));
+                builder.tree(createReturnSpecializeAndExecute(builder, currentExecutable, specialization.findNextSpecialization(), param));
                 builder.end(); // catch block
             }
 
-            endShortCircuit(builder, shortCircuit);
-            builder.newLine();
+            return builder.getRoot();
         }
 
-        private void buildExecute(CodeTreeBuilder builder, ActualParameter parameter, NodeFieldData field, ExecutableTypeData execType) {
-            if (field != null) {
-                Element accessElement = field.getAccessElement();
+        private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeFieldData targetField, ActualParameter sourceParameter) {
+            TypeData type = sourceParameter.getTypeSystemType();
+            ExecutableTypeData execType = targetField.getNodeData().findExecutableType(type);
+
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+            if (targetField != null) {
+                Element accessElement = targetField.getAccessElement();
                 if (accessElement.getKind() == ElementKind.METHOD) {
                     builder.startCall(accessElement.getSimpleName().toString()).end();
                 } else if (accessElement.getKind() == ElementKind.FIELD) {
@@ -1408,8 +1533,8 @@
                 } else {
                     throw new AssertionError();
                 }
-                if (parameter.getSpecification().isIndexed()) {
-                    builder.string("[" + parameter.getIndex() + "]");
+                if (sourceParameter.getSpecification().isIndexed()) {
+                    builder.string("[" + sourceParameter.getIndex() + "]");
                 }
                 builder.string(".");
             }
@@ -1418,16 +1543,20 @@
                 builder.string("frameValue");
             }
             builder.end();
+            return builder.getRoot();
         }
 
-        private boolean startShortCircuit(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter parameter, ActualParameter exceptionParam) {
+        private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, ExecutableTypeData currentExecutable, SpecializationData specialization,
+                        ActualParameter parameter, ActualParameter exceptionParam) {
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+
             NodeFieldData forField = specialization.getNode().findField(parameter.getSpecification().getName());
             if (forField == null) {
-                return false;
+                return body;
             }
 
             if (forField.getExecutionKind() != ExecutionKind.SHORT_CIRCUIT) {
-                return false;
+                return body;
             }
 
             ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter);
@@ -1442,51 +1571,44 @@
                 }
             }
 
-            builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(shortCircuitParam)).string(" = ");
+            builder.startStatement().type(shortCircuitParam.getType()).string(" ").string(valueName(shortCircuitParam)).string(" = ");
             ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex);
 
-            builder.tree(createTemplateMethodCall(builder, shortCircuitData, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null));
+            builder.tree(createTemplateMethodCall(builder, currentExecutable, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null));
 
             builder.end(); // statement
 
-            builder.declaration(parameter.getActualType(), valueName(parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getActualType()));
+            builder.declaration(parameter.getType(), targetVariableName, CodeTreeBuilder.createBuilder().defaultValue(parameter.getType()));
             builder.startIf().string(shortCircuitParam.getLocalName()).end();
             builder.startBlock();
+            builder.tree(body);
+            builder.end();
 
-            return true;
+            return builder.getRoot();
         }
 
-        private void endShortCircuit(CodeTreeBuilder builder, boolean shortCircuit) {
-            if (shortCircuit) {
-                builder.end();
-            }
-        }
-
-        private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, SpecializationData nextSpecialization, ActualParameter exceptionParam) {
+        private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam) {
             CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent);
             specializeCall.startCall("specializeAndExecute");
             specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class");
-            addInternalValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, true);
+            addInternalValueParameterNames(specializeCall, executable, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true,
+                            true);
             specializeCall.end().end();
 
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             builder.startReturn();
-            builder.tree(specializeCall.getRoot());
+            builder.tree(createExpectType(nextSpecialization.getNode(), executable, specializeCall.getRoot()));
             builder.end();
+
             return builder.getRoot();
         }
 
         private void buildSpecializeAndExecute(CodeTypeElement clazz, SpecializationData specialization) {
             NodeData node = specialization.getNode();
-            TypeData returnType = specialization.getReturnType().getActualTypeData(node.getTypeSystem());
-            ExecutableTypeData returnExecutableType = node.findExecutableType(returnType);
-            boolean canThrowUnexpected = returnExecutableType == null ? true : returnExecutableType.hasUnexpectedValue(getContext());
+            TypeData returnType = node.getGenericSpecialization().getReturnType().getTypeSystemType();
 
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), returnType.getPrimitiveType(), "specializeAndExecute");
             method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
-            if (canThrowUnexpected) {
-                method.addThrownType(getUnexpectedValueException());
-            }
             addInternalValueParameters(method, specialization.getNode().getGenericSpecialization(), true);
             clazz.add(method);
 
@@ -1498,7 +1620,7 @@
             builder.startStatement();
             builder.startCall("replace");
             builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState");
-            addInternalValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, true, true);
+            addInternalValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), specialization.getNode().getGenericSpecialization(), null, true, true);
             builder.end();
             builder.end(); // call replace
             builder.end(); // statement
@@ -1514,10 +1636,10 @@
             CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder();
             genericExecute.startCall(factoryClassName(specialization.getNode()), generatedMethodName);
             genericExecute.string("this");
-            addInternalValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), null, true, true);
+            addInternalValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), specialization.getNode().getGenericSpecialization(), null, true, true);
             genericExecute.end(); // call generated generic
 
-            CodeTree genericInvocation = createExpectType(node, returnExecutableType, genericExecute.getRoot());
+            CodeTree genericInvocation = genericExecute.getRoot();
 
             if (generatedGeneric != null && Utils.isVoid(generatedGeneric.getReturnType())) {
                 builder.statement(genericInvocation);
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Mon Apr 15 18:50:19 2013 +0200
@@ -46,7 +46,7 @@
 
     private List<SpecializationData> specializations;
     private List<SpecializationListenerData> specializationListeners;
-    private List<ExecutableTypeData> executableTypes;
+    private Map<Integer, List<ExecutableTypeData>> executableTypes;
     private List<ShortCircuitData> shortCircuits;
 
     public NodeData(TypeElement type, String id) {
@@ -92,7 +92,7 @@
             children.addAll(specializationListeners);
         }
         if (executableTypes != null) {
-            children.addAll(executableTypes);
+            children.addAll(getExecutableTypes());
         }
         if (shortCircuits != null) {
             children.addAll(shortCircuits);
@@ -134,9 +134,11 @@
     }
 
     public boolean supportsFrame() {
-        for (ExecutableTypeData execType : executableTypes) {
-            if (execType.findParameter("frameValue") == null) {
-                return false;
+        if (executableTypes != null) {
+            for (ExecutableTypeData execType : getExecutableTypes(-1)) {
+                if (execType.findParameter("frameValue") == null) {
+                    return false;
+                }
             }
         }
         return true;
@@ -213,9 +215,21 @@
         return null;
     }
 
+    public List<ExecutableTypeData> getExecutableTypes(int evaluatedCount) {
+        if (evaluatedCount == -1) {
+            List<ExecutableTypeData> typeData = new ArrayList<>();
+            for (int currentEvaluationCount : executableTypes.keySet()) {
+                typeData.addAll(executableTypes.get(currentEvaluationCount));
+            }
+            return typeData;
+        } else {
+            return executableTypes.get(evaluatedCount);
+        }
+    }
+
     public List<ExecutableTypeData> findGenericExecutableTypes(ProcessorContext context) {
         List<ExecutableTypeData> types = new ArrayList<>();
-        for (ExecutableTypeData type : executableTypes) {
+        for (ExecutableTypeData type : getExecutableTypes(0)) {
             if (!type.hasUnexpectedValue(context)) {
                 types.add(type);
             }
@@ -224,7 +238,7 @@
     }
 
     public ExecutableTypeData findExecutableType(TypeData prmitiveType) {
-        for (ExecutableTypeData type : executableTypes) {
+        for (ExecutableTypeData type : getExecutableTypes(0)) {
             if (Utils.typeEquals(type.getType().getPrimitiveType(), prmitiveType.getPrimitiveType())) {
                 return type;
             }
@@ -235,7 +249,7 @@
     public SpecializationData findUniqueSpecialization(TypeData type) {
         SpecializationData result = null;
         for (SpecializationData specialization : specializations) {
-            if (specialization.getReturnType().getActualTypeData(getTypeSystem()) == type) {
+            if (specialization.getReturnType().getTypeSystemType() == type) {
                 if (result != null) {
                     // Result not unique;
                     return null;
@@ -246,14 +260,6 @@
         return result;
     }
 
-    public List<TypeMirror> getExecutablePrimitiveTypeMirrors() {
-        List<TypeMirror> typeMirrors = new ArrayList<>();
-        for (ExecutableTypeData executableType : executableTypes) {
-            typeMirrors.add(executableType.getType().getPrimitiveType());
-        }
-        return typeMirrors;
-    }
-
     public NodeFieldData[] filterFields(FieldKind fieldKind, ExecutionKind usage) {
         List<NodeFieldData> filteredFields = new ArrayList<>();
         for (NodeFieldData field : getFields()) {
@@ -266,15 +272,6 @@
         return filteredFields.toArray(new NodeFieldData[filteredFields.size()]);
     }
 
-    public boolean hasUnexpectedExecutableTypes(ProcessorContext context) {
-        for (ExecutableTypeData type : getExecutableTypes()) {
-            if (type.hasUnexpectedValue(context)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     public boolean needsRewrites(ProcessorContext context) {
         boolean needsRewrites = false;
 
@@ -408,7 +405,7 @@
     }
 
     public List<ExecutableTypeData> getExecutableTypes() {
-        return executableTypes;
+        return getExecutableTypes(-1);
     }
 
     public List<ShortCircuitData> getShortCircuits() {
@@ -428,7 +425,7 @@
         this.specializationListeners = specializationListeners;
     }
 
-    void setExecutableTypes(List<ExecutableTypeData> executableTypes) {
+    void setExecutableTypes(Map<Integer, List<ExecutableTypeData>> executableTypes) {
         this.executableTypes = executableTypes;
     }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Mon Apr 15 18:50:19 2013 +0200
@@ -30,7 +30,7 @@
 public class NodeFieldData extends MessageContainer {
 
     public enum FieldKind {
-        CHILD, CHILDREN, FIELD
+        CHILD, CHILDREN, FINAL_FIELD
     }
 
     public enum ExecutionKind {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java	Mon Apr 15 18:50:19 2013 +0200
@@ -48,7 +48,7 @@
         return spec;
     }
 
-    private static List<TypeMirror> nodeTypeMirrors(NodeData nodeData) {
+    protected List<TypeMirror> nodeTypeMirrors(NodeData nodeData) {
         Set<TypeMirror> typeMirrors = new LinkedHashSet<>();
 
         for (ExecutableTypeData typeData : nodeData.getExecutableTypes()) {
@@ -66,11 +66,15 @@
 
     @Override
     public boolean isParsable(ExecutableElement method) {
-        return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null;
+        if (getAnnotationType() != null) {
+            return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null;
+        }
+
+        return true;
     }
 
     @SuppressWarnings("unused")
-    protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, String shortCircuitName) {
+    protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, boolean shortCircuitsEnabled, String shortCircuitName) {
         MethodSpec methodSpec = new MethodSpec(createReturnParameterSpec());
 
         if (getNode().supportsFrame()) {
@@ -80,7 +84,7 @@
         resolveAndAddImplicitThis(methodSpec, method);
 
         for (NodeFieldData field : getNode().getFields()) {
-            if (field.getKind() == FieldKind.FIELD) {
+            if (field.getKind() == FieldKind.FINAL_FIELD) {
                 ParameterSpec spec = new ParameterSpec(field.getName(), field.getType());
                 spec.setLocal(true);
                 methodSpec.addOptional(spec);
@@ -105,7 +109,9 @@
                     break;
                 }
 
-                methodSpec.addRequired(new ParameterSpec(shortCircuitValueName(valueName), getContext().getType(boolean.class)));
+                if (shortCircuitsEnabled) {
+                    methodSpec.addRequired(new ParameterSpec(shortCircuitValueName(valueName), getContext().getType(boolean.class)));
+                }
                 methodSpec.addRequired(createValueParameterSpec(valueName, field.getNodeData()));
             } else {
                 assert false;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Mon Apr 15 18:50:19 2013 +0200
@@ -155,21 +155,7 @@
             return nodeData; // error sync point
         }
 
-        if (Utils.typeEquals(nodeType.asType(), type.asType())) {
-            // filter fields if they were not split. (field are accessible anyway)
-            for (ListIterator<NodeFieldData> iterator = nodeData.getFields().listIterator(); iterator.hasNext();) {
-                NodeFieldData field = iterator.next();
-                if (field.getKind() == FieldKind.FIELD) {
-                    iterator.remove();
-                }
-            }
-        }
-
         List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type));
-        nodeData.setExtensionElements(getExtensionParser().parseAll(nodeData, elements));
-        if (nodeData.getExtensionElements() != null) {
-            elements.addAll(nodeData.getExtensionElements());
-        }
         parseMethods(nodeData, elements);
 
         if (nodeData.hasErrors()) {
@@ -300,23 +286,23 @@
         } else if (node.needsRewrites(context)) {
             SpecializationData specialization = specializations.get(0);
             GenericParser parser = new GenericParser(context, node);
-            MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, null);
+            MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, true, null);
 
             ExecutableTypeData anyGenericReturnType = node.findAnyGenericExecutableType(context);
             assert anyGenericReturnType != null;
 
-            ActualParameter returnType = new ActualParameter(specification.getReturnType(), anyGenericReturnType.getType().getPrimitiveType(), 0, false);
+            ActualParameter returnType = new ActualParameter(specification.getReturnType(), anyGenericReturnType.getType(), 0, false);
             List<ActualParameter> parameters = new ArrayList<>();
             for (ActualParameter specializationParameter : specialization.getParameters()) {
                 ParameterSpec parameterSpec = specification.findParameterSpec(specializationParameter.getSpecification().getName());
                 NodeFieldData field = node.findField(parameterSpec.getName());
-                TypeMirror actualType;
-                if (field == null || field.getKind() == FieldKind.FIELD) {
-                    actualType = specializationParameter.getActualType();
+                TypeData actualType;
+                if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
+                    actualType = specializationParameter.getTypeSystemType();
                 } else {
                     ExecutableTypeData paramType = field.getNodeData().findAnyGenericExecutableType(context);
                     assert paramType != null;
-                    actualType = paramType.getType().getPrimitiveType();
+                    actualType = paramType.getType();
                 }
                 parameters.add(new ActualParameter(parameterSpec, actualType, specializationParameter.getIndex(), specializationParameter.isImplicit()));
             }
@@ -329,18 +315,18 @@
         if (genericSpecialization != null) {
             if (genericSpecialization.isUseSpecializationsForGeneric()) {
                 for (ActualParameter parameter : genericSpecialization.getReturnTypeAndParameters()) {
-                    if (Utils.isObject(parameter.getActualType())) {
+                    if (Utils.isObject(parameter.getType())) {
                         continue;
                     }
                     Set<String> types = new HashSet<>();
                     for (SpecializationData specialization : specializations) {
                         ActualParameter actualParameter = specialization.findParameter(parameter.getLocalName());
                         if (actualParameter != null) {
-                            types.add(Utils.getQualifiedName(actualParameter.getActualType()));
+                            types.add(Utils.getQualifiedName(actualParameter.getType()));
                         }
                     }
                     if (types.size() > 1) {
-                        genericSpecialization.replaceParameter(parameter.getLocalName(), new ActualParameter(parameter, node.getTypeSystem().getGenericType()));
+                        genericSpecialization.replaceParameter(parameter.getLocalName(), new ActualParameter(parameter, node.getTypeSystem().getGenericTypeData()));
                     }
                 }
             }
@@ -408,12 +394,12 @@
                 continue;
             }
             List<String> paramIds = new LinkedList<>();
-            paramIds.add(Utils.getTypeId(other.getReturnType().getActualType()));
+            paramIds.add(Utils.getTypeId(other.getReturnType().getType()));
             for (ActualParameter param : other.getParameters()) {
                 if (other.getNode().findField(param.getSpecification().getName()) == null) {
                     continue;
                 }
-                paramIds.add(Utils.getTypeId(param.getActualType()));
+                paramIds.add(Utils.getTypeId(param.getType()));
             }
             assert lastSize == -1 || lastSize == paramIds.size();
             if (lastSize != -1 && lastSize != paramIds.size()) {
@@ -548,13 +534,22 @@
 
         nodeData.setNodeType(nodeType.asType());
         nodeData.setTypeSystem(typeSystem);
+        nodeData.setFields(parseFields(elements, typeHierarchy));
 
-        List<ExecutableTypeData> executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements));
-        nodeData.setExecutableTypes(executableTypes);
+        if (Utils.typeEquals(nodeType.asType(), templateType.asType())) {
+            // filter fields if they were not split. (field are accessible anyway)
+            for (ListIterator<NodeFieldData> iterator = nodeData.getFields().listIterator(); iterator.hasNext();) {
+                NodeFieldData field = iterator.next();
+                if (field.getKind() == FieldKind.FINAL_FIELD) {
+                    iterator.remove();
+                }
+            }
+        }
+
+        nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements)));
+
         parsedNodes.put(Utils.getQualifiedName(templateType), nodeData);
 
-        nodeData.setFields(parseFields(elements, typeHierarchy));
-
         return nodeData;
     }
 
@@ -633,38 +628,23 @@
         nodeData.addError("Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type));
     }
 
-    private static List<ExecutableTypeData> filterExecutableTypes(List<ExecutableTypeData> executableTypes) {
-        List<ExecutableTypeData> filteredExecutableTypes = new ArrayList<>();
-        for (ExecutableTypeData t1 : executableTypes) {
-            boolean add = true;
-            for (ExecutableTypeData t2 : executableTypes) {
-                if (t1 == t2) {
-                    continue;
-                }
-                if (Utils.typeEquals(t1.getType().getPrimitiveType(), t2.getType().getPrimitiveType())) {
-                    if (t1.isFinal() && !t2.isFinal()) {
-                        add = false;
-                    }
-                }
+    private static Map<Integer, List<ExecutableTypeData>> groupExecutableTypes(List<ExecutableTypeData> executableTypes) {
+        Map<Integer, List<ExecutableTypeData>> groupedTypes = new HashMap<>();
+        for (ExecutableTypeData type : executableTypes) {
+            int evaluatedCount = type.getEvaluatedCount();
+
+            List<ExecutableTypeData> types = groupedTypes.get(evaluatedCount);
+            if (types == null) {
+                types = new ArrayList<>();
+                groupedTypes.put(evaluatedCount, types);
             }
-            if (add) {
-                filteredExecutableTypes.add(t1);
-            }
+            types.add(type);
         }
 
-        Collections.sort(filteredExecutableTypes, new Comparator<ExecutableTypeData>() {
-
-            @Override
-            public int compare(ExecutableTypeData o1, ExecutableTypeData o2) {
-                int index1 = o1.getTypeSystem().findType(o1.getType());
-                int index2 = o2.getTypeSystem().findType(o2.getType());
-                if (index1 == -1 || index2 == -1) {
-                    return 0;
-                }
-                return index1 - index2;
-            }
-        });
-        return filteredExecutableTypes;
+        for (List<ExecutableTypeData> types : groupedTypes.values()) {
+            Collections.sort(types);
+        }
+        return groupedTypes;
     }
 
     private AnnotationMirror findFirstAnnotation(List<? extends Element> elements, Class<? extends Annotation> annotation) {
@@ -744,7 +724,7 @@
             execution = ExecutionKind.IGNORE;
             type = var.asType();
             mirror = null;
-            kind = FieldKind.FIELD;
+            kind = FieldKind.FINAL_FIELD;
         }
 
         NodeFieldData fieldData = new NodeFieldData(var, findAccessElement(var), mirror, kind, execution);
@@ -913,13 +893,13 @@
     private boolean isGenericShortCutMethod(NodeData node, TemplateMethod method) {
         for (ActualParameter parameter : method.getParameters()) {
             NodeFieldData field = node.findField(parameter.getSpecification().getName());
-            if (field == null || field.getKind() == FieldKind.FIELD) {
+            if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
                 continue;
             }
             ExecutableTypeData found = null;
             List<ExecutableTypeData> executableElements = field.getNodeData().findGenericExecutableTypes(context);
             for (ExecutableTypeData executable : executableElements) {
-                if (executable.getType().equalsType(parameter.getActualTypeData(node.getTypeSystem()))) {
+                if (executable.getType().equalsType(parameter.getTypeSystemType())) {
                     found = executable;
                     break;
                 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitData.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitData.java	Mon Apr 15 18:50:19 2013 +0200
@@ -62,7 +62,7 @@
 
         for (ActualParameter param : getParameters()) {
             ActualParameter specializationParam = specialization.findParameter(param.getLocalName());
-            if (!Utils.typeEquals(param.getActualType(), specializationParam.getActualType())) {
+            if (!Utils.typeEquals(param.getType(), specializationParam.getType())) {
                 return false;
             }
         }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java	Mon Apr 15 18:50:19 2013 +0200
@@ -49,7 +49,7 @@
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
         String shortCircuitValue = Utils.getAnnotationValue(String.class, mirror, "value");
-        return createDefaultMethodSpec(method, mirror, shortCircuitValue);
+        return createDefaultMethodSpec(method, mirror, true, shortCircuitValue);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Mon Apr 15 18:50:19 2013 +0200
@@ -84,10 +84,10 @@
         }
         for (ActualParameter parameter : getParameters()) {
             NodeFieldData field = getNode().findField(parameter.getSpecification().getName());
-            if (field == null || field.getKind() == FieldKind.FIELD) {
+            if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
                 continue;
             }
-            ExecutableTypeData type = field.getNodeData().findExecutableType(parameter.getActualTypeData(field.getNodeData().getTypeSystem()));
+            ExecutableTypeData type = field.getNodeData().findExecutableType(parameter.getTypeSystemType());
             if (type.hasUnexpectedValue(context)) {
                 return true;
             }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java	Mon Apr 15 18:50:19 2013 +0200
@@ -38,7 +38,7 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        return createDefaultMethodSpec(method, mirror, null);
+        return createDefaultMethodSpec(method, mirror, true, null);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java	Mon Apr 15 18:50:19 2013 +0200
@@ -40,7 +40,7 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        return createDefaultMethodSpec(method, mirror, null);
+        return createDefaultMethodSpec(method, mirror, true, null);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java	Mon Apr 15 18:50:19 2013 +0200
@@ -29,15 +29,17 @@
 public class ActualParameter {
 
     private final ParameterSpec specification;
-    private final TypeMirror actualType;
+    private TypeData typeSystemType;
     private TemplateMethod method;
     private final String localName;
     private final int index;
     private final boolean implicit;
+    private final TypeMirror type;
 
     public ActualParameter(ParameterSpec specification, TypeMirror actualType, int index, boolean implicit) {
         this.specification = specification;
-        this.actualType = actualType;
+        this.type = actualType;
+        this.typeSystemType = null;
 
         this.index = index;
         this.implicit = implicit;
@@ -49,7 +51,12 @@
         this.localName = valueName;
     }
 
-    public ActualParameter(ActualParameter parameter, TypeMirror otherType) {
+    public ActualParameter(ParameterSpec specification, TypeData actualType, int index, boolean implicit) {
+        this(specification, actualType.getPrimitiveType(), index, implicit);
+        this.typeSystemType = actualType;
+    }
+
+    public ActualParameter(ActualParameter parameter, TypeData otherType) {
         this(parameter.specification, otherType, parameter.index, parameter.implicit);
     }
 
@@ -77,12 +84,12 @@
         return method;
     }
 
-    public TypeMirror getActualType() {
-        return actualType;
+    public TypeMirror getType() {
+        return type;
     }
 
-    public TypeData getActualTypeData(TypeSystemData typeSystem) {
-        return typeSystem.findTypeData(actualType);
+    public TypeData getTypeSystemType() {
+        return typeSystemType;
     }
 
     public ActualParameter getPreviousParameter() {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java	Mon Apr 15 18:50:19 2013 +0200
@@ -60,8 +60,9 @@
         optional.add(spec);
     }
 
-    public void addRequired(ParameterSpec spec) {
+    public ParameterSpec addRequired(ParameterSpec spec) {
         required.add(spec);
+        return spec;
     }
 
     public List<TypeMirror> getImplicitRequiredTypes() {
@@ -80,10 +81,6 @@
         return optional;
     }
 
-    public void makeTypeDefinitions() {
-
-    }
-
     public List<ParameterSpec> getAll() {
         List<ParameterSpec> specs = new ArrayList<>();
         specs.add(getReturnType());
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Mon Apr 15 18:50:19 2013 +0200
@@ -188,13 +188,17 @@
         return prev;
     }
 
-    public List<TypeData> getSignature(TypeSystemData typeSystem) {
+    public TypeData getReturnSignature() {
+        return getReturnType().getTypeSystemType();
+    }
+
+    public List<TypeData> getSignature() {
         List<TypeData> types = new ArrayList<>();
-        for (ActualParameter parameter : getReturnTypeAndParameters()) {
+        for (ActualParameter parameter : getParameters()) {
             if (!parameter.getSpecification().isSignature()) {
                 continue;
             }
-            TypeData typeData = parameter.getActualTypeData(typeSystem);
+            TypeData typeData = parameter.getTypeSystemType();
             if (typeData != null) {
                 types.add(typeData);
             }
@@ -222,14 +226,27 @@
         return compare;
     }
 
+    public List<ActualParameter> getParametersAfter(ActualParameter genericParameter) {
+        boolean found = false;
+        List<ActualParameter> foundParameters = new ArrayList<>();
+        for (ActualParameter param : getParameters()) {
+            if (param.getLocalName().equals(genericParameter.getLocalName())) {
+                found = true;
+            } else if (found) {
+                foundParameters.add(param);
+            }
+        }
+        return foundParameters;
+    }
+
     public int compareBySignature(TemplateMethod compareMethod) {
         TypeSystemData typeSystem = getTemplate().getTypeSystem();
         if (typeSystem != compareMethod.getTemplate().getTypeSystem()) {
             throw new IllegalStateException("Cannot compare two methods with different type systems.");
         }
 
-        List<TypeData> signature1 = getSignature(typeSystem);
-        List<TypeData> signature2 = compareMethod.getSignature(typeSystem);
+        List<TypeData> signature1 = getSignature();
+        List<TypeData> signature2 = compareMethod.getSignature();
         if (signature1.size() != signature2.size()) {
             return signature2.size() - signature1.size();
         }
@@ -244,6 +261,12 @@
                 return 0;
             }
         }
+        if (result == 0) {
+            TypeData returnSignature1 = getReturnSignature();
+            TypeData returnSignature2 = compareMethod.getReturnSignature();
+
+            result = compareActualParameter(typeSystem, returnSignature1, returnSignature2);
+        }
 
         return result;
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Mon Apr 15 18:50:19 2013 +0200
@@ -34,6 +34,7 @@
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
+import com.oracle.truffle.codegen.processor.typesystem.*;
 
 public abstract class TemplateMethodParser<T extends Template, E extends TemplateMethod> {
 
@@ -69,6 +70,10 @@
         return context;
     }
 
+    public TypeSystemData getTypeSystem() {
+        return template.getTypeSystem();
+    }
+
     public abstract MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror);
 
     public abstract E create(TemplateMethod method);
@@ -263,16 +268,22 @@
         return parsedParams;
     }
 
-    private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template typeSystem, int index, boolean implicit) {
+    private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template originalTemplate, int index, boolean implicit) {
         TypeMirror resolvedType = mirror;
         if (hasError(resolvedType)) {
-            resolvedType = context.resolveNotYetCompiledType(mirror, typeSystem);
+            resolvedType = context.resolveNotYetCompiledType(mirror, originalTemplate);
         }
 
         if (!specification.matches(resolvedType)) {
             return null;
         }
-        return new ActualParameter(specification, resolvedType, index, implicit);
+
+        TypeData resolvedTypeData = getTypeSystem().findTypeData(resolvedType);
+        if (resolvedTypeData != null) {
+            return new ActualParameter(specification, resolvedTypeData, index, implicit);
+        } else {
+            return new ActualParameter(specification, resolvedType, index, implicit);
+        }
     }
 
     /* Helper class for parsing. */
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java	Mon Apr 15 18:50:19 2013 +0200
@@ -46,12 +46,12 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        MethodSpec spec = createDefaultMethodSpec(method, mirror, null);
+        MethodSpec spec = createDefaultMethodSpec(method, mirror, true, null);
         spec.setVariableRequiredArguments(true);
         spec.getRequired().clear();
 
         for (ActualParameter parameter : specialization.getRequiredParameters()) {
-            ParameterSpec paramSpec = new ParameterSpec(parameter.getLocalName(), parameter.getActualType(), getNode().getTypeSystem().getGenericType());
+            ParameterSpec paramSpec = new ParameterSpec(parameter.getLocalName(), parameter.getType(), getNode().getTypeSystem().getGenericType());
             paramSpec.setSignature(true);
             spec.addRequired(paramSpec);
         }
@@ -82,7 +82,7 @@
             if (specializationParameter == null) {
                 newParameters.add(parameter);
             } else {
-                newParameters.add(new ActualParameter(specializationParameter.getSpecification(), parameter.getActualType(), specializationParameter.getIndex(), parameter.isImplicit()));
+                newParameters.add(new ActualParameter(specializationParameter.getSpecification(), parameter.getTypeSystemType(), specializationParameter.getIndex(), parameter.isImplicit()));
             }
         }
         guard.setParameters(newParameters);
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java	Mon Apr 15 18:50:19 2013 +0200
@@ -51,7 +51,7 @@
     public TypeCastData create(TemplateMethod method) {
         TypeData targetType = findTypeByMethodName(method, "as");
         ActualParameter parameter = method.findParameter("valueValue");
-        return new TypeCastData(method, parameter.getActualTypeData(getTypeSystem()), targetType);
+        return new TypeCastData(method, parameter.getTypeSystemType(), targetType);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java	Mon Apr 15 18:50:19 2013 +0200
@@ -53,7 +53,7 @@
         assert checkedType != null;
         ActualParameter parameter = method.findParameter("valueValue");
         assert parameter != null;
-        return new TypeCheckData(method, checkedType, parameter.getActualTypeData(getTypeSystem()));
+        return new TypeCheckData(method, checkedType, parameter.getTypeSystemType());
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java	Mon Apr 15 18:50:19 2013 +0200
@@ -110,4 +110,19 @@
         return Utils.typeEquals(boxedType, actualTypeData.boxedType);
     }
 
+    public boolean needsCastTo(TypeData targetType) {
+        if (this.equals(targetType)) {
+            return false;
+        } else if (targetType.isGeneric()) {
+            return false;
+        } else if (targetType.isVoid()) {
+            return false;
+        }
+        return true;
+    }
+
+    public boolean isPrimitive() {
+        return Utils.isPrimitive(getPrimitiveType());
+    }
+
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java	Mon Apr 08 18:28:41 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java	Mon Apr 15 18:50:19 2013 +0200
@@ -34,10 +34,6 @@
         super(context, typeSystem);
     }
 
-    public TypeSystemData getTypeSystem() {
-        return template;
-    }
-
     @Override
     public final boolean isParsable(ExecutableElement method) {
         return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null;