changeset 9220:97ad6d3e7557

Codegen API changes. Executed child nodes are now defined using @NodeChildren instead of fields.
author Christian Humer <christian.humer@gmail.com>
date Sat, 20 Apr 2013 12:16:22 +0200
parents 1964871a642d
children 67bee207f20c
files graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChildren.java 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/TypeCast.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.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/ast/CodeExecutableElement.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTypeMirror.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.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/NodeChildData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.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/ParameterSpec.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java
diffstat 22 files changed, 785 insertions(+), 482 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/NodeChild.java	Sat Apr 20 12:16:22 2013 +0200
@@ -0,0 +1,36 @@
+/*
+ * 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.TYPE})
+public @interface NodeChild {
+
+    String value() default "";
+
+    Class<?> type() default NodeClass.InheritNode.class;
+
+    String[] executeWith() default {};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChildren.java	Sat Apr 20 12:16:22 2013 +0200
@@ -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.TYPE})
+public @interface NodeChildren {
+
+    NodeChild[] value() default {};
+
+}
--- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeClass.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeClass.java	Sat Apr 20 12:16:22 2013 +0200
@@ -30,6 +30,11 @@
 @Target({ElementType.TYPE})
 public @interface NodeClass {
 
-    Class<? extends Node> value();
+    public static final class InheritNode extends Node {
+    }
+
+    Class<? extends Node> value() default InheritNode.class;
+
+    boolean splitByMethodName() default false;
 
 }
--- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeCast.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeCast.java	Sat Apr 20 12:16:22 2013 +0200
@@ -24,11 +24,6 @@
 
 import java.lang.annotation.*;
 
-/**
- *
- *
- *
- */
 @Retention(RetentionPolicy.CLASS)
 @Target({ElementType.METHOD})
 public @interface TypeCast {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java	Sat Apr 20 12:16:22 2013 +0200
@@ -43,8 +43,8 @@
     private final TypeMirror nodeArray;
     private final TypeMirror unexpectedValueException;
     private final TypeMirror frame;
-    private final TypeMirror stableAnnotation;
-    private final TypeMirror contentStableAnnotation;
+    private final DeclaredType childAnnotation;
+    private final DeclaredType childrenAnnotation;
     private final TypeMirror typeConversion;
     private final TypeMirror truffleIntrinsics;
 
@@ -55,8 +55,8 @@
         nodeArray = context.getEnvironment().getTypeUtils().getArrayType(node);
         unexpectedValueException = getRequired(context, UnexpectedResultException.class);
         frame = getRequired(context, VirtualFrame.class);
-        stableAnnotation = getRequired(context, Child.class);
-        contentStableAnnotation = getRequired(context, Children.class);
+        childAnnotation = getRequired(context, Child.class);
+        childrenAnnotation = getRequired(context, Children.class);
         typeConversion = getRequired(context, TypeConversion.class);
         truffleIntrinsics = getRequired(context, TruffleIntrinsics.class);
     }
@@ -73,12 +73,12 @@
         return false;
     }
 
