changeset 8245:703c09f8640c

Implemented support for @NodeClass annotation to support builtins.
author Christian Humer <christian.humer@gmail.com>
date Wed, 06 Mar 2013 18:32:33 +0100
parents 10d37f893471
children 3862508afe2f
files graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/SimpleTypes.java graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.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/MethodParser.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/NodeParser.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/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/GuardData.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
diffstat 21 files changed, 597 insertions(+), 215 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/SimpleTypes.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/SimpleTypes.java	Wed Mar 06 18:32:33 2013 +0100
@@ -24,6 +24,6 @@
 
 import com.oracle.truffle.api.codegen.*;
 
-@TypeSystem({int.class, String.class})
+@TypeSystem({int.class, RuntimeString.class})
 class SimpleTypes {
 }
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java	Wed Mar 06 18:32:33 2013 +0100
@@ -36,8 +36,11 @@
  * <p>
  * This introduction to Codegen contains items in the following recommended order:
  *
+ * Prerequisites:
+ * 
+ *
  * <ul>
- * <li>How would you generate builtin functions? {@link com.oracle.truffle.api.codegen.test.BuiltinFunctionTest}</li>
+ * <li>How would you generate function nodes for runtime objects? {@link com.oracle.truffle.api.codegen.test.RuntimeString}</li>
  * </ul>
  * </p>
  *
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java	Wed Mar 06 18:32:33 2013 +0100
@@ -167,6 +167,46 @@
         return new LinkedHashSet<>(Arrays.asList(modifier));
     }
 
+    public static String getTypeId(TypeMirror mirror) {
+        switch (mirror.getKind()) {
+            case BOOLEAN:
+                return "Boolean";
+            case BYTE:
+                return "Byte";
+            case CHAR:
+                return "Char";
+            case DOUBLE:
+                return "Double";
+            case FLOAT:
+                return "Float";
+            case SHORT:
+                return "Short";
+            case INT:
+                return "Int";
+            case LONG:
+                return "Long";
+            case DECLARED:
+                return ((DeclaredType) mirror).asElement().getSimpleName().toString();
+            case ARRAY:
+                return getTypeId(((ArrayType) mirror).getComponentType()) + "Array";
+            case VOID:
+                return "Void";
+            case WILDCARD:
+                StringBuilder b = new StringBuilder();
+                WildcardType type = (WildcardType) mirror;
+                if (type.getExtendsBound() != null) {
+                    b.append("Extends").append(getTypeId(type.getExtendsBound()));
+                } else if (type.getSuperBound() != null) {
+                    b.append("Super").append(getTypeId(type.getExtendsBound()));
+                }
+                return b.toString();
+            case TYPEVAR:
+                return "Any";
+            default:
+                throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror);
+        }
+    }
+
     public static String getSimpleName(TypeElement element) {
         return getSimpleName(element.asType());
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java	Wed Mar 06 18:32:33 2013 +0100
@@ -51,7 +51,7 @@
 
         List<ParameterSpec> parameters = new ArrayList<>();
         parameters.add(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true));
-        return new MethodSpec(returnTypeSpec, parameters);
+        return new MethodSpec(new ArrayList<TypeMirror>(), returnTypeSpec, parameters);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Wed Mar 06 18:32:33 2013 +0100
@@ -41,7 +41,7 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        return createDefaultMethodSpec(null);
+        return createDefaultMethodSpec(method, mirror, null);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java	Wed Mar 06 18:32:33 2013 +0100
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import javax.lang.model.element.*;
+import javax.lang.model.type.*;
 
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.node.NodeFieldData.*;
@@ -54,12 +55,20 @@
         return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null;
     }
 
-    protected final MethodSpec createDefaultMethodSpec(String shortCircuitName) {
+    @SuppressWarnings("unused")
+    protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, String shortCircuitName) {
         List<ParameterSpec> defaultParameters = new ArrayList<>();
 
         if (getNode().supportsFrame()) {
-            ParameterSpec frameSpec = new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true);
-            defaultParameters.add(frameSpec);
+            defaultParameters.add(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true));
+        }
+
+        TypeMirror declaredType = Utils.findNearestEnclosingType(method).asType();
+
+        List<TypeMirror> prefixTypes = new ArrayList<>();
+
+        if (!method.getModifiers().contains(Modifier.STATIC) && !Utils.isAssignable(declaredType, template.getNodeType())) {
+            prefixTypes.add(getNode().getTemplateType().asType());
         }
 
         for (NodeFieldData field : getNode().getFields()) {
@@ -87,7 +96,7 @@
             }
         }
 
-        return new MethodSpec(createReturnParameterSpec(), defaultParameters);
+        return new MethodSpec(prefixTypes, createReturnParameterSpec(), defaultParameters);
     }
 
     private static String shortCircuitValueName(String valueName) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Wed Mar 06 18:32:33 2013 +0100
@@ -51,32 +51,18 @@
     }
 
     private static String factoryClassName(NodeData node) {
-        return nodeClassName(node) + "Factory";
-    }
-
-    private static String nodeClassName(NodeData node) {
-        return Utils.getSimpleName(node.getTemplateType().asType());
+        return node.getNodeId() + "Factory";
     }
 
-    private static String nodeClassName(SpecializationData specialization) {
-        String name = specializationId(specialization);
-        name += nodeClassName(specialization.getNode());
-        if (name.equals(Utils.getSimpleName(specialization.getNode().getNodeType())) || name.equals(Utils.getSimpleName(specialization.getNode().getTemplateType()))) {
-            name = name + "Impl";
+    private static String nodeSpecializationClassName(SpecializationData specialization) {
+        String nodeid = specialization.getNode().getNodeId();
+        if (nodeid.endsWith("Node") && !nodeid.equals("Node")) {
+            nodeid = nodeid.substring(0, nodeid.length() - 4);
         }
 
-        return name;
-    }
-
-    private static String specializationId(SpecializationData specialization) {
-        String name = "";
-        NodeData node = specialization.getNode();
-        if (node.getSpecializations().size() > 1) {
-            name = specialization.getMethodName();
-            if (name.startsWith("do")) {
-                name = name.substring(2);
-            }
-        }
+        String name = Utils.firstLetterUpperCase(nodeid);
+        name += Utils.firstLetterUpperCase(specialization.getId());
+        name += "Node";
         return name;
     }
 
@@ -88,7 +74,7 @@
         return valueName(parameter) + "Cast";
     }
 
-    private void addValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame) {
+    private void addValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame, boolean includeHidden) {
         if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) {
             method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue"));
         }
@@ -97,11 +83,15 @@
             if (forceFrame && spec.getName().equals("frame")) {
                 continue;
             }
+            if (!includeHidden && parameter.isHidden()) {
+                continue;
+            }
+
             method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(parameter)));
         }
     }
 
-    private static void addValueParameterNames(CodeTreeBuilder builder, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame) {
+    private static void addValueParameterNames(CodeTreeBuilder builder, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, boolean includeHidden) {
         if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) {
             builder.string("frameValue");
         }
@@ -111,6 +101,10 @@
                 continue;
             }
 
