changeset 8242:ac4e8c16ffdf

Added new codegen api classes NodeId, NodeClass to codegen along with some refactorings.
author Christian Humer <christian.humer@gmail.com>
date Mon, 04 Mar 2013 15:14:11 +0100
parents 91982900acee
children d81ff782fa1a
files graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeClass.java graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeId.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/NodeParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerData.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/template/TemplateMethod.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java
diffstat 10 files changed, 402 insertions(+), 218 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeClass.java	Mon Mar 04 15:14:11 2013 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, 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.api.codegen;
+
+import java.lang.annotation.*;
+
+import com.oracle.truffle.api.nodes.*;
+
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.TYPE})
+public @interface NodeClass {
+
+    Class<? extends Node> value();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeId.java	Mon Mar 04 15:14:11 2013 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012, 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.api.codegen;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface NodeId {
+
+    String value();
+
+}
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Mon Mar 04 15:13:25 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Mon Mar 04 15:14:11 2013 +0100
@@ -71,7 +71,7 @@
     private static String specializationId(SpecializationData specialization) {
         String name = "";
         NodeData node = specialization.getNode();
-        if (node.getSpecializations().length > 1) {
+        if (node.getSpecializations().size() > 1) {
             name = specialization.getMethodName();
             if (name.startsWith("do")) {
                 name = name.substring(2);
@@ -480,7 +480,7 @@
             if (node.needsFactory()) {
                 createFactoryMethods(node, clazz, createVisibility);
 
-                if (node.getSpecializations().length > 1) {
+                if (node.getSpecializations().size() > 1) {
                     clazz.add(createCreateSpecializedMethod(node, createVisibility));
                 }
 
@@ -781,10 +781,10 @@
 
             CodeTreeBuilder body = method.createBuilder();
             body.startReturn();
-            if (node.getSpecializations().length == 0) {
+            if (node.getSpecializations().isEmpty()) {
                 body.null_();
             } else {
-                body.startNew(nodeClassName(node.getSpecializations()[0]));
+                body.startNew(nodeClassName(node.getSpecializations().get(0)));
                 for (VariableElement var : method.getParameters()) {
                     body.string(var.getSimpleName().toString());
                 }
@@ -836,10 +836,10 @@
             addValueParameters(method, node.getGenericSpecialization(), false);
 
             CodeTreeBuilder body = method.createBuilder();
-            body.startStatement().string("boolean allowed = (minimumState == ").string(nodeClassName(node.getSpecializations()[0])).string(".class)").end();
+            body.startStatement().string("boolean allowed = (minimumState == ").string(nodeClassName(node.getSpecializations().get(0))).string(".class)").end();
 
-            for (int i = 1; i < node.getSpecializations().length; i++) {
-                SpecializationData specialization = node.getSpecializations()[i];
+            for (int i = 1; i < node.getSpecializations().size(); i++) {
+                SpecializationData specialization = node.getSpecializations().get(i);
                 body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeClassName(specialization)).string(".class)").end();
 
                 CodeTreeBuilder guarded = new CodeTreeBuilder(body);
@@ -859,11 +859,11 @@
             if (node.getGenericSpecialization().isUseSpecializationsForGeneric()) {
                 List<CodeExecutableElement> methods = new ArrayList<>();
 
-                SpecializationData[] specializations = node.getSpecializations();
+                List<SpecializationData> specializations = node.getSpecializations();
                 SpecializationData prev = null;
-                for (int i = 0; i < specializations.length; i++) {
-                    SpecializationData current = specializations[i];
-                    SpecializationData next = i + 1 < specializations.length ? specializations[i + 1] : null;
+                for (int i = 0; i < specializations.size(); i++) {
+                    SpecializationData current = specializations.get(i);
+                    SpecializationData next = i + 1 < specializations.size() ? specializations.get(i + 1) : null;
                     if (prev == null || current.isUninitialized()) {
                         prev = current;
                         continue;
@@ -1195,7 +1195,7 @@
             builder.string(" = ");
             ExecutableTypeData genericExecutableType = field.getNodeData().findGenericExecutableType(getContext(), param.getActualTypeData(node.getTypeSystem()));
             if (genericExecutableType == null) {
-                throw new AssertionError("Must have generic executable type. Parser validation most likely failed. " + Arrays.toString(field.getNodeData().getExecutableTypes()));
+                throw new AssertionError("Must have generic executable type. Parser validation most likely failed. " + (field.getNodeData().getExecutableTypes()));
             }
             buildExecute(builder, param, field, genericExecutableType);
             builder.end();
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Mon Mar 04 15:13:25 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Mon Mar 04 15:14:11 2013 +0100
@@ -35,18 +35,18 @@
 
 public class NodeData extends Template {
 
-    private NodeData parent;
+    private NodeData declaringNode;
     private List<NodeData> declaredChildren;
 
     private final TypeSystemData typeSystem;
+    private List<NodeFieldData> fields;
+    private TypeMirror nodeType;
 
-    private NodeFieldData[] fields;
-    private SpecializationData[] specializations;
-    private TemplateMethod[] specializationListeners;
-    private GuardData[] guards;
-    private ExecutableTypeData[] executableTypes;
-
-    private TypeMirror nodeType;
+    private List<SpecializationData> specializations;
+    private List<SpecializationListenerData> specializationListeners;
+    private List<GuardData> guards;
+    private List<ExecutableTypeData> executableTypes;
+    private List<ShortCircuitData> shortCircuits;
 
     public NodeData(TypeElement type, TypeSystemData typeSystem) {
         super(type, null);
@@ -95,12 +95,12 @@
         this.declaredChildren = declaredChildren;
 
         for (NodeData child : declaredChildren) {
-            child.parent = this;
+            child.declaringNode = this;
         }
     }
 
     public NodeData getParent() {
-        return parent;
+        return declaringNode;
     }
 
     public List<NodeData> getDeclaredChildren() {
@@ -121,17 +121,14 @@
             }
         }
 
-        methods.addAll(Arrays.asList(getSpecializationListeners()));
-        methods.addAll(Arrays.asList(getExecutableTypes()));
-        methods.addAll(Arrays.asList(getGuards()));
+        methods.addAll(getSpecializationListeners());
+        methods.addAll(getExecutableTypes());
+        methods.addAll(getGuards());
+        methods.addAll(getShortCircuits());
 
         return methods;
     }
 
-    public TemplateMethod[] getSpecializationListeners() {
-        return specializationListeners;
-    }
-
     public List<GuardData> findGuards(String name) {
         List<GuardData> foundGuards = new ArrayList<>();
         for (GuardData guardData : getGuards()) {
@@ -142,10 +139,6 @@
         return foundGuards;
     }
 
-    public ExecutableTypeData[] getExecutableTypes() {
-        return executableTypes;
-    }
-
     public ExecutableTypeData findGenericExecutableType(ProcessorContext context, TypeData type) {
         List<ExecutableTypeData> types = findGenericExecutableTypes(context);
         for (ExecutableTypeData availableType : types) {
@@ -189,47 +182,20 @@
         return result;
     }
 
-    public TypeMirror[] getExecutablePrimitiveTypeMirrors() {
-        TypeMirror[] typeMirrors = new TypeMirror[executableTypes.length];
-        for (int i = 0; i < executableTypes.length; i++) {
-            typeMirrors[i] = executableTypes[i].getType().getPrimitiveType();
+    public List<TypeMirror> getExecutablePrimitiveTypeMirrors() {
+        List<TypeMirror> typeMirrors = new ArrayList<>();
+        for (ExecutableTypeData executableType : executableTypes) {
+            typeMirrors.add(executableType.getType().getPrimitiveType());
         }
         return typeMirrors;
     }
 
-    void setExecutableTypes(ExecutableTypeData[] declaredExecuableTypes) {
-        this.executableTypes = declaredExecuableTypes;
-    }
-
-    void setFields(NodeFieldData[] fields) {
-        this.fields = fields;
-    }
-
-    void setSpecializations(SpecializationData[] specializations) {
-        this.specializations = specializations;
-    }
-
-    void setSpecializationListeners(TemplateMethod[] specializationListeners) {
-        this.specializationListeners = specializationListeners;
-    }
-
-    void setGuards(GuardData[] guards) {
-        this.guards = guards;
-    }
-
-    public GuardData[] getGuards() {
-        return guards;
-    }
-
     public NodeFieldData[] filterFields(FieldKind fieldKind, ExecutionKind usage) {
         List<NodeFieldData> filteredFields = new ArrayList<>();
-        NodeFieldData[] resolvedFields = getFields();
-        if (fields != null) {
-            for (NodeFieldData field : resolvedFields) {
-                if (usage == null || field.getExecutionKind() == usage) {
-                    if (fieldKind == null || field.getKind() == fieldKind) {
-                        filteredFields.add(field);
-                    }
+        for (NodeFieldData field : getFields()) {
+            if (usage == null || field.getExecutionKind() == usage) {
+                if (fieldKind == null || field.getKind() == fieldKind) {
+                    filteredFields.add(field);
                 }
             }
         }
@@ -258,7 +224,7 @@
             }
         }
 
-        needsRewrites &= specializations.length >= 2;
+        needsRewrites &= specializations.size() >= 2;
         return needsRewrites;
     }
 
@@ -279,18 +245,6 @@
         }
     }
 
-    public NodeFieldData[] getFields() {
-        return fields;
-    }
-
-    public NodeFieldData[] getDeclaredFields() {
-        return fields;
-    }
-
-    public SpecializationData[] getSpecializations() {
-        return specializations;
-    }
-
     public String dump() {
         StringBuilder b = new StringBuilder();
         b.append(String.format("[name = %s\n" + "  typeSystem = %s\n" + "  fields = %s\n" + "  types = %s\n" + "  specializations = %s\n" + "  guards = %s\n" + "]",
@@ -298,7 +252,7 @@
         return b.toString();
     }
 
-    private static String dumpList(Object[] array) {
+    private static String dumpList(List<?> array) {
         if (array == null) {
             return "null";
         }
@@ -324,4 +278,55 @@
         return null;
     }
 
+    public List<NodeFieldData> getFields() {
+        return fields;
+    }
+
+    void setFields(List<NodeFieldData> fields) {
+        this.fields = fields;
+    }
+
+    public List<SpecializationData> getSpecializations() {
+        return specializations;
+    }
+
+    public List<SpecializationListenerData> getSpecializationListeners() {
+        return specializationListeners;
+    }
+
+    public List<GuardData> getGuards() {
+        return guards;
+    }
+
+    public List<ExecutableTypeData> getExecutableTypes() {
+        return executableTypes;
+    }
+
+    public List<ShortCircuitData> getShortCircuits() {
+        return shortCircuits;
+    }
+
+    void setSpecializations(List<SpecializationData> specializations) {
+        this.specializations = specializations;
+        for (SpecializationData specialization : specializations) {
+            specialization.setNode(this);
+        }
+    }
+
+    void setSpecializationListeners(List<SpecializationListenerData> specializationListeners) {
+        this.specializationListeners = specializationListeners;
+    }
+
+    void setGuards(List<GuardData> guards) {
+        this.guards = guards;
+    }
+
+    void setExecutableTypes(List<ExecutableTypeData> executableTypes) {
+        this.executableTypes = executableTypes;
+    }
+
+    void setShortCircuits(List<ShortCircuitData> shortCircuits) {
+        this.shortCircuits = shortCircuits;
+    }
+
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Mon Mar 04 15:13:25 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Mon Mar 04 15:14:11 2013 +0100
@@ -112,10 +112,13 @@
 
     private NodeData parseNode(TypeElement type) {
         if (Utils.findAnnotationMirror(processingEnv, type, GeneratedBy.class) != null) {
-            // generated nodes get called again.
+            // generated nodes should not get called again.
             return null;
         }
-        if (!Utils.isAssignable(type.asType(), context.getTruffleTypes().getNode())) {
+
+        AnnotationMirror methodNodes = Utils.findAnnotationMirror(processingEnv, type, NodeClass.class);
+
+        if (methodNodes == null && !Utils.isAssignable(type.asType(), context.getTruffleTypes().getNode())) {
             return null; // not a node
         }
 
@@ -123,13 +126,149 @@
             return null; // not visible
         }
 
+        final NodeData nodeData = parseNodeData(type);
+        if (nodeData == null) {
+            // TODO error message for instanceBaseClass?
+            return null;
+        }
+
+        List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type));
+        nodeData.setExtensionElements(getExtensionParser().parseAll(type, elements));
+        if (nodeData.getExtensionElements() != null) {
+            elements.addAll(nodeData.getExtensionElements());
+        }
+
+        if (!parseMethods(nodeData, elements)) {
+            return null;
+        }
+        // TODO split
+
+        if (!finalizeSpecializations(nodeData)) {
+            return null;
+        }
+
+        if (!verifyNode(nodeData)) {
+            return null;
+        }
+
+        return nodeData;
+    }
+
+    private boolean parseMethods(final NodeData node, List<Element> elements) {
+        node.setGuards(new GuardParser(context, node, node.getTypeSystem()).parse(elements));
+        node.setShortCircuits(new ShortCircuitParser(context, node).parse(elements));
+        node.setSpecializationListeners(new SpecializationListenerParser(context, node).parse(elements));
+        List<SpecializationData> generics = new GenericParser(context, node).parse(elements);
+        List<SpecializationData> specializations = new SpecializationMethodParser(context, node).parse(elements);
+
+        if (generics == null || specializations == null || node.getGuards() == null || node.getShortCircuits() == null || node.getSpecializationListeners() == null) {
+            return false;
+        }
+
+        List<SpecializationData> allSpecializations = new ArrayList<>();
+        allSpecializations.addAll(generics);
+        allSpecializations.addAll(specializations);
+
+        node.setSpecializations(allSpecializations);
+
+        return true;
+    }
+
+    private boolean finalizeSpecializations(final NodeData node) {
+        List<SpecializationData> specializations = new ArrayList<>(node.getSpecializations());
+
+        List<SpecializationData> generics = new ArrayList<>();
+        for (SpecializationData spec : specializations) {
+            if (spec.isGeneric()) {
+                generics.add(spec);
+            }
+        }
+
+        SpecializationData genericSpecialization = null;
+        if (generics.size() > 1) {
+            for (SpecializationData generic : generics) {
+                log.error(generic.getMethod(), "Only one method with @%s is allowed per operation.", Generic.class.getSimpleName());
+            }
+            return false;
+        } else if (generics.size() == 1) {
+            genericSpecialization = generics.get(0);
+        }
+
+        if (specializations.size() > 1 && genericSpecialization == null) {
+            log.error(node.getTemplateType(), "Need a @%s method.", Generic.class.getSimpleName());
+            return false;
+        }
+
+        if (genericSpecialization != null) {
+            CodeExecutableElement uninitializedMethod = new CodeExecutableElement(Utils.modifiers(Modifier.PUBLIC), context.getType(void.class), "doUninitialized");
+            TemplateMethod uninializedMethod = new TemplateMethod(genericSpecialization.getId(), node, genericSpecialization.getSpecification(), uninitializedMethod,
+                            genericSpecialization.getMarkerAnnotation(), genericSpecialization.getReturnType(), genericSpecialization.getParameters());
+            specializations.add(new SpecializationData(uninializedMethod, false, true));
+        }
+
+        Collections.sort(specializations, new Comparator<SpecializationData>() {
+
+            @Override
+            public int compare(SpecializationData o1, SpecializationData o2) {
+                return compareSpecialization(node.getTypeSystem(), o1, o2);
+            }
+        });
+
+        node.setSpecializations(specializations);
+
+        return true;
+    }
+
+    private boolean verifyNode(NodeData nodeData) {
+        // verify specialization parameter length
+        if (!verifySpecializationParameters(nodeData)) {
+            return false;
+        }
+
+        // verify order is not ambiguous
+        if (!verifySpecializationOrder(nodeData)) {
+            return false;
+        }
+
+        if (!verifyMissingAbstractMethods(nodeData)) {
+            return false;
+        }
+
+        if (!assignShortCircuitsToSpecializations(nodeData)) {
+            return false;
+        }
+
+        if (!verifyConstructors(nodeData)) {
+            return false;
+        }
+
+// if (!verifyNamingConvention(specializations, "do")) {
+// return null;
+// }
+//
+// if (!verifyNamesUnique(specializations)) {
+// return null;
+// }
+
+        if (!verifyNamingConvention(nodeData.getShortCircuits(), "needs")) {
+            return false;
+        }
+
+        if (!verifySpecializationThrows(nodeData)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    private NodeData parseNodeData(TypeElement type) {
         List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type));
         List<TypeElement> typeHierarchy = findSuperClasses(new ArrayList<TypeElement>(), type);
         Collections.reverse(typeHierarchy);
 
         AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class);
         if (typeSystemMirror == null) {
-            log.error(type, "No @%s annotation found in type hierarchy.", TypeSystemReference.class.getSimpleName());
+            log.error(type, "No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), type.getQualifiedName().toString());
             return null;
         }
 
@@ -142,120 +281,24 @@
 
         NodeData nodeData = new NodeData(type, typeSystem);
 
-        nodeData.setExtensionElements(getExtensionParser().parseAll(type, elements));
-        if (nodeData.getExtensionElements() != null) {
-            elements.addAll(nodeData.getExtensionElements());
-        }
-
         List<ExecutableTypeData> executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements));
 
-        nodeData.setExecutableTypes(executableTypes.toArray(new ExecutableTypeData[executableTypes.size()]));
+        nodeData.setExecutableTypes(executableTypes);
 
         parsedNodes.put(Utils.getQualifiedName(type), nodeData);
 
-        NodeFieldData[] fields = parseFields(nodeData, elements, typeHierarchy);
+        List<NodeFieldData> fields = parseFields(nodeData, elements, typeHierarchy);
         if (fields == null) {
             return null;
         }
         nodeData.setFields(fields);
-
-        List<SpecializationData> genericSpecializations = new GenericParser(context, nodeData).parse(elements);
-        List<GuardData> guards = new GuardParser(context, nodeData, nodeData.getTypeSystem()).parse(elements);
-        nodeData.setGuards(guards.toArray(new GuardData[guards.size()]));
-
-        SpecializationMethodParser specializationParser = new SpecializationMethodParser(context, nodeData);
-        List<SpecializationData> specializations = specializationParser.parse(elements);
-        List<ShortCircuitData> shortCircuits = new ShortCircuitParser(context, nodeData).parse(elements);
-        List<TemplateMethod> listeners = new SpecializationListenerParser(context, nodeData).parse(elements);
-
-        if (specializations == null || genericSpecializations == null || shortCircuits == null || listeners == null || guards == null) {
-            return null;
-        }
-
-        SpecializationData genericSpecialization = null;
-        if (genericSpecializations.size() > 1) {
-            for (SpecializationData generic : genericSpecializations) {
-                log.error(generic.getMethod(), "Only one method with @%s is allowed per operation.", Generic.class.getSimpleName());
-            }
-            return null;
-        } else if (genericSpecializations.size() == 1) {
-            genericSpecialization = genericSpecializations.get(0);
-        }
-
-        if (specializations.size() > 1 && genericSpecialization == null) {
-            log.error(type, "Need a @%s method.", Generic.class.getSimpleName());
-            return null;
-        }
-
-        Collections.sort(specializations, new Comparator<SpecializationData>() {
-
-            @Override
-            public int compare(SpecializationData o1, SpecializationData o2) {
-                return compareSpecialization(typeSystem, o1, o2);
-            }
-        });
-
-        List<SpecializationData> allSpecializations = new ArrayList<>(specializations);
-        if (genericSpecialization != null) {
-            allSpecializations.add(genericSpecialization);
-            CodeExecutableElement uninitializedMethod = new CodeExecutableElement(Utils.modifiers(Modifier.PUBLIC), context.getType(void.class), "doUninitialized");
-            TemplateMethod uninializedMethod = new TemplateMethod(nodeData, genericSpecialization.getSpecification(), uninitializedMethod, genericSpecialization.getMarkerAnnotation(),
-                            genericSpecialization.getReturnType(), genericSpecialization.getParameters());
-            allSpecializations.add(0, new SpecializationData(uninializedMethod, false, true));
-        }
-
-        for (SpecializationData specialization : allSpecializations) {
-            specialization.setNode(nodeData);
-        }
-
-        // verify specialization parameter length
-        if (!verifySpecializationParameters(specializations)) {
-            return null;
-        }
-
-        // verify order is not ambiguous
-        if (!verifySpecializationOrder(typeSystem, specializations)) {
-            return null;
-        }
-
-        nodeData.setSpecializations(allSpecializations.toArray(new SpecializationData[allSpecializations.size()]));
-        nodeData.setSpecializationListeners(listeners.toArray(new TemplateMethod[listeners.size()]));
-
-        if (!verifyMissingAbstractMethods(nodeData, elements)) {
-            return null;
-        }
-
-        if (!assignShortCircuitsToSpecializations(nodeData, allSpecializations, shortCircuits)) {
-            return null;
-        }
-
-        if (!verifyConstructors(nodeData)) {
-            return null;
-        }
-
-        if (!verifyNamingConvention(specializations, "do")) {
-            return null;
-        }
-
-        if (!verifyNamesUnique(specializations)) {
-            return null;
-        }
-
-        if (!verifyNamingConvention(shortCircuits, "needs")) {
-            return null;
-        }
-
-        if (!verifySpecializationThrows(typeSystem, specializations)) {
-            return null;
-        }
-
         return nodeData;
     }
 
-    private boolean verifySpecializationParameters(List<SpecializationData> specializations) {
+    private boolean verifySpecializationParameters(NodeData nodeData) {
         boolean valid = true;
         int args = -1;
-        for (SpecializationData specializationData : specializations) {
+        for (SpecializationData specializationData : nodeData.getSpecializations()) {
             int specializationArgs = 0;
             for (ActualParameter param : specializationData.getParameters()) {
                 if (!param.getSpecification().isOptional()) {
@@ -269,20 +312,22 @@
             args = specializationArgs;
         }
         if (!valid) {
-            for (SpecializationData specialization : specializations) {
+            for (SpecializationData specialization : nodeData.getSpecializations()) {
                 context.getLog().error(specialization.getMethod(), specialization.getMarkerAnnotation(), "All specializations must have the same number of arguments.");
             }
         }
         return valid;
     }
 
-    private boolean verifyMissingAbstractMethods(NodeData nodeData, List<Element> elements) {
+    private boolean verifyMissingAbstractMethods(NodeData nodeData) {
         if (nodeData.needsFactory()) {
             // missing abstract methods only needs to be implemented
             // if we need go generate factory for it.
             return true;
         }
 
+        List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeData.getTemplateType()));
+
         Set<Element> unusedElements = new HashSet<>(elements);
         for (TemplateMethod method : nodeData.getAllTemplateMethods()) {
             unusedElements.remove(method.getMethod());
@@ -376,7 +421,7 @@
         return null;
     }
 
-    private NodeFieldData[] parseFields(NodeData nodeData, List<? extends Element> elements, final List<TypeElement> typeHierarchy) {
+    private List<NodeFieldData> parseFields(NodeData nodeData, List<? extends Element> elements, final List<TypeElement> typeHierarchy) {
         AnnotationMirror executionOrderMirror = findFirstAnnotation(typeHierarchy, ExecuteChildren.class);
         List<String> executionDefinition = null;
         if (executionOrderMirror != null) {
@@ -423,9 +468,8 @@
             return null;
         }
 
-        NodeFieldData[] fieldArray = fields.toArray(new NodeFieldData[fields.size()]);
-        sortByExecutionOrder(fieldArray, executionDefinition == null ? Collections.<String> emptyList() : executionDefinition, typeHierarchy);
-        return fieldArray;
+        sortByExecutionOrder(fields, executionDefinition == null ? Collections.<String> emptyList() : executionDefinition, typeHierarchy);
+        return fields;
     }
 
     private NodeFieldData parseField(NodeData parentNodeData, VariableElement var, Set<String> foundShortCircuits) {
@@ -510,8 +554,8 @@
         }
     }
 
-    private static void sortByExecutionOrder(NodeFieldData[] fields, final List<String> executionOrder, final List<TypeElement> typeHierarchy) {
-        Arrays.sort(fields, new Comparator<NodeFieldData>() {
+    private static void sortByExecutionOrder(List<NodeFieldData> fields, final List<String> executionOrder, final List<TypeElement> typeHierarchy) {
+        Collections.sort(fields, new Comparator<NodeFieldData>() {
 
             @Override
             public int compare(NodeFieldData o1, NodeFieldData o2) {
@@ -533,18 +577,17 @@
         });
     }
 
-    private boolean assignShortCircuitsToSpecializations(NodeData nodeData, List<SpecializationData> specializations, List<ShortCircuitData> shortCircuits) {
-
-        Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(shortCircuits);
+    private boolean assignShortCircuitsToSpecializations(NodeData node) {
+        Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits());
 
         boolean valid = true;
 
-        for (NodeFieldData field : nodeData.filterFields(null, ExecutionKind.SHORT_CIRCUIT)) {
+        for (NodeFieldData field : node.filterFields(null, ExecutionKind.SHORT_CIRCUIT)) {
             String valueName = field.getName();
             List<ShortCircuitData> availableCircuits = groupedShortCircuits.get(valueName);
 
             if (availableCircuits == null || availableCircuits.isEmpty()) {
-                log.error(nodeData.getTemplateType(), "@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName);
+                log.error(node.getTemplateType(), "@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName);
                 valid = false;
                 continue;
             }
@@ -567,14 +610,14 @@
 
             ShortCircuitData genericCircuit = null;
             for (ShortCircuitData circuit : availableCircuits) {
-                if (isGenericShortCutMethod(nodeData, circuit)) {
+                if (isGenericShortCutMethod(node, circuit)) {
                     genericCircuit = circuit;
                     break;
                 }
             }
 
             if (genericCircuit == null) {
-                log.error(nodeData.getTemplateType(), "No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName);
+                log.error(node.getTemplateType(), "No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName);
                 valid = false;
                 continue;
             }
@@ -590,8 +633,8 @@
             return valid;
         }
 
-        NodeFieldData[] fields = nodeData.filterFields(null, ExecutionKind.SHORT_CIRCUIT);
-        for (SpecializationData specialization : specializations) {
+        NodeFieldData[] fields = node.filterFields(null, ExecutionKind.SHORT_CIRCUIT);
+        for (SpecializationData specialization : node.getSpecializations()) {
             ShortCircuitData[] assignedShortCuts = new ShortCircuitData[fields.length];
 
             for (int i = 0; i < fields.length; i++) {
@@ -696,7 +739,10 @@
         return collection;
     }
 
-    private boolean verifySpecializationOrder(TypeSystemData typeSystem, List<SpecializationData> specializations) {
+    private boolean verifySpecializationOrder(NodeData node) {
+        TypeSystemData typeSystem = node.getTypeSystem();
+        List<SpecializationData> specializations = node.getSpecializations();
+
         for (int i = 0; i < specializations.size(); i++) {
             SpecializationData m1 = specializations.get(i);
             for (int j = i + 1; j < specializations.size(); j++) {
@@ -724,13 +770,15 @@
         return true;
     }
 
-    private boolean verifySpecializationThrows(TypeSystemData typeSystem, List<SpecializationData> specializations) {
+    private boolean verifySpecializationThrows(NodeData node) {
+        TypeSystemData typeSystem = node.getTypeSystem();
+
         Map<String, SpecializationData> specializationMap = new HashMap<>();
-        for (SpecializationData spec : specializations) {
+        for (SpecializationData spec : node.getSpecializations()) {
             specializationMap.put(spec.getMethodName(), spec);
         }
         boolean valid = true;
-        for (SpecializationData sourceSpecialization : specializations) {
+        for (SpecializationData sourceSpecialization : node.getSpecializations()) {
             if (sourceSpecialization.getExceptions() != null) {
                 for (SpecializationThrowsData throwsData : sourceSpecialization.getExceptions()) {
                     SpecializationData targetSpecialization = specializationMap.get(throwsData.getTransitionToName());
@@ -772,8 +820,22 @@
     }
 
     private static int compareSpecializationWithoutOrder(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) {
-        if (m1.getSpecification() != m2.getSpecification()) {
-            throw new UnsupportedOperationException("Cannot compare two specializations with different specifications.");
+        if (m1 == m2) {
+            return 0;
+        }
+
+        if (m1.isUninitialized() && !m2.isUninitialized()) {
+            return -1;
+        } else if (!m1.isUninitialized() && m2.isUninitialized()) {
+            return 1;
+        } else if (m1.isGeneric() && !m2.isGeneric()) {
+            return 1;
+        } else if (!m1.isGeneric() && m2.isGeneric()) {
+            return -1;
+        }
+
+        if (m1.getTemplate() != m2.getTemplate()) {
+            throw new UnsupportedOperationException("Cannot compare two specializations with different templates.");
         }
 
         int result = compareActualParameter(typeSystem, m1.getReturnType(), m2.getReturnType());
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Mon Mar 04 15:13:25 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Mon Mar 04 15:14:11 2013 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.codegen.processor.node;
 
+import java.util.*;
+
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.template.*;
 
@@ -106,10 +108,10 @@
     }
 
     public SpecializationData findNextSpecialization() {
-        SpecializationData[] specializations = node.getSpecializations();
-        for (int i = 0; i < specializations.length - 1; i++) {
-            if (specializations[i] == this) {
-                return specializations[i + 1];
+        List<SpecializationData> specializations = node.getSpecializations();
+        for (int i = 0; i < specializations.size() - 1; i++) {
+            if (specializations.get(i) == this) {
+                return specializations.get(i + 1);
             }
         }
         return null;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerData.java	Mon Mar 04 15:14:11 2013 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012, 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.node;
+
+import com.oracle.truffle.codegen.processor.template.*;
+
+public class SpecializationListenerData extends TemplateMethod {
+
+    public SpecializationListenerData(TemplateMethod method) {
+        super(method);
+    }
+
+}
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java	Mon Mar 04 15:13:25 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java	Mon Mar 04 15:14:11 2013 +0100
@@ -30,7 +30,7 @@
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
 
-public class SpecializationListenerParser extends MethodParser<TemplateMethod> {
+public class SpecializationListenerParser extends MethodParser<SpecializationListenerData> {
 
     private final MethodSpec specification;
 
@@ -50,8 +50,8 @@
     }
 
     @Override
-    public TemplateMethod create(TemplateMethod method) {
-        return method;
+    public SpecializationListenerData create(TemplateMethod method) {
+        return new SpecializationListenerData(method);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Mon Mar 04 15:13:25 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Mon Mar 04 15:14:11 2013 +0100
@@ -26,6 +26,7 @@
 
 public class TemplateMethod {
 
+    private final String id;
     private final Template template;
     private final MethodSpec specification;
     private final ExecutableElement method;
@@ -33,13 +34,14 @@
     private final ActualParameter returnType;
     private final ActualParameter[] parameters;
 
-    public TemplateMethod(Template template, MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType, ActualParameter[] parameters) {
+    public TemplateMethod(String id, Template template, MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType, ActualParameter[] parameters) {
         this.template = template;
         this.specification = specification;
         this.method = method;
         this.markerAnnotation = markerAnnotation;
         this.returnType = returnType;
         this.parameters = parameters;
+        this.id = id;
 
         if (parameters != null) {
             for (ActualParameter param : parameters) {
@@ -49,7 +51,11 @@
     }
 
     public TemplateMethod(TemplateMethod method) {
-        this(method.template, method.specification, method.method, method.markerAnnotation, method.returnType, method.parameters);
+        this(method.id, method.template, method.specification, method.method, method.markerAnnotation, method.returnType, method.parameters);
+    }
+
+    public String getId() {
+        return id;
     }
 
     public Template getTemplate() {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Mon Mar 04 15:13:25 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Mon Mar 04 15:14:11 2013 +0100
@@ -31,6 +31,7 @@
 import javax.lang.model.type.*;
 import javax.lang.model.util.*;
 
+import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
 
@@ -149,8 +150,15 @@
             }
             return null;
         }
+
+        String id = method.getSimpleName().toString();
+        AnnotationMirror idAnnotation = Utils.findAnnotationMirror(context.getEnvironment(), method, NodeId.class);
+        if (idAnnotation != null) {
+            id = Utils.getAnnotationValueString(idAnnotation, "value");
+        }
+
         ActualParameter[] paramMirrors = parameters.toArray(new ActualParameter[parameters.size()]);
-        return create(new TemplateMethod(template, methodSpecification, method, annotation, returnTypeMirror, paramMirrors));
+        return create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, paramMirrors));
     }
 
     private List<ActualParameter> parseParameters(ExecutableElement method, List<ParameterSpec> parameterSpecs) {