changeset 10600:e93efe3ba5f4

Truffle-DSL: rewritten polymorphic optimization for simpler generated code.
author Christian Humer <christian.humer@gmail.com>
date Tue, 02 Jul 2013 14:51:05 +0200
parents ebf5c5c23564
children 5acc3f3016b7
files graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeData.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemParser.java
diffstat 6 files changed, 214 insertions(+), 160 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Mon Jul 01 21:08:20 2013 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Tue Jul 02 14:51:05 2013 +0200
@@ -35,8 +35,10 @@
 import com.oracle.truffle.api.nodes.NodeInfo.Kind;
 import com.oracle.truffle.dsl.processor.*;
 import com.oracle.truffle.dsl.processor.ast.*;
-import com.oracle.truffle.dsl.processor.node.NodeChildData.*;
+import com.oracle.truffle.dsl.processor.node.NodeChildData.Cardinality;
+import com.oracle.truffle.dsl.processor.node.NodeChildData.ExecutionKind;
 import com.oracle.truffle.dsl.processor.template.*;
+import com.oracle.truffle.dsl.processor.template.TemplateMethod.*;
 import com.oracle.truffle.dsl.processor.typesystem.*;
 
 public class NodeCodeGenerator extends CompilationUnitFactory<NodeData> {
@@ -77,11 +79,10 @@
         }
 
         String name = Utils.firstLetterUpperCase(nodeid);
-        int index = specialization == null ? 0 : node.getPolymorphicSpecializations().indexOf(specialization);
-        if (index == 0) {
+        if (specialization == node.getGenericPolymorphicSpecializtion()) {
             name += "PolymorphicNode";
         } else {
-            name += "Polymorphic" + index + "Node";
+            name += "Polymorphic" + polymorphicIndex(node, specialization) + "Node";
         }
         return name;
     }
@@ -98,6 +99,30 @@
         return valueName(parameter) + "Cast";
     }
 