+            if (!includeHidden && parameter.isHidden()) {
+                continue;
+            }
+
             if (unexpectedValueName != null && parameter.getName().equals(unexpectedValueName)) {
                 builder.string("ex.getResult()");
             } else {
@@ -119,7 +113,7 @@
         }
     }
 
-    private static void addValueParameterNamesWithCasts(CodeTreeBuilder body, SpecializationData valueSpecialization, SpecializationData targetSpecialization) {
+    private static void addValueParameterNamesWithCasts(CodeTreeBuilder body, SpecializationData valueSpecialization, SpecializationData targetSpecialization, boolean includeHidden) {
         NodeData node = targetSpecialization.getNode();
         TypeSystemData typeSystem = node.getTypeSystem();
 
@@ -127,6 +121,10 @@
             ActualParameter valueParameter = valueSpecialization.findParameter(targetParameter.getName());
             TypeData targetType = targetParameter.getActualTypeData(typeSystem);
 
+            if (!includeHidden && (targetParameter.isHidden() || valueParameter.isHidden())) {
+                continue;
+            }
+
             TypeData valueType = null;
             if (valueParameter != null) {
                 valueType = valueParameter.getActualTypeData(typeSystem);
@@ -144,15 +142,34 @@
         return getSimpleName(operation.getTemplateType()) + "Gen";
     }
 
-    private static void startCallOperationMethod(CodeTreeBuilder body, TemplateMethod method) {
+    private static void startCallOperationMethod(CodeTreeBuilder body, TemplateMethod templateMethod, boolean castedValues) {
         body.startGroup();
-        if (body.findMethod().getModifiers().contains(STATIC)) {
-            body.string(THIS_NODE_LOCAL_VAR_NAME);
+        ExecutableElement method = templateMethod.getMethod();
+
+        TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement());
+        NodeData node = (NodeData) templateMethod.getTemplate();
+
+        boolean accessible = templateMethod.canBeAccessedByInstanceOf(node.getNodeType());
+        if (accessible) {
+            if (body.findMethod().getModifiers().contains(STATIC)) {
+                body.string(THIS_NODE_LOCAL_VAR_NAME);
+            } else {
+                body.string("super");
+            }
         } else {
-            body.string("super");
+            if (method.getModifiers().contains(STATIC)) {
+                body.type(targetClass.asType());
+            } else {
+                ActualParameter parameter = templateMethod.getParameters().get(0);
+                if (castedValues) {
+                    body.string(castValueName(parameter));
+                } else {
+                    body.string(valueName(parameter));
+                }
+            }
         }
         body.string(".");
-        body.startCall(method.getMethodName());
+        body.startCall(method.getSimpleName().toString());
     }
 
     private static String generatedGenericMethodName(SpecializationData specialization) {
@@ -168,7 +185,7 @@
                 if (prev == null || prev.isUninitialized()) {
                     return prefix;
                 } else {
-                    return prefix + specializationId(current);
+                    return prefix + current.getId();
                 }
             }
             prev = current;
@@ -249,8 +266,8 @@
                 if ((guard.isOnSpecialization() && onSpecialization) || (guard.isOnExecution() && !onSpecialization)) {
                     builder.string(andOperator);
 
-                    startCallOperationMethod(builder, guard.getGuardDeclaration());
-                    addValueParameterNamesWithCasts(builder, valueSpecialization, guardedSpecialization);
+                    startCallOperationMethod(builder, guard.getGuardDeclaration(), true);
+                    addValueParameterNamesWithCasts(builder, valueSpecialization, guardedSpecialization, false);
 
                     builder.end().end(); // call
                     andOperator = " && ";
@@ -705,15 +722,21 @@
             }
 
             List<TypeMirror> nodeTypesList = new ArrayList<>();
+            TypeMirror prev = null;
+            boolean allSame = true;
             for (NodeData child : children) {
-                nodeTypesList.add(child.getTemplateType().asType());
+                nodeTypesList.add(child.getNodeType());
+                if (prev != null && !Utils.typeEquals(child.getNodeType(), prev)) {
+                    allSame = false;
+                }
+                prev = child.getNodeType();
             }
             TypeMirror commonNodeSuperType = Utils.getCommonSuperType(getContext(), nodeTypesList.toArray(new TypeMirror[nodeTypesList.size()]));
 
             Types types = getContext().getEnvironment().getTypeUtils();
             TypeMirror factoryType = getContext().getType(NodeFactory.class);
             TypeMirror baseType;
-            if (children.size() == 1) {
+            if (allSame) {
                 baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), commonNodeSuperType);
             } else {
                 baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null));
@@ -784,7 +807,7 @@
             if (node.getSpecializations().isEmpty()) {
                 body.null_();
             } else {
-                body.startNew(nodeClassName(node.getSpecializations().get(0)));
+                body.startNew(nodeSpecializationClassName(node.getSpecializations().get(0)));
                 for (VariableElement var : method.getParameters()) {
                     body.string(var.getSimpleName().toString());
                 }
@@ -816,14 +839,14 @@
                         body.startElseIf();
                     }
                     body.string("specializationClass == ").type(type.getBoxedType()).string(".class").end().startBlock();
-                    body.startReturn().startNew(nodeClassName(specialization));
+                    body.startReturn().startNew(nodeSpecializationClassName(specialization));
                     body.string(THIS_NODE_LOCAL_VAR_NAME);
                     body.end().end(); // new, return
 
                     body.end(); // if
                 }
             }
-            body.startReturn().startNew(nodeClassName(node.getGenericSpecialization()));
+            body.startReturn().startNew(nodeSpecializationClassName(node.getGenericSpecialization()));
             body.string(THIS_NODE_LOCAL_VAR_NAME);
             body.end().end();
             return method;
@@ -833,17 +856,17 @@
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), node.getNodeType(), "specialize");
             method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME));
             method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
-            addValueParameters(method, node.getGenericSpecialization(), false);
+            addValueParameters(method, node.getGenericSpecialization(), false, true);
 
             CodeTreeBuilder body = method.createBuilder();
-            body.startStatement().string("boolean allowed = (minimumState == ").string(nodeClassName(node.getSpecializations().get(0))).string(".class)").end();
+            body.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end();
 
             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();
+                body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(specialization)).string(".class)").end();
 
                 CodeTreeBuilder guarded = new CodeTreeBuilder(body);
-                guarded.startReturn().startNew(nodeClassName(specialization));
+                guarded.startReturn().startNew(nodeSpecializationClassName(specialization));
                 guarded.string(THIS_NODE_LOCAL_VAR_NAME);
                 guarded.end().end();
 
@@ -871,7 +894,7 @@
                         String methodName = generatedGenericMethodName(current);
                         CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, methodName);
                         method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME));
-                        addValueParameters(method, node.getGenericSpecialization(), true);
+                        addValueParameters(method, node.getGenericSpecialization(), true, true);
 
                         emitGeneratedGenericSpecialization(method.createBuilder(), current, next);
 
@@ -884,7 +907,7 @@
             } else {
                 CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, generatedGenericMethodName(null));
                 method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME));