-    private TypeMirror getRequired(ProcessorContext context, Class clazz) {
+    private DeclaredType getRequired(ProcessorContext context, Class clazz) {
         TypeMirror type = context.getType(clazz);
         if (type == null) {
             errors.add(String.format("Could not find required type: %s", clazz.getSimpleName()));
         }
-        return type;
+        return (DeclaredType) type;
     }
 
     public TypeMirror getTruffleIntrinsics() {
@@ -105,11 +105,11 @@
         return unexpectedValueException;
     }
 
-    public TypeMirror getStableAnnotation() {
-        return stableAnnotation;
+    public DeclaredType getChildAnnotation() {
+        return childAnnotation;
     }
 
-    public TypeMirror getContentStableAnnotation() {
-        return contentStableAnnotation;
+    public DeclaredType getChildrenAnnotation() {
+        return childrenAnnotation;
     }
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java	Sat Apr 20 12:16:22 2013 +0200
@@ -32,6 +32,7 @@
 import javax.lang.model.util.*;
 
 import com.oracle.truffle.codegen.processor.ast.*;
+import com.oracle.truffle.codegen.processor.ast.CodeTypeMirror.DeclaredCodeTypeMirror;
 import com.oracle.truffle.codegen.processor.compiler.*;
 
 /**
@@ -63,17 +64,20 @@
         return types;
     }
 
+    public static DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) {
+        return new DeclaredCodeTypeMirror(typeElem, Arrays.asList(typeArgs));
+    }
+
     public static List<AnnotationMirror> collectAnnotations(ProcessorContext context, AnnotationMirror markerAnnotation, String elementName, Element element,
                     Class<? extends Annotation> annotationClass) {
-        List<AnnotationMirror> result = Utils.getAnnotationValueList(AnnotationMirror.class, markerAnnotation, elementName);
+        List<AnnotationMirror> result = new ArrayList<>();
+        if (markerAnnotation != null) {
+            result.addAll(Utils.getAnnotationValueList(AnnotationMirror.class, markerAnnotation, elementName));
+        }
         AnnotationMirror explicit = Utils.findAnnotationMirror(context.getEnvironment(), element, annotationClass);
         if (explicit != null) {
             result.add(explicit);
         }
-
-        for (AnnotationMirror mirror : result) {
-            assert Utils.typeEquals(mirror.getAnnotationType(), context.getType(annotationClass));
-        }
         return result;
     }
 
@@ -319,6 +323,8 @@
                 return getSimpleName(mirror);
             case ERROR:
                 throw new CompileErrorException("Type error " + mirror);
+            case NONE:
+                return "$none";
             default:
                 throw new RuntimeException("Unknown type specified " + mirror + " mirror: " + mirror);
         }
@@ -371,7 +377,7 @@
         return null;
     }
 
-    private static List<Element> getElementHierarchy(Element e) {
+    public static List<Element> getElementHierarchy(Element e) {
         List<Element> elements = new ArrayList<>();
         elements.add(e);
 
@@ -589,7 +595,7 @@
 
         @Override
         public Object visitEnumConstant(VariableElement c, Void p) {
-            return c.getConstantValue();
+            return c;
         }
 
         @Override
@@ -772,11 +778,7 @@
 
     public static Modifier getVisibility(Set<Modifier> modifier) {
         for (Modifier mod : modifier) {
-            if (mod == Modifier.PUBLIC) {
-                return mod;
-            } else if (mod == Modifier.PRIVATE) {
-                return mod;
-            } else if (mod == Modifier.PROTECTED) {
+            if (mod == Modifier.PUBLIC || mod == Modifier.PRIVATE || mod == Modifier.PROTECTED) {
                 return mod;
             }
         }
@@ -813,4 +815,20 @@
         return getQualifiedName(actualType).equals("java.lang.Object");
     }
 
+    public static boolean isFieldAccessible(Element element, VariableElement variable) {
+        TypeElement type = Utils.findNearestEnclosingType(element);
+        TypeElement varType = Utils.findNearestEnclosingType(variable);
+
+        while (type != null) {
+            if (typeEquals(type.asType(), varType.asType())) {
+                return true;
+            }
+            if (type.getSuperclass() != null) {
+                type = Utils.fromTypeMirror(type.getSuperclass());
+            } else {
+                type = null;
+            }
+        }
+        return false;
+    }
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java	Sat Apr 20 12:16:22 2013 +0200
@@ -215,7 +215,7 @@
             copy.addAnnotationMirror(mirror);
         }
         for (VariableElement var : method.getParameters()) {
-            copy.addParameter(var);
+            copy.addParameter(CodeVariableElement.clone(var));
         }
         for (Element element : method.getEnclosedElements()) {
             copy.add(element);
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTypeMirror.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTypeMirror.java	Sat Apr 20 12:16:22 2013 +0200
@@ -63,11 +63,17 @@
 
     public static class DeclaredCodeTypeMirror extends CodeTypeMirror implements DeclaredType {
 
-        private final CodeTypeElement clazz;
+        private final TypeElement clazz;
+        private final List<? extends TypeMirror> typeArguments;
 
-        public DeclaredCodeTypeMirror(CodeTypeElement clazz) {
+        public DeclaredCodeTypeMirror(TypeElement clazz) {
+            this(clazz, Collections.<TypeMirror> emptyList());
+        }
+
+        public DeclaredCodeTypeMirror(TypeElement clazz, List<? extends TypeMirror> typeArguments) {
             super(TypeKind.DECLARED);
             this.clazz = clazz;
+            this.typeArguments = typeArguments;
         }
 
         @Override
@@ -82,7 +88,7 @@
 
         @Override
         public List<? extends TypeMirror> getTypeArguments() {
-            return Collections.emptyList();
+            return typeArguments;
         }
 
         @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java	Sat Apr 20 12:16:22 2013 +0200
@@ -123,9 +123,9 @@
         writeClassImpl(e);
     }
 
-    private String useImport(TypeMirror type) {
+    private String useImport(Element enclosedType, TypeMirror type) {
         if (imports != null) {
-            return imports.useImport(type);
+            return imports.createTypeReference(enclosedType, type);
         } else {
             return Utils.getSimpleName(type);
         }
@@ -133,7 +133,7 @@
 
     private void writeClassImpl(CodeTypeElement e) {
         for (AnnotationMirror annotation : e.getAnnotationMirrors()) {
-            visitAnnotation(annotation);
+            visitAnnotation(e, annotation);
             writeLn();
         }
 
@@ -145,12 +145,12 @@
         }
         write(e.getSimpleName());
         if (e.getSuperclass() != null && !getQualifiedName(e.getSuperclass()).equals("java.lang.Object")) {
-            write(" extends ").write(useImport(e.getSuperclass()));
+            write(" extends ").write(useImport(e, e.getSuperclass()));
         }
         if (e.getImplements().size() > 0) {
             write(" implements ");
             for (int i = 0; i < e.getImplements().size(); i++) {
-                write(useImport(e.getImplements().get(i)));
+                write(useImport(e, e.getImplements().get(i)));
                 if (i < e.getImplements().size() - 1) {
                     write(", ");
                 }
@@ -255,8 +255,8 @@
         Element parent = f.getEnclosingElement();
 
         for (AnnotationMirror annotation : f.getAnnotationMirrors()) {
-            visitAnnotation(annotation);
-            writeLn();
+            visitAnnotation(f, annotation);
+            write(" ");
         }
 
         CodeTree init = null;
@@ -275,7 +275,7 @@
             }
         } else {
             writeModifiers(f.getModifiers());
-            write(useImport(f.asType()));
+            write(useImport(f, f.asType()));
 
             if (f.getEnclosingElement().getKind() == ElementKind.METHOD) {
                 ExecutableElement method = (ExecutableElement) f.getEnclosingElement();
@@ -294,8 +294,8 @@
         return null;
     }
 
-    public void visitAnnotation(AnnotationMirror e) {
-        write("@").write(useImport(e.getAnnotationType()));
+    public void visitAnnotation(Element enclosedElement, AnnotationMirror e) {
+        write("@").write(useImport(enclosedElement, e.getAnnotationType()));
 
         if (!e.getElementValues().isEmpty()) {
             write("(");
@@ -303,7 +303,7 @@
 
             Map<? extends ExecutableElement, ? extends AnnotationValue> values = e.getElementValues();
             if (defaultElement != null && values.size() == 1 && values.get(defaultElement) != null) {
-                visitAnnotationValue(values.get(defaultElement));
+                visitAnnotationValue(enclosedElement, values.get(defaultElement));
             } else {
                 Set<? extends ExecutableElement> methodsSet = values.keySet();
                 List<ExecutableElement> methodsList = new ArrayList<>();
@@ -327,7 +327,7 @@
                     AnnotationValue value = values.get(method);
                     write(method.getSimpleName().toString());
                     write(" = ");
-                    visitAnnotationValue(value);
+                    visitAnnotationValue(enclosedElement, value);
 
                     if (i < methodsList.size() - 1) {
                         write(", ");
@@ -339,12 +339,18 @@
         }
     }
 
-    public void visitAnnotationValue(AnnotationValue e) {
-        e.accept(new AnnotationValueWriterVisitor(), null);
+    public void visitAnnotationValue(Element enclosedElement, AnnotationValue e) {
+        e.accept(new AnnotationValueWriterVisitor(enclosedElement), null);
     }
 
     private class AnnotationValueWriterVisitor extends AbstractAnnotationValueVisitor7<Void, Void> {
 
+        private final Element enclosedElement;
+
+        public AnnotationValueWriterVisitor(Element enclosedElement) {
+            this.enclosedElement = enclosedElement;
+        }
+
         @Override
         public Void visitBoolean(boolean b, Void p) {
             write(Boolean.toString(b));
@@ -403,14 +409,14 @@
 
         @Override
         public Void visitType(TypeMirror t, Void p) {
-            write(useImport(t));
+            write(useImport(enclosedElement, t));
             write(".class");
             return null;
         }
 
         @Override
         public Void visitEnumConstant(VariableElement c, Void p) {
-            write(useImport(c.asType()));
+            write(useImport(enclosedElement, c.asType()));
             write(".");
             write(c.getSimpleName().toString());
             return null;
@@ -418,7 +424,7 @@
 
         @Override
         public Void visitAnnotation(AnnotationMirror a, Void p) {
-            AbstractCodeWriter.this.visitAnnotation(a);
+            AbstractCodeWriter.this.visitAnnotation(enclosedElement, a);
             return null;
         }
 
@@ -427,7 +433,7 @@
             write("{");
             for (int i = 0; i < vals.size(); i++) {
                 AnnotationValue value = vals.get(i);
-                AbstractCodeWriter.this.visitAnnotationValue(value);
+                AbstractCodeWriter.this.visitAnnotationValue(enclosedElement, value);
                 if (i < vals.size() - 1) {
                     write(", ");
                 }
@@ -459,14 +465,14 @@
     @Override
     public Void visitExecutable(CodeExecutableElement e, Void p) {
         for (AnnotationMirror annotation : e.getAnnotationMirrors()) {
-            visitAnnotation(annotation);
+            visitAnnotation(e, annotation);
             writeLn();
         }
 
         writeModifiers(e.getModifiers());
 
         if (e.getReturnType() != null) {
-            write(useImport(e.getReturnType()));
+            write(useImport(e, e.getReturnType()));
             write(" ");
         }
         write(e.getSimpleName());
@@ -485,7 +491,7 @@
         if (throwables.size() > 0) {
             write(" throws ");
             for (int i = 0; i < throwables.size(); i++) {
-                write(useImport(throwables.get(i)));
+                write(useImport(e, throwables.get(i)));
                 if (i < throwables.size() - 1) {
                     write(", ");
                 }
@@ -549,20 +555,20 @@
                 break;
             case STATIC_FIELD_REFERENCE:
                 if (e.getString() != null) {
-                    write(imports.useStaticFieldImport(e.getType(), e.getString()));
+                    write(imports.createStaticFieldReference(e, e.getType(), e.getString()));
                 } else {
                     write("null");
                 }
                 break;
             case STATIC_METHOD_REFERENCE:
                 if (e.getString() != null) {
-                    write(imports.useStaticMethodImport(e.getType(), e.getString()));
+                    write(imports.createStaticMethodReference(e, e.getType(), e.getString()));
                 } else {
                     write("null");
                 }
                 break;
             case TYPE:
-                write(useImport(e.getType()));
+                write(useImport(e, e.getType()));
                 break;
             default:
                 assert false;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java	Sat Apr 20 12:16:22 2013 +0200
@@ -29,8 +29,8 @@
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.codegen.processor.*;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality;
 import com.oracle.truffle.codegen.processor.template.*;
-import com.oracle.truffle.codegen.processor.template.ParameterSpec.*;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
 public class ExecutableTypeMethodParser extends NodeMethodParser<ExecutableTypeData> {
@@ -46,7 +46,7 @@
         MethodSpec spec = createDefaultMethodSpec(method, mirror, false, null);
         spec.setVariableRequiredArguments(true);
         ParameterSpec other = new ParameterSpec("other", nodeTypeMirrors(getNode()));
-        other.setCardinality(Cardinality.MULTIPLE);
+        other.setCardinality(Cardinality.MANY);
         other.setSignature(true);
         other.setIndexed(true);
         spec.addRequired(other);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java	Sat Apr 20 12:16:22 2013 +0200
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.codegen.processor.node;
+
+import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+
+import com.oracle.truffle.codegen.processor.template.*;
+
+public class NodeChildData extends MessageContainer {
+
+    public enum Cardinality {
+        ONE, MANY;
+
+        public boolean isMany() {
+            return this == MANY;
+        }
+
+        public boolean isOne() {
+            return this == ONE;
+        }
+    }
+
+    public enum ExecutionKind {
+        DEFAULT, SHORT_CIRCUIT
+    }
+
+    private final Element sourceElement;
+    private final AnnotationMirror sourceAnnotationMirror;
+
+    private final String name;
+    private final TypeMirror type;
+    private final Element accessElement;
+
+    private final Cardinality cardinality;
+    private final ExecutionKind executionKind;
+    private NodeData nodeData;
+
+    public NodeChildData(Element sourceElement, AnnotationMirror sourceMirror, String name, TypeMirror nodeType, Element accessElement, Cardinality cardinality, ExecutionKind executionKind) {
+        this.sourceElement = sourceElement;
+        this.sourceAnnotationMirror = sourceMirror;
+        this.name = name;
+        this.type = nodeType;
+        this.accessElement = accessElement;
+        this.cardinality = cardinality;
+        this.executionKind = executionKind;
+    }
+
+    @Override
+    public Element getMessageElement() {
+        return sourceElement;
+    }
+
+    @Override
+    public AnnotationMirror getMessageAnnotation() {
+        return sourceAnnotationMirror;
+    }
+
+    public boolean isShortCircuit() {
+        return executionKind == ExecutionKind.SHORT_CIRCUIT;
+    }
+
+    void setNode(NodeData nodeData) {
+        this.nodeData = nodeData;
+        getMessages().addAll(nodeData.collectMessages());
+    }
+
+    public Element getAccessElement() {
+        return accessElement;
+    }
+
+    public TypeMirror getNodeType() {
+        return type;
+    }
+
+    public Cardinality getCardinality() {
+        return cardinality;
+    }
+
+    public ExecutionKind getExecutionKind() {
+        return executionKind;
+    }
+
+    public NodeData getNodeData() {
+        return nodeData;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String toString() {
+        return "NodeFieldData[name=" + getName() + ", kind=" + cardinality + ", execution=" + executionKind + ", node=" + getNodeData() + "]";
+    }
+
+}
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Sat Apr 20 12:16:22 2013 +0200
@@ -34,8 +34,8 @@
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.ast.*;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.FieldKind;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.ExecutionKind;
 import com.oracle.truffle.codegen.processor.template.*;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
@@ -236,8 +236,14 @@
         return builder.getRoot();
     }
 
-    private static String genClassName(Template operation) {
-        return getSimpleName(operation.getTemplateType()) + "Gen";
+    private static String genClassName(NodeData node) {
+        String nodeid = node.getNodeId();
+        if (nodeid.endsWith("Node") && !nodeid.equals("Node")) {
+            nodeid = nodeid.substring(0, nodeid.length() - 4);
+        }
+        String name = Utils.firstLetterUpperCase(nodeid);
+        name += "GenNode";
+        return name;
     }
 
     private String generatedGenericMethodName(SpecializationData specialization) {
@@ -299,7 +305,7 @@
             valuesNeedsCast = new HashSet<>();
             for (GuardData guard : targetSpecialization.getGuards()) {
                 for (ActualParameter parameter : guard.getParameters()) {
-                    NodeFieldData field = node.findField(parameter.getSpecification().getName());
+                    NodeChildData field = node.findChild(parameter.getSpecification().getName());
                     if (field == null) {
                         continue;
                     }
@@ -366,8 +372,8 @@
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
         // Implict guards based on method signature
         for (ActualParameter guardedParam : guardedSpecialization.getParameters()) {
-            NodeFieldData field = guardedSpecialization.getNode().findField(guardedParam.getSpecification().getName());
-            if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
+            NodeChildData field = guardedSpecialization.getNode().findChild(guardedParam.getSpecification().getName());
+            if (field == null) {
                 continue;
             }
             ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName());
@@ -391,8 +397,8 @@
         // Implict guards based on method signature
         String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
         for (ActualParameter guardedParam : guardedSpecialization.getParameters()) {
-            NodeFieldData field = guardedSpecialization.getNode().findField(guardedParam.getSpecification().getName());
-            if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
+            NodeChildData field = guardedSpecialization.getNode().findChild(guardedParam.getSpecification().getName());
+            if (field == null) {
                 continue;
             }
             ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName());
@@ -410,7 +416,7 @@
         return builder.isEmpty() ? null : builder.getRoot();
     }
 
-    private CodeTree createImplicitGuard(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) {
+    private CodeTree createImplicitGuard(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, ActualParameter target) {
         NodeData node = field.getNodeData();
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
 
@@ -444,7 +450,7 @@
         return builder.getRoot();
     }
 
-    private CodeTree createCast(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) {
+    private CodeTree createCast(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, ActualParameter target) {
         NodeData node = field.getNodeData();
         TypeData sourceType = source.getTypeSystemType();
         TypeData targetType = target.getTypeSystemType();
@@ -503,22 +509,49 @@
         builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end();
     }
 
+    private static List<ExecutableElement> findUserConstructors(TypeMirror nodeType) {
+        List<ExecutableElement> constructors = new ArrayList<>();
+        for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(nodeType).getEnclosedElements())) {
+            if (constructor.getModifiers().contains(PRIVATE)) {
+                continue;
+            }
+            if (isCopyConstructor(constructor)) {
+                continue;
+            }
+            constructors.add(constructor);
+        }
+
+        if (constructors.isEmpty()) {
+            constructors.add(new CodeExecutableElement(null, Utils.getSimpleName(nodeType)));
+        }
+
+        return constructors;
+    }
+
+    private static boolean isCopyConstructor(ExecutableElement element) {
+        if (element.getParameters().size() != 1) {
+            return false;
+        }
+        VariableElement var = element.getParameters().get(0);
+        TypeElement type = Utils.findNearestEnclosingType(var);
+
+        if (!Utils.typeEquals(var.asType(), type.asType())) {
+            return false;
+        }
+        return true;
+    }
+
     @Override
     protected void createChildren(NodeData node) {
         Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>();
-        if (node.getDeclaredChildren() != null && !node.getDeclaredChildren().isEmpty()) {
-            for (NodeData nodeChild : node.getDeclaredChildren()) {
+        if (node.getDeclaredNodes() != null && !node.getDeclaredNodes().isEmpty()) {
+            for (NodeData nodeChild : node.getDeclaredNodes()) {
                 NodeCodeGenerator generator = new NodeCodeGenerator(getContext());
                 childTypes.put(nodeChild, generator.process(null, nodeChild).getEnclosedElements());
             }
         }
 
-        if (node.getExtensionElements() != null && !node.getExtensionElements().isEmpty()) {
-            NodeGenFactory factory = new NodeGenFactory(context);
-            add(factory, node);
-        }
-
-        if (node.needsFactory() || node.getNodeChildren().size() > 0) {
+        if (node.needsFactory() || node.getNodeDeclaringChildren().size() > 0) {
             add(new NodeFactoryFactory(context, childTypes), node);
         }
     }
@@ -531,36 +564,130 @@
 
         @Override
         protected CodeTypeElement create(NodeData node) {
-            CodeTypeElement clazz = createClass(node, modifiers(PUBLIC, ABSTRACT), genClassName(node), node.getTemplateType().asType(), false);
-
-            for (ExecutableElement executable : ElementFilter.constructorsIn(node.getTemplateType().getEnclosedElements())) {
-                CodeExecutableElement superConstructor = createSuperConstructor(clazz, executable);
+            CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), genClassName(node), node.getNodeType(), false);
 
-                if (superConstructor != null) {
-                    if (superConstructor.getParameters().size() == 1 && Utils.typeEquals(superConstructor.getParameters().get(0).asType(), node.getTemplateType().asType())) {
-                        String originalName = superConstructor.getParameters().get(0).getSimpleName().toString();
-                        superConstructor.getParameters().clear();
-                        superConstructor.getParameters().add(new CodeVariableElement(clazz.asType(), originalName));
-                    }
-                    clazz.add(superConstructor);
-                }
+            for (NodeChildData child : node.getChildren()) {
+                clazz.add(createChildField(child));
             }
 
+            createConstructors(node, clazz);
+
             if (node.getExtensionElements() != null) {
                 clazz.getEnclosedElements().addAll(node.getExtensionElements());
             }
 
-            node.setNodeType(clazz.asType());
-
             return clazz;
         }
 
+        private void createConstructors(NodeData node, CodeTypeElement clazz) {
+            List<ExecutableElement> signatureConstructors = new ArrayList<>();
+            ExecutableElement copyConstructor = null;
+            List<? extends ExecutableElement> constructors = ElementFilter.constructorsIn(Utils.fromTypeMirror(node.getNodeType()).getEnclosedElements());
+            for (ExecutableElement constructor : constructors) {
+                if (constructor.getModifiers().contains(Modifier.PRIVATE) || constructor.getParameters().isEmpty()) {
+                    continue;
+                }
+
+                if (isCopyConstructor(constructor)) {
+                    assert copyConstructor == null;
+                    copyConstructor = createConstructor(clazz, constructor, true);
+                } else {
+                    signatureConstructors.add(createConstructor(clazz, constructor, false));
+                }
+            }
+
+            if (copyConstructor == null && node.needsRewrites(getContext())) {
+                clazz.add(createConstructor(clazz, null, true));
+            } else if (copyConstructor != null) {
+                clazz.add(copyConstructor);
+            }
+
+            if (signatureConstructors.isEmpty() && !node.getChildren().isEmpty()) {
+                clazz.add(createConstructor(clazz, null, false));
+            } else {
+                clazz.getEnclosedElements().addAll(signatureConstructors);
+            }
+        }
+
+        private CodeExecutableElement createConstructor(CodeTypeElement type, ExecutableElement superConstructor, boolean copyConstructor) {
+            CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString());
+            CodeTreeBuilder builder = method.createBuilder();
+            if (!copyConstructor) {
+                if (superConstructor != null) {
+                    for (VariableElement param : superConstructor.getParameters()) {
+                        method.getParameters().add(CodeVariableElement.clone(param));
+                    }
+                }
+                for (NodeChildData child : getModel().getChildren()) {
+                    method.getParameters().add(new CodeVariableElement(child.getNodeType(), child.getName()));
+                }
+            } else {
+                if (!(superConstructor == null && getModel().getChildren().isEmpty())) {
+                    method.getParameters().add(new CodeVariableElement(type.asType(), "copy"));
+                }
+            }
+
+            if (superConstructor != null) {
+                builder.startStatement();
+                builder.startSuperCall();
+                if (copyConstructor) {
+                    builder.string("copy");
+                } else {
+                    for (VariableElement param : superConstructor.getParameters()) {
+                        builder.string(param.getSimpleName().toString());
+                    }
+                }
+                builder.end();
+                builder.end();
+            }
+
+            for (NodeChildData child : getModel().getChildren()) {
+
+                builder.startStatement();
+                builder.string("this.").string(child.getName()).string(" = ");
+
+                if (child.getCardinality() == Cardinality.MANY) {
+                    builder.startCall("adoptChildren");
+                } else {
+                    builder.startCall("adoptChild");
+                }
+
+                builder.startGroup();
+                if (copyConstructor) {
+                    builder.string("copy.");
+                }
+                builder.string(child.getName());
+                builder.end();
+
+                builder.end();
+                builder.end();
+
+            }
+
+            return method;
+        }
+
+        private CodeVariableElement createChildField(NodeChildData child) {
+            DeclaredType annotationType;
+            if (child.getCardinality() == Cardinality.MANY) {
+                annotationType = getContext().getTruffleTypes().getChildrenAnnotation();
+            } else {
+                annotationType = getContext().getTruffleTypes().getChildAnnotation();
+            }
+
+            CodeVariableElement var = new CodeVariableElement(child.getNodeType(), child.getName());
+            var.getModifiers().add(Modifier.PROTECTED);
+            var.getAnnotationMirrors().add(new CodeAnnotationMirror(annotationType));
+            return var;
+        }
     }
 
     private class NodeFactoryFactory extends ClassElementFactory<NodeData> {
 
         private final Map<NodeData, List<TypeElement>> childTypes;
 
+        private CodeTypeElement generatedNode;
+
         public NodeFactoryFactory(ProcessorContext context, Map<NodeData, List<TypeElement>> childElements) {
             super(context);
             this.childTypes = childElements;
@@ -585,6 +712,10 @@
             Modifier createVisibility = Utils.getVisibility(clazz.getModifiers());
 
             if (node.needsFactory()) {
+                NodeGenFactory factory = new NodeGenFactory(context);
+                add(factory, node);
+                generatedNode = factory.getElement();
+
                 createFactoryMethods(node, clazz, createVisibility);
 
                 if (node.getSpecializations().size() > 1) {
@@ -603,15 +734,15 @@
                 }
 
                 for (SpecializationData specialization : node.getSpecializations()) {
-                    add(new SpecializedNodeFactory(context), specialization);
+                    add(new SpecializedNodeFactory(context, generatedNode), specialization);
                 }
 
-                TypeMirror nodeFactory = getContext().getEnvironment().getTypeUtils().getDeclaredType(Utils.fromTypeMirror(getContext().getType(NodeFactory.class)), node.getNodeType());
+                TypeMirror nodeFactory = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getType(NodeFactory.class)), node.getNodeType());
                 clazz.getImplements().add(nodeFactory);
                 clazz.add(createCreateNodeMethod(node));
                 clazz.add(createCreateNodeSpecializedMethod(node));
                 clazz.add(createGetNodeClassMethod(node));
-                clazz.add(createGetNodeSignaturesMethod(node));
+                clazz.add(createGetNodeSignaturesMethod());
                 clazz.add(createGetChildrenSignatureMethod(node));
                 clazz.add(createGetInstanceMethod(node, createVisibility));
                 clazz.add(createInstanceConstant(node, clazz.asType()));
@@ -636,7 +767,7 @@
                 }
             }
 
-            List<NodeData> children = node.getNodeChildren();
+            List<NodeData> children = node.getNodeDeclaringChildren();
             if (node.getParent() == null && children.size() > 0) {
                 clazz.add(createGetFactories(node));
             }
@@ -644,24 +775,22 @@
         }
 
         private CodeExecutableElement createGetNodeClassMethod(NodeData node) {
-            Types types = getContext().getEnvironment().getTypeUtils();
-            TypeMirror returnType = types.getDeclaredType(Utils.fromTypeMirror(getContext().getType(Class.class)), node.getNodeType());
+            TypeMirror returnType = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getType(Class.class)), node.getNodeType());
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeClass");
             CodeTreeBuilder builder = method.createBuilder();
             builder.startReturn().typeLiteral(node.getNodeType()).end();
             return method;
         }
 
-        private CodeExecutableElement createGetNodeSignaturesMethod(NodeData node) {
-            Types types = getContext().getEnvironment().getTypeUtils();
+        private CodeExecutableElement createGetNodeSignaturesMethod() {
             TypeElement listType = Utils.fromTypeMirror(getContext().getType(List.class));
             TypeMirror classType = getContext().getType(Class.class);
-            TypeMirror returnType = types.getDeclaredType(listType, types.getDeclaredType(listType, classType));
+            TypeMirror returnType = Utils.getDeclaredType(listType, Utils.getDeclaredType(listType, classType));
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeSignatures");
             CodeTreeBuilder builder = method.createBuilder();
             builder.startReturn();
             builder.startStaticCall(getContext().getType(Arrays.class), "asList");
-            List<ExecutableElement> constructors = findUserConstructors(node);
+            List<ExecutableElement> constructors = findUserConstructors(generatedNode.asType());
             for (ExecutableElement constructor : constructors) {
                 builder.tree(createAsList(builder, Utils.asTypeMirrors(constructor.getParameters()), classType));
             }
@@ -676,8 +805,8 @@
             TypeMirror classType = getContext().getType(Class.class);
             TypeMirror nodeType = getContext().getTruffleTypes().getNode();
             TypeMirror wildcardNodeType = types.getWildcardType(nodeType, null);
-            classType = types.getDeclaredType(Utils.fromTypeMirror(classType), wildcardNodeType);
-            TypeMirror returnType = types.getDeclaredType(listType, classType);
+            classType = Utils.getDeclaredType(Utils.fromTypeMirror(classType), wildcardNodeType);
+            TypeMirror returnType = Utils.getDeclaredType(listType, classType);
 
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getExecutionSignature");
             CodeTreeBuilder builder = method.createBuilder();
@@ -687,16 +816,16 @@
             SpecializationData data = node.getSpecializations().get(0);
             for (ActualParameter parameter : data.getParameters()) {
                 ParameterSpec spec = parameter.getSpecification();
-                NodeFieldData field = node.findField(spec.getName());
-                if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
+                NodeChildData field = node.findChild(spec.getName());
+                if (field == null) {
                     continue;
                 }
 
                 TypeMirror type;
-                if (field.getKind() == FieldKind.CHILDREN && field.getType().getKind() == TypeKind.ARRAY) {
-                    type = ((ArrayType) field.getType()).getComponentType();
+                if (field.getCardinality() == Cardinality.MANY && field.getNodeType().getKind() == TypeKind.ARRAY) {
+                    type = ((ArrayType) field.getNodeType()).getComponentType();
                 } else {
-                    type = field.getType();
+                    type = field.getNodeType();
                 }
 
                 signatureTypes.add(type);
@@ -726,7 +855,7 @@
             method.addParameter(arguments);
 
             CodeTreeBuilder builder = method.createBuilder();
-            List<ExecutableElement> signatures = findUserConstructors(node);
+            List<ExecutableElement> signatures = findUserConstructors(generatedNode.asType());
             boolean ifStarted = false;
 
             for (ExecutableElement element : signatures) {
@@ -805,9 +934,8 @@
         }
 
         private ExecutableElement createGetInstanceMethod(NodeData node, Modifier visibility) {
-            Types types = getContext().getEnvironment().getTypeUtils();
             TypeElement nodeFactoryType = Utils.fromTypeMirror(getContext().getType(NodeFactory.class));
-            TypeMirror returnType = types.getDeclaredType(nodeFactoryType, node.getNodeType());
+            TypeMirror returnType = Utils.getDeclaredType(nodeFactoryType, node.getNodeType());
 
             CodeExecutableElement method = new CodeExecutableElement(modifiers(), returnType, "getInstance");
             if (visibility != null) {
@@ -850,7 +978,7 @@
         }
 
         private ExecutableElement createGetFactories(NodeData node) {
-            List<NodeData> children = node.getNodeChildren();
+            List<NodeData> children = node.getNodeDeclaringChildren();
             if (node.needsFactory()) {
                 children.add(node);
             }
@@ -871,11 +999,11 @@
             TypeMirror factoryType = getContext().getType(NodeFactory.class);
             TypeMirror baseType;
             if (allSame) {
-                baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), commonNodeSuperType);
+                baseType = Utils.getDeclaredType(Utils.fromTypeMirror(factoryType), commonNodeSuperType);
             } else {
-                baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null));
+                baseType = Utils.getDeclaredType(Utils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null));
             }
-            TypeMirror listType = types.getDeclaredType(Utils.fromTypeMirror(getContext().getType(List.class)), baseType);
+            TypeMirror listType = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getType(List.class)), baseType);
 
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), listType, "getFactories");
 
@@ -904,28 +1032,12 @@
         }
 
         private void createFactoryMethods(NodeData node, CodeTypeElement clazz, Modifier createVisibility) {
-            List<ExecutableElement> constructors = findUserConstructors(node);
+            List<ExecutableElement> constructors = findUserConstructors(generatedNode.asType());
             for (ExecutableElement constructor : constructors) {
                 clazz.add(createCreateMethod(node, createVisibility, constructor));
             }
         }
 
-        private List<ExecutableElement> findUserConstructors(NodeData node) {
-            List<ExecutableElement> constructors = new ArrayList<>();
-            for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(node.getNodeType()).getEnclosedElements())) {
-                if (constructor.getModifiers().contains(PRIVATE)) {
-                    continue;
-                }
-
-                // skip node rewrite constructor
-                if (constructor.getParameters().size() == 1 && typeEquals(constructor.getParameters().get(0).asType(), node.getNodeType())) {
-                    continue;
-                }
-                constructors.add(constructor);
-            }
-            return constructors;
-        }
-
         private CodeExecutableElement createCreateMethod(NodeData node, Modifier visibility, ExecutableElement constructor) {
             CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), constructor);
             method.setSimpleName(CodeNames.of("create"));
@@ -962,6 +1074,12 @@
             method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "specializationClass"));
 
             CodeTreeBuilder body = method.createBuilder();
+
+            body.startStatement();
+            body.type(generatedNode.asType()).string(" ").string(THIS_NODE_LOCAL_VAR_NAME + "Cast");
+            body.string(" = ").string("(").type(generatedNode.asType()).string(") ").string(THIS_NODE_LOCAL_VAR_NAME);
+            body.end();
+
             boolean first = true;
             for (TypeData type : node.getTypeSystem().getTypes()) {
                 SpecializationData specialization = node.findUniqueSpecialization(type);
@@ -974,21 +1092,21 @@
                     }
                     body.string("specializationClass == ").type(type.getBoxedType()).string(".class").end().startBlock();
                     body.startReturn().startNew(nodeSpecializationClassName(specialization));
-                    body.string(THIS_NODE_LOCAL_VAR_NAME);
+                    body.string(THIS_NODE_LOCAL_VAR_NAME + "Cast");
                     body.end().end(); // new, return
 
                     body.end(); // if
                 }
             }
             body.startReturn().startNew(nodeSpecializationClassName(node.getGenericSpecialization()));
-            body.string(THIS_NODE_LOCAL_VAR_NAME);
+            body.string(THIS_NODE_LOCAL_VAR_NAME + "Cast");
             body.end().end();
             return method;
         }
 
         private CodeExecutableElement createSpecializeMethod(NodeData node) {
             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(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME));
             method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
             addInternalValueParameters(method, node.getGenericSpecialization(), true);
 
@@ -1100,14 +1218,21 @@
 
     private class SpecializedNodeFactory extends ClassElementFactory<SpecializationData> {
 
-        public SpecializedNodeFactory(ProcessorContext context) {
+        private final CodeTypeElement nodeGen;
+
+        public SpecializedNodeFactory(ProcessorContext context, CodeTypeElement nodeGen) {
             super(context);
+            this.nodeGen = nodeGen;
         }
 
         @Override
         public CodeTypeElement create(SpecializationData specialization) {
             NodeData node = specialization.getNode();
-            CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), node.getNodeType(), false);
+            TypeMirror baseType = node.getNodeType();
+            if (nodeGen != null) {
+                baseType = nodeGen.asType();
+            }
+            CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), baseType, false);
             return clazz;
         }
 
@@ -1231,8 +1356,8 @@
 
             List<ActualParameter> executeParameters = new ArrayList<>();
             for (ActualParameter sourceParameter : executable.getParameters()) {
-                NodeFieldData field = specialization.getNode().findField(sourceParameter.getSpecification().getName());
-                if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
+                NodeChildData field = specialization.getNode().findChild(sourceParameter.getSpecification().getName());
+                if (field == null) {
                     continue;
                 }
 
@@ -1433,8 +1558,8 @@
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
 
             for (ActualParameter targetParameter : targetParameters) {
-                NodeFieldData field = sourceNode.findField(targetParameter.getSpecification().getName());
-                if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
+                NodeChildData field = sourceNode.findChild(targetParameter.getSpecification().getName());
+                if (field == null) {
                     continue;
                 }
                 TypeData targetType = targetParameter.getTypeSystemType();
@@ -1518,14 +1643,16 @@
             return builder.getRoot();
         }
 
-        private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeFieldData targetField, ActualParameter sourceParameter) {
+        private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData targetField, ActualParameter sourceParameter) {
             TypeData type = sourceParameter.getTypeSystemType();
             ExecutableTypeData execType = targetField.getNodeData().findExecutableType(type);
 
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             if (targetField != null) {
                 Element accessElement = targetField.getAccessElement();
-                if (accessElement.getKind() == ElementKind.METHOD) {
+                if (accessElement == null) {
+                    builder.string("this.").string(targetField.getName());
+                } else if (accessElement.getKind() == ElementKind.METHOD) {
                     builder.startCall(accessElement.getSimpleName().toString()).end();
                 } else if (accessElement.getKind() == ElementKind.FIELD) {
                     builder.string("this.").string(accessElement.getSimpleName().toString());
@@ -1549,7 +1676,7 @@
                         ActualParameter parameter, ActualParameter exceptionParam) {
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
 
-            NodeFieldData forField = specialization.getNode().findField(parameter.getSpecification().getName());
+            NodeChildData forField = specialization.getNode().findChild(parameter.getSpecification().getName());
             if (forField == null) {
                 return body;
             }
@@ -1571,11 +1698,11 @@
             return builder.getRoot();
         }
 
-        private CodeTree createShortCircuitValue(CodeTreeBuilder parent, ExecutableTypeData currentExecutable, SpecializationData specialization, NodeFieldData forField,
+        private CodeTree createShortCircuitValue(CodeTreeBuilder parent, ExecutableTypeData currentExecutable, SpecializationData specialization, NodeChildData forField,
                         ActualParameter shortCircuitParam, ActualParameter exceptionParam) {
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             int shortCircuitIndex = 0;
-            for (NodeFieldData field : specialization.getNode().getFields()) {
+            for (NodeChildData field : specialization.getNode().getChildren()) {
                 if (field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) {
                     if (field == forField) {
                         break;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Sat Apr 20 12:16:22 2013 +0200
@@ -28,8 +28,7 @@
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.FieldKind;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.ExecutionKind;
 import com.oracle.truffle.codegen.processor.template.*;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
@@ -37,9 +36,11 @@
 
     private final String nodeId;
     private NodeData declaringNode;
-    private List<NodeData> declaredChildren = new ArrayList<>();
+    private List<NodeData> declaredNodes = new ArrayList<>();
+    private boolean splitByMethodName;
 
     private TypeSystemData typeSystem;
+    private List<NodeChildData> children;
     private List<NodeFieldData> fields;
     private TypeMirror nodeType;
     private ParameterSpec instanceParameterSpec;
@@ -58,7 +59,7 @@
         super(splitSource.getTemplateType(), templateMethodName, null);
         this.nodeId = nodeId;
         this.declaringNode = splitSource.declaringNode;
-        this.declaredChildren = splitSource.declaredChildren;
+        this.declaredNodes = splitSource.declaredNodes;
         this.typeSystem = splitSource.typeSystem;
         this.nodeType = splitSource.nodeType;
         this.specializations = splitSource.specializations;
@@ -66,41 +67,58 @@
         this.executableTypes = splitSource.executableTypes;
         this.shortCircuits = splitSource.shortCircuits;
         this.fields = splitSource.fields;
+        this.children = splitSource.children;
+    }
+
+    public boolean isSplitByMethodName() {
+        return splitByMethodName;
     }
 
     void setTypeSystem(TypeSystemData typeSystem) {
         this.typeSystem = typeSystem;
     }
 
+    void setFields(List<NodeFieldData> fields) {
+        this.fields = fields;
+    }
+
+    public List<NodeFieldData> getFields() {
+        return fields;
+    }
+
+    void setSplitByMethodName(boolean splitByMethodName) {
+        this.splitByMethodName = splitByMethodName;
+    }
+
     @Override
     protected List<MessageContainer> findChildContainers() {
-        List<MessageContainer> children = new ArrayList<>();
-        if (declaredChildren != null) {
-            children.addAll(declaredChildren);
+        List<MessageContainer> containerChildren = new ArrayList<>();
+        if (declaredNodes != null) {
+            containerChildren.addAll(declaredNodes);
         }
         if (typeSystem != null) {
-            children.add(typeSystem);
+            containerChildren.add(typeSystem);
         }
         if (specializations != null) {
             for (MessageContainer specialization : specializations) {
                 if (specialization.getMessageElement() != null) {
-                    children.add(specialization);
+                    containerChildren.add(specialization);
                 }
             }
         }
         if (specializationListeners != null) {
-            children.addAll(specializationListeners);
+            containerChildren.addAll(specializationListeners);
         }
         if (executableTypes != null) {
-            children.addAll(getExecutableTypes());
+            containerChildren.addAll(getExecutableTypes());
         }
         if (shortCircuits != null) {
-            children.addAll(shortCircuits);
+            containerChildren.addAll(shortCircuits);
         }
-        if (fields != null) {
-            children.addAll(fields);
+        if (containerChildren != null) {
+            containerChildren.addAll(containerChildren);
         }
-        return children;
+        return containerChildren;
     }
 
     public ParameterSpec getInstanceParameterSpec() {
@@ -144,19 +162,19 @@
         return true;
     }
 
-    public List<NodeData> getNodeChildren() {
-        List<NodeData> children = new ArrayList<>();
-        for (NodeData child : getDeclaredChildren()) {
+    public List<NodeData> getNodeDeclaringChildren() {
+        List<NodeData> nodeChildren = new ArrayList<>();
+        for (NodeData child : getDeclaredNodes()) {
             if (child.needsFactory()) {
-                children.add(child);
+                nodeChildren.add(child);
             }
-            children.addAll(child.getNodeChildren());
+            nodeChildren.addAll(child.getNodeDeclaringChildren());
         }
-        return children;
+        return nodeChildren;
     }
 
-    void setDeclaredChildren(List<NodeData> declaredChildren) {
-        this.declaredChildren = declaredChildren;
+    void setDeclaredNodes(List<NodeData> declaredChildren) {
+        this.declaredNodes = declaredChildren;
 
         for (NodeData child : declaredChildren) {
             child.declaringNode = this;
@@ -167,8 +185,8 @@
         return declaringNode;
     }
 
-    public List<NodeData> getDeclaredChildren() {
-        return declaredChildren;
+    public List<NodeData> getDeclaredNodes() {
+        return declaredNodes;
     }
 
     public void setNodeType(TypeMirror nodeType) {
@@ -260,16 +278,14 @@
         return result;
     }
 
-    public NodeFieldData[] filterFields(FieldKind fieldKind, ExecutionKind usage) {
-        List<NodeFieldData> filteredFields = new ArrayList<>();
-        for (NodeFieldData field : getFields()) {
+    public NodeChildData[] filterFields(ExecutionKind usage) {
+        List<NodeChildData> filteredFields = new ArrayList<>();
+        for (NodeChildData field : getChildren()) {
             if (usage == null || field.getExecutionKind() == usage) {
-                if (fieldKind == null || field.getKind() == fieldKind) {
-                    filteredFields.add(field);
-                }
+                filteredFields.add(field);
             }
         }
-        return filteredFields.toArray(new NodeFieldData[filteredFields.size()]);
+        return filteredFields.toArray(new NodeChildData[filteredFields.size()]);
     }
 
     public boolean needsRewrites(ProcessorContext context) {
@@ -313,13 +329,13 @@
 
         dumpProperty(builder, indent, "templateClass", Utils.getQualifiedName(getTemplateType()));
         dumpProperty(builder, indent, "typeSystem", getTypeSystem());
-        dumpProperty(builder, indent, "fields", getFields());
+        dumpProperty(builder, indent, "fields", getChildren());
         dumpProperty(builder, indent, "executableTypes", getExecutableTypes());
         dumpProperty(builder, indent, "specializations", getSpecializations());
         dumpProperty(builder, indent, "messages", collectMessages());
-        if (getDeclaredChildren().size() > 0) {
+        if (getDeclaredNodes().size() > 0) {
             builder.append(String.format("\n%s  children = [", indent));
-            for (NodeData node : getDeclaredChildren()) {
+            for (NodeData node : getDeclaredNodes()) {
                 builder.append("\n");
                 builder.append(node.dump(level + 1));
             }
@@ -365,8 +381,8 @@
         return b.toString();
     }
 
-    public NodeFieldData findField(String name) {
-        for (NodeFieldData field : getFields()) {
+    public NodeChildData findChild(String name) {
+        for (NodeChildData field : getChildren()) {
             if (field.getName().equals(name)) {
                 return field;
             }
@@ -374,12 +390,12 @@
         return null;
     }
 
-    public List<NodeFieldData> getFields() {
-        return fields;
+    public List<NodeChildData> getChildren() {
+        return children;
     }
 
-    void setFields(List<NodeFieldData> fields) {
-        this.fields = fields;
+    void setChildren(List<NodeChildData> fields) {
+        this.children = fields;
     }
 
     public List<SpecializationData> getSpecializations() {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Sat Apr 20 12:16:22 2013 +0200
@@ -29,88 +29,27 @@
 
 public class NodeFieldData extends MessageContainer {
 
-    public enum FieldKind {
-        CHILD, CHILDREN, FINAL_FIELD
-    }
-
-    public enum ExecutionKind {
-        DEFAULT, IGNORE, SHORT_CIRCUIT
-    }
-
-    private final VariableElement fieldElement;
-    private final Element accessElement;
-    private final AnnotationMirror childAnnotationMirror;
-
-    private final FieldKind fieldKind;
-    private final ExecutionKind executionKind;
-    private NodeData nodeData;
+    private VariableElement variable;
 
-    public NodeFieldData(VariableElement fieldElement, Element accessElement, AnnotationMirror childAnnotationMirror, FieldKind fieldKind, ExecutionKind executionKind) {
-        this.fieldElement = fieldElement;
-        this.accessElement = accessElement;
-        this.childAnnotationMirror = childAnnotationMirror;
-        this.fieldKind = fieldKind;
-        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 NodeFieldData(VariableElement var) {
+        this.variable = var;
     }
 
     @Override
     public Element getMessageElement() {
-        return fieldElement;
-    }
-
-    public boolean isShortCircuit() {
-        return executionKind == ExecutionKind.SHORT_CIRCUIT;
+        return variable;
     }
 
-    void setNode(NodeData nodeData) {
-        this.nodeData = nodeData;
-        getMessages().addAll(nodeData.collectMessages());
-    }
-
-    public VariableElement getFieldElement() {
-        return fieldElement;
-    }
-
-    public Element getAccessElement() {
-        return accessElement;
-    }
-
-    public AnnotationMirror getChildAnnotationMirror() {
-        return childAnnotationMirror;
+    public String getName() {
+        return variable.getSimpleName().toString();
     }
 
     public TypeMirror getType() {
-        return fieldElement.asType();
-    }
-
-    public FieldKind getKind() {
-        return fieldKind;
-    }
-
-    public ExecutionKind getExecutionKind() {
-        return executionKind;
+        return variable.asType();
     }
 
-    public NodeData getNodeData() {
-        return nodeData;
-    }
-
-    public String getName() {
-        return fieldElement.getSimpleName().toString();
-    }
-
-    @Override
-    public String toString() {
-        return "NodeFieldData[name=" + getName() + ", kind=" + fieldKind + ", execution=" + executionKind + ", node=" + getNodeData() + "]";
+    public VariableElement getVariable() {
+        return variable;
     }
 
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java	Sat Apr 20 12:16:22 2013 +0200
@@ -28,9 +28,9 @@
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.*;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.ExecutionKind;
 import com.oracle.truffle.codegen.processor.template.*;
-import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
 
 public abstract class NodeMethodParser<E extends TemplateMethod> extends TemplateMethodParser<NodeData, E> {
 
@@ -84,37 +84,36 @@
         resolveAndAddImplicitThis(methodSpec, method);
 
         for (NodeFieldData field : getNode().getFields()) {
-            if (field.getKind() == FieldKind.FINAL_FIELD) {
+            if (!Utils.isFieldAccessible(method, field.getVariable())) {
                 ParameterSpec spec = new ParameterSpec(field.getName(), field.getType());
                 spec.setLocal(true);
                 methodSpec.addOptional(spec);
             }
         }
 
-        for (NodeFieldData field : getNode().getFields()) {
-            if (field.getExecutionKind() == ExecutionKind.IGNORE) {
-                continue;
-            }
+        // children are null when parsing executable types
+        if (getNode().getChildren() != null) {
+            for (NodeChildData child : getNode().getChildren()) {
+                if (child.getExecutionKind() == ExecutionKind.DEFAULT) {
+                    ParameterSpec spec = createValueParameterSpec(child.getName(), child.getNodeData());
+                    if (child.getCardinality().isMany()) {
+                        spec.setCardinality(Cardinality.MANY);
+                        spec.setIndexed(true);
+                    }
+                    methodSpec.addRequired(spec);
+                } else if (child.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) {
+                    String valueName = child.getName();
+                    if (shortCircuitName != null && valueName.equals(shortCircuitName)) {
+                        break;
+                    }
 
-            if (field.getExecutionKind() == ExecutionKind.DEFAULT) {
-                ParameterSpec spec = createValueParameterSpec(field.getName(), field.getNodeData());
-                if (field.getKind() == FieldKind.CHILDREN) {
-                    spec.setCardinality(Cardinality.MULTIPLE);
-                    spec.setIndexed(true);
+                    if (shortCircuitsEnabled) {
+                        methodSpec.addRequired(new ParameterSpec(shortCircuitValueName(valueName), getContext().getType(boolean.class)));
+                    }
+                    methodSpec.addRequired(createValueParameterSpec(valueName, child.getNodeData()));
+                } else {
+                    assert false;
                 }
-                methodSpec.addRequired(spec);
-            } else if (field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) {
-                String valueName = field.getName();
-                if (shortCircuitName != null && valueName.equals(shortCircuitName)) {
-                    break;
-                }
-
-                if (shortCircuitsEnabled) {
-                    methodSpec.addRequired(new ParameterSpec(shortCircuitValueName(valueName), getContext().getType(boolean.class)));
-                }
-                methodSpec.addRequired(createValueParameterSpec(valueName, field.getNodeData()));
-            } else {
-                assert false;
             }
         }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Sat Apr 20 12:16:22 2013 +0200
@@ -31,11 +31,10 @@
 import javax.tools.Diagnostic.Kind;
 
 import com.oracle.truffle.api.codegen.*;
-import com.oracle.truffle.api.nodes.Node.Child;
-import com.oracle.truffle.api.nodes.Node.Children;
+import com.oracle.truffle.api.codegen.NodeClass.InheritNode;
 import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.FieldKind;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.ExecutionKind;
 import com.oracle.truffle.codegen.processor.template.*;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
@@ -74,7 +73,7 @@
 
     @Override
     protected NodeData filterErrorElements(NodeData model) {
-        for (Iterator<NodeData> iterator = model.getDeclaredChildren().iterator(); iterator.hasNext();) {
+        for (Iterator<NodeData> iterator = model.getDeclaredNodes().iterator(); iterator.hasNext();) {
             NodeData node = filterErrorElements(iterator.next());
             if (node == null) {
                 iterator.remove();
@@ -115,73 +114,100 @@
         parsedNodes.put(typeName, rootNode);
 
         if (rootNode != null) {
-            children.addAll(rootNode.getDeclaredChildren());
-            rootNode.setDeclaredChildren(children);
+            children.addAll(rootNode.getDeclaredNodes());
+            rootNode.setDeclaredNodes(children);
         }
 
         return rootNode;
     }
 
-    private NodeData parseNode(TypeElement type) {
-        if (Utils.findAnnotationMirror(processingEnv, type, GeneratedBy.class) != null) {
+    private NodeData parseNode(TypeElement templateType) {
+        if (Utils.findAnnotationMirror(processingEnv, templateType, GeneratedBy.class) != null) {
             // generated nodes should not get called again.
             return null;
         }
 
-        AnnotationMirror methodNodes = Utils.findAnnotationMirror(processingEnv, type, NodeClass.class);
+        AnnotationMirror methodNodes = Utils.findAnnotationMirror(processingEnv, templateType, NodeClass.class);
 
-        if (methodNodes == null && !Utils.isAssignable(type.asType(), context.getTruffleTypes().getNode())) {
+        if (methodNodes == null && !Utils.isAssignable(templateType.asType(), context.getTruffleTypes().getNode())) {
             return null; // not a node
         }
 
-        if (type.getModifiers().contains(Modifier.PRIVATE)) {
+        if (templateType.getModifiers().contains(Modifier.PRIVATE)) {
             // TODO error message here!?
             return null; // not visible, not a node
         }
 
-        TypeElement nodeType;
-        boolean needsSplit;
-        if (methodNodes != null) {
-            needsSplit = methodNodes != null;
-            nodeType = Utils.fromTypeMirror(Utils.getAnnotationValue(TypeMirror.class, methodNodes, "value"));
-        } else {
-            needsSplit = false;
-            nodeType = type;
+        List<TypeElement> lookupTypes = findSuperClasses(new ArrayList<TypeElement>(), templateType);
+        Collections.reverse(lookupTypes);
+
+        AnnotationMirror nodeClass = findFirstAnnotation(lookupTypes, NodeClass.class);
+        TypeMirror nodeType = null;
+        if (Utils.isAssignable(templateType.asType(), context.getTruffleTypes().getNode())) {
+            nodeType = templateType.asType();
+        }
+        if (nodeClass != null) {
+            nodeType = inheritType(nodeClass, "value", nodeType);
+        }
+
+        if (nodeType == null) {
+            // FIXME error
+            return null;
         }
 
-        NodeData nodeData = parseNodeData(type, nodeType);
+        Set<Element> elementSet = new HashSet<>(context.getEnvironment().getElementUtils().getAllMembers(templateType));
+        if (!Utils.typeEquals(templateType.asType(), nodeType)) {
+            elementSet.addAll(context.getEnvironment().getElementUtils().getAllMembers(Utils.fromTypeMirror(nodeType)));
+
+            List<TypeElement> nodeLookupTypes = findSuperClasses(new ArrayList<TypeElement>(), Utils.fromTypeMirror(nodeType));
+            Collections.reverse(nodeLookupTypes);
+            lookupTypes.addAll(nodeLookupTypes);
 
-        if (nodeData.hasErrors()) {
-            return nodeData; // error sync point
+            Set<TypeElement> types = new HashSet<>();
+            for (ListIterator<TypeElement> iterator = lookupTypes.listIterator(); iterator.hasNext();) {
+                TypeElement typeElement = iterator.next();
+                if (types.contains(typeElement)) {
+                    iterator.remove();
+                } else {
+                    types.add(typeElement);
+                }
+            }
+        }
+        List<Element> elements = new ArrayList<>(elementSet);
+
+        NodeData node = parseNodeData(templateType, nodeType, elements, lookupTypes);
+
+        if (node.hasErrors()) {
+            return node; // error sync point
         }
 
-        List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type));
-        parseMethods(nodeData, elements);
+        parseMethods(node, elements);
 
-        if (nodeData.hasErrors()) {
-            return nodeData;
+        if (node.hasErrors()) {
+            return node;
         }
 
         List<NodeData> nodes;
-        if (needsSplit) {
-            nodes = splitNodeData(nodeData);
+
+        if (node.isSplitByMethodName()) {
+            nodes = splitNodeData(node);
         } else {
             nodes = new ArrayList<>();
-            nodes.add(nodeData);
+            nodes.add(node);
         }
 
         for (NodeData splittedNode : nodes) {
             finalizeSpecializations(elements, splittedNode);
-            verifyNode(splittedNode);
+            verifyNode(splittedNode, elements);
         }
 
-        if (needsSplit) {
-            nodeData.setDeclaredChildren(nodes);
-            nodeData.setSpecializationListeners(new ArrayList<SpecializationListenerData>());
-            nodeData.setSpecializations(new ArrayList<SpecializationData>());
-            return nodeData;
+        if (node.isSplitByMethodName()) {
+            node.setDeclaredNodes(nodes);
+            node.setSpecializationListeners(new ArrayList<SpecializationListenerData>());
+            node.setSpecializations(new ArrayList<SpecializationData>());
+            return node;
         } else {
-            return nodeData;
+            return node;
         }
     }
 
@@ -295,12 +321,12 @@
             List<ActualParameter> parameters = new ArrayList<>();
             for (ActualParameter specializationParameter : specialization.getParameters()) {
                 ParameterSpec parameterSpec = specification.findParameterSpec(specializationParameter.getSpecification().getName());
-                NodeFieldData field = node.findField(parameterSpec.getName());
+                NodeChildData child = node.findChild(parameterSpec.getName());
                 TypeData actualType;
-                if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
+                if (child == null) {
                     actualType = specializationParameter.getTypeSystemType();
                 } else {
-                    ExecutableTypeData paramType = field.getNodeData().findAnyGenericExecutableType(context);
+                    ExecutableTypeData paramType = child.getNodeData().findAnyGenericExecutableType(context);
                     assert paramType != null;
                     actualType = paramType.getType();
                 }
@@ -396,7 +422,7 @@
             List<String> paramIds = new LinkedList<>();
             paramIds.add(Utils.getTypeId(other.getReturnType().getType()));
             for (ActualParameter param : other.getParameters()) {
-                if (other.getNode().findField(param.getSpecification().getName()) == null) {
+                if (other.getNode().findChild(param.getSpecification().getName()) == null) {
                     continue;
                 }
                 paramIds.add(Utils.getTypeId(param.getType()));
@@ -498,11 +524,11 @@
         return signatures;
     }
 
-    private void verifyNode(NodeData nodeData) {
+    private void verifyNode(NodeData nodeData, List<? extends Element> elements) {
         // verify order is not ambiguous
         verifySpecializationOrder(nodeData);
 
-        verifyMissingAbstractMethods(nodeData);
+        verifyMissingAbstractMethods(nodeData, elements);
 
         assignShortCircuitsToSpecializations(nodeData);
 
@@ -513,15 +539,12 @@
         verifySpecializationThrows(nodeData);
     }
 
-    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);
+    private NodeData parseNodeData(TypeElement templateType, TypeMirror nodeType, List<? extends Element> elements, List<TypeElement> lookupTypes) {
         NodeData nodeData = new NodeData(templateType, templateType.getSimpleName().toString());
 
-        AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class);
+        AnnotationMirror typeSystemMirror = findFirstAnnotation(lookupTypes, TypeSystemReference.class);
         if (typeSystemMirror == null) {
-            nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), nodeType.getQualifiedName().toString());
+            nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), Utils.getQualifiedName(nodeType));
             return nodeData;
         }
 
@@ -532,23 +555,21 @@
             return nodeData;
         }
 
-        nodeData.setNodeType(nodeType.asType());
-        nodeData.setTypeSystem(typeSystem);
-        nodeData.setFields(parseFields(elements, typeHierarchy));
-
-        if (Utils.typeEquals(nodeType.asType(), templateType.asType())) {
-            // filter fields if they were not split. (field are accessible anyway)
-            for (ListIterator<NodeFieldData> iterator = nodeData.getFields().listIterator(); iterator.hasNext();) {
-                NodeFieldData field = iterator.next();
-                if (field.getKind() == FieldKind.FINAL_FIELD) {
-                    iterator.remove();
-                }
-            }
+        boolean splitByMethodName = false;
+        AnnotationMirror nodeClass = findFirstAnnotation(lookupTypes, NodeClass.class);
+        if (nodeClass != null) {
+            splitByMethodName = Utils.getAnnotationValue(Boolean.class, nodeClass, "splitByMethodName");
         }
 
+        nodeData.setNodeType(nodeType);
+        nodeData.setSplitByMethodName(splitByMethodName);
+        nodeData.setTypeSystem(typeSystem);
+        nodeData.setFields(parseFields(elements));
         nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements)));
+        parsedNodes.put(Utils.getQualifiedName(templateType), nodeData);
 
-        parsedNodes.put(Utils.getQualifiedName(templateType), nodeData);
+        // parseChildren invokes cyclic parsing.
+        nodeData.setChildren(parseChildren(elements, lookupTypes));
 
         return nodeData;
     }
@@ -577,14 +598,14 @@
         return valid;
     }
 
-    private void verifyMissingAbstractMethods(NodeData nodeData) {
+    private static void verifyMissingAbstractMethods(NodeData nodeData, List<? extends Element> originalElements) {
         if (!nodeData.needsFactory()) {
             // missing abstract methods only needs to be implemented
             // if we need go generate factory for it.
             return;
         }
 
-        List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeData.getTemplateType()));
+        List<Element> elements = new ArrayList<>(originalElements);
 
         Set<Element> unusedElements = new HashSet<>(elements);
         for (TemplateMethod method : nodeData.getAllTemplateMethods()) {
@@ -594,6 +615,12 @@
             unusedElements.removeAll(nodeData.getExtensionElements());
         }
 
+        for (NodeChildData child : nodeData.getChildren()) {
+            if (child.getAccessElement() != null) {
+                unusedElements.remove(child.getAccessElement());
+            }
+        }
+
         for (ExecutableElement unusedMethod : ElementFilter.methodsIn(unusedElements)) {
             if (unusedMethod.getModifiers().contains(Modifier.ABSTRACT)) {
                 nodeData.addError("The type %s must implement the inherited abstract method %s.", Utils.getSimpleName(nodeData.getTemplateType()), Utils.getReadableSignature(unusedMethod));
@@ -608,8 +635,17 @@
         }
 
         TypeElement type = Utils.fromTypeMirror(nodeData.getNodeType());
+        List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());
 
-        List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());
+        boolean parametersFound = false;
+        for (ExecutableElement constructor : constructors) {
+            if (!constructor.getParameters().isEmpty()) {
+                parametersFound = true;
+            }
+        }
+        if (!parametersFound) {
+            return;
+        }
         for (ExecutableElement e : constructors) {
             if (e.getParameters().size() == 1) {
                 TypeMirror firstArg = e.getParameters().get(0).asType();
@@ -657,16 +693,20 @@
         return null;
     }
 
-    private List<NodeFieldData> parseFields(List<? extends Element> elements, final List<TypeElement> typeHierarchy) {
-        AnnotationMirror executionOrderMirror = findFirstAnnotation(typeHierarchy, ExecuteChildren.class);
-        List<String> executionDefinition = null;
-        if (executionOrderMirror != null) {
-            executionDefinition = new ArrayList<>();
-            for (String object : Utils.getAnnotationValueList(String.class, executionOrderMirror, "value")) {
-                executionDefinition.add(object);
+    private static List<NodeFieldData> parseFields(List<? extends Element> elements) {
+        List<NodeFieldData> fields = new ArrayList<>();
+        for (VariableElement field : ElementFilter.fieldsIn(elements)) {
+            if (field.getModifiers().contains(Modifier.STATIC)) {
+                continue;
+            }
+            if (field.getModifiers().contains(Modifier.PUBLIC) || field.getModifiers().contains(Modifier.PROTECTED)) {
+                fields.add(new NodeFieldData(field));
             }
         }
+        return fields;
+    }
 
+    private List<NodeChildData> parseChildren(List<? extends Element> elements, final List<TypeElement> typeHierarchy) {
         Set<String> shortCircuits = new HashSet<>();
         for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
             AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class);
@@ -675,136 +715,114 @@
             }
         }
 
-        List<NodeFieldData> fields = new ArrayList<>();
-        for (VariableElement var : ElementFilter.fieldsIn(elements)) {
-            if (var.getModifiers().contains(Modifier.STATIC)) {
-                continue;
+        List<NodeChildData> parsedChildren = new ArrayList<>();
+        List<TypeElement> typeHierarchyReversed = new ArrayList<>(typeHierarchy);
+        Collections.reverse(typeHierarchyReversed);
+        for (TypeElement type : typeHierarchyReversed) {
+            AnnotationMirror nodeClassMirror = Utils.findAnnotationMirror(processingEnv, type, NodeClass.class);
+            AnnotationMirror nodeChildrenMirror = Utils.findAnnotationMirror(processingEnv, type, NodeChildren.class);
+
+            TypeMirror nodeClassType = type.getSuperclass();
+            if (!Utils.isAssignable(nodeClassType, context.getTruffleTypes().getNode())) {
+                nodeClassType = null;
             }
 
-            if (executionDefinition != null) {
-                if (!executionDefinition.contains(var.getSimpleName().toString())) {
-                    continue;
-                }
+            if (nodeClassMirror != null) {
+                nodeClassType = inheritType(nodeClassMirror, "value", nodeClassType);
             }
 
-            NodeFieldData field = parseField(var, shortCircuits);
-            if (field != null) {
-                fields.add(field);
-            }
-        }
-        sortByExecutionOrder(fields, executionDefinition == null ? Collections.<String> emptyList() : executionDefinition, typeHierarchy);
-        return fields;
-    }
+            List<AnnotationMirror> children = Utils.collectAnnotations(context, nodeChildrenMirror, "value", type, NodeChild.class);
+            for (AnnotationMirror childMirror : children) {
+                String name = Utils.getAnnotationValue(String.class, childMirror, "value");
+
+                Cardinality cardinality = Cardinality.ONE;
 
-    private NodeFieldData parseField(VariableElement var, Set<String> foundShortCircuits) {
-        AnnotationMirror childMirror = Utils.findAnnotationMirror(processingEnv, var, Child.class);
-        AnnotationMirror childrenMirror = Utils.findAnnotationMirror(processingEnv, var, Children.class);
-
-        FieldKind kind;
+                TypeMirror childType = inheritType(childMirror, "type", nodeClassType);
+                if (childType.getKind() == TypeKind.ARRAY) {
+                    cardinality = Cardinality.MANY;
+                }
 
-        ExecutionKind execution;
-        if (foundShortCircuits.contains(var.getSimpleName().toString())) {
-            execution = ExecutionKind.SHORT_CIRCUIT;
-        } else {
-            execution = ExecutionKind.DEFAULT;
-        }
+                Element getter = findGetter(elements, name, childType);
 
-        AnnotationMirror mirror;
-        TypeMirror type;
+                ExecutionKind kind = ExecutionKind.DEFAULT;
+                if (shortCircuits.contains(name)) {
+                    kind = ExecutionKind.SHORT_CIRCUIT;
+                }
 
-        if (childMirror != null) {
-            mirror = childMirror;
-            type = var.asType();
-            kind = FieldKind.CHILD;
-        } else if (childrenMirror != null) {
-            mirror = childrenMirror;
-            type = getComponentType(var.asType());
-            kind = FieldKind.CHILDREN;
-        } else {
-            execution = ExecutionKind.IGNORE;
-            type = var.asType();
-            mirror = null;
-            kind = FieldKind.FINAL_FIELD;
-        }
+                NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, getter, cardinality, kind);
+
+                parsedChildren.add(nodeChild);
+
+                verifyNodeChild(nodeChild);
+                if (nodeChild.hasErrors()) {
+                    continue;
+                }
 
-        NodeFieldData fieldData = new NodeFieldData(var, findAccessElement(var), mirror, kind, execution);
-        if (type != null && mirror != null) {
-            TypeElement typeElement = Utils.fromTypeMirror(type);
-            if (typeElement == null) {
-                return null;
-            }
-            NodeData fieldNodeData = resolveNode(typeElement);
-            fieldData.setNode(fieldNodeData);
+                NodeData fieldNodeData = resolveNode(Utils.fromTypeMirror(childType));
+                nodeChild.setNode(fieldNodeData);
 
-            if (fieldNodeData == null) {
-                fieldData.addError("Node type '%s' is invalid.", Utils.getQualifiedName(type));
-            } else if (fieldNodeData.findGenericExecutableTypes(context).isEmpty()) {
-                fieldData.addError("No executable generic types found for node '%s'.", Utils.getQualifiedName(type));
+                if (fieldNodeData == null) {
+                    nodeChild.addError("Node type '%s' is invalid.", Utils.getQualifiedName(type));
+                } else if (fieldNodeData.findGenericExecutableTypes(context).isEmpty()) {
+                    nodeChild.addError("No executable generic types found for node '%s'.", Utils.getQualifiedName(type));
+                }
             }
         }
 
-        if (fieldData.getAccessElement().getModifiers().contains(Modifier.PRIVATE)) {
-            return null;
+        List<NodeChildData> filteredChildren = new ArrayList<>();
+        Set<String> encounteredNames = new HashSet<>();
+        for (int i = parsedChildren.size() - 1; i >= 0; i--) {
+            NodeChildData child = parsedChildren.get(i);
+            if (!encounteredNames.contains(child.getName())) {
+                filteredChildren.add(0, child);
+                encounteredNames.add(child.getName());
+            }
         }
-
-        return fieldData;
+        return filteredChildren;
     }
 
-    private Element findAccessElement(VariableElement variableElement) {
-        Element enclosed = variableElement.getEnclosingElement();
-        if (!enclosed.getKind().isClass()) {
-            throw new IllegalArgumentException("Field must be enclosed in a class.");
-        }
-
-        String methodName;
-        if (Utils.typeEquals(variableElement.asType(), context.getType(boolean.class))) {
-            methodName = "is" + Utils.firstLetterUpperCase(variableElement.getSimpleName().toString());
-        } else {
-            methodName = "get" + Utils.firstLetterUpperCase(variableElement.getSimpleName().toString());
+    private static void verifyNodeChild(NodeChildData nodeChild) {
+        if (nodeChild.getNodeType() == null) {
+            nodeChild.addError("No valid node type could be resoleved.");
         }
+        // FIXME verify node child
+        // FIXME verify node type set
+    }
 
-        ExecutableElement getter = null;
-        for (ExecutableElement method : ElementFilter.methodsIn(enclosed.getEnclosedElements())) {
-            if (method.getSimpleName().toString().equals(methodName) && method.getParameters().size() == 0 && !Utils.typeEquals(method.getReturnType(), context.getType(void.class))) {
-                getter = method;
-                break;
-            }
-        }
-        if (getter != null && !getter.getModifiers().contains(Modifier.PRIVATE)) {
-            return getter;
+    private TypeMirror inheritType(AnnotationMirror annotation, String valueName, TypeMirror parentType) {
+        TypeMirror inhertNodeType = context.getType(InheritNode.class);
+        TypeMirror value = Utils.getAnnotationValue(TypeMirror.class, annotation, valueName);
+        if (Utils.typeEquals(inhertNodeType, value)) {
+            return parentType;
         } else {
-            return variableElement;
+            return value;
         }
     }
 
-    private static void sortByExecutionOrder(List<NodeFieldData> fields, final List<String> executionOrder, final List<TypeElement> typeHierarchy) {
-        Collections.sort(fields, new Comparator<NodeFieldData>() {
+    private Element findGetter(List<? extends Element> elements, String variableName, TypeMirror type) {
+        if (type == null) {
+            return null;
+        }
+        String methodName;
+        if (Utils.typeEquals(type, context.getType(boolean.class))) {
+            methodName = "is" + Utils.firstLetterUpperCase(variableName);
+        } else {
+            methodName = "get" + Utils.firstLetterUpperCase(variableName);
+        }
 
-            @Override
-            public int compare(NodeFieldData o1, NodeFieldData o2) {
-                // sort by execution order
-                int index1 = executionOrder.indexOf(o1.getName());
-                int index2 = executionOrder.indexOf(o2.getName());
-                if (index1 == -1 || index2 == -1) {
-                    // sort by type hierarchy
-                    index1 = typeHierarchy.indexOf(o1.getFieldElement().getEnclosingElement());
-                    index2 = typeHierarchy.indexOf(o2.getFieldElement().getEnclosingElement());
-
-                    // finally sort by name (will emit warning)
-                    if (index1 == -1 || index2 == -1) {
-                        return o1.getName().compareTo(o2.getName());
-                    }
-                }
-                return index1 - index2;
+        for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
+            if (method.getSimpleName().toString().equals(methodName) && method.getParameters().size() == 0 && Utils.typeEquals(method.getReturnType(), type)) {
+                return method;
             }
-        });
+        }
+        return null;
     }
 
     private void assignShortCircuitsToSpecializations(NodeData node) {
         Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits());
 
         boolean valid = true;
-        for (NodeFieldData field : node.filterFields(null, ExecutionKind.SHORT_CIRCUIT)) {
+        for (NodeChildData field : node.filterFields(ExecutionKind.SHORT_CIRCUIT)) {
             String valueName = field.getName();
             List<ShortCircuitData> availableCircuits = groupedShortCircuits.get(valueName);
 
@@ -855,7 +873,7 @@
             return;
         }
 
-        NodeFieldData[] fields = node.filterFields(null, ExecutionKind.SHORT_CIRCUIT);
+        NodeChildData[] fields = node.filterFields(ExecutionKind.SHORT_CIRCUIT);
         for (SpecializationData specialization : node.getSpecializations()) {
             List<ShortCircuitData> assignedShortCuts = new ArrayList<>(fields.length);
 
@@ -892,8 +910,8 @@
 
     private boolean isGenericShortCutMethod(NodeData node, TemplateMethod method) {
         for (ActualParameter parameter : method.getParameters()) {
-            NodeFieldData field = node.findField(parameter.getSpecification().getName());
-            if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
+            NodeChildData field = node.findChild(parameter.getSpecification().getName());
+            if (field == null) {
                 continue;
             }
             ExecutableTypeData found = null;
@@ -924,13 +942,6 @@
         return group;
     }
 
-    private TypeMirror getComponentType(TypeMirror type) {
-        if (type instanceof ArrayType) {
-            return getComponentType(((ArrayType) type).getComponentType());
-        }
-        return type;
-    }
-
     private static List<TypeElement> findSuperClasses(List<TypeElement> collection, TypeElement element) {
         if (element.getSuperclass() != null) {
             TypeElement superElement = Utils.fromTypeMirror(element.getSuperclass());
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java	Sat Apr 20 12:16:22 2013 +0200
@@ -29,7 +29,7 @@
 
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.ExecutionKind;
 import com.oracle.truffle.codegen.processor.template.*;
 
 public class ShortCircuitParser extends NodeMethodParser<ShortCircuitData> {
@@ -40,8 +40,8 @@
         super(context, node);
 
         shortCircuitValues = new HashSet<>();
-        NodeFieldData[] shortCircuitFields = node.filterFields(null, ExecutionKind.SHORT_CIRCUIT);
-        for (NodeFieldData field : shortCircuitFields) {
+        NodeChildData[] shortCircuitFields = node.filterFields(ExecutionKind.SHORT_CIRCUIT);
+        for (NodeChildData field : shortCircuitFields) {
             shortCircuitValues.add(field.getName());
         }
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Sat Apr 20 12:16:22 2013 +0200
@@ -26,7 +26,6 @@
 
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.*;
 import com.oracle.truffle.codegen.processor.template.*;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
@@ -83,8 +82,8 @@
             return true;
         }
         for (ActualParameter parameter : getParameters()) {
-            NodeFieldData field = getNode().findField(parameter.getSpecification().getName());
-            if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
+            NodeChildData field = getNode().findChild(parameter.getSpecification().getName());
+            if (field == null) {
                 continue;
             }
             ExecutableTypeData type = field.getNodeData().findExecutableType(parameter.getTypeSystemType());
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.java	Sat Apr 20 12:16:22 2013 +0200
@@ -99,7 +99,6 @@
         if (element.getModifiers().contains(Modifier.PRIVATE)) {
             return null;
         }
-
         CodeExecutableElement executable = CodeExecutableElement.clone(getContext().getEnvironment(), element);
         executable.setReturnType(null);
         executable.setSimpleName(CodeNames.of(type.getSimpleName().toString()));
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java	Sat Apr 20 12:16:22 2013 +0200
@@ -27,7 +27,7 @@
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality;
 
 public class MethodSpec {
 
@@ -151,11 +151,11 @@
 
         for (ParameterSpec requiredSpec : getRequired()) {
             b.append(sep);
-            if (requiredSpec.getCardinality() == Cardinality.MULTIPLE) {
+            if (requiredSpec.getCardinality() == Cardinality.MANY) {
                 b.append("{");
             }
             b.append(createTypeSignature(requiredSpec, false));
-            if (requiredSpec.getCardinality() == Cardinality.MULTIPLE) {
+            if (requiredSpec.getCardinality() == Cardinality.MANY) {
                 b.append("}");
             }
             sep = ", ";
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java	Sat Apr 20 12:16:22 2013 +0200
@@ -27,14 +27,11 @@
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.codegen.processor.*;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality;
 import com.oracle.truffle.codegen.processor.template.MethodSpec.TypeDef;
 
 public class ParameterSpec {
 
-    public enum Cardinality {
-        ONE, MULTIPLE;
-    }
-
     private final String name;
     private final List<TypeMirror> allowedTypes;
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Tue Apr 16 11:03:40 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Sat Apr 20 12:16:22 2013 +0200
@@ -33,7 +33,7 @@
 
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
 public abstract class TemplateMethodParser<T extends Template, E extends TemplateMethod> {
@@ -226,7 +226,7 @@
         ConsumableListIterator<ParameterSpec> required = new ConsumableListIterator<>(spec.getRequired());
         while (required.get() != null || types.get() != null) {
             if (required.get() == null || types.get() == null) {
-                if (required.get() != null && required.get().getCardinality() == Cardinality.MULTIPLE) {
+                if (required.get() != null && required.get().getCardinality() == Cardinality.MANY) {
                     required.consume();
                     specificationParameterIndex = 0;
                     continue;
@@ -236,7 +236,7 @@
             boolean implicit = types.getIndex() < spec.getImplicitRequiredTypes().size();
             ActualParameter resolvedParameter = matchParameter(required.get(), types.get(), template, specificationParameterIndex, implicit);
             if (resolvedParameter == null) {
-                if (required.get().getCardinality() == Cardinality.MULTIPLE) {
+                if (required.get().getCardinality() == Cardinality.MANY) {
                     required.consume();
                     continue;
                 }
@@ -248,7 +248,7 @@
                 if (required.get().getCardinality() == Cardinality.ONE) {
                     required.consume();
                     specificationParameterIndex = 0;
-                } else if (required.get().getCardinality() == Cardinality.MULTIPLE) {
+                } else if (required.get().getCardinality() == Cardinality.MANY) {
                     specificationParameterIndex++;
                 }
             }