+    private static String executeCachedName(SpecializationData polymorphic) {
+        NodeData node = polymorphic.getNode();
+        boolean generic = polymorphic == node.getGenericPolymorphicSpecializtion();
+
+        if (generic) {
+            return "executeCachedGeneric0";
+        } else {
+            return "executeCached" + polymorphicIndex(node, polymorphic);
+        }
+    }
+
+    private static int polymorphicIndex(NodeData node, SpecializationData polymorphic) {
+        int index = 0;
+        for (SpecializationData specialization : node.getPolymorphicSpecializations()) {
+            if (specialization == polymorphic) {
+                break;
+            }
+            if (specialization != node.getGenericPolymorphicSpecializtion()) {
+                index++;
+            }
+        }
+        return index;
+    }
+
     private void addInternalValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame, boolean evaluated) {
         if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) {
             method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue"));
@@ -660,15 +685,17 @@
 
                 createFactoryMethods(node, clazz, createVisibility);
 
-                PolymorphicNodeFactory generic = null;
-                for (SpecializationData specialization : node.getPolymorphicSpecializations()) {
-                    PolymorphicNodeFactory polymorphicFactory = new PolymorphicNodeFactory(context, generic == null ? generatedNode : generic.getElement(), generic == null);
-                    add(polymorphicFactory, specialization);
-                    if (generic == null) {
-                        generic = polymorphicFactory;
+                if (node.getPolymorphicDepth() > 1) {
+                    PolymorphicNodeFactory generic = new PolymorphicNodeFactory(getContext(), generatedNode, true);
+                    add(generic, node.getGenericPolymorphicSpecializtion());
+
+                    for (SpecializationData specialization : node.getPolymorphicSpecializations()) {
+                        if (specialization == node.getGenericPolymorphicSpecializtion()) {
+                            continue;
+                        }
+                        add(new PolymorphicNodeFactory(context, generic.getElement(), false), specialization);
                     }
                 }
-
                 for (SpecializationData specialization : node.getSpecializations()) {
                     if (!specialization.isReachable()) {
                         continue;
@@ -1044,10 +1071,6 @@
             return clazz;
         }
 
-        protected String typeGetterName(ActualParameter parameter) {
-            return "get" + Utils.firstLetterUpperCase(parameter.getLocalName()) + "Type";
-        }
-
         @Override
         protected void createChildren(SpecializationData specialization) {
             NodeData node = specialization.getNode();
@@ -1067,17 +1090,17 @@
                     builder.statement("this.next0 = adoptChild(next0)");
                     clazz.add(setter);
 
-                    createTypeGetters(clazz, node.getGenericSpecialization());
+                    createIsCompatible(clazz, null);
 
                     clazz.add(createCreateSpecialization(node));
 
-                    CodeExecutableElement genericCachedExecute = null;
+                    CodeExecutableElement genericCachedExecute = createCachedExecute(node, node.getGenericPolymorphicSpecializtion(), null);
+                    clazz.add(genericCachedExecute);
                     for (SpecializationData polymorph : node.getPolymorphicSpecializations()) {
-                        CodeExecutableElement cachedExecute = createCachedExecute(node, polymorph, genericCachedExecute);
-                        clazz.add(cachedExecute);
-                        if (genericCachedExecute == null) {
-                            genericCachedExecute = cachedExecute;
+                        if (polymorph == node.getGenericPolymorphicSpecializtion()) {
+                            continue;
                         }
+                        clazz.add(createCachedExecute(node, polymorph, genericCachedExecute));
                     }
                 }
 
@@ -1142,31 +1165,59 @@
             return method;
         }
 
-        protected void createTypeGetters(CodeTypeElement clazz, SpecializationData specialization) {
-            for (ActualParameter parameter : specialization.getReturnTypeAndParameters()) {
-                if (!parameter.getSpecification().isSignature()) {
-                    continue;
+        protected void createIsCompatible(CodeTypeElement clazz, SpecializationData specialization) {
+            CodeExecutableElement isCompatible = new CodeExecutableElement(modifiers(PROTECTED), context.getType(boolean.class), "isCompatible0");
+            isCompatible.addParameter(new CodeVariableElement(getContext().getType(Class.class), "type"));
+
+            if (specialization == null) {
+                isCompatible.getModifiers().add(ABSTRACT);
+            } else if (specialization.isGeneric()) {
+                isCompatible.createBuilder().startThrow().startNew(getContext().getType(AssertionError.class)).end().end();
+            } else if (specialization.isPolymorphic()) {
+                isCompatible.createBuilder().startReturn().string("type != getClass() && next0.isCompatible0(type)").end();
+            } else if (specialization.isUninitialized()) {
+                isCompatible.createBuilder().returnTrue();
+            } else {
+                NodeData node = specialization.getNode();
+                CodeTreeBuilder builder = isCompatible.createBuilder();
+
+                Signature specializationSignature = specialization.getSignature();
+                List<SpecializationData> compatible = new ArrayList<>();
+                for (SpecializationData polymorphic : node.getPolymorphicSpecializations()) {
+                    if (specializationSignature.isCompatibleTo(polymorphic.getSignature())) {
+                        compatible.add(polymorphic);
+                    }
                 }
-                CodeExecutableElement typeGetter = new CodeExecutableElement(modifiers(PROTECTED), context.getType(Class.class), typeGetterName(parameter));
-                CodeTreeBuilder builder = typeGetter.createBuilder();
-                builder.startReturn().typeLiteral(parameter.getType()).end();
-                clazz.add(typeGetter);
+
+                if (compatible.isEmpty()) {
+                    builder.returnFalse();
+                } else {
+                    builder.startIf();
+                    String and = "";
+                    for (SpecializationData polymorphic : compatible) {
+                        builder.string(and);
+                        builder.string("type == ").string(nodePolymorphicClassName(node, polymorphic)).string(".class");
+                        and = " || ";
+                    }
+                    builder.end().startBlock();
+                    builder.startReturn().startCall("next0", "isCompatible0").string("type").end().end();
+                    builder.end();
+                    builder.returnFalse();
+                }
             }
+
+            clazz.add(isCompatible);
         }
 
         private CodeExecutableElement createCachedExecute(NodeData node, SpecializationData polymorph, CodeExecutableElement genericPolymorphMethod) {
-            int index = node.getPolymorphicSpecializations().indexOf(polymorph);
-            assert index != -1;
-            boolean generic = index == 0;
-
-            String name = "executeCached" + index;
+            String name = executeCachedName(polymorph);
             CodeExecutableElement cachedExecute = new CodeExecutableElement(modifiers(PROTECTED), polymorph.getReturnType().getType(), name);
             addInternalValueParameters(cachedExecute, polymorph, true, true);
 
-            if (generic) {
+            if (polymorph == node.getGenericPolymorphicSpecializtion()) {
                 cachedExecute.getModifiers().add(ABSTRACT);
             } else {
-                SpecializationData genericPolymorph = node.getPolymorphicSpecializations().get(0);
+                SpecializationData genericPolymorph = node.getGenericPolymorphicSpecializtion();
                 CodeTreeBuilder builder = cachedExecute.createBuilder();
                 ExecutableTypeData genericExecutable = new ExecutableTypeData(genericPolymorph, genericPolymorphMethod, node.getTypeSystem(), genericPolymorph.getReturnType().getTypeSystemType());
                 ExecutableTypeData specificExecutable = new ExecutableTypeData(polymorph, cachedExecute, node.getTypeSystem(), polymorph.getReturnType().getTypeSystemType());
@@ -1476,7 +1527,7 @@
                         builder.startWhile().string("searchNode != null").end();
                         builder.startBlock();
                         builder.statement("searchNode = searchNode.getParent()");
-                        builder.startIf().instanceOf("searchNode", nodePolymorphicClassName(node, node.getPolymorphicSpecializations().get(0))).end();
+                        builder.startIf().instanceOf("searchNode", nodePolymorphicClassName(node, node.getGenericPolymorphicSpecializtion())).end();
                         builder.startBlock().breakStatement().end();
                         builder.end();
                         builder.startStatement().startCall("searchNode", "replace");
@@ -1535,11 +1586,12 @@
         }
 
         private CodeTree createRewritePolymorphic(CodeTreeBuilder parent, NodeData node) {
+            String className = nodePolymorphicClassName(node, node.getGenericPolymorphicSpecializtion());
             CodeTreeBuilder builder = parent.create();
             builder.startStatement();
-            builder.string(nodePolymorphicClassName(node, null));
+            builder.string(className);
             builder.string(" polymorphic = ");
-            builder.startNew(nodePolymorphicClassName(node, null)).string("this").end();
+            builder.startNew(className).string("this").end();
             builder.end();
             for (NodeChildData child : node.getChildren()) {
                 builder.startStatement().string("this.").string(child.getName()).string(" = null").end();
@@ -1776,13 +1828,13 @@
         private CodeTree createReturnOptimizeTypes(CodeTreeBuilder parent, SpecializationData specialization, ActualParameter param) {
             NodeData node = specialization.getNode();
             assert !node.getPolymorphicSpecializations().isEmpty();
-            SpecializationData generic = node.getPolymorphicSpecializations().get(0);
+            SpecializationData generic = node.getGenericPolymorphicSpecializtion();
 
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             builder.startReturn();
 
             CodeTreeBuilder execute = new CodeTreeBuilder(builder);
-            execute.startCall("next0", "executeCached0");
+            execute.startCall("next0", executeCachedName(generic));
             addInternalValueParameterNames(execute, specialization, generic, param.getLocalName(), true, true);
             execute.end();
 
@@ -1965,7 +2017,6 @@
 
         @Override
         protected void createChildren(SpecializationData specialization) {
-// super.createChildren(specialization);
             CodeTypeElement clazz = getElement();
 
             createConstructors(clazz);
@@ -1974,6 +2025,7 @@
             if (generic) {
                 getElement().add(createOptimizeTypes());
                 createCachedExecuteMethods(specialization);
+                createIsCompatible(clazz, specialization);
             }
         }
 
@@ -1981,65 +2033,31 @@
             NodeData node = getModel().getNode();
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), getContext().getType(void.class), "optimizeTypes");
             CodeTreeBuilder builder = method.createBuilder();
-            builder.startStatement().string(baseClassName(node)).string(" node = this.next0").end();
-            TypeMirror classType = getContext().getType(Class.class);
-
-            SpecializationData genericSpecialization = node.getGenericSpecialization();
-
-            CodeTreeBuilder whileBodyBuilder = builder.create();
-            for (ActualParameter parameter : node.getGenericSpecialization().getReturnTypeAndParameters()) {
-                if (!parameter.getSpecification().isSignature()) {
-                    continue;
-                }
-
-                ActualParameter genericParameter = genericSpecialization.findParameter(parameter.getLocalName());
-
-                String name = parameter.getLocalName() + "Type";
-
-                builder.declaration(classType, name, builder.create().startCall("node", typeGetterName(parameter)).end().getRoot());
-
-                whileBodyBuilder.startIf().string(name).string(" != ").startCall("node", typeGetterName(parameter)).end().end();
-                whileBodyBuilder.startBlock();
-                whileBodyBuilder.startStatement().string(name).string(" = ").typeLiteral(genericParameter.getType()).end();
-                whileBodyBuilder.end();
-            }
-
-            builder.startWhile().string("node != null && !(").instanceOf("node", nodeSpecializationClassName(node.getUninitializedSpecialization())).string(")").end();
-            builder.startBlock();
-            builder.tree(whileBodyBuilder.getRoot());
-            builder.statement("node = node.next0");
-            builder.end();
 
             boolean elseIf = false;
-            for (SpecializationData polymorph : node.getPolymorphicSpecializations()) {
-                elseIf = builder.startIf(elseIf);
-                String and = "";
+            for (SpecializationData polymorphic : node.getPolymorphicSpecializations()) {
+                String className = nodePolymorphicClassName(node, polymorphic);
+
+                String sep = "";
                 StringBuilder reason = new StringBuilder("Optimized polymorphic types for (");
-                for (ActualParameter parameter : polymorph.getReturnTypeAndParameters()) {
+                for (ActualParameter parameter : polymorphic.getReturnTypeAndParameters()) {
                     if (!parameter.getSpecification().isSignature()) {
                         continue;
                     }
-                    String name = parameter.getLocalName() + "Type";
-                    builder.string(and).string(name).string(" == ").typeLiteral(parameter.getType());
-
-                    if (!and.isEmpty()) {
-                        reason.append(", ");
-                    }
-                    reason.append(Utils.getSimpleName(parameter.getType()));
-                    and = " && ";
+                    reason.append(sep).append(Utils.getSimpleName(parameter.getType()));
+                    sep = ", ";
                 }
                 reason.append(")");
-                builder.end();
-                builder.startBlock();
 
-                String className = nodePolymorphicClassName(node, polymorph);
-                builder.startIf().string("getClass() != ").string(className).string(".class").end();
-                builder.startBlock();
+                elseIf = builder.startIf(elseIf);
+                builder.startCall("isCompatible0");
+                builder.startGroup().string(className).string(".class").end();
+                builder.end().end().startBlock();
+
                 builder.startStatement().startCall("super", "replace");
                 builder.startNew(className).string("this").end();
                 builder.doubleQuote(reason.toString());
                 builder.end().end(); // call
-                builder.end(); // block
                 builder.end();
             }
             return method;
@@ -2098,9 +2116,8 @@
 
             NodeData node = specialization.getNode();
 
-            if (!specialization.isGeneric() && !specialization.isUninitialized() && !specialization.isPolymorphic() && node.needsRewrites(getContext()) && node.getPolymorphicDepth() > 1) {
-
-                createTypeGetters(clazz, specialization);
+            if (node.needsRewrites(getContext()) && node.getPolymorphicDepth() > 1) {
+                createIsCompatible(clazz, specialization);
             }
 
             createExecuteMethods(specialization);
@@ -2152,45 +2169,39 @@
         protected void createCachedExecuteMethods(SpecializationData specialization) {
             NodeData node = specialization.getNode();
             CodeTypeElement clazz = getElement();
-            int index = 0;
             for (SpecializationData polymorphic : node.getPolymorphicSpecializations()) {
-                boolean matchFound = false;
-                if (!specialization.isGeneric() && !specialization.isUninitialized() && !specialization.isPolymorphic()) {
-                    matchFound = polymorphic.getSignature().hasAnyParameterMatch(specialization.getSignature());
+                if (!specialization.getSignature().isCompatibleTo(polymorphic.getSignature())) {
+                    continue;
                 }
+                ExecutableElement executeCached = nodeGen.getMethod(executeCachedName(polymorphic));
+                ExecutableTypeData execType = new ExecutableTypeData(polymorphic, executeCached, node.getTypeSystem(), polymorphic.getReturnType().getTypeSystemType());
 
-                if (matchFound || index == 0) {
-                    ExecutableElement executeCached = nodeGen.getMethod("executeCached" + index);
-                    ExecutableTypeData execType = new ExecutableTypeData(polymorphic, executeCached, node.getTypeSystem(), polymorphic.getReturnType().getTypeSystemType());
-
-                    CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, false);
-                    CodeTreeBuilder builder = executeMethod.createBuilder();
+                CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, false);
+                CodeTreeBuilder builder = executeMethod.createBuilder();
 
-                    if (specialization.isGeneric() || specialization.isPolymorphic()) {
-                        builder.startThrow().startNew(getContext().getType(AssertionError.class));
-                        builder.doubleQuote("Should not be reached.");
-                        builder.end().end();
-                    } else if (specialization.isUninitialized()) {
-                        builder.tree(createAppendPolymorphic(builder, specialization));
-                    } else {
-                        CodeTreeBuilder elseBuilder = new CodeTreeBuilder(builder);
-                        elseBuilder.startReturn().startCall("this.next0", "executeCached" + index);
-                        addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, true);
-                        elseBuilder.end().end();
-                        CodeTreeBuilder execute = new CodeTreeBuilder(builder);
-                        execute.tree(createGenericInvoke(builder, polymorphic, specialization));
-                        boolean forceElse = !specialization.getExceptions().isEmpty();
-                        builder.tree(createGuardAndCast(builder, null, polymorphic, specialization, true, execute.getRoot(), elseBuilder.getRoot(), true, forceElse));
-                    }
-                    clazz.add(executeMethod);
+                if (specialization.isGeneric() || specialization.isPolymorphic()) {
+                    builder.startThrow().startNew(getContext().getType(AssertionError.class));
+                    builder.doubleQuote("Should not be reached.");
+                    builder.end().end();
+                } else if (specialization.isUninitialized()) {
+                    builder.tree(createAppendPolymorphic(builder, specialization));
+                } else {
+                    CodeTreeBuilder elseBuilder = new CodeTreeBuilder(builder);
+                    elseBuilder.startReturn().startCall("this.next0", executeCachedName(polymorphic));
+                    addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, true);
+                    elseBuilder.end().end();
+                    CodeTreeBuilder execute = new CodeTreeBuilder(builder);
+                    execute.tree(createGenericInvoke(builder, polymorphic, specialization));
+                    boolean forceElse = !specialization.getExceptions().isEmpty();
+                    builder.tree(createGuardAndCast(builder, null, polymorphic, specialization, true, execute.getRoot(), elseBuilder.getRoot(), true, forceElse));
                 }
-                index++;
+                clazz.add(executeMethod);
             }
         }
 
         private CodeTree createAppendPolymorphic(CodeTreeBuilder parent, SpecializationData specialization) {
             NodeData node = specialization.getNode();
-            String genericClassName = nodePolymorphicClassName(node, null);
+            String genericClassName = nodePolymorphicClassName(node, node.getGenericPolymorphicSpecializtion());
 
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end();
@@ -2376,11 +2387,7 @@
 
             CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent);
             if (specialization.isPolymorphic()) {
-                int index = 0;
-                if (executable.hasUnexpectedValue(getContext())) {
-                    index = specialization.getNode().getPolymorphicSpecializations().indexOf(specialization);
-                }
-                returnBuilder.startCall("next0", "executeCached" + index);
+                returnBuilder.startCall("next0", executeCachedName(specialization));
                 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true);
                 returnBuilder.end();
             } else if (specialization.isUninitialized()) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java	Mon Jul 01 21:08:20 2013 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java	Tue Jul 02 14:51:05 2013 +0200
@@ -47,6 +47,7 @@
 
     private List<SpecializationData> specializations;
     private List<SpecializationData> polymorphicSpecializations;
+    private SpecializationData genericPolymoprhicSpecialization;
     private List<SpecializationListenerData> specializationListeners;
     private Map<Integer, List<ExecutableTypeData>> executableTypes;
     private List<ShortCircuitData> shortCircuits;
@@ -521,6 +522,14 @@
         return polymorphicSpecializations;
     }
 
+    void setGenericPolymoprhicSpecialization(SpecializationData genericPolymoprhicSpecialization) {
+        this.genericPolymoprhicSpecialization = genericPolymoprhicSpecialization;
+    }
+
+    public SpecializationData getGenericPolymorphicSpecializtion() {
+        return genericPolymoprhicSpecialization;
+    }
+
     void setSpecializationListeners(List<SpecializationListenerData> specializationListeners) {
         this.specializationListeners = specializationListeners;
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java	Mon Jul 01 21:08:20 2013 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java	Tue Jul 02 14:51:05 2013 +0200
@@ -33,9 +33,10 @@
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.dsl.processor.*;
-import com.oracle.truffle.dsl.processor.node.NodeChildData.*;
+import com.oracle.truffle.dsl.processor.node.NodeChildData.Cardinality;
+import com.oracle.truffle.dsl.processor.node.NodeChildData.ExecutionKind;
 import com.oracle.truffle.dsl.processor.template.*;
-import com.oracle.truffle.dsl.processor.template.TemplateMethod.*;
+import com.oracle.truffle.dsl.processor.template.TemplateMethod.Signature;
 import com.oracle.truffle.dsl.processor.typesystem.*;
 
 public class NodeParser extends TemplateParser<NodeData> {
@@ -200,7 +201,7 @@
         for (NodeData splittedNode : nodes) {
             finalizeSpecializations(elements, splittedNode);
             verifyNode(splittedNode, elements);
-            splittedNode.setPolymorphicSpecializations(createPolymorphicSpecializations(splittedNode));
+            createPolymorphicSpecializations(splittedNode);
             assignShortCircuitsToSpecializations(splittedNode);
         }
 
@@ -212,13 +213,14 @@
         return node;
     }
 
-    private List<SpecializationData> createPolymorphicSpecializations(NodeData node) {
+    private void createPolymorphicSpecializations(NodeData node) {
         if (!node.needsRewrites(context) || node.getPolymorphicDepth() <= 1) {
-            return Collections.emptyList();
+            node.setPolymorphicSpecializations(Collections.<SpecializationData> emptyList());
+            return;
         }
 
         Signature genericSignature = node.getGenericSpecialization().getSignature();
-        Set<Signature> signatures = new HashSet<>();
+        Set<Signature> signatures = new TreeSet<>();
 
         for (SpecializationData specialization1 : node.getSpecializations()) {
             Signature signature = specialization1.getSignature();
@@ -247,8 +249,8 @@
         }
 
         List<Signature> sortedSignatures = new ArrayList<>(signatures);
-        Collections.sort(sortedSignatures);
 
+        SpecializationData polymorphicGeneric = null;
         List<SpecializationData> specializations = new ArrayList<>();
         SpecializationData generic = node.getGenericSpecialization();
         for (Signature signature : sortedSignatures) {
@@ -256,15 +258,15 @@
             specialization.forceFrame(context.getTruffleTypes().getFrame());
             specialization.setNode(node);
             specialization.updateSignature(signature);
+            specializations.add(specialization);
 
-            if (specialization.isGenericSpecialization(context)) {
-                specializations.add(0, specialization);
-            } else {
-                specializations.add(specialization);
+            if (genericSignature.equals(signature)) {
+                polymorphicGeneric = specialization;
             }
         }
 
-        return specializations;
+        node.setGenericPolymoprhicSpecialization(polymorphicGeneric);
+        node.setPolymorphicSpecializations(specializations);
     }
 
     private NodeData parseNodeData(TypeElement templateType, TypeMirror nodeType, List<? extends Element> elements, List<TypeElement> lookupTypes) {
@@ -1071,7 +1073,7 @@
     }
 
     private static Map<Integer, List<ExecutableTypeData>> groupExecutableTypes(List<ExecutableTypeData> executableTypes) {
-        Map<Integer, List<ExecutableTypeData>> groupedTypes = new HashMap<>();
+        Map<Integer, List<ExecutableTypeData>> groupedTypes = new TreeMap<>();
         for (ExecutableTypeData type : executableTypes) {
             int evaluatedCount = type.getEvaluatedCount();
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java	Mon Jul 01 21:08:20 2013 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java	Tue Jul 02 14:51:05 2013 +0200
@@ -28,6 +28,7 @@
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.dsl.processor.*;
+import com.oracle.truffle.dsl.processor.template.TemplateMethod.Signature;
 import com.oracle.truffle.dsl.processor.typesystem.*;
 
 /**
@@ -315,23 +316,6 @@
             return types.hashCode();
         }
 
-        public int compareTo(Signature o) {
-            if (o.size() != size()) {
-                return size() - o.size();
-            }
-
-            int typeSum = 0;
-            int otherTypeSum = 0;
-            for (int i = 0; i < types.size(); i++) {
-                TypeData type = types.get(i);
-                TypeData otherType = o.get(i);
-                typeSum += type.isGeneric() ? 1 : 0;
-                otherTypeSum += otherType.isGeneric() ? 1 : 0;
-            }
-
-            return typeSum - otherTypeSum;
-        }
-
         public int size() {
             return types.size();
         }
@@ -340,6 +324,28 @@
             return types.get(index);
         }
 
+        public int compareTo(Signature other) {
+            if (this == other) {
+                return 0;
+            } else if (types.size() != other.types.size()) {
+                return types.size() - other.types.size();
+            } else if (types.isEmpty()) {
+                return 0;
+            }
+
+            for (int i = 0; i < types.size(); i++) {
+                TypeData type1 = types.get(i);
+                TypeData type2 = other.types.get(i);
+
+                int comparison = type1.compareTo(type2);
+                if (comparison != 0) {
+                    return comparison;
+                }
+            }
+
+            return 0;
+        }
+
         public Signature combine(Signature genericSignature, Signature other) {
             assert types.size() == other.types.size();
             assert genericSignature.types.size() == other.types.size();
@@ -388,6 +394,25 @@
             }
             return false;
         }
+
+        public boolean isCompatibleTo(Signature signature) {
+            if (size() != signature.size()) {
+                return false;
+            }
+
+            for (int i = 0; i < size(); i++) {
+                TypeData o1 = get(i);
+                TypeData o2 = signature.get(i);
+                if (o1.equals(o2)) {
+                    continue;
+                } else if (o2.isGeneric()) {
+                    continue;
+                } else {
+                    return false;
+                }
+            }
+            return true;
+        }
     }
 
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeData.java	Mon Jul 01 21:08:20 2013 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeData.java	Tue Jul 02 14:51:05 2013 +0200
@@ -30,17 +30,19 @@
 import com.oracle.truffle.dsl.processor.*;
 import com.oracle.truffle.dsl.processor.template.*;
 
-public class TypeData extends MessageContainer {
+public class TypeData extends MessageContainer implements Comparable<TypeData> {
 
     private final TypeSystemData typeSystem;
     private final AnnotationValue annotationValue;
     private final TypeMirror primitiveType;
     private final TypeMirror boxedType;
 
+    private final int index;
     private final List<TypeCastData> typeCasts = new ArrayList<>();
     private final List<TypeCheckData> typeChecks = new ArrayList<>();
 
-    public TypeData(TypeSystemData typeSystem, AnnotationValue value, TypeMirror primitiveType, TypeMirror boxedType) {
+    public TypeData(TypeSystemData typeSystem, int index, AnnotationValue value, TypeMirror primitiveType, TypeMirror boxedType) {
+        this.index = index;
         this.typeSystem = typeSystem;
         this.annotationValue = value;
         this.primitiveType = primitiveType;
@@ -101,6 +103,13 @@
         return Utils.typeEquals(boxedType, getTypeSystem().getVoidType().getBoxedType());
     }
 
+    public int compareTo(TypeData o) {
+        if (this.equals(o)) {
+            return 0;
+        }
+        return index - o.index;
+    }
+
     @Override
     public String toString() {
         return getClass().getSimpleName() + "[" + Utils.getSimpleName(primitiveType) + "]";
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemParser.java	Mon Jul 01 21:08:20 2013 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemParser.java	Tue Jul 02 14:51:05 2013 +0200
@@ -76,7 +76,7 @@
         }
 
         TypeMirror genericType = context.getType(Object.class);
-        TypeData voidType = new TypeData(typeSystem, null, context.getType(void.class), context.getType(Void.class));
+        TypeData voidType = new TypeData(typeSystem, typeSystem.getTypes().size(), null, context.getType(void.class), context.getType(Void.class));
 
         typeSystem.setGenericType(genericType);
         typeSystem.setVoidType(voidType);
@@ -151,9 +151,10 @@
         final AnnotationValue annotationValue = Utils.getAnnotationValue(typeSystem.getTemplateTypeAnnotation(), "value");
         final TypeMirror objectType = context.getType(Object.class);
 
+        int index = 0;
         for (TypeMirror primitiveType : typeMirrors) {
             TypeMirror boxedType = Utils.boxType(context, primitiveType);
-            TypeData typeData = new TypeData(typeSystem, annotationValue, primitiveType, boxedType);
+            TypeData typeData = new TypeData(typeSystem, index, annotationValue, primitiveType, boxedType);
 
             if (isPrimitiveWrapper(primitiveType)) {
                 typeData.addError("Types must not contain primitive wrapper types.");
@@ -164,11 +165,12 @@
             }
 
             types.add(typeData);
+            index++;
         }
 
         verifyTypeOrder(types);
 
-        types.add(new TypeData(typeSystem, annotationValue, objectType, objectType));
+        types.add(new TypeData(typeSystem, index, annotationValue, objectType, objectType));
 
         return types;
     }