-                addValueParameters(method, node.getGenericSpecialization(), true);
+                addValueParameters(method, node.getGenericSpecialization(), true, true);
                 emitInvokeDoMethod(method.createBuilder(), node.getGenericSpecialization(), 0);
                 return Arrays.asList(method);
             }
@@ -906,7 +929,7 @@
 
                 builder.startReturn().startCall(generatedGenericMethodName(next));
                 builder.string(THIS_NODE_LOCAL_VAR_NAME);
-                addValueParameterNames(builder, next, null, true);
+                addValueParameterNames(builder, next, null, true, true);
                 builder.end().end();
             }
         }
@@ -917,8 +940,8 @@
             }
 
             builder.startReturn();
-            startCallOperationMethod(builder, specialization);
-            addValueParameterNamesWithCasts(builder, specialization.getNode().getGenericSpecialization(), specialization);
+            startCallOperationMethod(builder, specialization, true);
+            addValueParameterNamesWithCasts(builder, specialization.getNode().getGenericSpecialization(), specialization, false);
             builder.end().end(); // start call operation
             builder.end(); // return
 
@@ -928,7 +951,7 @@
 
                     builder.startReturn().startCall(generatedGenericMethodName(exception.getTransitionTo()));
                     builder.string(THIS_NODE_LOCAL_VAR_NAME);
-                    addValueParameterNames(builder, exception.getTransitionTo(), null, true);
+                    addValueParameterNames(builder, exception.getTransitionTo(), null, true, true);
                     builder.end().end();
                 }
                 builder.end();
@@ -945,7 +968,7 @@
         @Override
         public CodeTypeElement create(SpecializationData specialization) {
             NodeData node = specialization.getNode();
-            CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeClassName(specialization), node.getNodeType(), false);
+            CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), node.getNodeType(), false);
             return clazz;
         }
 
@@ -1110,7 +1133,7 @@
                 builder.startCall(factoryClassName(node), "specialize");
                 builder.string("this");
                 builder.typeLiteral(builder.findMethod().getEnclosingElement().asType());
-                addValueParameterNames(builder, specialization, null, false);
+                addValueParameterNames(builder, specialization, null, false, true);
                 builder.end(); // call replace, call specialize
             } else {
                 builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end();
@@ -1129,17 +1152,17 @@
             if ((specialization.isUninitialized() || specialization.isGeneric()) && node.needsRewrites(getContext())) {
                 builder.startReturn().startCall(factoryClassName(node), generatedGenericMethodName(null));
                 builder.string("this");
-                addValueParameterNames(builder, specialization, null, true);
+                addValueParameterNames(builder, specialization, null, true, true);
                 builder.end().end();
             } else {
                 builder.startReturn();
 
                 if (specialization.isUninitialized()) {
-                    startCallOperationMethod(builder, specialization.getNode().getGenericSpecialization());
+                    startCallOperationMethod(builder, specialization.getNode().getGenericSpecialization(), false);
                 } else {
-                    startCallOperationMethod(builder, specialization);
+                    startCallOperationMethod(builder, specialization, false);
                 }
-                addValueParameterNames(builder, specialization, null, false);
+                addValueParameterNames(builder, specialization, null, false, false);
                 builder.end().end(); // operation call
                 builder.end(); // return
             }
@@ -1156,17 +1179,14 @@
 
         private CodeTree createExecuteChildren(CodeTreeBuilder parent, SpecializationData specialization) {
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+
             for (ActualParameter parameter : specialization.getParameters()) {
                 NodeFieldData field = specialization.getNode().findField(parameter.getSpecification().getName());
                 if (field == null) {
                     continue;
                 }
 
-                if (parameter.getActualTypeData(specialization.getNode().getTypeSystem()).isGeneric()) {
-                    buildGenericValueExecute(builder, specialization, parameter, field, null);
-                } else {
-                    buildSpecializedValueExecute(builder, specialization, parameter, field);
-                }
+                buildFieldExecute(builder, specialization, parameter, field, null);
             }
             return builder.getRoot();
         }
@@ -1174,33 +1194,55 @@
         private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) {
             for (TemplateMethod listener : node.getSpecializationListeners()) {
                 builder.startStatement();
-                startCallOperationMethod(builder, listener);
-                addValueParameterNames(builder, listener, null, false);
+                startCallOperationMethod(builder, listener, false);
+                addValueParameterNames(builder, listener, null, false, false);
                 builder.end().end();
                 builder.end(); // statement
             }
         }
 
-        private void buildGenericValueExecute(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter param, NodeFieldData field, ActualParameter exceptionParam) {
-            NodeData node = specialization.getNode();
+        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());
 
-            builder.startStatement();
-            if (!shortCircuit) {
-                builder.type(specialization.getNode().getTypeSystem().getGenericType());
-                builder.string(" ");
+            if (!shortCircuit && unexpected) {
+                builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).end();
+            }
+
+            if (unexpected) {
+                builder.startTryBlock();
             }
 
-            builder.string(valueName(param));
-            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. " + (field.getNodeData().getExecutableTypes()));
+            if (!shortCircuit && !unexpected) {
+                builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).string(" = ");
+            } else {
+                builder.startStatement().string(valueName(param)).string(" = ");
             }
-            buildExecute(builder, param, field, genericExecutableType);
+            buildExecute(builder, param, field, execType);
             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) {
+                        continue;
+                    }
+                    if (execute) {
+                        buildFieldExecute(builder, specialization.getNode().getGenericSpecialization(), exParam, exField, param);
+                    } else if (exParam.getName().equals(param.getName())) {
+                        execute = true;
+                    }
+                }
+                builder.tree(createReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param));
+                builder.end(); // catch block
+            }
+
             endShortCircuit(builder, shortCircuit);
+            builder.newLine();
         }
 
         private void buildExecute(CodeTreeBuilder builder, ActualParameter parameter, NodeFieldData field, ExecutableTypeData execType) {
@@ -1219,52 +1261,12 @@
                 builder.string(".");
             }
             builder.startCall(execType.getMethodName());
-            if (execType.getParameters().length == 1) {
+            if (execType.getParameters().size() == 1) {
                 builder.string("frameValue");
             }
             builder.end();
         }
 
-        private void buildSpecializedValueExecute(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter param, NodeFieldData field) {
-            boolean shortCircuit = startShortCircuit(builder, specialization, param, null);
-
-            if (!shortCircuit) {
-                builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).end();
-            }
-
-            ExecutableTypeData execType = field.getNodeData().findExecutableType(param.getActualTypeData(field.getNodeData().getTypeSystem()));
-
-            if (execType.hasUnexpectedValue(getContext())) {
-                builder.startTryBlock();
-            }
-
-            builder.startStatement().string(valueName(param)).string(" = ");
-            buildExecute(builder, param, field, execType);
-            builder.end();
-
-            if (execType.hasUnexpectedValue(getContext())) {
-                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) {
-                        continue;
-                    }
-                    if (execute) {
-                        buildGenericValueExecute(builder, specialization.getNode().getGenericSpecialization(), exParam, exField, param);
-                    } else if (exParam.getName().equals(param.getName())) {
-                        execute = true;
-                    }
-                }
-                builder.tree(createReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param));
-                builder.end(); // catch block
-            }
-
-            endShortCircuit(builder, shortCircuit);
-            builder.newLine();
-        }
-
         private boolean startShortCircuit(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter parameter, ActualParameter exceptionParam) {
             NodeFieldData forField = specialization.getNode().findField(parameter.getSpecification().getName());
             if (forField == null) {
@@ -1290,8 +1292,8 @@
             builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(shortCircuitParam)).string(" = ");
             ShortCircuitData shortCircuitData = specialization.getShortCircuits()[shortCircuitIndex];
 
-            startCallOperationMethod(builder, shortCircuitData);
-            addValueParameterNames(builder, shortCircuitData, exceptionParam != null ? exceptionParam.getName() : null, false);
+            startCallOperationMethod(builder, shortCircuitData, false);
+            addValueParameterNames(builder, shortCircuitData, exceptionParam != null ? exceptionParam.getName() : null, false, false);
             builder.end().end(); // call operation
 
             builder.end(); // statement
@@ -1312,8 +1314,8 @@
         private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, SpecializationData nextSpecialization, ActualParameter exceptionParam) {
             CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent);
             specializeCall.startCall("specializeAndExecute");
-            specializeCall.string(nodeClassName(nextSpecialization) + ".class");
-            addValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getName() : null, true);
+            specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class");
+            addValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getName() : null, true, true);
             specializeCall.end().end();
 
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
@@ -1334,7 +1336,7 @@
             if (canThrowUnexpected) {
                 method.addThrownType(getUnexpectedValueException());
             }
-            addValueParameters(method, specialization.getNode().getGenericSpecialization(), true);
+            addValueParameters(method, specialization.getNode().getGenericSpecialization(), true, true);
             clazz.add(method);
 
             CodeTreeBuilder builder = method.createBuilder();
@@ -1345,7 +1347,7 @@
             builder.startStatement();
             builder.startCall("replace");
             builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState");
-            addValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, false);
+            addValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, false, true);
             builder.end();
             builder.end(); // call replace
             builder.end(); // statement
@@ -1356,7 +1358,7 @@
             CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder();
             genericExecute.startCall(factoryClassName(specialization.getNode()), generatedMethodName);
             genericExecute.string("this");
-            addValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), null, true);
+            addValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), null, true, true);
             genericExecute.end(); // call generated generic
 
             CodeTree genericInvocation = createExpectType(node, returnExecutableType, genericExecute.getRoot());
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Wed Mar 06 18:32:33 2013 +0100
@@ -35,12 +35,14 @@
 
 public class NodeData extends Template {
 
+    private final String nodeId;
     private NodeData declaringNode;
-    private List<NodeData> declaredChildren;
+    private List<NodeData> declaredChildren = new ArrayList<>();
 
     private final TypeSystemData typeSystem;
     private List<NodeFieldData> fields;
     private TypeMirror nodeType;
+    private ParameterSpec instanceParameterSpec;
 
     private List<SpecializationData> specializations;
     private List<SpecializationListenerData> specializationListeners;
@@ -48,11 +50,46 @@
     private List<ExecutableTypeData> executableTypes;
     private List<ShortCircuitData> shortCircuits;
 
-    public NodeData(TypeElement type, TypeSystemData typeSystem) {
+    public NodeData(TypeElement type, TypeSystemData typeSystem, String id) {
         super(type, null);
+        this.nodeId = id;
         this.typeSystem = typeSystem;
     }
 
+    public NodeData(NodeData copy, String nodeId) {
+        super(copy.getTemplateType(), null);
+        this.nodeId = nodeId;
+        this.declaringNode = copy.declaringNode;
+        this.declaredChildren = copy.declaredChildren;
+        this.typeSystem = copy.typeSystem;
+        this.nodeType = copy.nodeType;
+        this.specializations = copy.specializations;
+        this.specializationListeners = copy.specializationListeners;
+        this.guards = copy.guards;
+        this.executableTypes = copy.executableTypes;
+        this.shortCircuits = copy.shortCircuits;
+
+        List<NodeFieldData> fieldsCopy = new ArrayList<>();
+        for (NodeFieldData field : copy.fields) {
+            NodeFieldData newField = new NodeFieldData(field);
+            newField.setNode(this);
+            fieldsCopy.add(newField);
+        }
+        this.fields = fieldsCopy;
+    }
+
+    public ParameterSpec getInstanceParameterSpec() {
+        return instanceParameterSpec;
+    }
+
+    public void setInstanceParameterSpec(ParameterSpec instanceParameter) {
+        this.instanceParameterSpec = instanceParameter;
+    }
+
+    public String getNodeId() {
+        return nodeId;
+    }
+
     public TypeMirror getNodeType() {
         if (nodeType != null) {
             return nodeType;
@@ -247,8 +284,9 @@
 
     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" + "]",
-                        Utils.getQualifiedName(getTemplateType()), getTypeSystem(), dumpList(fields), dumpList(getExecutableTypes()), dumpList(getSpecializations()), dumpList(guards)));
+        b.append(String.format("[id = %s, name = %s\n  typeSystem = %s\n  fields = %s\n  types = %s\n  specializations = %s\n  guards = %s\n  enclosing = %s\n  enclosed = %s\n]", getNodeId(),
+                        Utils.getQualifiedName(getTemplateType()), getTypeSystem(), dumpList(fields), dumpList(getExecutableTypes()), dumpList(getSpecializations()), dumpList(guards),
+                        dumpList(getDeclaredChildren()), getParent()));
         return b.toString();
     }
 
@@ -287,7 +325,21 @@
     }
 
     public List<SpecializationData> getSpecializations() {
-        return specializations;
+        return getSpecializations(false);
+    }
+
+    public List<SpecializationData> getSpecializations(boolean userDefinedOnly) {
+        if (userDefinedOnly) {
+            List<SpecializationData> specs = new ArrayList<>();
+            for (SpecializationData spec : specializations) {
+                if (spec.getMethod() != null) {
+                    specs.add(spec);
+                }
+            }
+            return specs;
+        } else {
+            return specializations;
+        }
     }
 
     public List<SpecializationListenerData> getSpecializationListeners() {
@@ -308,8 +360,10 @@
 
     void setSpecializations(List<SpecializationData> specializations) {
         this.specializations = specializations;
-        for (SpecializationData specialization : specializations) {
-            specialization.setNode(this);
+        if (this.specializations != null) {
+            for (SpecializationData specialization : specializations) {
+                specialization.setNode(this);
+            }
         }
     }
 
@@ -329,4 +383,9 @@
         this.shortCircuits = shortCircuits;
     }
 
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "[" + getNodeId() + "]";
+    }
+
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Wed Mar 06 18:32:33 2013 +0100
@@ -41,7 +41,7 @@
 
     private final FieldKind fieldKind;
     private final ExecutionKind executionKind;
-    private final NodeData nodeData;
+    private NodeData nodeData;
 
     public NodeFieldData(NodeData typeNodeData, VariableElement fieldElement, Element accessElement, AnnotationMirror childAnnotationMirror, FieldKind fieldKind, ExecutionKind executionKind) {
         this.fieldElement = fieldElement;
@@ -52,10 +52,23 @@
         this.executionKind = executionKind;
     }
 
+    NodeFieldData(NodeFieldData field) {
+        this.fieldElement = field.fieldElement;
+        this.accessElement = field.accessElement;
+        this.childAnnotationMirror = field.childAnnotationMirror;
+        this.fieldKind = field.fieldKind;
+        this.executionKind = field.executionKind;
+        this.nodeData = field.nodeData;
+    }
+
     public boolean isShortCircuit() {
         return executionKind == ExecutionKind.SHORT_CIRCUIT;
     }
 
+    void setNode(NodeData nodeData) {
+        this.nodeData = nodeData;
+    }
+
     public VariableElement getFieldElement() {
         return fieldElement;
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Wed Mar 06 18:32:33 2013 +0100
@@ -44,7 +44,6 @@
     public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, SpecializationListener.class);
 
     private Map<String, NodeData> parsedNodes;
-    private TypeElement originalType;
 
     public NodeParser(ProcessorContext c) {
         super(c);
@@ -53,23 +52,14 @@
     @Override
     protected NodeData parse(Element element, AnnotationMirror mirror) {
         assert element instanceof TypeElement;
+        NodeData node = null;
         try {
             parsedNodes = new HashMap<>();
-            originalType = (TypeElement) element;
-
-            return parseInnerClassHierarchy((TypeElement) element);
+            node = parseInnerClassHierarchy((TypeElement) element);
         } finally {
-            if (Log.DEBUG) {
-                NodeData parsed = parsedNodes.get(Utils.getQualifiedName(originalType));
-                if (parsed != null) {
-                    String dump = parsed.dump();
-                    log.error("Node parsed: %s", dump);
-                    System.out.println("Parsed: " + dump);
-                }
-            }
             parsedNodes = null;
-            originalType = null;
         }
+        return node;
     }
 
     @Override
@@ -88,9 +78,10 @@
         }
         NodeData rootNode = resolveNode(rootType);
         if (rootNode == null && children.size() > 0) {
-            rootNode = new NodeData(rootType, null);
+            rootNode = new NodeData(rootType, null, rootType.getSimpleName().toString());
         }
         if (rootNode != null) {
+            children.addAll(rootNode.getDeclaredChildren());
             rootNode.setDeclaredChildren(children);
         }
 
@@ -104,6 +95,18 @@
             if (node != null) {
                 parsedNodes.put(typeName, node);
             }
+
+            if (Log.DEBUG) {
+                NodeData parsed = parsedNodes.get(Utils.getQualifiedName(currentType));
+                if (parsed != null) {
+                    String dump = parsed.dump();
+                    String valid = node != null ? "" : " failed";
+                    String msg = String.format("Node parsing %s : %s", valid, dump);
+                    log.error(msg);
+                    System.out.println(msg);
+                }
+            }
+
             return node;
         }
         return parsedNodes.get(typeName);
@@ -121,13 +124,22 @@
             return null; // not a node
         }
 
+        TypeElement nodeType;
+        boolean needsSplit;
+        if (methodNodes != null) {
+            needsSplit = methodNodes != null;
+            nodeType = Utils.fromTypeMirror(Utils.getAnnotationValueType(methodNodes, "value"));
+        } else {
+            needsSplit = false;
+            nodeType = type;
+        }
+
         if (type.getModifiers().contains(Modifier.PRIVATE)) {
             return null; // not visible
         }
 
-        final NodeData nodeData = parseNodeData(type);
+        NodeData nodeData = parseNodeData(type, nodeType);
         if (nodeData == null) {
-            // TODO error message for instanceBaseClass?
             return null;
         }
 
@@ -140,17 +152,96 @@
         if (!parseMethods(nodeData, elements)) {
             return null;
         }
-        // TODO split
 
-        if (!finalizeSpecializations(nodeData)) {
+        List<NodeData> nodes;
+        if (needsSplit) {
+            nodes = splitNodeData(nodeData);
+            if (nodes == null) {
+                return null;
+            }
+        } else {
+            nodes = new ArrayList<>();
+            nodes.add(nodeData);
+        }
+
+        boolean valid = true;
+        for (NodeData splittedNode : nodes) {
+            if (!finalizeSpecializations(splittedNode)) {
+                valid = false;
+            }
+            if (!verifyNode(splittedNode)) {
+                valid = false;
+            }
+        }
+        if (!valid) {
             return null;
         }
 
-        if (!verifyNode(nodeData)) {
-            return null;
+        if (needsSplit) {
+            nodeData.setDeclaredChildren(nodes);
+            nodeData.setSpecializationListeners(new ArrayList<SpecializationListenerData>());
+            nodeData.setSpecializations(new ArrayList<SpecializationData>());
+            return nodeData;
+        } else {
+            return nodeData;
+        }
+    }
+
+    private static List<NodeData> splitNodeData(NodeData node) {
+        SortedMap<String, List<SpecializationData>> groupedSpecializations = groupByNodeId(node.getSpecializations());
+        SortedMap<String, List<SpecializationListenerData>> groupedListeners = groupByNodeId(node.getSpecializationListeners());
+
+        Set<String> ids = new TreeSet<>();
+        ids.addAll(groupedSpecializations.keySet());
+        ids.addAll(groupedListeners.keySet());
+
+        List<NodeData> splitted = new ArrayList<>();
+        for (String id : ids) {
+            List<SpecializationData> specializations = groupedSpecializations.get(id);
+            List<SpecializationListenerData> listeners = groupedListeners.get(id);
+
+            if (specializations == null) {
+                specializations = new ArrayList<>();
+            }
+
+            if (listeners == null) {
+                listeners = new ArrayList<>();
+            }
+
+            String nodeId = node.getNodeId();
+            if (nodeId.endsWith("Node") && !nodeId.equals("Node")) {
+                nodeId = nodeId.substring(0, nodeId.length() - 4);
+            }
+            String newNodeId = nodeId + Utils.firstLetterUpperCase(id);
+            NodeData copy = new NodeData(node, newNodeId);
+
+            copy.setSpecializations(specializations);
+            copy.setSpecializationListeners(listeners);
+
+            splitted.add(copy);
         }
 
-        return nodeData;
+        if (splitted.isEmpty()) {
+            splitted.add(node);
+        }
+
+        node.setSpecializations(new ArrayList<SpecializationData>());
+        node.setSpecializationListeners(new ArrayList<SpecializationListenerData>());
+
+        return splitted;
+    }
+
+    private static <M extends TemplateMethod> SortedMap<String, List<M>> groupByNodeId(List<M> methods) {
+        SortedMap<String, List<M>> grouped = new TreeMap<>();
+        for (M m : methods) {
+            List<M> list = grouped.get(m.getId());
+            if (list == null) {
+                list = new ArrayList<>();
+                grouped.put(m.getId(), list);
+            }
+            list.add(m);
+        }
+        return grouped;
     }
 
     private boolean parseMethods(final NodeData node, List<Element> elements) {
@@ -176,6 +267,10 @@
     private boolean finalizeSpecializations(final NodeData node) {
         List<SpecializationData> specializations = new ArrayList<>(node.getSpecializations());
 
+        if (specializations.isEmpty()) {
+            return true;
+        }
+
         List<SpecializationData> generics = new ArrayList<>();
         for (SpecializationData spec : specializations) {
             if (spec.isGeneric()) {
@@ -191,6 +286,8 @@
             return false;
         } else if (generics.size() == 1) {
             genericSpecialization = generics.get(0);
+        } else {
+            // TODO support generation of generic if not ambiguous.
         }
 
         if (specializations.size() > 1 && genericSpecialization == null) {
@@ -215,9 +312,101 @@
 
         node.setSpecializations(specializations);
 
+        for (SpecializationData specialization : specializations) {
+            specialization.setId(findUniqueSpecializationId(specialization));
+        }
+
         return true;
     }
 
+    private static String findUniqueSpecializationId(SpecializationData specialization) {
+
+        String name;
+        if (specialization.isGeneric()) {
+            name = "Generic";
+        } else if (specialization.isUninitialized()) {
+            name = "Uninitialized";
+        } else {
+            List<SpecializationData> specializations = new ArrayList<>(specialization.getNode().getSpecializations());
+            for (ListIterator<SpecializationData> iterator = specializations.listIterator(); iterator.hasNext();) {
+                SpecializationData data = iterator.next();
+                if (data.isGeneric() || data.isUninitialized()) {
+                    iterator.remove();
+                }
+            }
+
+            Map<ParameterSpec, Set<String>> usedIds = new HashMap<>();
+            for (SpecializationData other : specializations) {
+                for (ActualParameter param : other.getReturnTypeAndParameters()) {
+                    if (other.getNode().findField(param.getSpecification().getName()) == null) {
+                        continue;
+                    }
+
+                    Set<String> types = usedIds.get(param.getSpecification());
+                    if (types == null) {
+                        types = new HashSet<>();
+                        usedIds.put(param.getSpecification(), types);
+                    }
+                    types.add(Utils.getTypeId(param.getActualType()));
+                }
+            }
+
+            List<ParameterSpec> ambiguousSpecs = new ArrayList<>();
+            for (ActualParameter param : specialization.getReturnTypeAndParameters()) {
+                Set<String> ids = usedIds.get(param.getSpecification());
+                if (ids != null && ids.size() > 1) {
+                    ambiguousSpecs.add(param.getSpecification());
+                }
+            }
+
+            String specializationId = findSpecializationId(specialization, ambiguousSpecs);
+            int specializationIndex = 0;
+            int totalIndex = 0;
+
+            for (SpecializationData other : specializations) {
+                String id = findSpecializationId(other, ambiguousSpecs);
+                if (id.equals(specializationId)) {
+                    totalIndex++;
+                    if (specialization == other) {
+                        specializationIndex = totalIndex;
+                    }
+                }
+            }
+
+            if (specializationIndex != totalIndex) {
+                name = specializationId + specializationIndex;
+            } else {
+                name = specializationId;
+            }
+        }
+        return name;
+    }
+
+    private static String findSpecializationId(SpecializationData specialization, List<ParameterSpec> specs) {
+        boolean allSame = true;
+        ActualParameter prevParam = specialization.getReturnType();
+        for (ParameterSpec spec : specs) {
+            ActualParameter param = specialization.findParameter(spec);
+            if (!Utils.typeEquals(prevParam.getActualType(), param.getActualType())) {
+                allSame = false;
+                break;
+            }
+            prevParam = param;
+        }
+
+        if (allSame) {
+            return Utils.getTypeId(prevParam.getActualType());
+        } else {
+            StringBuilder nameBuilder = new StringBuilder();
+            nameBuilder.append(Utils.getTypeId(prevParam.getActualType()));
+            for (ParameterSpec spec : specs) {
+                ActualParameter param = specialization.findParameter(spec);
+                nameBuilder.append(Utils.getTypeId(param.getActualType()));
+            }
+            return nameBuilder.toString();
+        }
+    }
+
     private boolean verifyNode(NodeData nodeData) {
         // verify specialization parameter length
         if (!verifySpecializationParameters(nodeData)) {
@@ -260,37 +449,49 @@
         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);
+    private NodeData parseNodeData(TypeElement templateType, TypeElement nodeType) {
+        List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeType));
+        List<TypeElement> typeHierarchy = findSuperClasses(new ArrayList<TypeElement>(), nodeType);
         Collections.reverse(typeHierarchy);
 
         AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class);
         if (typeSystemMirror == null) {
-            log.error(type, "No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), type.getQualifiedName().toString());
+            log.error(templateType, "No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), nodeType.getQualifiedName().toString());
             return null;
         }
 
         TypeMirror typeSytemType = Utils.getAnnotationValueType(typeSystemMirror, "value");
         final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true);
         if (typeSystem == null) {
-            log.error(type, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType));
+            log.error(templateType, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType));
             return null;
         }
 
-        NodeData nodeData = new NodeData(type, typeSystem);
+        String nodeId = templateType.getSimpleName().toString();
+        if (nodeId.endsWith("Node") && !nodeId.equals("Node")) {
+            nodeId = nodeId.substring(0, nodeId.length() - 4);
+        }
+
+        NodeData nodeData = new NodeData(templateType, typeSystem, templateType.getSimpleName().toString());
+        nodeData.setNodeType(nodeType.asType());
 
         List<ExecutableTypeData> executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements));
 
         nodeData.setExecutableTypes(executableTypes);
 
-        parsedNodes.put(Utils.getQualifiedName(type), nodeData);
+        parsedNodes.put(Utils.getQualifiedName(nodeType), nodeData);
 
         List<NodeFieldData> fields = parseFields(nodeData, elements, typeHierarchy);
         if (fields == null) {
             return null;
         }
         nodeData.setFields(fields);
+
+        if (!Utils.isAssignable(templateType.asType(), nodeType.asType())) {
+// nodeData.setInstanceParameterSpec(new ParameterSpec("instance", templateType.asType(), false,
+// true));
+        }
+
         return nodeData;
     }
 
@@ -669,6 +870,7 @@
         return valid;
     }
 
+    @SuppressWarnings("unused")
     private boolean verifyNamesUnique(List<? extends TemplateMethod> methods) {
         boolean valid = true;
         for (int i = 0; i < methods.size(); i++) {
@@ -770,8 +972,6 @@
     }
 
     private boolean verifySpecializationThrows(NodeData node) {
-        TypeSystemData typeSystem = node.getTypeSystem();
-
         Map<String, SpecializationData> specializationMap = new HashMap<>();
         for (SpecializationData spec : node.getSpecializations()) {
             specializationMap.put(spec.getMethodName(), spec);
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java	Wed Mar 06 18:32:33 2013 +0100
@@ -55,7 +55,7 @@
             return null;
         }
 
-        return createDefaultMethodSpec(shortCircuitValue);
+        return createDefaultMethodSpec(method, mirror, shortCircuitValue);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java	Wed Mar 06 18:32:33 2013 +0100
@@ -32,16 +32,13 @@
 
 public class SpecializationListenerParser extends MethodParser<SpecializationListenerData> {
 
-    private final MethodSpec specification;
-
     public SpecializationListenerParser(ProcessorContext context, NodeData node) {
         super(context, node);
-        this.specification = createDefaultMethodSpec(null);
     }
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        return specification;
+        return createDefaultMethodSpec(method, mirror, null);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java	Wed Mar 06 18:32:33 2013 +0100
@@ -35,16 +35,13 @@
 
 public class SpecializationMethodParser extends MethodParser<SpecializationData> {
 
-    private final MethodSpec specification;
-
     public SpecializationMethodParser(ProcessorContext context, NodeData operation) {
         super(context, operation);
-        this.specification = createDefaultMethodSpec(null);
     }
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        return specification;
+        return createDefaultMethodSpec(method, mirror, null);
     }
 
     @Override
@@ -148,7 +145,7 @@
     }
 
     private static boolean isGuardCompatible(SpecializationData specialization, GuardData guard) {
-        Iterator<ActualParameter> guardParameters = Arrays.asList(guard.getParameters()).iterator();
+        Iterator<ActualParameter> guardParameters = guard.getParameters().iterator();
         for (ActualParameter param : specialization.getParameters()) {
             if (param.getSpecification().isOptional()) {
                 continue;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java	Wed Mar 06 18:32:33 2013 +0100
@@ -33,12 +33,14 @@
     private TemplateMethod method;
     private final String name;
     private final int index;
+    private final boolean hidden;
 
-    public ActualParameter(ParameterSpec specification, TypeMirror actualType, int index) {
+    public ActualParameter(ParameterSpec specification, TypeMirror actualType, int index, boolean hidden) {
         this.specification = specification;
         this.actualType = actualType;
 
         this.index = index;
+        this.hidden = hidden;
         String valueName = specification.getName() + "Value";
         if (specification.isIndexed()) {
             valueName = valueName + index;
@@ -46,6 +48,10 @@
         this.name = valueName;
     }
 
+    public boolean isHidden() {
+        return hidden;
+    }
+
     public int getIndex() {
         return index;
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java	Wed Mar 06 18:32:33 2013 +0100
@@ -24,16 +24,25 @@
 
 import java.util.*;
 
+import javax.lang.model.type.*;
+
 public class MethodSpec {
 
+    private final List<TypeMirror> implicitTypes;
+
     private final ParameterSpec returnType;
     private final List<ParameterSpec> parameters;
 
-    public MethodSpec(ParameterSpec returnType, List<ParameterSpec> parameters) {
+    public MethodSpec(List<TypeMirror> prefixTypes, ParameterSpec returnType, List<ParameterSpec> parameters) {
+        this.implicitTypes = prefixTypes;
         this.returnType = returnType;
         this.parameters = parameters;
     }
 
+    public List<TypeMirror> getImplicitTypes() {
+        return implicitTypes;
+    }
+
     public ParameterSpec getReturnType() {
         return returnType;
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Wed Mar 06 18:32:33 2013 +0100
@@ -22,19 +22,25 @@
  */
 package com.oracle.truffle.codegen.processor.template;
 
+import java.util.*;
+
 import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+
+import com.oracle.truffle.codegen.processor.*;
 
 public class TemplateMethod {
 
-    private final String id;
+    private String id;
     private final Template template;
     private final MethodSpec specification;
     private final ExecutableElement method;
     private final AnnotationMirror markerAnnotation;
     private final ActualParameter returnType;
-    private final ActualParameter[] parameters;
+    private final List<ActualParameter> parameters;
 
-    public TemplateMethod(String id, 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,
+                    List<ActualParameter> parameters) {
         this.template = template;
         this.specification = specification;
         this.method = method;
@@ -54,6 +60,10 @@
         this(method.id, method.template, method.specification, method.method, method.markerAnnotation, method.returnType, method.parameters);
     }
 
+    public void setId(String id) {
+        this.id = id;
+    }
+
     public String getId() {
         return id;
     }
@@ -70,7 +80,7 @@
         return returnType;
     }
 
-    public ActualParameter[] getParameters() {
+    public List<ActualParameter> getParameters() {
         return parameters;
     }
 
@@ -83,15 +93,27 @@
         return null;
     }
 
+    public List<ActualParameter> getReturnTypeAndParameters() {
+        List<ActualParameter> allParameters = new ArrayList<>(getParameters().size() + 1);
+        allParameters.add(getReturnType());
+        allParameters.addAll(getParameters());
+        return Collections.unmodifiableList(allParameters);
+    }
+
     public ActualParameter findParameter(ParameterSpec spec) {
         for (ActualParameter param : getParameters()) {
-            if (param.getSpecification() == spec) {
+            if (param.getSpecification().getName().equals(spec.getName())) {
                 return param;
             }
         }
         return null;
     }
 
+    public boolean canBeAccessedByInstanceOf(TypeMirror type) {
+        TypeMirror methodType = Utils.findNearestEnclosingType(getMethod()).asType();
+        return Utils.isAssignable(type, methodType) || Utils.isAssignable(methodType, type);
+    }
+
     public ExecutableElement getMethod() {
         return method;
     }
@@ -106,7 +128,7 @@
 
     @Override
     public String toString() {
-        return getClass().getSimpleName() + " [method = " + method + "]";
+        return "id = " + getId() + ", " + getClass().getSimpleName() + " [method = " + getMethod() + "]";
     }
 
     public ActualParameter getPreviousParam(ActualParameter searchParam) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Wed Mar 06 18:32:33 2013 +0100
@@ -102,7 +102,7 @@
                 continue;
             }
 
-            E parsedMethod = parseNew(method, mirror);
+            E parsedMethod = parse(method, mirror);
             if (parsedMethod != null) {
                 parsedMethods.add(parsedMethod);
             } else {
@@ -115,7 +115,7 @@
         return parsedMethods;
     }
 
-    private E parseNew(ExecutableElement method, AnnotationMirror annotation) {
+    private E parse(ExecutableElement method, AnnotationMirror annotation) {
         MethodSpec methodSpecification = createSpecification(method, annotation);
         if (methodSpecification == null) {
             return null;
@@ -127,7 +127,7 @@
         List<ParameterSpec> parameterSpecs = new ArrayList<>();
         parameterSpecs.addAll(methodSpecification.getParameters());
 
-        ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, method.getReturnType(), template, 0);
+        ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, method.getReturnType(), template, 0, false);
         if (returnTypeMirror == null) {
             if (isEmitErrors()) {
                 String expectedReturnType = createTypeSignature(returnTypeSpec, typeDefs, true);
@@ -141,10 +141,16 @@
             return null;
         }
 
-        List<ActualParameter> parameters = parseParameters(method, parameterSpecs);
+        List<TypeMirror> parameterTypes = new ArrayList<>();
+        parameterTypes.addAll(methodSpecification.getImplicitTypes());
+        for (VariableElement var : method.getParameters()) {
+            parameterTypes.add(var.asType());
+        }
+
+        List<ActualParameter> parameters = parseParameters(parameterTypes, parameterSpecs, methodSpecification.getImplicitTypes().size());
         if (parameters == null) {
             if (isEmitErrors()) {
-                String message = String.format("Method signature mismatch. Expected signature: \n%s",
+                String message = String.format("Method signature %s does not match to the expected signature: \n%s", createActualSignature(methodSpecification, method),
                                 createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs));
                 context.getLog().error(method, annotation, message);
             }
@@ -157,35 +163,56 @@
             id = Utils.getAnnotationValueString(idAnnotation, "value");
         }
 
-        ActualParameter[] paramMirrors = parameters.toArray(new ActualParameter[parameters.size()]);
-        return create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, paramMirrors));
+        return create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, parameters));
     }
 
-    private List<ActualParameter> parseParameters(ExecutableElement method, List<ParameterSpec> parameterSpecs) {
-        Iterator<? extends VariableElement> parameterIterator = method.getParameters().iterator();
+    private static String createActualSignature(MethodSpec spec, ExecutableElement method) {
+        List<String> types = new ArrayList<>();
+        for (TypeMirror implicitType : spec.getImplicitTypes()) {
+            types.add("implicit " + Utils.getSimpleName(implicitType));
+        }
+        for (VariableElement var : method.getParameters()) {
+            types.add(Utils.getSimpleName(var.asType()));
+        }
+
+        StringBuilder b = new StringBuilder("(");
+        for (Iterator<String> iterator = types.iterator(); iterator.hasNext();) {
+            b.append(iterator.next());
+            if (iterator.hasNext()) {
+                b.append(", ");
+            }
+        }
+        b.append(")");
+        return b.toString();
+    }
+
+    private List<ActualParameter> parseParameters(List<TypeMirror> types, List<ParameterSpec> parameterSpecs, int hiddenCount) {
+        Iterator<? extends TypeMirror> parameterIterator = types.iterator();
         Iterator<? extends ParameterSpec> specificationIterator = parameterSpecs.iterator();
 
-        VariableElement parameter = parameterIterator.hasNext() ? parameterIterator.next() : null;
+        TypeMirror parameter = parameterIterator.hasNext() ? parameterIterator.next() : null;
         ParameterSpec specification = specificationIterator.hasNext() ? specificationIterator.next() : null;
 
-        int specificationIndex = 0;
+        int globalParameterIndex = 0;
+        int specificationParameterIndex = 0;
         List<ActualParameter> resolvedParameters = new ArrayList<>();
         while (parameter != null || specification != null) {
             if (parameter == null || specification == null) {
                 if (specification != null && (specification.isOptional() || specification.getCardinality() == Cardinality.MULTIPLE)) {
                     specification = specificationIterator.hasNext() ? specificationIterator.next() : null;
-                    specificationIndex = 0;
+                    specificationParameterIndex = 0;
                     continue;
                 }
                 return null;
             }
 
-            ActualParameter resolvedParameter = matchParameter(specification, parameter.asType(), template, specificationIndex);
+            boolean hidden = globalParameterIndex < hiddenCount;
+            ActualParameter resolvedParameter = matchParameter(specification, parameter, template, specificationParameterIndex, hidden);
             if (resolvedParameter == null) {
                 // mismatch
                 if (specification.isOptional()) {
                     specification = specificationIterator.hasNext() ? specificationIterator.next() : null;
-                    specificationIndex = 0;
+                    specificationParameterIndex = 0;
                 } else {
                     return null;
                 }
@@ -196,17 +223,19 @@
                 if (specification.getCardinality() == Cardinality.ONE) {
                     parameter = parameterIterator.hasNext() ? parameterIterator.next() : null;
                     specification = specificationIterator.hasNext() ? specificationIterator.next() : null;
-                    specificationIndex = 0;
+                    globalParameterIndex++;
+                    specificationParameterIndex = 0;
                 } else if (specification.getCardinality() == Cardinality.MULTIPLE) {
                     parameter = parameterIterator.hasNext() ? parameterIterator.next() : null;
-                    specificationIndex++;
+                    globalParameterIndex++;
+                    specificationParameterIndex++;
                 }
             }
         }
         return resolvedParameters;
     }
 
-    private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template typeSystem, int index) {
+    private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template typeSystem, int index, boolean hidden) {
         TypeMirror resolvedType = mirror;
         if (hasError(resolvedType)) {
             resolvedType = context.resolveNotYetCompiledType(mirror, typeSystem);
@@ -215,7 +244,7 @@
         if (!specification.matches(resolvedType)) {
             return null;
         }
-        return new ActualParameter(specification, resolvedType, index);
+        return new ActualParameter(specification, resolvedType, index, hidden);
     }
 
     protected List<TypeDef> createTypeDefinitions(ParameterSpec returnType, List<? extends ParameterSpec> parameters) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java	Wed Mar 06 18:32:33 2013 +0100
@@ -26,15 +26,8 @@
 
 public class GuardData extends TemplateMethod {
 
-    private final Template origin;
-
-    public GuardData(TemplateMethod method, Template origin) {
+    public GuardData(TemplateMethod method) {
         super(method);
-        this.origin = origin;
-    }
-
-    public Template getOrigin() {
-        return origin;
     }
 
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java	Wed Mar 06 18:32:33 2013 +0100
@@ -26,6 +26,7 @@
 import java.util.*;
 
 import javax.lang.model.element.*;
+import javax.lang.model.type.*;
 
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
@@ -47,7 +48,7 @@
         List<ParameterSpec> specs = new ArrayList<>();
         specs.add(new ParameterSpec("valueN", typeSystem, false, Cardinality.MULTIPLE));
         ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), false);
-        return new MethodSpec(returnTypeSpec, specs);
+        return new MethodSpec(Collections.<TypeMirror> emptyList(), returnTypeSpec, specs);
     }
 
     @Override
@@ -57,7 +58,7 @@
 
     @Override
     public GuardData create(TemplateMethod method) {
-        return new GuardData(method, template);
+        return new GuardData(method);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java	Wed Mar 06 18:32:33 2013 +0100
@@ -26,6 +26,7 @@
 import java.util.*;
 
 import javax.lang.model.element.*;
+import javax.lang.model.type.*;
 
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
@@ -47,7 +48,7 @@
         List<ParameterSpec> specs = new ArrayList<>();
         specs.add(new ParameterSpec("value", getTypeSystem(), false, Cardinality.ONE));
         ParameterSpec returnTypeSpec = new ParameterSpec("returnType", targetType.getPrimitiveType(), false);
-        MethodSpec spec = new MethodSpec(returnTypeSpec, specs);
+        MethodSpec spec = new MethodSpec(Collections.<TypeMirror> emptyList(), returnTypeSpec, specs);
         return spec;
     }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java	Wed Mar 06 18:27:57 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java	Wed Mar 06 18:32:33 2013 +0100
@@ -26,6 +26,7 @@
 import java.util.*;
 
 import javax.lang.model.element.*;
+import javax.lang.model.type.*;
 
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
@@ -47,7 +48,7 @@
         List<ParameterSpec> specs = new ArrayList<>();
         specs.add(new ParameterSpec("value", getTypeSystem(), false, Cardinality.ONE));
         ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), false);
-        MethodSpec spec = new MethodSpec(returnTypeSpec, specs);
+        MethodSpec spec = new MethodSpec(Collections.<TypeMirror> emptyList(), returnTypeSpec, specs);
         return spec;
     }