changeset 8250:edc414f52e2b

Merge.
author Christian Humer <christian.humer@gmail.com>
date Tue, 12 Mar 2013 11:38:52 +0100
parents aad7e9f4f71c (diff) 2c5df42999dd (current diff)
children cb70ed101b5f
files agent/make/bugspot.bat agent/src/share/classes/sun/jvm/hotspot/asm/amd64/AMD64FloatRegister.java agent/src/share/classes/sun/jvm/hotspot/bugspot/BugSpot.java agent/src/share/classes/sun/jvm/hotspot/bugspot/BugSpotAgent.java agent/src/share/classes/sun/jvm/hotspot/bugspot/JavaLineNumberInfo.java agent/src/share/classes/sun/jvm/hotspot/bugspot/Main.java agent/src/share/classes/sun/jvm/hotspot/bugspot/PCFinder.java agent/src/share/classes/sun/jvm/hotspot/bugspot/PackageScanner.java agent/src/share/classes/sun/jvm/hotspot/bugspot/RegisterPanel.java agent/src/share/classes/sun/jvm/hotspot/bugspot/StackTraceEntry.java agent/src/share/classes/sun/jvm/hotspot/bugspot/StackTracePanel.java agent/src/share/classes/sun/jvm/hotspot/bugspot/ThreadListPanel.java agent/src/share/classes/sun/jvm/hotspot/bugspot/VariablePanel.java agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/AddressTreeNodeAdapter.java agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/DoubleTreeNodeAdapter.java agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/EnumTreeNodeAdapter.java agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/FieldTreeNodeAdapter.java agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/FloatTreeNodeAdapter.java agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/LongTreeNodeAdapter.java agent/src/share/classes/sun/jvm/hotspot/bugspot/tree/ObjectTreeNodeAdapter.java agent/src/share/classes/sun/jvm/hotspot/livejvm/BreakpointEvent.java agent/src/share/classes/sun/jvm/hotspot/livejvm/CIntegerAccessor.java agent/src/share/classes/sun/jvm/hotspot/livejvm/CStringAccessor.java agent/src/share/classes/sun/jvm/hotspot/livejvm/Event.java agent/src/share/classes/sun/jvm/hotspot/livejvm/ExceptionEvent.java agent/src/share/classes/sun/jvm/hotspot/livejvm/JNIHandleAccessor.java agent/src/share/classes/sun/jvm/hotspot/livejvm/ServiceabilityAgentJVMDIModule.java agent/src/share/classes/sun/jvm/hotspot/memory/BinaryTreeDictionary.java agent/src/share/classes/sun/jvm/hotspot/tools/PermStat.java agent/src/share/native/jvmdi/sa.cpp agent/src/share/native/jvmdi/sa.dsp agent/src/share/native/jvmdi/sa.dsw agent/src/share/native/jvmdi/sa.hpp graal/com.oracle.graal.amd64/src/com/oracle/graal/amd64/AMD64Address.java graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Address.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DirectCallOp.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoopSafepointInsertionPhase.java graal/com.oracle.graal.ptx/src/com/oracle/graal/ptx/PTXAddress.java make/bsd/makefiles/wb.make make/linux/makefiles/wb.make make/solaris/makefiles/kernel.make make/solaris/makefiles/wb.make make/windows/makefiles/wb.make mx/projects src/share/tools/whitebox/sun/hotspot/WhiteBox.java src/share/tools/whitebox/sun/hotspot/parser/DiagnosticCommand.java src/share/vm/utilities/machineCodePrinter.cpp src/share/vm/utilities/machineCodePrinter.hpp test/runtime/7158988/TestFieldMonitor.sh
diffstat 53 files changed, 1875 insertions(+), 793 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryOperationTest.java	Tue Mar 12 11:38:52 2013 +0100
@@ -0,0 +1,76 @@
+/*
+ * 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.test;
+
+import com.oracle.truffle.api.codegen.*;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode;
+
+public class BinaryOperationTest {
+
+    static int convertInt(Object value) {
+        if (value instanceof Number) {
+            return ((Number) value).intValue();
+        } else if (value instanceof String) {
+            return Integer.parseInt((String) value);
+        }
+        throw new RuntimeException("Invalid datatype");
+    }
+
+    @NodeClass(BinaryNode.class)
+    abstract static class BinaryNode extends ValueNode {
+
+        @Child protected ValueNode leftNode;
+        @Child protected ValueNode rightNode;
+
+        public BinaryNode(ValueNode left, ValueNode right) {
+            this.leftNode = left;
+            this.rightNode = right;
+        }
+
+        public BinaryNode(BinaryNode prev) {
+            this(prev.leftNode, prev.rightNode);
+        }
+
+        @Specialization
+        int add(int left, int right) {
+            return left + right;
+        }
+
+        @Generic
+        int add(Object left, Object right) {
+            return convertInt(left) + convertInt(right);
+        }
+
+        @Specialization
+        int sub(int left, int right) {
+            return left + right;
+        }
+
+        @Generic
+        int sub(Object left, Object right) {
+            return convertInt(left) + convertInt(right);
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/RuntimeStringTest.java	Tue Mar 12 11:38:52 2013 +0100
@@ -0,0 +1,158 @@
+/*
+ * 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.test;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.codegen.*;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode;
+
+public class RuntimeStringTest {
+
+    @Test
+    public void testSubstr() {
+        assertExecute(new RuntimeString("es"), "substr", new RuntimeString("test"), 1, 3);
+    }
+
+    @Test
+    public void testConcat() {
+        assertExecute(new RuntimeString("concatconcat"), "concat", new RuntimeString("concat"), new RuntimeString("concat"));
+    }
+
+    @Test(expected = ArrayIndexOutOfBoundsException.class)
+    public void testConcatFail() {
+        assertExecute(new RuntimeString("concatconcat"), "concat", new RuntimeString("concat"));
+    }
+
+    @Test
+    public void testFindMethodByMethodName() {
+        // TODO
+    }
+
+    private static void assertExecute(Object expectedResult, String name, Object... argumentsArray) {
+        ArgNode[] args = new ArgNode[argumentsArray.length];
+        for (int i = 0; i < args.length; i++) {
+            args[i] = new ArgNode(argumentsArray, i);
+        }
+
+        BuiltinNode node = null;
+        for (NodeFactory<BuiltinNode> nodeFactory : RuntimeStringTestFactory.getFactories()) {
+            GeneratedBy generated = nodeFactory.getClass().getAnnotation(GeneratedBy.class);
+            Assert.assertNotNull(generated);
+            Assert.assertNotSame("", generated.methodName());
+            if (generated.methodName().equals(name)) {
+                node = nodeFactory.createNode((Object) args);
+                break;
+            }
+        }
+        Assert.assertNotNull("Node not found", node);
+        CallTarget target = Truffle.getRuntime().createCallTarget(new TestRootNode(node));
+        Assert.assertEquals(expectedResult, target.call());
+    }
+
+    static class ArgNode extends ValueNode {
+
+        final Object[] arguments;
+        final int index;
+
+        ArgNode(Object[] args, int index) {
+            this.arguments = args;
+            this.index = index;
+        }
+
+        @Override
+        Object execute() {
+            return arguments[index];
+        }
+    }
+
+    abstract static class BuiltinNode extends ValueNode {
+
+        @Children ArgNode[] parameters;
+
+        BuiltinNode(ArgNode[] parameters) {
+            this.parameters = adoptChildren(parameters);
+        }
+
+        BuiltinNode(BuiltinNode prev) {
+            this(prev.parameters);
+        }
+
+    }
+
+    @NodeClass(BuiltinNode.class)
+    static class RuntimeString {
+
+        private final String internal;
+
+        public RuntimeString(String internal) {
+            this.internal = internal;
+        }
+
+        @Specialization
+        static RuntimeString concat(RuntimeString s1, RuntimeString s2) {
+            return new RuntimeString(s1.internal + s2.internal);
+        }
+
+        @Specialization
+        RuntimeString substr(int beginIndex, int endIndex) {
+            return new RuntimeString(internal.substring(beginIndex, endIndex));
+        }
+
+        @Generic
+        RuntimeString substr(Object beginIndex, Object endIndex) {
+            return substr(convertInt(beginIndex), convertInt(endIndex));
+        }
+
+        static int convertInt(Object value) {
+            if (value instanceof Number) {
+                return ((Number) value).intValue();
+            } else if (value instanceof String) {
+                return Integer.parseInt((String) value);
+            }
+            throw new RuntimeException("Invalid datatype");
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof RuntimeString) {
+                return internal.equals(((RuntimeString) obj).internal);
+            }
+            return super.equals(obj);
+        }
+
+        @Override
+        public int hashCode() {
+            return internal.hashCode();
+        }
+
+        @Override
+        public String toString() {
+            return internal;
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java	Tue Mar 12 11:38:52 2013 +0100
@@ -0,0 +1,71 @@
+/*
+ * 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.test;
+
+import com.oracle.truffle.api.codegen.*;
+import com.oracle.truffle.api.codegen.test.RuntimeStringTest.RuntimeString;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+public class TypeSystemTest {
+
+    @TypeSystem({int.class, RuntimeString.class})
+    static class SimpleTypes {
+    }
+
+    @TypeSystemReference(SimpleTypes.class)
+    abstract static class ValueNode extends Node {
+
+        int executeInt() throws UnexpectedResultException {
+            return SimpleTypesGen.SIMPLETYPES.expectInteger(execute());
+        }
+
+        RuntimeString executeString() {
+            return new RuntimeString(execute().toString());
+        }
+
+        @SuppressWarnings("static-method")
+        final long executeSpecial() {
+            return 42L;
+        }
+
+        abstract Object execute();
+
+    }
+
+    @TypeSystemReference(SimpleTypes.class)
+    static class TestRootNode extends RootNode {
+
+        @Child private ValueNode node;
+
+        public TestRootNode(ValueNode node) {
+            this.node = adoptChild(node);
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return node.execute();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java	Tue Mar 12 11:38:52 2013 +0100
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+/**
+ * <p>This package contains basic tests of the Truffle-Source-Code-Generation (short Codegen) API and serves at the same
+ * time as an introduction to the Codegen API for language implementors. Every test gives an example on how to use the construct explained in the class description.</p>
+ *
+ * <p>
+ * This API relies heavily on the concepts described in {@link com.oracle.truffle.api.test}. We assume that the
+ * reader is already familiarized with those concepts.
+ * </p>
+ *
+ * <p>
+ * TODO general description
+ * </p>
+ *
+ * <p>
+ * This introduction to Codegen contains items in the following recommended order:
+ *
+ * Prerequisites:
+ * 
+ *
+ * <ul>
+ * <li>What do I need to get started? {@link com.oracle.truffle.api.codegen.test.TypeSystemTest}</li>
+ * <li>How would you generate function nodes for runtime objects? {@link com.oracle.truffle.api.codegen.test.RuntimeStringTest}</li>
+ * </ul>
+ * </p>
+ *
+ */
+package com.oracle.truffle.api.codegen.test;
+
--- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GeneratedBy.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GeneratedBy.java	Tue Mar 12 11:38:52 2013 +0100
@@ -25,12 +25,14 @@
 import java.lang.annotation.*;
 
 /**
- * Marks a type to be generated by another class.
+ * Marks a type to be generated by another class or a method.
  */
-@Retention(RetentionPolicy.CLASS)
+@Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.TYPE})
 public @interface GeneratedBy {
 
     Class<?> value();
 
+    String methodName() default "";
+
 }
--- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GuardCheck.java	Tue Mar 12 10:02:20 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * 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.*;
-
-/**
- * 
- * 
- * @see SpecializationGuard
- */
-@Retention(RetentionPolicy.CLASS)
-@Target({ElementType.METHOD})
-public @interface GuardCheck {
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeClass.java	Tue Mar 12 11:38:52 2013 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.codegen;
+
+import java.lang.annotation.*;
+
+import com.oracle.truffle.api.nodes.*;
+
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.TYPE})
+public @interface NodeClass {
+
+    Class<? extends Node> value();
+
+}
--- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeFactory.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeFactory.java	Tue Mar 12 11:38:52 2013 +0100
@@ -24,6 +24,8 @@
 
 import java.util.*;
 
+import com.oracle.truffle.api.nodes.*;
+
 /**
  * Enables the dynamic creation of generated nodes. It provides an convenient way to instantiate
  * generated node classes without using reflection.
@@ -63,4 +65,10 @@
      */
     List<List<Class<?>>> getNodeSignatures();
 
+    /**
+     * Returns a list of children that will be executed by the created node. This is useful for base
+     * nodes that can execute a variable amount of nodes.
+     */
+    List<Class<? extends Node>> getChildrenSignature();
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeId.java	Tue Mar 12 11:38:52 2013 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.codegen;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface NodeId {
+
+    String value();
+
+}
--- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java	Tue Mar 12 11:38:52 2013 +0100
@@ -32,8 +32,8 @@
 
     int order() default DEFAULT_ORDER;
 
-    SpecializationThrows[] exceptions() default {};
+    Class<? extends Throwable>[] rewriteOn() default {};
 
-    SpecializationGuard[] guards() default {};
+    String[] guards() default {};
 
 }
--- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationGuard.java	Tue Mar 12 10:02:20 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * 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.*;
-
-/**
- * Specifies the use of a guard for a specialization.
- */
-@Retention(RetentionPolicy.CLASS)
-@Target({ElementType.METHOD})
-public @interface SpecializationGuard {
-
-    /**
-     * Specifies the name of the guard method annotated by {@link GuardCheck} specified as method in
-     * the {@link TypeSystem} class.
-     */
-    String methodName();
-
-    /**
-     * Determines if a guard check is invoked on specialization. Defaults to true.
-     */
-    boolean onSpecialization() default true;
-
-    /**
-     * Determines if a guard check is invoked on execution. Defaults to true.
-     */
-    boolean onExecution() default true;
-
-}
--- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationThrows.java	Tue Mar 12 10:02:20 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.codegen;
-
-import java.lang.annotation.*;
-
-@Retention(RetentionPolicy.CLASS)
-@Target({ElementType.METHOD})
-public @interface SpecializationThrows {
-
-    Class<? extends Throwable> javaClass();
-
-    String transitionTo();
-}
--- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystem.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystem.java	Tue Mar 12 11:38:52 2013 +0100
@@ -28,8 +28,8 @@
  * <p>
  * Annotates a type system class that represents type information for a node. Generates code for
  * converting and managing types. Methods contained in the type system may be annotated with
- * {@link TypeCast}, {@link TypeCheck} or {@link GuardCheck}. These methods alter the default
- * behavior of the type system.
+ * {@link TypeCast} or {@link TypeCheck}. These methods alter the default behavior of the type
+ * system.
  * </p>
  * 
  * 
@@ -62,7 +62,6 @@
  * 
  * @see TypeCast
  * @see TypeCheck
- * @see GuardCheck
  */
 @Retention(RetentionPolicy.CLASS)
 @Target({ElementType.TYPE})
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java	Tue Mar 12 11:38:52 2013 +0100
@@ -55,9 +55,17 @@
         return boxedType;
     }
 
+    public static List<TypeMirror> asTypeMirrors(List<? extends Element> elements) {
+        List<TypeMirror> types = new ArrayList<>(elements.size());
+        for (Element element : elements) {
+            types.add(element.asType());
+        }
+        return types;
+    }
+
     public static List<AnnotationMirror> collectAnnotations(ProcessorContext context, AnnotationMirror markerAnnotation, String elementName, Element element,
                     Class<? extends Annotation> annotationClass) {
-        List<AnnotationMirror> result = Utils.getAnnotationValueList(markerAnnotation, elementName);
+        List<AnnotationMirror> result = Utils.getAnnotationValueList(AnnotationMirror.class, markerAnnotation, elementName);
         AnnotationMirror explicit = Utils.findAnnotationMirror(context.getEnvironment(), element, annotationClass);
         if (explicit != null) {
             result.add(explicit);
@@ -167,6 +175,46 @@
         return new LinkedHashSet<>(Arrays.asList(modifier));
     }
 
+    public static String getTypeId(TypeMirror mirror) {
+        switch (mirror.getKind()) {
+            case BOOLEAN:
+                return "Boolean";
+            case BYTE:
+                return "Byte";
+            case CHAR:
+                return "Char";
+            case DOUBLE:
+                return "Double";
+            case FLOAT:
+                return "Float";
+            case SHORT:
+                return "Short";
+            case INT:
+                return "Int";
+            case LONG:
+                return "Long";
+            case DECLARED:
+                return ((DeclaredType) mirror).asElement().getSimpleName().toString();
+            case ARRAY:
+                return getTypeId(((ArrayType) mirror).getComponentType()) + "Array";
+            case VOID:
+                return "Void";
+            case WILDCARD:
+                StringBuilder b = new StringBuilder();
+                WildcardType type = (WildcardType) mirror;
+                if (type.getExtendsBound() != null) {
+                    b.append("Extends").append(getTypeId(type.getExtendsBound()));
+                } else if (type.getSuperBound() != null) {
+                    b.append("Super").append(getTypeId(type.getExtendsBound()));
+                }
+                return b.toString();
+            case TYPEVAR:
+                return "Any";
+            default:
+                throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror);
+        }
+    }
+
     public static String getSimpleName(TypeElement element) {
         return getSimpleName(element.asType());
     }
@@ -428,29 +476,32 @@
     }
 
     @SuppressWarnings("unchecked")
-    public static <T> List<T> getAnnotationValueList(AnnotationMirror mirror, String name) {
+    public static <T> List<T> getAnnotationValueList(Class<T> expectedListType, AnnotationMirror mirror, String name) {
+        List<? extends AnnotationValue> values = getAnnotationValue(List.class, mirror, name);
         List<T> result = new ArrayList<>();
-        List<? extends AnnotationValue> values = (List<? extends AnnotationValue>) getAnnotationValue(mirror, name).getValue();
+
         for (AnnotationValue value : values) {
-            result.add((T) value.getValue());
+            result.add(resolveAnnotationValue(expectedListType, value));
         }
         return result;
     }
 
-    public static TypeMirror getAnnotationValueType(AnnotationMirror mirror, String name) {
-        return (TypeMirror) getAnnotationValue(mirror, name).getValue();
+    public static <T> T getAnnotationValue(Class<T> expectedType, AnnotationMirror mirror, String name) {
+        return resolveAnnotationValue(expectedType, getAnnotationValue(mirror, name));
     }
 
-    public static TypeMirror getAnnotationValueTypeMirror(AnnotationMirror mirror, String name) {
-        return (TypeMirror) getAnnotationValue(mirror, name).getValue();
-    }
-
-    public static String getAnnotationValueString(AnnotationMirror mirror, String name) {
-        return (String) getAnnotationValue(mirror, name).getValue();
-    }
-
-    public static int getAnnotationValueInt(AnnotationMirror mirror, String name) {
-        return (int) getAnnotationValue(mirror, name).getValue();
+    @SuppressWarnings({"unchecked"})
+    private static <T> T resolveAnnotationValue(Class<T> expectedType, AnnotationValue value) {
+        Object unboxedValue = value.accept(new AnnotationValueVisitorImpl(), null);
+        if (unboxedValue != null) {
+            if (expectedType == TypeMirror.class && unboxedValue instanceof String) {
+                return null;
+            }
+            if (!expectedType.isAssignableFrom(unboxedValue.getClass())) {
+                throw new ClassCastException(unboxedValue.getClass().getName() + " not assignable from " + expectedType.getName());
+            }
+        }
+        return (T) unboxedValue;
     }
 
     public static AnnotationValue getAnnotationValue(AnnotationMirror mirror, String name) {
@@ -470,9 +521,79 @@
         if (value == null) {
             value = valueMethod.getDefaultValue();
         }
+
         return value;
     }
 
+    private static class AnnotationValueVisitorImpl extends AbstractAnnotationValueVisitor7<Object, Void> {
+
+        @Override
+        public Object visitBoolean(boolean b, Void p) {
+            return Boolean.valueOf(b);
+        }
+
+        @Override
+        public Object visitByte(byte b, Void p) {
+            return Byte.valueOf(b);
+        }
+
+        @Override
+        public Object visitChar(char c, Void p) {
+            return c;
+        }
+
+        @Override
+        public Object visitDouble(double d, Void p) {
+            return d;
+        }
+
+        @Override
+        public Object visitFloat(float f, Void p) {
+            return f;
+        }
+
+        @Override
+        public Object visitInt(int i, Void p) {
+            return i;
+        }
+
+        @Override
+        public Object visitLong(long i, Void p) {
+            return i;
+        }
+
+        @Override
+        public Object visitShort(short s, Void p) {
+            return s;
+        }
+
+        @Override
+        public Object visitString(String s, Void p) {
+            return s;
+        }
+
+        @Override
+        public Object visitType(TypeMirror t, Void p) {
+            return t;
+        }
+
+        @Override
+        public Object visitEnumConstant(VariableElement c, Void p) {
+            return c.getConstantValue();
+        }
+
+        @Override
+        public Object visitAnnotation(AnnotationMirror a, Void p) {
+            return a;
+        }
+
+        @Override
+        public Object visitArray(List<? extends AnnotationValue> vals, Void p) {
+            return vals;
+        }
+
+    }
+
     public static boolean getAnnotationValueBoolean(AnnotationMirror mirror, String name) {
         return (Boolean) getAnnotationValue(mirror, name).getValue();
     }
@@ -591,6 +712,14 @@
         }
         String qualified1 = getQualifiedName(type1);
         String qualified2 = getQualifiedName(type2);
+
+        if (type1.getKind() == TypeKind.ARRAY || type2.getKind() == TypeKind.ARRAY) {
+            if (type1.getKind() == TypeKind.ARRAY && type2.getKind() == TypeKind.ARRAY) {
+                return typeEquals(((ArrayType) type1).getComponentType(), ((ArrayType) type2).getComponentType());
+            } else {
+                return false;
+            }
+        }
         return qualified1.equals(qualified2);
     }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java	Tue Mar 12 11:38:52 2013 +0100
@@ -204,7 +204,7 @@
         return v.visitExecutable(this, p);
     }
 
-    public static CodeExecutableElement clone(ProcessingEnvironment env, ExecutableElement method) {
+    public static CodeExecutableElement clone(@SuppressWarnings("unused") ProcessingEnvironment env, ExecutableElement method) {
         CodeExecutableElement copy = new CodeExecutableElement(method.getReturnType(), method.getSimpleName().toString());
         for (TypeMirror thrownType : method.getThrownTypes()) {
             copy.addThrownType(thrownType);
@@ -220,7 +220,6 @@
         for (Element element : method.getEnclosedElements()) {
             copy.add(element);
         }
-        copy.setBody(Utils.getMethodBody(env, method));
         copy.getModifiers().addAll(method.getModifiers());
         return copy;
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java	Tue Mar 12 11:38:52 2013 +0100
@@ -495,7 +495,7 @@
     }
 
     public CodeTreeBuilder create() {
-        return new CodeTreeBuilder(null);
+        return new CodeTreeBuilder(this);
     }
 
     public CodeTreeBuilder type(TypeMirror type) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java	Tue Mar 12 11:38:52 2013 +0100
@@ -123,6 +123,14 @@
         writeClassImpl(e);
     }
 
+    private String useImport(TypeMirror type) {
+        if (imports != null) {
+            return imports.useImport(type);
+        } else {
+            return Utils.getSimpleName(type);
+        }
+    }
+
     private void writeClassImpl(CodeTypeElement e) {
         for (AnnotationMirror annotation : e.getAnnotationMirrors()) {
             visitAnnotation(annotation);
@@ -137,12 +145,12 @@
         }
         write(e.getSimpleName());
         if (e.getSuperclass() != null && !getQualifiedName(e.getSuperclass()).equals("java.lang.Object")) {
-            write(" extends ").write(typeSimpleName(e.getSuperclass()));
+            write(" extends ").write(useImport(e.getSuperclass()));
         }
         if (e.getImplements().size() > 0) {
             write(" implements ");
             for (int i = 0; i < e.getImplements().size(); i++) {
-                write(typeSimpleName(e.getImplements().get(i)));
+                write(useImport(e.getImplements().get(i)));
                 if (i < e.getImplements().size() - 1) {
                     write(", ");
                 }
@@ -267,7 +275,7 @@
             }
         } else {
             writeModifiers(f.getModifiers());
-            write(typeSimpleName(f.asType()));
+            write(useImport(f.asType()));
 
             if (f.getEnclosingElement().getKind() == ElementKind.METHOD) {
                 ExecutableElement method = (ExecutableElement) f.getEnclosingElement();
@@ -287,7 +295,7 @@
     }
 
     public void visitAnnotation(AnnotationMirror e) {
-        write("@").write(typeSimpleName(e.getAnnotationType()));
+        write("@").write(useImport(e.getAnnotationType()));
 
         if (!e.getElementValues().isEmpty()) {
             write("(");
@@ -395,14 +403,14 @@
 
         @Override
         public Void visitType(TypeMirror t, Void p) {
-            write(typeSimpleName(t));
+            write(useImport(t));
             write(".class");
             return null;
         }
 
         @Override
         public Void visitEnumConstant(VariableElement c, Void p) {
-            write(typeSimpleName(c.asType()));
+            write(useImport(c.asType()));
             write(".");
             write(c.getSimpleName().toString());
             return null;
@@ -458,7 +466,7 @@
         writeModifiers(e.getModifiers());
 
         if (e.getReturnType() != null) {
-            write(typeSimpleName(e.getReturnType()));
+            write(useImport(e.getReturnType()));
             write(" ");
         }
         write(e.getSimpleName());
@@ -477,7 +485,7 @@
         if (throwables.size() > 0) {
             write(" throws ");
             for (int i = 0; i < throwables.size(); i++) {
-                write(typeSimpleName(throwables.get(i)));
+                write(useImport(throwables.get(i)));
                 if (i < throwables.size() - 1) {
                     write(", ");
                 }
@@ -554,7 +562,7 @@
                 }
                 break;
             case TYPE:
-                write(imports.useImport(e.getType()));
+                write(useImport(e.getType()));
                 break;
             default:
                 assert false;
@@ -562,10 +570,6 @@
         }
     }
 
-    private static String typeSimpleName(TypeMirror type) {
-        return Utils.getSimpleName(type);
-    }
-
     protected void writeHeader() {
         // default implementation does nothing
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java	Tue Mar 12 11:38:52 2013 +0100
@@ -359,6 +359,100 @@
 
         public void visitAnnotation(AnnotationMirror e) {
             addImport(e.getAnnotationType());
+            if (!e.getElementValues().isEmpty()) {
+                Map<? extends ExecutableElement, ? extends AnnotationValue> values = e.getElementValues();
+                Set<? extends ExecutableElement> methodsSet = values.keySet();
+                List<ExecutableElement> methodsList = new ArrayList<>();
+                for (ExecutableElement method : methodsSet) {
+                    if (values.get(method) == null) {
+                        continue;
+                    }
+                    methodsList.add(method);
+                }
+
+                for (int i = 0; i < methodsList.size(); i++) {
+                    AnnotationValue value = values.get(methodsList.get(i));
+                    visitAnnotationValue(value);
+                }
+            }
+        }
+
+        public void visitAnnotationValue(AnnotationValue e) {
+            e.accept(new AnnotationValueReferenceVisitor(), null);
+        }
+
+        private class AnnotationValueReferenceVisitor extends AbstractAnnotationValueVisitor7<Void, Void> {
+
+            @Override
+            public Void visitBoolean(boolean b, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitByte(byte b, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitChar(char c, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitDouble(double d, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitFloat(float f, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitInt(int i, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitLong(long i, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitShort(short s, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitString(String s, Void p) {
+                return null;
+            }
+
+            @Override
+            public Void visitType(TypeMirror t, Void p) {
+                addImport(t);
+                return null;
+            }
+
+            @Override
+            public Void visitEnumConstant(VariableElement c, Void p) {
+                addImport(c.asType());
+                return null;
+            }
+
+            @Override
+            public Void visitAnnotation(AnnotationMirror a, Void p) {
+                ReferenceCollector.this.visitAnnotation(a);
+                return null;
+            }
+
+            @Override
+            public Void visitArray(List<? extends AnnotationValue> vals, Void p) {
+                for (int i = 0; i < vals.size(); i++) {
+                    ReferenceCollector.this.visitAnnotationValue(vals.get(i));
+                }
+                return null;
+            }
         }
 
         @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/AbstractCompiler.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/AbstractCompiler.java	Tue Mar 12 11:38:52 2013 +0100
@@ -39,6 +39,9 @@
     }
 
     protected static Object field(Object o, String fieldName) throws Exception {
+        if (o == null) {
+            return null;
+        }
         Field field = o.getClass().getField(fieldName);
         field.setAccessible(true);
         return field.get(o);
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java	Tue Mar 12 11:38:52 2013 +0100
@@ -88,7 +88,7 @@
         } else {
             AnnotationMirror foundExtension = Utils.findAnnotationMirror(context.getEnvironment(), mirror.getAnnotationType().asElement(), ExtensionAnnotation.class);
             if (foundExtension != null) {
-                String className = Utils.getAnnotationValueString(foundExtension, "processorClassName");
+                String className = Utils.getAnnotationValue(String.class, foundExtension, "processorClassName");
                 Class<?> processorClass;
                 try {
                     processorClass = Class.forName(className);
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java	Tue Mar 12 11:38:52 2013 +0100
@@ -51,7 +51,7 @@
 
         List<ParameterSpec> parameters = new ArrayList<>();
         parameters.add(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true));
-        return new MethodSpec(returnTypeSpec, parameters);
+        return new MethodSpec(new ArrayList<TypeMirror>(), returnTypeSpec, parameters);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Tue Mar 12 11:38:52 2013 +0100
@@ -41,7 +41,7 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        return createDefaultMethodSpec(null);
+        return createDefaultMethodSpec(method, mirror, null);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java	Tue Mar 12 11:38:52 2013 +0100
@@ -25,9 +25,10 @@
 import java.util.*;
 
 import javax.lang.model.element.*;
+import javax.lang.model.type.*;
 
 import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind;
+import com.oracle.truffle.codegen.processor.node.NodeFieldData.*;
 import com.oracle.truffle.codegen.processor.template.*;
 import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
 
@@ -54,10 +55,21 @@
         return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null;
     }
 
-    protected final MethodSpec createDefaultMethodSpec(String shortCircuitName) {
+    @SuppressWarnings("unused")
+    protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, String shortCircuitName) {
         List<ParameterSpec> defaultParameters = new ArrayList<>();
-        ParameterSpec frameSpec = new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true);
-        defaultParameters.add(frameSpec);
+
+        if (getNode().supportsFrame()) {
+            defaultParameters.add(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true));
+        }
+
+        TypeMirror declaredType = Utils.findNearestEnclosingType(method).asType();
+
+        List<TypeMirror> prefixTypes = new ArrayList<>();
+
+        if (!method.getModifiers().contains(Modifier.STATIC) && !Utils.isAssignable(declaredType, template.getNodeType())) {
+            prefixTypes.add(getNode().getTemplateType().asType());
+        }
 
         for (NodeFieldData field : getNode().getFields()) {
             if (field.getExecutionKind() == ExecutionKind.IGNORE) {
@@ -65,7 +77,12 @@
             }
 
             if (field.getExecutionKind() == ExecutionKind.DEFAULT) {
-                defaultParameters.add(createValueParameterSpec(field.getName(), field.getNodeData(), false));
+                ParameterSpec spec = createValueParameterSpec(field.getName(), field.getNodeData(), false);
+                if (field.getKind() == FieldKind.CHILDREN) {
+                    spec.setCardinality(Cardinality.MULTIPLE);
+                    spec.setIndexed(true);
+                }
+                defaultParameters.add(spec);
             } else if (field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) {
                 String valueName = field.getName();
                 if (shortCircuitName != null && valueName.equals(shortCircuitName)) {
@@ -79,7 +96,7 @@
             }
         }
 
-        return new MethodSpec(createReturnParameterSpec(), defaultParameters);
+        return new MethodSpec(prefixTypes, createReturnParameterSpec(), defaultParameters);
     }
 
     private static String shortCircuitValueName(String valueName) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Tue Mar 12 11:38:52 2013 +0100
@@ -34,7 +34,7 @@
 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.*;
 import com.oracle.truffle.codegen.processor.template.*;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
@@ -51,73 +51,49 @@
     }
 
     private static String factoryClassName(NodeData node) {
-        return nodeClassName(node) + "Factory";
-    }
-
-    private static String nodeClassName(NodeData node) {
-        return Utils.getSimpleName(node.getTemplateType().asType());
+        return node.getNodeId() + "Factory";
     }
 
-    private static String nodeClassName(SpecializationData specialization) {
-        String name = specializationId(specialization);
-        name += nodeClassName(specialization.getNode());
-        if (name.equals(Utils.getSimpleName(specialization.getNode().getNodeType())) || name.equals(Utils.getSimpleName(specialization.getNode().getTemplateType()))) {
-            name = name + "Impl";
+    private static String nodeSpecializationClassName(SpecializationData specialization) {
+        String nodeid = specialization.getNode().getNodeId();
+        if (nodeid.endsWith("Node") && !nodeid.equals("Node")) {
+            nodeid = nodeid.substring(0, nodeid.length() - 4);
         }
 
+        String name = Utils.firstLetterUpperCase(nodeid);
+        name += Utils.firstLetterUpperCase(specialization.getId());
+        name += "Node";
         return name;
     }
 
-    private static String specializationId(SpecializationData specialization) {
-        String name = "";
-        NodeData node = specialization.getNode();
-        if (node.getSpecializations().length > 1) {
-            name = specialization.getMethodName();
-            if (name.startsWith("do")) {
-                name = name.substring(2);
-            }
-        }
-        return name;
-    }
-
-    private static String valueName(NodeFieldData field) {
-        return field.getName() + "Value";
-    }
-
     private static String valueName(ActualParameter param) {
-        NodeData node = (NodeData) param.getMethod().getTemplate();
-        NodeFieldData field = node.findField(param.getSpecification().getName());
-        if (field != null) {
-            return valueName(field);
-        } else {
-            return param.getSpecification().getName();
-        }
+        return param.getName();
     }
 
     private static String castValueName(ActualParameter parameter) {
         return valueName(parameter) + "Cast";
     }
 
-    private static String castValueName(NodeFieldData field) {
-        return valueName(field) + "Cast";
-    }
-
-    private void addValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame) {
-        if (forceFrame) {
-            method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frame"));
+    private void addValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame, boolean includeHidden) {
+        if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) {
+            method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue"));
         }
         for (ActualParameter parameter : specialization.getParameters()) {
             ParameterSpec spec = parameter.getSpecification();
             if (forceFrame && spec.getName().equals("frame")) {
                 continue;
             }
+            if (!includeHidden && parameter.isHidden()) {
+                continue;
+            }
+
             method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(parameter)));
         }
     }
 
-    private static void addValueParameterNames(CodeTreeBuilder builder, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame) {
-        if (forceFrame) {
-            builder.string("frame");
+    private static void addValueParameterNames(CodeTreeBuilder builder, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, boolean includeHidden) {
+        if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) {
+            builder.string("frameValue");
         }
         for (ActualParameter parameter : specialization.getParameters()) {
             ParameterSpec spec = parameter.getSpecification();
@@ -125,7 +101,11 @@
                 continue;
             }
 
-            if (unexpectedValueName != null && spec.getName().equals(unexpectedValueName)) {
+            if (!includeHidden && parameter.isHidden()) {
+                continue;
+            }
+
+            if (unexpectedValueName != null && parameter.getName().equals(unexpectedValueName)) {
                 builder.string("ex.getResult()");
             } else {
                 builder.string(valueName(parameter));
@@ -133,14 +113,18 @@
         }
     }
 
-    private static void addValueParameterNamesWithCasts(CodeTreeBuilder body, SpecializationData valueSpecialization, SpecializationData targetSpecialization) {
+    private static void addValueParameterNamesWithCasts(CodeTreeBuilder body, SpecializationData valueSpecialization, SpecializationData targetSpecialization, boolean includeHidden) {
         NodeData node = targetSpecialization.getNode();
         TypeSystemData typeSystem = node.getTypeSystem();
 
         for (ActualParameter targetParameter : targetSpecialization.getParameters()) {
-            ActualParameter valueParameter = valueSpecialization.findParameter(targetParameter.getSpecification().getName());
+            ActualParameter valueParameter = valueSpecialization.findParameter(targetParameter.getName());
             TypeData targetType = targetParameter.getActualTypeData(typeSystem);
 
+            if (!includeHidden && (targetParameter.isHidden() || valueParameter.isHidden())) {
+                continue;
+            }
+
             TypeData valueType = null;
             if (valueParameter != null) {
                 valueType = valueParameter.getActualTypeData(typeSystem);
@@ -158,15 +142,41 @@
         return getSimpleName(operation.getTemplateType()) + "Gen";
     }
 
-    private static void startCallOperationMethod(CodeTreeBuilder body, TemplateMethod method) {
+    private void startCallOperationMethod(CodeTreeBuilder body, TemplateMethod templateMethod, boolean castedValues) {
         body.startGroup();
-        if (body.findMethod().getModifiers().contains(STATIC)) {
-            body.string(THIS_NODE_LOCAL_VAR_NAME);
+        ExecutableElement method = templateMethod.getMethod();
+
+        TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement());
+        NodeData node = (NodeData) templateMethod.getTemplate();
+
+        boolean accessible = templateMethod.canBeAccessedByInstanceOf(node.getNodeType());
+        if (accessible) {
+            if (body.findMethod().getModifiers().contains(STATIC)) {
+                body.string(THIS_NODE_LOCAL_VAR_NAME);
+            } else {
+                body.string("super");
+            }
         } else {
-            body.string("super");
+            if (method.getModifiers().contains(STATIC)) {
+                body.type(targetClass.asType());
+            } else {
+                ActualParameter parameter = templateMethod.getParameters().get(0);
+                if (castedValues) {
+                    NodeFieldData field = node.findField(parameter.getSpecification().getName());
+                    NodeData fieldNode = field.getNodeData();
+                    ExecutableTypeData execType = fieldNode.findExecutableType(parameter.getActualTypeData(node.getTypeSystem()));
+                    if (execType.hasUnexpectedValue(getContext())) {
+                        body.string(castValueName(parameter));
+                    } else {
+                        body.string(valueName(parameter));
+                    }
+                } else {
+                    body.string(valueName(parameter));
+                }
+            }
         }
         body.string(".");
-        body.startCall(method.getMethodName());
+        body.startCall(method.getSimpleName().toString());
     }
 
     private static String generatedGenericMethodName(SpecializationData specialization) {
@@ -182,7 +192,7 @@
                 if (prev == null || prev.isUninitialized()) {
                     return prefix;
                 } else {
-                    return prefix + specializationId(current);
+                    return prefix + current.getId();
                 }
             }
             prev = current;
@@ -253,8 +263,7 @@
         return builder.getRoot();
     }
 
-    private static CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization,
-                    boolean onSpecialization) {
+    private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, boolean onSpecialization) {
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
         String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
         if (guardedSpecialization.getGuards().length > 0) {
@@ -263,8 +272,8 @@
                 if ((guard.isOnSpecialization() && onSpecialization) || (guard.isOnExecution() && !onSpecialization)) {
                     builder.string(andOperator);
 
-                    startCallOperationMethod(builder, guard.getGuardDeclaration());
-                    addValueParameterNamesWithCasts(builder, valueSpecialization, guardedSpecialization);
+                    startCallOperationMethod(builder, guard.getGuardDeclaration(), true);
+                    addValueParameterNamesWithCasts(builder, valueSpecialization, guardedSpecialization, false);
 
                     builder.end().end(); // call
                     andOperator = " && ";
@@ -276,13 +285,14 @@
     }
 
     private CodeTree createCasts(CodeTreeBuilder parent, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) {
-        NodeData node = guardedSpecialization.getNode();
-
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
         // Implict guards based on method signature
-        for (NodeFieldData field : node.getFields()) {
-            ActualParameter guardedParam = guardedSpecialization.findParameter(field.getName());
-            ActualParameter valueParam = valueSpecialization.findParameter(field.getName());
+        for (ActualParameter guardedParam : guardedSpecialization.getParameters()) {
+            NodeFieldData field = guardedSpecialization.getNode().findField(guardedParam.getSpecification().getName());
+            if (field == null) {
+                continue;
+            }
+            ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getName());
 
             CodeTree cast = createCast(parent, field, valueParam, guardedParam);
             if (cast == null) {
@@ -295,14 +305,15 @@
     }
 
     private CodeTree createImplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) {
-        NodeData node = guardedSpecialization.getNode();
-
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
         // Implict guards based on method signature
         String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
-        for (NodeFieldData field : node.getFields()) {
-            ActualParameter guardedParam = guardedSpecialization.findParameter(field.getName());
-            ActualParameter valueParam = valueSpecialization.findParameter(field.getName());
+        for (ActualParameter guardedParam : guardedSpecialization.getParameters()) {
+            NodeFieldData field = guardedSpecialization.getNode().findField(guardedParam.getSpecification().getName());
+            if (field == null) {
+                continue;
+            }
+            ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getName());
 
             CodeTree implicitGuard = createImplicitGuard(builder, field, valueParam, guardedParam);
             if (implicitGuard == null) {
@@ -339,7 +350,7 @@
         }
 
         startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(target.getActualTypeData(node.getTypeSystem())));
-        builder.string(valueName(field));
+        builder.string(valueName(source));
         builder.end().end(); // call
 
         if (field.isShortCircuit()) {
@@ -371,7 +382,7 @@
 
         CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), valueName(target));
 
-        return createLazyAssignment(parent, castValueName(field), target.getActualType(), condition, value);
+        return createLazyAssignment(parent, castValueName(target), target.getActualType(), condition, value);
     }
 
     /**
@@ -492,7 +503,7 @@
             if (node.needsFactory()) {
                 createFactoryMethods(node, clazz, createVisibility);
 
-                if (node.getSpecializations().length > 1) {
+                if (node.getSpecializations().size() > 1) {
                     clazz.add(createCreateSpecializedMethod(node, createVisibility));
                 }
 
@@ -515,6 +526,7 @@
                 clazz.add(createCreateNodeSpecializedMethod(node));
                 clazz.add(createGetNodeClassMethod(node));
                 clazz.add(createGetNodeSignaturesMethod(node));
+                clazz.add(createGetChildrenSignatureMethod(node));
                 clazz.add(createGetInstanceMethod(node, createVisibility));
                 clazz.add(createInstanceConstant(node, clazz.asType()));
             }
@@ -565,21 +577,62 @@
             builder.startStaticCall(getContext().getType(Arrays.class), "asList");
             List<ExecutableElement> constructors = findUserConstructors(node);
             for (ExecutableElement constructor : constructors) {
-                builder.startGroup();
-                builder.type(getContext().getType(Arrays.class));
-                builder.string(".<").type(getContext().getType(Class.class)).string(">");
-                builder.startCall("asList");
-                for (VariableElement param : constructor.getParameters()) {
-                    builder.typeLiteral(param.asType());
-                }
-                builder.end();
-                builder.end();
+                builder.tree(createAsList(builder, Utils.asTypeMirrors(constructor.getParameters()), classType));
             }
             builder.end();
             builder.end();
             return method;
         }
 
+        private CodeExecutableElement createGetChildrenSignatureMethod(NodeData node) {
+            Types types = getContext().getEnvironment().getTypeUtils();
+            TypeElement listType = Utils.fromTypeMirror(getContext().getType(List.class));
+            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);
+
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getChildrenSignature");
+            CodeTreeBuilder builder = method.createBuilder();
+
+            List<TypeMirror> signatureTypes = new ArrayList<>();
+            assert !node.getSpecializations().isEmpty();
+            SpecializationData data = node.getSpecializations().get(0);
+            for (ActualParameter parameter : data.getParameters()) {
+                ParameterSpec spec = parameter.getSpecification();
+                NodeFieldData field = node.findField(spec.getName());
+                if (field == null) {
+                    continue;
+                }
+
+                TypeMirror type;
+                if (field.getKind() == FieldKind.CHILDREN && field.getType().getKind() == TypeKind.ARRAY) {
+                    type = ((ArrayType) field.getType()).getComponentType();
+                } else {
+                    type = field.getType();
+                }
+
+                signatureTypes.add(type);
+            }
+
+            builder.startReturn().tree(createAsList(builder, signatureTypes, classType)).end();
+            return method;
+        }
+
+        private CodeTree createAsList(CodeTreeBuilder parent, List<TypeMirror> types, TypeMirror elementClass) {
+            CodeTreeBuilder builder = parent.create();
+            builder.startGroup();
+            builder.type(getContext().getType(Arrays.class));
+            builder.string(".<").type(elementClass).string(">");
+            builder.startCall("asList");
+            for (TypeMirror typeMirror : types) {
+                builder.typeLiteral(typeMirror);
+            }
+            builder.end().end();
+            return builder.getRoot();
+        }
+
         private CodeExecutableElement createCreateNodeMethod(NodeData node) {
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNode");
             CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Object.class), "arguments");
@@ -717,15 +770,21 @@
             }
 
             List<TypeMirror> nodeTypesList = new ArrayList<>();
+            TypeMirror prev = null;
+            boolean allSame = true;
             for (NodeData child : children) {
-                nodeTypesList.add(child.getTemplateType().asType());
+                nodeTypesList.add(child.getNodeType());
+                if (prev != null && !Utils.typeEquals(child.getNodeType(), prev)) {
+                    allSame = false;
+                }
+                prev = child.getNodeType();
             }
             TypeMirror commonNodeSuperType = Utils.getCommonSuperType(getContext(), nodeTypesList.toArray(new TypeMirror[nodeTypesList.size()]));
 
             Types types = getContext().getEnvironment().getTypeUtils();
             TypeMirror factoryType = getContext().getType(NodeFactory.class);
             TypeMirror baseType;
-            if (children.size() == 1) {
+            if (allSame) {
                 baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), commonNodeSuperType);
             } else {
                 baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null));
@@ -793,10 +852,10 @@
 
             CodeTreeBuilder body = method.createBuilder();
             body.startReturn();
-            if (node.getSpecializations().length == 0) {
+            if (node.getSpecializations().isEmpty()) {
                 body.null_();
             } else {
-                body.startNew(nodeClassName(node.getSpecializations()[0]));
+                body.startNew(nodeSpecializationClassName(node.getSpecializations().get(0)));
                 for (VariableElement var : method.getParameters()) {
                     body.string(var.getSimpleName().toString());
                 }
@@ -828,14 +887,14 @@
                         body.startElseIf();
                     }
                     body.string("specializationClass == ").type(type.getBoxedType()).string(".class").end().startBlock();
-                    body.startReturn().startNew(nodeClassName(specialization));
+                    body.startReturn().startNew(nodeSpecializationClassName(specialization));
                     body.string(THIS_NODE_LOCAL_VAR_NAME);
                     body.end().end(); // new, return
 
                     body.end(); // if
                 }
             }
-            body.startReturn().startNew(nodeClassName(node.getGenericSpecialization()));
+            body.startReturn().startNew(nodeSpecializationClassName(node.getGenericSpecialization()));
             body.string(THIS_NODE_LOCAL_VAR_NAME);
             body.end().end();
             return method;
@@ -845,17 +904,17 @@
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), node.getNodeType(), "specialize");
             method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME));
             method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
-            addValueParameters(method, node.getGenericSpecialization(), false);
+            addValueParameters(method, node.getGenericSpecialization(), false, true);
 
             CodeTreeBuilder body = method.createBuilder();
-            body.startStatement().string("boolean allowed = (minimumState == ").string(nodeClassName(node.getSpecializations()[0])).string(".class)").end();
+            body.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end();
 
-            for (int i = 1; i < node.getSpecializations().length; i++) {
-                SpecializationData specialization = node.getSpecializations()[i];
-                body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeClassName(specialization)).string(".class)").end();
+            for (int i = 1; i < node.getSpecializations().size(); i++) {
+                SpecializationData specialization = node.getSpecializations().get(i);
+                body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(specialization)).string(".class)").end();
 
                 CodeTreeBuilder guarded = new CodeTreeBuilder(body);
-                guarded.startReturn().startNew(nodeClassName(specialization));
+                guarded.startReturn().startNew(nodeSpecializationClassName(specialization));
                 guarded.string(THIS_NODE_LOCAL_VAR_NAME);
                 guarded.end().end();
 
@@ -871,11 +930,11 @@
             if (node.getGenericSpecialization().isUseSpecializationsForGeneric()) {
                 List<CodeExecutableElement> methods = new ArrayList<>();
 
-                SpecializationData[] specializations = node.getSpecializations();
+                List<SpecializationData> specializations = node.getSpecializations();
                 SpecializationData prev = null;
-                for (int i = 0; i < specializations.length; i++) {
-                    SpecializationData current = specializations[i];
-                    SpecializationData next = i + 1 < specializations.length ? specializations[i + 1] : null;
+                for (int i = 0; i < specializations.size(); i++) {
+                    SpecializationData current = specializations.get(i);
+                    SpecializationData next = i + 1 < specializations.size() ? specializations.get(i + 1) : null;
                     if (prev == null || current.isUninitialized()) {
                         prev = current;
                         continue;
@@ -883,7 +942,7 @@
                         String methodName = generatedGenericMethodName(current);
                         CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, methodName);
                         method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME));
-                        addValueParameters(method, node.getGenericSpecialization(), true);
+                        addValueParameters(method, node.getGenericSpecialization(), true, true);
 
                         emitGeneratedGenericSpecialization(method.createBuilder(), current, next);
 
@@ -896,7 +955,7 @@
             } else {
                 CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, generatedGenericMethodName(null));
                 method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME));
-                addValueParameters(method, node.getGenericSpecialization(), true);
+                addValueParameters(method, node.getGenericSpecialization(), true, true);
                 emitInvokeDoMethod(method.createBuilder(), node.getGenericSpecialization(), 0);
                 return Arrays.asList(method);
             }
@@ -918,29 +977,29 @@
 
                 builder.startReturn().startCall(generatedGenericMethodName(next));
                 builder.string(THIS_NODE_LOCAL_VAR_NAME);
-                addValueParameterNames(builder, next, null, true);
+                addValueParameterNames(builder, next, null, true, true);
                 builder.end().end();
             }
         }
 
         private void emitInvokeDoMethod(CodeTreeBuilder builder, SpecializationData specialization, int level) {
-            if (specialization.getExceptions().length > 0) {
+            if (!specialization.getExceptions().isEmpty()) {
                 builder.startTryBlock();
             }
 
             builder.startReturn();
-            startCallOperationMethod(builder, specialization);
-            addValueParameterNamesWithCasts(builder, specialization.getNode().getGenericSpecialization(), specialization);
+            startCallOperationMethod(builder, specialization, true);
+            addValueParameterNamesWithCasts(builder, specialization.getNode().getGenericSpecialization(), specialization, false);
             builder.end().end(); // start call operation
             builder.end(); // return
 
-            if (specialization.getExceptions().length > 0) {
+            if (!specialization.getExceptions().isEmpty()) {
                 for (SpecializationThrowsData exception : specialization.getExceptions()) {
                     builder.end().startCatchBlock(exception.getJavaClass(), "ex" + level);
 
                     builder.startReturn().startCall(generatedGenericMethodName(exception.getTransitionTo()));
                     builder.string(THIS_NODE_LOCAL_VAR_NAME);
-                    addValueParameterNames(builder, exception.getTransitionTo(), null, true);
+                    addValueParameterNames(builder, exception.getTransitionTo(), null, true, true);
                     builder.end().end();
                 }
                 builder.end();
@@ -957,7 +1016,7 @@
         @Override
         public CodeTypeElement create(SpecializationData specialization) {
             NodeData node = specialization.getNode();
-            CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeClassName(specialization), node.getNodeType(), false);
+            CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), node.getNodeType(), false);
             return clazz;
         }
 
@@ -981,7 +1040,7 @@
                 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod());
                 if (method.getParameters().size() == 1) {
                     CodeVariableElement var = CodeVariableElement.clone(method.getParameters().get(0));
-                    var.setName("frame");
+                    var.setName("frameValue");
                     method.getParameters().set(0, var);
                 }
                 method.getModifiers().remove(Modifier.ABSTRACT);
@@ -996,7 +1055,7 @@
             }
 
             if (node.needsRewrites(getContext()) && !specialization.isGeneric() && !specialization.isUninitialized()) {
-                buildSpecializeStateMethod(clazz, specialization);
+                buildSpecializeAndExecute(clazz, specialization);
             }
         }
 
@@ -1014,7 +1073,7 @@
             CodeTree primaryExecuteCall = null;
 
             CodeTreeBuilder executeBuilder = CodeTreeBuilder.createBuilder();
-            buildExecute(executeBuilder, null, execType);
+            buildExecute(executeBuilder, null, null, execType);
             primaryExecuteCall = executeBuilder.getRoot();
 
             if (needsTry) {
@@ -1122,7 +1181,7 @@
                 builder.startCall(factoryClassName(node), "specialize");
                 builder.string("this");
                 builder.typeLiteral(builder.findMethod().getEnclosingElement().asType());
-                addValueParameterNames(builder, specialization, null, false);
+                addValueParameterNames(builder, specialization, null, false, true);
                 builder.end(); // call replace, call specialize
             } else {
                 builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end();
@@ -1134,29 +1193,29 @@
         private CodeTree createExecute(CodeTreeBuilder parent, SpecializationData specialization) {
             NodeData node = specialization.getNode();
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-            if (specialization.getExceptions().length > 0) {
+            if (!specialization.getExceptions().isEmpty()) {
                 builder.startTryBlock();
             }
 
             if ((specialization.isUninitialized() || specialization.isGeneric()) && node.needsRewrites(getContext())) {
                 builder.startReturn().startCall(factoryClassName(node), generatedGenericMethodName(null));
                 builder.string("this");
-                addValueParameterNames(builder, specialization, null, true);
+                addValueParameterNames(builder, specialization, null, true, true);
                 builder.end().end();
             } else {
                 builder.startReturn();
 
                 if (specialization.isUninitialized()) {
-                    startCallOperationMethod(builder, specialization.getNode().getGenericSpecialization());
+                    startCallOperationMethod(builder, specialization.getNode().getGenericSpecialization(), false);
                 } else {
-                    startCallOperationMethod(builder, specialization);
+                    startCallOperationMethod(builder, specialization, false);
                 }
-                addValueParameterNames(builder, specialization, null, false);
+                addValueParameterNames(builder, specialization, null, false, false);
                 builder.end().end(); // operation call
                 builder.end(); // return
             }
 
-            if (specialization.getExceptions().length > 0) {
+            if (!specialization.getExceptions().isEmpty()) {
                 for (SpecializationThrowsData exception : specialization.getExceptions()) {
                     builder.end().startCatchBlock(exception.getJavaClass(), "ex");
                     builder.tree(createReturnSpecializeAndExecute(parent, exception.getTransitionTo(), null));
@@ -1168,18 +1227,14 @@
 
         private CodeTree createExecuteChildren(CodeTreeBuilder parent, SpecializationData specialization) {
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-            for (NodeFieldData field : specialization.getNode().getFields()) {
-                if (field.getExecutionKind() == ExecutionKind.IGNORE) {
+
+            for (ActualParameter parameter : specialization.getParameters()) {
+                NodeFieldData field = specialization.getNode().findField(parameter.getSpecification().getName());
+                if (field == null) {
                     continue;
                 }
 
-                ActualParameter parameterType = specialization.findParameter(field.getName());
-
-                if (parameterType.getActualTypeData(specialization.getNode().getTypeSystem()).isGeneric()) {
-                    buildGenericValueExecute(builder, specialization, field, null);
-                } else {
-                    buildSpecializedValueExecute(builder, specialization, field);
-                }
+                buildFieldExecute(builder, specialization, parameter, field, null);
             }
             return builder.getRoot();
         }
@@ -1187,37 +1242,58 @@
         private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) {
             for (TemplateMethod listener : node.getSpecializationListeners()) {
                 builder.startStatement();
-                startCallOperationMethod(builder, listener);
-                addValueParameterNames(builder, listener, null, false);
+                startCallOperationMethod(builder, listener, false);
+                addValueParameterNames(builder, listener, null, false, false);
                 builder.end().end();
                 builder.end(); // statement
             }
         }
 
-        private void buildGenericValueExecute(CodeTreeBuilder builder, SpecializationData specialization, NodeFieldData field, NodeFieldData exceptionSpec) {
-            ActualParameter specParameter = specialization.findParameter(field.getName());
-            NodeData node = specialization.getNode();
-            boolean shortCircuit = startShortCircuit(builder, specialization, field, exceptionSpec);
+        private void buildFieldExecute(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter param, NodeFieldData field, ActualParameter exceptionParam) {
+            boolean shortCircuit = startShortCircuit(builder, specialization, param, exceptionParam);
+            ExecutableTypeData execType = field.getNodeData().findExecutableType(param.getActualTypeData(field.getNodeData().getTypeSystem()));
+            boolean unexpected = execType.hasUnexpectedValue(getContext());
 
-            builder.startStatement();
-            if (!shortCircuit) {
-                builder.type(specialization.getNode().getTypeSystem().getGenericType());
-                builder.string(" ");
+            if (!shortCircuit && unexpected) {
+                builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).end();
+            }
+
+            if (unexpected) {
+                builder.startTryBlock();
             }
 
-            builder.string(valueName(specParameter));
-            builder.string(" = ");
-            ExecutableTypeData genericExecutableType = field.getNodeData().findGenericExecutableType(getContext(), specParameter.getActualTypeData(node.getTypeSystem()));
-            if (genericExecutableType == null) {
-                throw new AssertionError("Must have generic executable type. Parser validation most likely failed. " + Arrays.toString(field.getNodeData().getExecutableTypes()));
+            if (!shortCircuit && !unexpected) {
+                builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).string(" = ");
+            } else {
+                builder.startStatement().string(valueName(param)).string(" = ");
             }
-            buildExecute(builder, field, genericExecutableType);
+            buildExecute(builder, param, field, execType);
             builder.end();
 
+            if (unexpected) {
+                builder.end().startCatchBlock(getUnexpectedValueException(), "ex");
+                SpecializationData generic = specialization.getNode().getGenericSpecialization();
+                boolean execute = false;
+                for (ActualParameter exParam : generic.getParameters()) {
+                    NodeFieldData exField = generic.getNode().findField(exParam.getSpecification().getName());
+                    if (exField == null) {
+                        continue;
+                    }
+                    if (execute) {
+                        buildFieldExecute(builder, specialization.getNode().getGenericSpecialization(), exParam, exField, param);
+                    } else if (exParam.getName().equals(param.getName())) {
+                        execute = true;
+                    }
+                }
+                builder.tree(createReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param));
+                builder.end(); // catch block
+            }
+
             endShortCircuit(builder, shortCircuit);
+            builder.newLine();
         }
 
-        private void buildExecute(CodeTreeBuilder builder, NodeFieldData field, ExecutableTypeData execType) {
+        private void buildExecute(CodeTreeBuilder builder, ActualParameter parameter, NodeFieldData field, ExecutableTypeData execType) {
             if (field != null) {
                 Element accessElement = field.getAccessElement();
                 if (accessElement.getKind() == ElementKind.METHOD) {
@@ -1227,60 +1303,28 @@
                 } else {
                     throw new AssertionError();
                 }
+                if (parameter.getSpecification().isIndexed()) {
+                    builder.string("[" + parameter.getIndex() + "]");
+                }
                 builder.string(".");
             }
             builder.startCall(execType.getMethodName());
-            if (execType.getParameters().length == 1) {
-                builder.string("frame");
+            if (execType.getParameters().size() == 1) {
+                builder.string("frameValue");
             }
             builder.end();
         }
 
-        private void buildSpecializedValueExecute(CodeTreeBuilder builder, SpecializationData specialization, NodeFieldData field) {
-            ActualParameter param = specialization.findParameter(field.getName());
-            boolean shortCircuit = startShortCircuit(builder, specialization, field, null);
-
-            if (!shortCircuit) {
-                builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).end();
-            }
-
-            ExecutableTypeData execType = field.getNodeData().findExecutableType(param.getActualTypeData(field.getNodeData().getTypeSystem()));
-
-            if (execType.hasUnexpectedValue(getContext())) {
-                builder.startTryBlock();
+        private boolean startShortCircuit(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter parameter, ActualParameter exceptionParam) {
+            NodeFieldData forField = specialization.getNode().findField(parameter.getSpecification().getName());
+            if (forField == null) {
+                return false;
             }
 
-            builder.startStatement().string(valueName(field)).string(" = ");
-            buildExecute(builder, field, execType);
-            builder.end();
-
-            if (execType.hasUnexpectedValue(getContext())) {
-                builder.end().startCatchBlock(getUnexpectedValueException(), "ex");
-                boolean execute = false;
-                for (NodeFieldData exField : specialization.getNode().getFields()) {
-                    if (exField.getExecutionKind() == ExecutionKind.IGNORE) {
-                        continue;
-                    }
-                    if (execute) {
-                        buildGenericValueExecute(builder, specialization.getNode().getGenericSpecialization(), exField, field);
-                    } else if (exField == field) {
-                        execute = true;
-                    }
-                }
-                builder.tree(createReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param.getSpecification()));
-                builder.end(); // catch block
-            }
-
-            endShortCircuit(builder, shortCircuit);
-            builder.newLine();
-        }
-
-        private boolean startShortCircuit(CodeTreeBuilder builder, SpecializationData specialization, NodeFieldData forField, NodeFieldData exceptionField) {
             if (forField.getExecutionKind() != ExecutionKind.SHORT_CIRCUIT) {
                 return false;
             }
 
-            ActualParameter parameter = specialization.findParameter(forField.getName());
             ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter);
 
             int shortCircuitIndex = 0;
@@ -1296,14 +1340,14 @@
             builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(shortCircuitParam)).string(" = ");
             ShortCircuitData shortCircuitData = specialization.getShortCircuits()[shortCircuitIndex];
 
-            startCallOperationMethod(builder, shortCircuitData);
-            addValueParameterNames(builder, shortCircuitData, exceptionField != null ? exceptionField.getName() : null, false);
+            startCallOperationMethod(builder, shortCircuitData, false);
+            addValueParameterNames(builder, shortCircuitData, exceptionParam != null ? exceptionParam.getName() : null, false, false);
             builder.end().end(); // call operation
 
             builder.end(); // statement
 
             builder.declaration(parameter.getActualType(), valueName(parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getActualType()));
-            builder.startIf().string(shortCircuitParam.getSpecification().getName()).end();
+            builder.startIf().string(shortCircuitParam.getName()).end();
             builder.startBlock();
 
             return true;
@@ -1315,11 +1359,11 @@
             }
         }
 
-        private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, SpecializationData nextSpecialization, ParameterSpec exceptionSpec) {
+        private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, SpecializationData nextSpecialization, ActualParameter exceptionParam) {
             CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent);
             specializeCall.startCall("specializeAndExecute");
-            specializeCall.string(nodeClassName(nextSpecialization) + ".class");
-            addValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionSpec != null ? exceptionSpec.getName() : null, true);
+            specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class");
+            addValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getName() : null, true, true);
             specializeCall.end().end();
 
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
@@ -1329,7 +1373,7 @@
             return builder.getRoot();
         }
 
-        private void buildSpecializeStateMethod(CodeTypeElement clazz, SpecializationData specialization) {
+        private void buildSpecializeAndExecute(CodeTypeElement clazz, SpecializationData specialization) {
             NodeData node = specialization.getNode();
             TypeData returnType = specialization.getReturnType().getActualTypeData(node.getTypeSystem());
             ExecutableTypeData returnExecutableType = node.findExecutableType(returnType);
@@ -1340,7 +1384,7 @@
             if (canThrowUnexpected) {
                 method.addThrownType(getUnexpectedValueException());
             }
-            addValueParameters(method, specialization.getNode().getGenericSpecialization(), true);
+            addValueParameters(method, specialization.getNode().getGenericSpecialization(), true, true);
             clazz.add(method);
 
             CodeTreeBuilder builder = method.createBuilder();
@@ -1351,7 +1395,7 @@
             builder.startStatement();
             builder.startCall("replace");
             builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState");
-            addValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, false);
+            addValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, false, true);
             builder.end();
             builder.end(); // call replace
             builder.end(); // statement
@@ -1362,7 +1406,7 @@
             CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder();
             genericExecute.startCall(factoryClassName(specialization.getNode()), generatedMethodName);
             genericExecute.string("this");
-            addValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), null, true);
+            addValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), null, true, true);
             genericExecute.end(); // call generated generic
 
             CodeTree genericInvocation = createExpectType(node, returnExecutableType, genericExecute.getRoot());
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Tue Mar 12 11:38:52 2013 +0100
@@ -35,22 +35,59 @@
 
 public class NodeData extends Template {
 
-    private NodeData parent;
-    private List<NodeData> declaredChildren;
+    private final String nodeId;
+    private NodeData declaringNode;
+    private List<NodeData> declaredChildren = new ArrayList<>();
 
     private final TypeSystemData typeSystem;
+    private List<NodeFieldData> fields;
+    private TypeMirror nodeType;
+    private ParameterSpec instanceParameterSpec;
 
-    private NodeFieldData[] fields;
-    private SpecializationData[] specializations;
-    private TemplateMethod[] specializationListeners;
-    private GuardData[] guards;
-    private ExecutableTypeData[] executableTypes;
+    private List<SpecializationData> specializations;
+    private List<SpecializationListenerData> specializationListeners;
+    private List<GuardData> guards;
+    private List<ExecutableTypeData> executableTypes;
+    private List<ShortCircuitData> shortCircuits;
+
+    public NodeData(TypeElement type, TypeSystemData typeSystem, String id) {
+        super(type, null, null);
+        this.nodeId = id;
+        this.typeSystem = typeSystem;
+    }
 
-    private TypeMirror nodeType;
+    public NodeData(NodeData copy, String templateMethodName, String nodeId) {
+        super(copy.getTemplateType(), templateMethodName, null);
+        this.nodeId = nodeId;
+        this.declaringNode = copy.declaringNode;
+        this.declaredChildren = copy.declaredChildren;
+        this.typeSystem = copy.typeSystem;
+        this.nodeType = copy.nodeType;
+        this.specializations = copy.specializations;
+        this.specializationListeners = copy.specializationListeners;
+        this.guards = copy.guards;
+        this.executableTypes = copy.executableTypes;
+        this.shortCircuits = copy.shortCircuits;
 
-    public NodeData(TypeElement type, TypeSystemData typeSystem) {
-        super(type, null);
-        this.typeSystem = typeSystem;
+        List<NodeFieldData> fieldsCopy = new ArrayList<>();
+        for (NodeFieldData field : copy.fields) {
+            NodeFieldData newField = new NodeFieldData(field);
+            newField.setNode(this);
+            fieldsCopy.add(newField);
+        }
+        this.fields = fieldsCopy;
+    }
+
+    public ParameterSpec getInstanceParameterSpec() {
+        return instanceParameterSpec;
+    }
+
+    public void setInstanceParameterSpec(ParameterSpec instanceParameter) {
+        this.instanceParameterSpec = instanceParameter;
+    }
+
+    public String getNodeId() {
+        return nodeId;
     }
 
     public TypeMirror getNodeType() {
@@ -71,6 +108,15 @@
         return !noSpecialization;
     }
 
+    public boolean supportsFrame() {
+        for (ExecutableTypeData execType : executableTypes) {
+            if (execType.findParameter("frameValue") == null) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     public List<NodeData> getNodeChildren() {
         List<NodeData> children = new ArrayList<>();
         for (NodeData child : getDeclaredChildren()) {
@@ -86,12 +132,12 @@
         this.declaredChildren = declaredChildren;
 
         for (NodeData child : declaredChildren) {
-            child.parent = this;
+            child.declaringNode = this;
         }
     }
 
     public NodeData getParent() {
-        return parent;
+        return declaringNode;
     }
 
     public List<NodeData> getDeclaredChildren() {
@@ -112,17 +158,14 @@
             }
         }
 
-        methods.addAll(Arrays.asList(getSpecializationListeners()));
-        methods.addAll(Arrays.asList(getExecutableTypes()));
-        methods.addAll(Arrays.asList(getGuards()));
+        methods.addAll(getSpecializationListeners());
+        methods.addAll(getExecutableTypes());
+        methods.addAll(getGuards());
+        methods.addAll(getShortCircuits());
 
         return methods;
     }
 
-    public TemplateMethod[] getSpecializationListeners() {
-        return specializationListeners;
-    }
-
     public List<GuardData> findGuards(String name) {
         List<GuardData> foundGuards = new ArrayList<>();
         for (GuardData guardData : getGuards()) {
@@ -133,10 +176,6 @@
         return foundGuards;
     }
 
-    public ExecutableTypeData[] getExecutableTypes() {
-        return executableTypes;
-    }
-
     public ExecutableTypeData findGenericExecutableType(ProcessorContext context, TypeData type) {
         List<ExecutableTypeData> types = findGenericExecutableTypes(context);
         for (ExecutableTypeData availableType : types) {
@@ -180,47 +219,20 @@
         return result;
     }
 
-    public TypeMirror[] getExecutablePrimitiveTypeMirrors() {
-        TypeMirror[] typeMirrors = new TypeMirror[executableTypes.length];
-        for (int i = 0; i < executableTypes.length; i++) {
-            typeMirrors[i] = executableTypes[i].getType().getPrimitiveType();
+    public List<TypeMirror> getExecutablePrimitiveTypeMirrors() {
+        List<TypeMirror> typeMirrors = new ArrayList<>();
+        for (ExecutableTypeData executableType : executableTypes) {
+            typeMirrors.add(executableType.getType().getPrimitiveType());
         }
         return typeMirrors;
     }
 
-    void setExecutableTypes(ExecutableTypeData[] declaredExecuableTypes) {
-        this.executableTypes = declaredExecuableTypes;
-    }
-
-    void setFields(NodeFieldData[] fields) {
-        this.fields = fields;
-    }
-
-    void setSpecializations(SpecializationData[] specializations) {
-        this.specializations = specializations;
-    }
-
-    void setSpecializationListeners(TemplateMethod[] specializationListeners) {
-        this.specializationListeners = specializationListeners;
-    }
-
-    void setGuards(GuardData[] guards) {
-        this.guards = guards;
-    }
-
-    public GuardData[] getGuards() {
-        return guards;
-    }
-
     public NodeFieldData[] filterFields(FieldKind fieldKind, ExecutionKind usage) {
         List<NodeFieldData> filteredFields = new ArrayList<>();
-        NodeFieldData[] resolvedFields = getFields();
-        if (fields != null) {
-            for (NodeFieldData field : resolvedFields) {
-                if (usage == null || field.getExecutionKind() == usage) {
-                    if (fieldKind == null || field.getKind() == fieldKind) {
-                        filteredFields.add(field);
-                    }
+        for (NodeFieldData field : getFields()) {
+            if (usage == null || field.getExecutionKind() == usage) {
+                if (fieldKind == null || field.getKind() == fieldKind) {
+                    filteredFields.add(field);
                 }
             }
         }
@@ -249,7 +261,7 @@
             }
         }
 
-        needsRewrites &= specializations.length >= 2;
+        needsRewrites &= specializations.size() >= 2;
         return needsRewrites;
     }
 
@@ -270,26 +282,15 @@
         }
     }
 
-    public NodeFieldData[] getFields() {
-        return fields;
-    }
-
-    public NodeFieldData[] getDeclaredFields() {
-        return fields;
-    }
-
-    public SpecializationData[] getSpecializations() {
-        return specializations;
-    }
-
     public String dump() {
         StringBuilder b = new StringBuilder();
-        b.append(String.format("[name = %s\n" + "  typeSystem = %s\n" + "  fields = %s\n" + "  types = %s\n" + "  specializations = %s\n" + "  guards = %s\n" + "]",
-                        Utils.getQualifiedName(getTemplateType()), getTypeSystem(), dumpList(fields), dumpList(getExecutableTypes()), dumpList(getSpecializations()), dumpList(guards)));
+        b.append(String.format("[id = %s, name = %s\n  typeSystem = %s\n  fields = %s\n  types = %s\n  specializations = %s\n  guards = %s\n  enclosing = %s\n  enclosed = %s\n]", getNodeId(),
+                        Utils.getQualifiedName(getTemplateType()), getTypeSystem(), dumpList(fields), dumpList(getExecutableTypes()), dumpList(getSpecializations()), dumpList(guards),
+                        dumpList(getDeclaredChildren()), getParent()));
         return b.toString();
     }
 
-    private static String dumpList(Object[] array) {
+    private static String dumpList(List<?> array) {
         if (array == null) {
             return "null";
         }
@@ -315,4 +316,76 @@
         return null;
     }
 
+    public List<NodeFieldData> getFields() {
+        return fields;
+    }
+
+    void setFields(List<NodeFieldData> fields) {
+        this.fields = fields;
+    }
+
+    public List<SpecializationData> getSpecializations() {
+        return getSpecializations(false);
+    }
+
+    public List<SpecializationData> getSpecializations(boolean userDefinedOnly) {
+        if (userDefinedOnly) {
+            List<SpecializationData> specs = new ArrayList<>();
+            for (SpecializationData spec : specializations) {
+                if (spec.getMethod() != null) {
+                    specs.add(spec);
+                }
+            }
+            return specs;
+        } else {
+            return specializations;
+        }
+    }
+
+    public List<SpecializationListenerData> getSpecializationListeners() {
+        return specializationListeners;
+    }
+
+    public List<GuardData> getGuards() {
+        return guards;
+    }
+
+    public List<ExecutableTypeData> getExecutableTypes() {
+        return executableTypes;
+    }
+
+    public List<ShortCircuitData> getShortCircuits() {
+        return shortCircuits;
+    }
+
+    void setSpecializations(List<SpecializationData> specializations) {
+        this.specializations = specializations;
+        if (this.specializations != null) {
+            for (SpecializationData specialization : specializations) {
+                specialization.setNode(this);
+            }
+        }
+    }
+
+    void setSpecializationListeners(List<SpecializationListenerData> specializationListeners) {
+        this.specializationListeners = specializationListeners;
+    }
+
+    void setGuards(List<GuardData> guards) {
+        this.guards = guards;
+    }
+
+    void setExecutableTypes(List<ExecutableTypeData> executableTypes) {
+        this.executableTypes = executableTypes;
+    }
+
+    void setShortCircuits(List<ShortCircuitData> shortCircuits) {
+        this.shortCircuits = shortCircuits;
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "[" + getNodeId() + "]";
+    }
+
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Tue Mar 12 11:38:52 2013 +0100
@@ -28,7 +28,7 @@
 public class NodeFieldData {
 
     public enum FieldKind {
-        FIELD, CHILD, CHILDREN
+        CHILD, CHILDREN
     }
 
     public enum ExecutionKind {
@@ -41,7 +41,7 @@
 
     private final FieldKind fieldKind;
     private final ExecutionKind executionKind;
-    private final NodeData nodeData;
+    private NodeData nodeData;
 
     public NodeFieldData(NodeData typeNodeData, VariableElement fieldElement, Element accessElement, AnnotationMirror childAnnotationMirror, FieldKind fieldKind, ExecutionKind executionKind) {
         this.fieldElement = fieldElement;
@@ -52,10 +52,23 @@
         this.executionKind = executionKind;
     }
 
+    NodeFieldData(NodeFieldData field) {
+        this.fieldElement = field.fieldElement;
+        this.accessElement = field.accessElement;
+        this.childAnnotationMirror = field.childAnnotationMirror;
+        this.fieldKind = field.fieldKind;
+        this.executionKind = field.executionKind;
+        this.nodeData = field.nodeData;
+    }
+
     public boolean isShortCircuit() {
         return executionKind == ExecutionKind.SHORT_CIRCUIT;
     }
 
+    void setNode(NodeData nodeData) {
+        this.nodeData = nodeData;
+    }
+
     public VariableElement getFieldElement() {
         return fieldElement;
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Tue Mar 12 11:38:52 2013 +0100
@@ -41,11 +41,9 @@
 
 public class NodeParser extends TemplateParser<NodeData> {
 
-    public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Generic.class, GuardCheck.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class,
-                    SpecializationGuard.class, SpecializationListener.class, SpecializationThrows.class);
+    public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, SpecializationListener.class);
 
     private Map<String, NodeData> parsedNodes;
-    private TypeElement originalType;
 
     public NodeParser(ProcessorContext c) {
         super(c);
@@ -54,23 +52,14 @@
     @Override
     protected NodeData parse(Element element, AnnotationMirror mirror) {
         assert element instanceof TypeElement;
+        NodeData node = null;
         try {
             parsedNodes = new HashMap<>();
-            originalType = (TypeElement) element;
-
-            return parseInnerClassHierarchy((TypeElement) element);
+            node = resolveNode((TypeElement) element);
         } finally {
-            if (Log.DEBUG) {
-                NodeData parsed = parsedNodes.get(Utils.getQualifiedName(originalType));
-                if (parsed != null) {
-                    String dump = parsed.dump();
-                    log.error("Node parsed: %s", dump);
-                    System.out.println("Parsed: " + dump);
-                }
-            }
             parsedNodes = null;
-            originalType = null;
         }
+        return node;
     }
 
     @Override
@@ -78,182 +67,450 @@
         return true;
     }
 
-    private NodeData parseInnerClassHierarchy(TypeElement rootType) {
+    private NodeData resolveNode(TypeElement rootType) {
+        String typeName = Utils.getQualifiedName(rootType);
+        if (parsedNodes.containsKey(typeName)) {
+            return parsedNodes.get(typeName);
+        }
+
         List<? extends TypeElement> types = ElementFilter.typesIn(rootType.getEnclosedElements());
+
         List<NodeData> children = new ArrayList<>();
         for (TypeElement childElement : types) {
-            NodeData childNode = parseInnerClassHierarchy(childElement);
+            NodeData childNode = resolveNode(childElement);
             if (childNode != null) {
                 children.add(childNode);
             }
         }
-        NodeData rootNode = resolveNode(rootType);
+        NodeData rootNode = parseNode(rootType);
         if (rootNode == null && children.size() > 0) {
-            rootNode = new NodeData(rootType, null);
+            rootNode = new NodeData(rootType, null, rootType.getSimpleName().toString());
+        }
+
+        parsedNodes.put(typeName, rootNode);
+
+        if (rootNode != null) {
+            children.addAll(rootNode.getDeclaredChildren());
+            rootNode.setDeclaredChildren(children);
         }
-        if (rootNode != null) {
-            rootNode.setDeclaredChildren(children);
+
+        if (Log.DEBUG) {
+            NodeData parsed = parsedNodes.get(typeName);
+            if (parsed != null) {
+                String dump = parsed.dump();
+                String valid = rootNode != null ? "" : " failed";
+                String msg = String.format("Node parsing %s : %s", valid, dump);
+                log.error(msg);
+                System.out.println(msg);
+            }
         }
 
         return rootNode;
     }
 
-    private NodeData resolveNode(TypeElement currentType) {
-        String typeName = Utils.getQualifiedName(currentType);
-        if (!parsedNodes.containsKey(typeName)) {
-            NodeData node = parseNode(currentType);
-            if (node != null) {
-                parsedNodes.put(typeName, node);
-            }
-            return node;
-        }
-        return parsedNodes.get(typeName);
-    }
-
     private NodeData parseNode(TypeElement type) {
         if (Utils.findAnnotationMirror(processingEnv, type, GeneratedBy.class) != null) {
-            // generated nodes get called again.
+            // generated nodes should not get called again.
             return null;
         }
-        if (!Utils.isAssignable(type.asType(), context.getTruffleTypes().getNode())) {
+
+        AnnotationMirror methodNodes = Utils.findAnnotationMirror(processingEnv, type, NodeClass.class);
+
+        if (methodNodes == null && !Utils.isAssignable(type.asType(), context.getTruffleTypes().getNode())) {
             return null; // not a node
         }
 
+        TypeElement nodeType;
+        boolean needsSplit;
+        if (methodNodes != null) {
+            needsSplit = methodNodes != null;
+            nodeType = Utils.fromTypeMirror(Utils.getAnnotationValue(TypeMirror.class, methodNodes, "value"));
+        } else {
+            needsSplit = false;
+            nodeType = type;
+        }
+
         if (type.getModifiers().contains(Modifier.PRIVATE)) {
             return null; // not visible
         }
 
-        List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type));
-        List<TypeElement> typeHierarchy = findSuperClasses(new ArrayList<TypeElement>(), type);
-        Collections.reverse(typeHierarchy);
-
-        AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class);
-        if (typeSystemMirror == null) {
-            log.error(type, "No @%s annotation found in type hierarchy.", TypeSystemReference.class.getSimpleName());
+        NodeData nodeData = parseNodeData(type, nodeType);
+        if (nodeData == null) {
             return null;
         }
 
-        TypeMirror typeSytemType = Utils.getAnnotationValueType(typeSystemMirror, "value");
-        final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true);
-        if (typeSystem == null) {
-            log.error(type, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType));
-            return null;
-        }
-
-        NodeData nodeData = new NodeData(type, typeSystem);
-
+        List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type));
         nodeData.setExtensionElements(getExtensionParser().parseAll(type, elements));
         if (nodeData.getExtensionElements() != null) {
             elements.addAll(nodeData.getExtensionElements());
         }
 
-        List<ExecutableTypeData> executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements));
-
-        nodeData.setExecutableTypes(executableTypes.toArray(new ExecutableTypeData[executableTypes.size()]));
-
-        parsedNodes.put(Utils.getQualifiedName(type), nodeData);
-
-        NodeFieldData[] fields = parseFields(nodeData, elements, typeHierarchy);
-        if (fields == null) {
+        if (!parseMethods(nodeData, elements)) {
             return null;
         }
-        nodeData.setFields(fields);
 
-        List<SpecializationData> genericSpecializations = new GenericParser(context, nodeData).parse(elements);
-        List<GuardData> guards = new GuardParser(context, nodeData, nodeData.getTypeSystem()).parse(elements);
-        nodeData.setGuards(guards.toArray(new GuardData[guards.size()]));
+        List<NodeData> nodes;
+        if (needsSplit) {
+            nodes = splitNodeData(nodeData);
+            if (nodes == null) {
+                return null;
+            }
+        } else {
+            nodes = new ArrayList<>();
+            nodes.add(nodeData);
+        }
 
-        SpecializationMethodParser specializationParser = new SpecializationMethodParser(context, nodeData);
-        List<SpecializationData> specializations = specializationParser.parse(elements);
-        List<ShortCircuitData> shortCircuits = new ShortCircuitParser(context, nodeData).parse(elements);
-        List<TemplateMethod> listeners = new SpecializationListenerParser(context, nodeData).parse(elements);
+        boolean valid = true;
+        for (NodeData splittedNode : nodes) {
+            if (!finalizeSpecializations(splittedNode)) {
+                valid = false;
+            }
+            if (!verifyNode(splittedNode)) {
+                valid = false;
+            }
+        }
 
-        if (specializations == null || genericSpecializations == null || shortCircuits == null || listeners == null || guards == null) {
+        if (!valid) {
             return null;
         }
 
+        if (needsSplit) {
+            nodeData.setDeclaredChildren(nodes);
+            nodeData.setSpecializationListeners(new ArrayList<SpecializationListenerData>());
+            nodeData.setSpecializations(new ArrayList<SpecializationData>());
+            return nodeData;
+        } else {
+            return nodeData;
+        }
+    }
+
+    private static List<NodeData> splitNodeData(NodeData node) {
+        SortedMap<String, List<SpecializationData>> groupedSpecializations = groupByNodeId(node.getSpecializations());
+        SortedMap<String, List<SpecializationListenerData>> groupedListeners = groupByNodeId(node.getSpecializationListeners());
+
+        Set<String> ids = new TreeSet<>();
+        ids.addAll(groupedSpecializations.keySet());
+        ids.addAll(groupedListeners.keySet());
+
+        List<NodeData> splitted = new ArrayList<>();
+        for (String id : ids) {
+            List<SpecializationData> specializations = groupedSpecializations.get(id);
+            List<SpecializationListenerData> listeners = groupedListeners.get(id);
+
+            if (specializations == null) {
+                specializations = new ArrayList<>();
+            }
+
+            if (listeners == null) {
+                listeners = new ArrayList<>();
+            }
+
+            String nodeId = node.getNodeId();
+            if (nodeId.endsWith("Node") && !nodeId.equals("Node")) {
+                nodeId = nodeId.substring(0, nodeId.length() - 4);
+            }
+            String newNodeId = nodeId + Utils.firstLetterUpperCase(id);
+            NodeData copy = new NodeData(node, id, newNodeId);
+
+            copy.setSpecializations(specializations);
+            copy.setSpecializationListeners(listeners);
+
+            splitted.add(copy);
+        }
+
+        node.setSpecializations(new ArrayList<SpecializationData>());
+        node.setSpecializationListeners(new ArrayList<SpecializationListenerData>());
+
+        return splitted;
+    }
+
+    private static <M extends TemplateMethod> SortedMap<String, List<M>> groupByNodeId(List<M> methods) {
+        SortedMap<String, List<M>> grouped = new TreeMap<>();
+        for (M m : methods) {
+            List<M> list = grouped.get(m.getId());
+            if (list == null) {
+                list = new ArrayList<>();
+                grouped.put(m.getId(), list);
+            }
+            list.add(m);
+        }
+        return grouped;
+    }
+
+    private boolean parseMethods(final NodeData node, List<Element> elements) {
+        node.setGuards(new GuardParser(context, node, node.getTypeSystem()).parse(elements));
+        node.setShortCircuits(new ShortCircuitParser(context, node).parse(elements));
+        node.setSpecializationListeners(new SpecializationListenerParser(context, node).parse(elements));
+        List<SpecializationData> generics = new GenericParser(context, node).parse(elements);
+        List<SpecializationData> specializations = new SpecializationMethodParser(context, node).parse(elements);
+
+        if (generics == null || specializations == null || node.getGuards() == null || node.getShortCircuits() == null || node.getSpecializationListeners() == null) {
+            return false;
+        }
+
+        List<SpecializationData> allSpecializations = new ArrayList<>();
+        allSpecializations.addAll(generics);
+        allSpecializations.addAll(specializations);
+
+        node.setSpecializations(allSpecializations);
+
+        return true;
+    }
+
+    private boolean finalizeSpecializations(final NodeData node) {
+        List<SpecializationData> specializations = new ArrayList<>(node.getSpecializations());
+
+        if (specializations.isEmpty()) {
+            return true;
+        }
+
+        List<SpecializationData> generics = new ArrayList<>();
+        for (SpecializationData spec : specializations) {
+            if (spec.isGeneric()) {
+                generics.add(spec);
+            }
+        }
+
         SpecializationData genericSpecialization = null;
-        if (genericSpecializations.size() > 1) {
-            for (SpecializationData generic : genericSpecializations) {
+        if (generics.size() > 1) {
+            for (SpecializationData generic : generics) {
                 log.error(generic.getMethod(), "Only one method with @%s is allowed per operation.", Generic.class.getSimpleName());
             }
-            return null;
-        } else if (genericSpecializations.size() == 1) {
-            genericSpecialization = genericSpecializations.get(0);
+            return false;
+        } else if (generics.size() == 1) {
+            genericSpecialization = generics.get(0);
+        } else {
+            // TODO support generation of generic if not ambiguous.
         }
 
         if (specializations.size() > 1 && genericSpecialization == null) {
-            log.error(type, "Need a @%s method.", Generic.class.getSimpleName());
-            return null;
+            log.error(node.getTemplateType(), "Need a @%s method.", Generic.class.getSimpleName());
+            return false;
+        }
+
+        if (genericSpecialization != null) {
+            CodeExecutableElement uninitializedMethod = new CodeExecutableElement(Utils.modifiers(Modifier.PUBLIC), context.getType(void.class), "doUninitialized");
+            TemplateMethod uninializedMethod = new TemplateMethod(genericSpecialization.getId(), node, genericSpecialization.getSpecification(), uninitializedMethod,
+                            genericSpecialization.getMarkerAnnotation(), genericSpecialization.getReturnType(), genericSpecialization.getParameters());
+            specializations.add(new SpecializationData(uninializedMethod, false, true));
         }
 
         Collections.sort(specializations, new Comparator<SpecializationData>() {
 
             @Override
             public int compare(SpecializationData o1, SpecializationData o2) {
-                return compareSpecialization(typeSystem, o1, o2);
+                return compareSpecialization(node.getTypeSystem(), o1, o2);
             }
         });
 
-        List<SpecializationData> allSpecializations = new ArrayList<>(specializations);
-        if (genericSpecialization != null) {
-            allSpecializations.add(genericSpecialization);
-            CodeExecutableElement uninitializedMethod = new CodeExecutableElement(Utils.modifiers(Modifier.PUBLIC), context.getType(void.class), "doUninitialized");
-            TemplateMethod uninializedMethod = new TemplateMethod(nodeData, genericSpecialization.getSpecification(), uninitializedMethod, genericSpecialization.getMarkerAnnotation(),
-                            genericSpecialization.getReturnType(), genericSpecialization.getParameters());
-            allSpecializations.add(0, new SpecializationData(uninializedMethod, false, true));
+        node.setSpecializations(specializations);
+
+        for (SpecializationData specialization : specializations) {
+            specialization.setId(findUniqueSpecializationId(specialization));
         }
 
-        for (SpecializationData specialization : allSpecializations) {
-            specialization.setNode(nodeData);
+        return true;
+    }
+
+    private static String findUniqueSpecializationId(SpecializationData specialization) {
+
+        String name;
+        if (specialization.isGeneric()) {
+            name = "Generic";
+        } else if (specialization.isUninitialized()) {
+            name = "Uninitialized";
+        } else {
+            List<SpecializationData> specializations = new ArrayList<>(specialization.getNode().getSpecializations());
+            for (ListIterator<SpecializationData> iterator = specializations.listIterator(); iterator.hasNext();) {
+                SpecializationData data = iterator.next();
+                if (data.isGeneric() || data.isUninitialized()) {
+                    iterator.remove();
+                }
+            }
+
+            Map<ParameterSpec, Set<String>> usedIds = new HashMap<>();
+            for (SpecializationData other : specializations) {
+                for (ActualParameter param : other.getReturnTypeAndParameters()) {
+                    if (other.getNode().findField(param.getSpecification().getName()) == null) {
+                        continue;
+                    }
+
+                    Set<String> types = usedIds.get(param.getSpecification());
+                    if (types == null) {
+                        types = new HashSet<>();
+                        usedIds.put(param.getSpecification(), types);
+                    }
+                    types.add(Utils.getTypeId(param.getActualType()));
+                }
+            }
+
+            List<ParameterSpec> ambiguousSpecs = new ArrayList<>();
+            for (ActualParameter param : specialization.getReturnTypeAndParameters()) {
+                Set<String> ids = usedIds.get(param.getSpecification());
+                if (ids != null && ids.size() > 1) {
+                    ambiguousSpecs.add(param.getSpecification());
+                }
+            }
+
+            String specializationId = findSpecializationId(specialization, ambiguousSpecs);
+            int specializationIndex = 0;
+            int totalIndex = 0;
+
+            for (SpecializationData other : specializations) {
+                String id = findSpecializationId(other, ambiguousSpecs);
+                if (id.equals(specializationId)) {
+                    totalIndex++;
+                    if (specialization == other) {
+                        specializationIndex = totalIndex;
+                    }
+                }
+            }
+
+            if (specializationIndex != totalIndex) {
+                name = specializationId + specializationIndex;
+            } else {
+                name = specializationId;
+            }
+        }
+        return name;
+    }
+
+    private static String findSpecializationId(SpecializationData specialization, List<ParameterSpec> specs) {
+        boolean allSame = true;
+        ActualParameter prevParam = specialization.getReturnType();
+        for (ParameterSpec spec : specs) {
+            ActualParameter param = specialization.findParameter(spec);
+            if (!Utils.typeEquals(prevParam.getActualType(), param.getActualType())) {
+                allSame = false;
+                break;
+            }
+            prevParam = param;
+        }
+
+        if (allSame) {
+            return Utils.getTypeId(prevParam.getActualType());
+        } else {
+            StringBuilder nameBuilder = new StringBuilder();
+            nameBuilder.append(Utils.getTypeId(prevParam.getActualType()));
+            for (ParameterSpec spec : specs) {
+                ActualParameter param = specialization.findParameter(spec);
+                nameBuilder.append(Utils.getTypeId(param.getActualType()));
+            }
+            return nameBuilder.toString();
+        }
+    }
+
+    private boolean verifyNode(NodeData nodeData) {
+        // verify specialization parameter length
+        if (!verifySpecializationParameters(nodeData)) {
+            return false;
         }
 
         // verify order is not ambiguous
-        if (!verifySpecializationOrder(typeSystem, specializations)) {
+        if (!verifySpecializationOrder(nodeData)) {
+            return false;
+        }
+
+        if (!verifyMissingAbstractMethods(nodeData)) {
+            return false;
+        }
+
+        if (!assignShortCircuitsToSpecializations(nodeData)) {
+            return false;
+        }
+
+        if (!verifyConstructors(nodeData)) {
+            return false;
+        }
+
+// if (!verifyNamingConvention(specializations, "do")) {
+// return null;
+// }
+//
+// if (!verifyNamesUnique(specializations)) {
+// return null;
+// }
+
+        if (!verifyNamingConvention(nodeData.getShortCircuits(), "needs")) {
+            return false;
+        }
+
+        if (!verifySpecializationThrows(nodeData)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    private NodeData parseNodeData(TypeElement templateType, TypeElement nodeType) {
+        List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeType));
+        List<TypeElement> typeHierarchy = findSuperClasses(new ArrayList<TypeElement>(), nodeType);
+        Collections.reverse(typeHierarchy);
+
+        AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class);
+        if (typeSystemMirror == null) {
+            log.error(templateType, "No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), nodeType.getQualifiedName().toString());
             return null;
         }
 
-        nodeData.setSpecializations(allSpecializations.toArray(new SpecializationData[allSpecializations.size()]));
-        nodeData.setSpecializationListeners(listeners.toArray(new TemplateMethod[listeners.size()]));
-
-        if (!verifyMissingAbstractMethods(nodeData, elements)) {
-            return null;
-        }
-
-        if (!assignShortCircuitsToSpecializations(nodeData, allSpecializations, shortCircuits)) {
-            return null;
-        }
-
-        if (!verifyConstructors(nodeData)) {
+        TypeMirror typeSytemType = Utils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value");
+        final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true);
+        if (typeSystem == null) {
+            log.error(templateType, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType));
             return null;
         }
 
-        if (!verifyNamingConvention(specializations, "do")) {
-            return null;
-        }
+        NodeData nodeData = new NodeData(templateType, typeSystem, templateType.getSimpleName().toString());
+        nodeData.setNodeType(nodeType.asType());
+
+        List<ExecutableTypeData> executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements));
 
-        if (!verifyNamesUnique(specializations)) {
+        nodeData.setExecutableTypes(executableTypes);
+
+        parsedNodes.put(Utils.getQualifiedName(templateType), nodeData);
+
+        List<NodeFieldData> fields = parseFields(nodeData, elements, typeHierarchy);
+        if (fields == null) {
             return null;
         }
-
-        if (!verifyNamingConvention(shortCircuits, "needs")) {
-            return null;
-        }
-
-        if (!verifySpecializationThrows(typeSystem, specializations)) {
-            return null;
-        }
+        nodeData.setFields(fields);
 
         return nodeData;
     }
 
-    private boolean verifyMissingAbstractMethods(NodeData nodeData, List<Element> elements) {
+    private boolean verifySpecializationParameters(NodeData nodeData) {
+        boolean valid = true;
+        int args = -1;
+        for (SpecializationData specializationData : nodeData.getSpecializations()) {
+            int specializationArgs = 0;
+            for (ActualParameter param : specializationData.getParameters()) {
+                if (!param.getSpecification().isOptional()) {
+                    specializationArgs++;
+                }
+            }
+            if (args != -1 && args != specializationArgs) {
+                valid = false;
+                break;
+            }
+            args = specializationArgs;
+        }
+        if (!valid) {
+            for (SpecializationData specialization : nodeData.getSpecializations()) {
+                context.getLog().error(specialization.getMethod(), specialization.getMarkerAnnotation(), "All specializations must have the same number of arguments.");
+            }
+        }
+        return valid;
+    }
+
+    private boolean verifyMissingAbstractMethods(NodeData nodeData) {
         if (nodeData.needsFactory()) {
             // missing abstract methods only needs to be implemented
             // if we need go generate factory for it.
             return true;
         }
 
+        List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeData.getTemplateType()));
+
         Set<Element> unusedElements = new HashSet<>(elements);
         for (TemplateMethod method : nodeData.getAllTemplateMethods()) {
             unusedElements.remove(method.getMethod());
@@ -347,13 +604,13 @@
         return null;
     }
 
-    private NodeFieldData[] parseFields(NodeData nodeData, List<? extends Element> elements, final List<TypeElement> typeHierarchy) {
+    private List<NodeFieldData> parseFields(NodeData nodeData, List<? extends Element> elements, final List<TypeElement> typeHierarchy) {
         AnnotationMirror executionOrderMirror = findFirstAnnotation(typeHierarchy, ExecuteChildren.class);
         List<String> executionDefinition = null;
         if (executionOrderMirror != null) {
             executionDefinition = new ArrayList<>();
-            for (Object object : Utils.getAnnotationValueList(executionOrderMirror, "value")) {
-                executionDefinition.add((String) object);
+            for (String object : Utils.getAnnotationValueList(String.class, executionOrderMirror, "value")) {
+                executionDefinition.add(object);
             }
         }
 
@@ -361,7 +618,7 @@
         for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
             AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class);
             if (mirror != null) {
-                shortCircuits.add(Utils.getAnnotationValueString(mirror, "value"));
+                shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value"));
             }
         }
 
@@ -394,9 +651,8 @@
             return null;
         }
 
-        NodeFieldData[] fieldArray = fields.toArray(new NodeFieldData[fields.size()]);
-        sortByExecutionOrder(fieldArray, executionDefinition == null ? Collections.<String> emptyList() : executionDefinition, typeHierarchy);
-        return fieldArray;
+        sortByExecutionOrder(fields, executionDefinition == null ? Collections.<String> emptyList() : executionDefinition, typeHierarchy);
+        return fields;
     }
 
     private NodeFieldData parseField(NodeData parentNodeData, VariableElement var, Set<String> foundShortCircuits) {
@@ -424,10 +680,10 @@
             nodeType = getComponentType(var.asType());
             kind = FieldKind.CHILDREN;
         } else {
-            mirror = null;
+            execution = ExecutionKind.IGNORE;
             nodeType = null;
-            kind = FieldKind.FIELD;
-            execution = ExecutionKind.IGNORE;
+            mirror = null;
+            kind = null;
         }
 
         NodeData fieldNodeData = null;
@@ -444,13 +700,12 @@
                 context.getLog().error(errorElement, "No executable generic types found for node '%s'.", Utils.getQualifiedName(nodeType));
                 return null;
             }
+
+            // TODO correct handling of access elements
+            if (var.getModifiers().contains(Modifier.PRIVATE) && Utils.typeEquals(var.getEnclosingElement().asType(), parentNodeData.getTemplateType().asType())) {
+                execution = ExecutionKind.IGNORE;
+            }
         }
-
-        // TODO correct handling of access elements
-        if (var.getModifiers().contains(Modifier.PRIVATE) && Utils.typeEquals(var.getEnclosingElement().asType(), parentNodeData.getTemplateType().asType())) {
-            execution = ExecutionKind.IGNORE;
-        }
-
         return new NodeFieldData(fieldNodeData, var, findAccessElement(var), mirror, kind, execution);
     }
 
@@ -482,8 +737,8 @@
         }
     }
 
-    private static void sortByExecutionOrder(NodeFieldData[] fields, final List<String> executionOrder, final List<TypeElement> typeHierarchy) {
-        Arrays.sort(fields, new Comparator<NodeFieldData>() {
+    private static void sortByExecutionOrder(List<NodeFieldData> fields, final List<String> executionOrder, final List<TypeElement> typeHierarchy) {
+        Collections.sort(fields, new Comparator<NodeFieldData>() {
 
             @Override
             public int compare(NodeFieldData o1, NodeFieldData o2) {
@@ -505,18 +760,17 @@
         });
     }
 
-    private boolean assignShortCircuitsToSpecializations(NodeData nodeData, List<SpecializationData> specializations, List<ShortCircuitData> shortCircuits) {
-
-        Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(shortCircuits);
+    private boolean assignShortCircuitsToSpecializations(NodeData node) {
+        Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits());
 
         boolean valid = true;
 
-        for (NodeFieldData field : nodeData.filterFields(null, ExecutionKind.SHORT_CIRCUIT)) {
+        for (NodeFieldData field : node.filterFields(null, ExecutionKind.SHORT_CIRCUIT)) {
             String valueName = field.getName();
             List<ShortCircuitData> availableCircuits = groupedShortCircuits.get(valueName);
 
             if (availableCircuits == null || availableCircuits.isEmpty()) {
-                log.error(nodeData.getTemplateType(), "@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName);
+                log.error(node.getTemplateType(), "@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName);
                 valid = false;
                 continue;
             }
@@ -539,14 +793,14 @@
 
             ShortCircuitData genericCircuit = null;
             for (ShortCircuitData circuit : availableCircuits) {
-                if (isGenericShortCutMethod(nodeData, circuit)) {
+                if (isGenericShortCutMethod(node, circuit)) {
                     genericCircuit = circuit;
                     break;
                 }
             }
 
             if (genericCircuit == null) {
-                log.error(nodeData.getTemplateType(), "No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName);
+                log.error(node.getTemplateType(), "No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName);
                 valid = false;
                 continue;
             }
@@ -562,8 +816,8 @@
             return valid;
         }
 
-        NodeFieldData[] fields = nodeData.filterFields(null, ExecutionKind.SHORT_CIRCUIT);
-        for (SpecializationData specialization : specializations) {
+        NodeFieldData[] fields = node.filterFields(null, ExecutionKind.SHORT_CIRCUIT);
+        for (SpecializationData specialization : node.getSpecializations()) {
             ShortCircuitData[] assignedShortCuts = new ShortCircuitData[fields.length];
 
             for (int i = 0; i < fields.length; i++) {
@@ -599,6 +853,7 @@
         return valid;
     }
 
+    @SuppressWarnings("unused")
     private boolean verifyNamesUnique(List<? extends TemplateMethod> methods) {
         boolean valid = true;
         for (int i = 0; i < methods.size(); i++) {
@@ -617,9 +872,9 @@
     }
 
     private boolean isGenericShortCutMethod(NodeData node, TemplateMethod method) {
-        for (NodeFieldData field : node.getFields()) {
-            ActualParameter parameter = method.findParameter(field.getName());
-            if (parameter == null) {
+        for (ActualParameter parameter : method.getParameters()) {
+            NodeFieldData field = node.findField(parameter.getSpecification().getName());
+            if (field == null) {
                 continue;
             }
             ExecutableTypeData found = null;
@@ -668,7 +923,10 @@
         return collection;
     }
 
-    private boolean verifySpecializationOrder(TypeSystemData typeSystem, List<SpecializationData> specializations) {
+    private boolean verifySpecializationOrder(NodeData node) {
+        TypeSystemData typeSystem = node.getTypeSystem();
+        List<SpecializationData> specializations = node.getSpecializations();
+
         for (int i = 0; i < specializations.size(); i++) {
             SpecializationData m1 = specializations.get(i);
             for (int j = i + 1; j < specializations.size(); j++) {
@@ -696,31 +954,19 @@
         return true;
     }
 
-    private boolean verifySpecializationThrows(TypeSystemData typeSystem, List<SpecializationData> specializations) {
+    private boolean verifySpecializationThrows(NodeData node) {
         Map<String, SpecializationData> specializationMap = new HashMap<>();
-        for (SpecializationData spec : specializations) {
+        for (SpecializationData spec : node.getSpecializations()) {
             specializationMap.put(spec.getMethodName(), spec);
         }
         boolean valid = true;
-        for (SpecializationData sourceSpecialization : specializations) {
+        for (SpecializationData sourceSpecialization : node.getSpecializations()) {
             if (sourceSpecialization.getExceptions() != null) {
                 for (SpecializationThrowsData throwsData : sourceSpecialization.getExceptions()) {
-                    SpecializationData targetSpecialization = specializationMap.get(throwsData.getTransitionToName());
-                    AnnotationValue value = Utils.getAnnotationValue(throwsData.getAnnotationMirror(), "transitionTo");
-
-                    if (targetSpecialization == null) {
-                        log.error(throwsData.getSpecialization().getMethod(), throwsData.getAnnotationMirror(), value, "Specialization with name '%s' not found.", throwsData.getTransitionToName());
-                        valid = false;
-                    } else if (compareSpecialization(typeSystem, sourceSpecialization, targetSpecialization) >= 0) {
-                        log.error(throwsData.getSpecialization().getMethod(), throwsData.getAnnotationMirror(), value,
-                                        "The order of the target specializalization must be higher than the source specialization.", throwsData.getTransitionToName());
-                        valid = false;
-                    }
-
                     for (SpecializationThrowsData otherThrowsData : sourceSpecialization.getExceptions()) {
                         if (otherThrowsData != throwsData && Utils.typeEquals(otherThrowsData.getJavaClass(), throwsData.getJavaClass())) {
-                            AnnotationValue javaClassValue = Utils.getAnnotationValue(throwsData.getAnnotationMirror(), "javaClass");
-                            log.error(throwsData.getSpecialization().getMethod(), throwsData.getAnnotationMirror(), javaClassValue, "Duplicate exception type.", throwsData.getTransitionToName());
+                            AnnotationValue javaClassValue = Utils.getAnnotationValue(throwsData.getAnnotationMirror(), "rewriteOn");
+                            log.error(throwsData.getSpecialization().getMethod(), throwsData.getAnnotationMirror(), javaClassValue, "Duplicate exception type.");
                             valid = false;
                         }
                     }
@@ -744,8 +990,22 @@
     }
 
     private static int compareSpecializationWithoutOrder(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) {
-        if (m1.getSpecification() != m2.getSpecification()) {
-            throw new UnsupportedOperationException("Cannot compare two specializations with different specifications.");
+        if (m1 == m2) {
+            return 0;
+        }
+
+        if (m1.isUninitialized() && !m2.isUninitialized()) {
+            return -1;
+        } else if (!m1.isUninitialized() && m2.isUninitialized()) {
+            return 1;
+        } else if (m1.isGeneric() && !m2.isGeneric()) {
+            return 1;
+        } else if (!m1.isGeneric() && m2.isGeneric()) {
+            return -1;
+        }
+
+        if (m1.getTemplate() != m2.getTemplate()) {
+            throw new UnsupportedOperationException("Cannot compare two specializations with different templates.");
         }
 
         int result = compareActualParameter(typeSystem, m1.getReturnType(), m2.getReturnType());
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitData.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitData.java	Tue Mar 12 11:38:52 2013 +0100
@@ -61,8 +61,7 @@
         }
 
         for (ActualParameter param : getParameters()) {
-            ParameterSpec paramSpec = param.getSpecification();
-            ActualParameter specializationParam = specialization.findParameter(paramSpec.getName());
+            ActualParameter specializationParam = specialization.findParameter(param.getName());
             if (!Utils.typeEquals(param.getActualType(), specializationParam.getActualType())) {
                 return false;
             }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java	Tue Mar 12 11:38:52 2013 +0100
@@ -48,14 +48,14 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        String shortCircuitValue = Utils.getAnnotationValueString(mirror, "value");
+        String shortCircuitValue = Utils.getAnnotationValue(String.class, mirror, "value");
 
         if (!shortCircuitValues.contains(shortCircuitValue)) {
             getContext().getLog().error(method, mirror, "Invalid short circuit value %s.", shortCircuitValue);
             return null;
         }
 
-        return createDefaultMethodSpec(shortCircuitValue);
+        return createDefaultMethodSpec(method, mirror, shortCircuitValue);
     }
 
     @Override
@@ -65,7 +65,7 @@
 
     @Override
     public ShortCircuitData create(TemplateMethod method) {
-        String shortCircuitValue = Utils.getAnnotationValueString(method.getMarkerAnnotation(), "value");
+        String shortCircuitValue = Utils.getAnnotationValue(String.class, method.getMarkerAnnotation(), "value");
         assert shortCircuitValue != null;
         assert shortCircuitValues.contains(shortCircuitValue);
         return new ShortCircuitData(method, shortCircuitValue);
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Tue Mar 12 11:38:52 2013 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.codegen.processor.node;
 
+import java.util.*;
+
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.template.*;
 
@@ -30,13 +32,13 @@
     private final int order;
     private final boolean generic;
     private final boolean uninitialized;
-    private final SpecializationThrowsData[] exceptions;
+    private final List<SpecializationThrowsData> exceptions;
     private SpecializationGuardData[] guards;
     private ShortCircuitData[] shortCircuits;
     private boolean useSpecializationsForGeneric = true;
     private NodeData node;
 
-    public SpecializationData(TemplateMethod template, int order, SpecializationThrowsData[] exceptions) {
+    public SpecializationData(TemplateMethod template, int order, List<SpecializationThrowsData> exceptions) {
         super(template);
         this.order = order;
         this.generic = false;
@@ -53,7 +55,7 @@
         this.order = Specialization.DEFAULT_ORDER;
         this.generic = generic;
         this.uninitialized = uninitialized;
-        this.exceptions = new SpecializationThrowsData[0];
+        this.exceptions = Collections.emptyList();
         this.guards = new SpecializationGuardData[0];
     }
 
@@ -81,7 +83,7 @@
         return uninitialized;
     }
 
-    public SpecializationThrowsData[] getExceptions() {
+    public List<SpecializationThrowsData> getExceptions() {
         return exceptions;
     }
 
@@ -106,10 +108,10 @@
     }
 
     public SpecializationData findNextSpecialization() {
-        SpecializationData[] specializations = node.getSpecializations();
-        for (int i = 0; i < specializations.length - 1; i++) {
-            if (specializations[i] == this) {
-                return specializations[i + 1];
+        List<SpecializationData> specializations = node.getSpecializations();
+        for (int i = 0; i < specializations.size() - 1; i++) {
+            if (specializations.get(i) == this) {
+                return specializations.get(i + 1);
             }
         }
         return null;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerData.java	Tue Mar 12 11:38:52 2013 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.codegen.processor.node;
+
+import com.oracle.truffle.codegen.processor.template.*;
+
+public class SpecializationListenerData extends TemplateMethod {
+
+    public SpecializationListenerData(TemplateMethod method) {
+        super(method);
+    }
+
+}
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java	Tue Mar 12 11:38:52 2013 +0100
@@ -30,18 +30,15 @@
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
 
-public class SpecializationListenerParser extends MethodParser<TemplateMethod> {
-
-    private final MethodSpec specification;
+public class SpecializationListenerParser extends MethodParser<SpecializationListenerData> {
 
     public SpecializationListenerParser(ProcessorContext context, NodeData node) {
         super(context, node);
-        this.specification = createDefaultMethodSpec(null);
     }
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        return specification;
+        return createDefaultMethodSpec(method, mirror, null);
     }
 
     @Override
@@ -50,8 +47,8 @@
     }
 
     @Override
-    public TemplateMethod create(TemplateMethod method) {
-        return method;
+    public SpecializationListenerData create(TemplateMethod method) {
+        return new SpecializationListenerData(method);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java	Tue Mar 12 11:38:52 2013 +0100
@@ -35,16 +35,13 @@
 
 public class SpecializationMethodParser extends MethodParser<SpecializationData> {
 
-    private final MethodSpec specification;
-
     public SpecializationMethodParser(ProcessorContext context, NodeData operation) {
         super(context, operation);
-        this.specification = createDefaultMethodSpec(null);
     }
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        return specification;
+        return createDefaultMethodSpec(method, mirror, null);
     }
 
     @Override
@@ -58,27 +55,24 @@
     }
 
     private SpecializationData parseSpecialization(TemplateMethod method) {
-        int order = Utils.getAnnotationValueInt(method.getMarkerAnnotation(), "order");
+        int order = Utils.getAnnotationValue(Integer.class, method.getMarkerAnnotation(), "order");
         if (order < 0 && order != Specialization.DEFAULT_ORDER) {
             getContext().getLog().error(method.getMethod(), method.getMarkerAnnotation(), "Invalid order attribute %d. The value must be >= 0 or the default value.");
             return null;
         }
 
-        List<AnnotationMirror> exceptionDefs = Utils.collectAnnotations(getContext(), method.getMarkerAnnotation(), "exceptions", method.getMethod(), SpecializationThrows.class);
-        SpecializationThrowsData[] exceptionData = new SpecializationThrowsData[exceptionDefs.size()];
-        for (int i = 0; i < exceptionData.length; i++) {
-            AnnotationMirror mirror = exceptionDefs.get(i);
-            TypeMirror javaClass = Utils.getAnnotationValueType(mirror, "javaClass");
-            String transitionTo = Utils.getAnnotationValueString(mirror, "transitionTo");
-            exceptionData[i] = new SpecializationThrowsData(mirror, javaClass, transitionTo);
+        List<TypeMirror> exceptionTypes = Utils.getAnnotationValueList(TypeMirror.class, method.getMarkerAnnotation(), "rewriteOn");
+        List<SpecializationThrowsData> exceptionData = new ArrayList<>();
+        for (TypeMirror exceptionType : exceptionTypes) {
+            exceptionData.add(new SpecializationThrowsData(method.getMarkerAnnotation(), exceptionType));
 
-            if (!Utils.canThrowType(method.getMethod().getThrownTypes(), javaClass)) {
-                getContext().getLog().error(method.getMethod(), "Method must specify a throws clause with the exception type '%s'.", Utils.getQualifiedName(javaClass));
+            if (!Utils.canThrowType(method.getMethod().getThrownTypes(), exceptionType)) {
+                getContext().getLog().error(method.getMethod(), "Method must specify a throws clause with the exception type '%s'.", Utils.getQualifiedName(exceptionType));
                 return null;
             }
         }
 
-        Arrays.sort(exceptionData, new Comparator<SpecializationThrowsData>() {
+        Collections.sort(exceptionData, new Comparator<SpecializationThrowsData>() {
 
             @Override
             public int compare(SpecializationThrowsData o1, SpecializationThrowsData o2) {
@@ -87,24 +81,24 @@
         });
         SpecializationData specialization = new SpecializationData(method, order, exceptionData);
         boolean valid = true;
-        List<AnnotationMirror> guardDefs = Utils.collectAnnotations(getContext(), method.getMarkerAnnotation(), "guards", method.getMethod(), SpecializationGuard.class);
+        List<String> guardDefs = Utils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards");
         SpecializationGuardData[] guardData = new SpecializationGuardData[guardDefs.size()];
         for (int i = 0; i < guardData.length; i++) {
-            AnnotationMirror guardMirror = guardDefs.get(i);
-            String guardMethod = Utils.getAnnotationValueString(guardMirror, "methodName");
-            boolean onSpecialization = Utils.getAnnotationValueBoolean(guardMirror, "onSpecialization");
-            boolean onExecution = Utils.getAnnotationValueBoolean(guardMirror, "onExecution");
+            String guardMethod = guardDefs.get(i);
+
+            boolean onSpecialization = true;
+            boolean onExecution = true;
 
             if (!onSpecialization && !onExecution) {
                 String message = "Either onSpecialization, onExecution or both must be enabled.";
-                getContext().getLog().error(method.getMethod(), guardMirror, message);
+                getContext().getLog().error(method.getMethod(), message);
                 valid = false;
                 continue;
             }
 
             guardData[i] = new SpecializationGuardData(guardMethod, onSpecialization, onExecution);
 
-            GuardData compatibleGuard = matchSpecializationGuard(guardMirror, specialization, guardData[i]);
+            GuardData compatibleGuard = matchSpecializationGuard(specialization, guardData[i]);
             if (compatibleGuard != null) {
                 guardData[i].setGuardDeclaration(compatibleGuard);
             } else {
@@ -121,7 +115,7 @@
         return specialization;
     }
 
-    private GuardData matchSpecializationGuard(AnnotationMirror mirror, SpecializationData specialization, SpecializationGuardData specializationGuard) {
+    private GuardData matchSpecializationGuard(SpecializationData specialization, SpecializationGuardData specializationGuard) {
         List<GuardData> foundGuards = getNode().findGuards(specializationGuard.getGuardMethod());
 
         GuardData compatibleGuard = null;
@@ -142,8 +136,8 @@
             }
             List<TypeDef> typeDefs = createTypeDefinitions(returnTypeSpec, expectedParameterSpecs);
             String expectedSignature = TemplateMethodParser.createExpectedSignature(specializationGuard.getGuardMethod(), returnTypeSpec, expectedParameterSpecs, typeDefs);
-            AnnotationValue value = Utils.getAnnotationValue(mirror, "methodName");
-            getContext().getLog().error(specialization.getMethod(), mirror, value, "No guard with signature '%s' found in type system.", expectedSignature);
+            AnnotationValue value = Utils.getAnnotationValue(specialization.getMarkerAnnotation(), "guards");
+            getContext().getLog().error(specialization.getMethod(), specialization.getMarkerAnnotation(), value, "No guard with signature '%s' found in type system.", expectedSignature);
             return null;
         }
 
@@ -151,7 +145,7 @@
     }
 
     private static boolean isGuardCompatible(SpecializationData specialization, GuardData guard) {
-        Iterator<ActualParameter> guardParameters = Arrays.asList(guard.getParameters()).iterator();
+        Iterator<ActualParameter> guardParameters = guard.getParameters().iterator();
         for (ActualParameter param : specialization.getParameters()) {
             if (param.getSpecification().isOptional()) {
                 continue;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationThrowsData.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationThrowsData.java	Tue Mar 12 11:38:52 2013 +0100
@@ -29,13 +29,11 @@
 
     private final AnnotationMirror annotationMirror;
     private final TypeMirror javaClass;
-    private final String transitionTo;
     private SpecializationData specialization;
 
-    public SpecializationThrowsData(AnnotationMirror annotationMirror, TypeMirror javaClass, String transitionTo) {
+    public SpecializationThrowsData(AnnotationMirror annotationMirror, TypeMirror javaClass) {
         this.annotationMirror = annotationMirror;
         this.javaClass = javaClass;
-        this.transitionTo = transitionTo;
     }
 
     void setSpecialization(SpecializationData specialization) {
@@ -54,16 +52,7 @@
         return annotationMirror;
     }
 
-    public String getTransitionToName() {
-        return transitionTo;
-    }
-
     public SpecializationData getTransitionTo() {
-        for (SpecializationData s : specialization.getNode().getSpecializations()) {
-            if (s.getMethodName().equals(transitionTo)) {
-                return s;
-            }
-        }
-        return null;
+        return specialization.findNextSpecialization();
     }
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java	Tue Mar 12 11:38:52 2013 +0100
@@ -31,10 +31,33 @@
     private final ParameterSpec specification;
     private final TypeMirror actualType;
     private TemplateMethod method;
+    private final String name;
+    private final int index;
+    private final boolean implicit;
 
-    public ActualParameter(ParameterSpec specification, TypeMirror actualType) {
+    public ActualParameter(ParameterSpec specification, TypeMirror actualType, int index, boolean implicit) {
         this.specification = specification;
         this.actualType = actualType;
+
+        this.index = index;
+        this.implicit = implicit;
+        String valueName = specification.getName() + "Value";
+        if (specification.isIndexed()) {
+            valueName = valueName + index;
+        }
+        this.name = valueName;
+    }
+
+    public boolean isHidden() {
+        return implicit;
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public String getName() {
+        return name;
     }
 
     void setMethod(TemplateMethod method) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.java	Tue Mar 12 11:38:52 2013 +0100
@@ -128,6 +128,10 @@
 
         CodeAnnotationMirror generatedByAnnotation = new CodeAnnotationMirror((DeclaredType) getContext().getType(GeneratedBy.class));
         generatedByAnnotation.setElementValue(generatedByAnnotation.findExecutableElement("value"), new CodeAnnotationValue(templateType.asType()));
+        if (model.getTemplateMethodName() != null) {
+            generatedByAnnotation.setElementValue(generatedByAnnotation.findExecutableElement("methodName"), new CodeAnnotationValue(model.getTemplateMethodName()));
+        }
+
         clazz.addAnnotationMirror(generatedByAnnotation);
 
         context.registerType(model.getTemplateType(), clazz.asType());
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java	Tue Mar 12 11:38:52 2013 +0100
@@ -24,16 +24,25 @@
 
 import java.util.*;
 
+import javax.lang.model.type.*;
+
 public class MethodSpec {
 
+    private final List<TypeMirror> implicitTypes;
+
     private final ParameterSpec returnType;
     private final List<ParameterSpec> parameters;
 
-    public MethodSpec(ParameterSpec returnType, List<ParameterSpec> parameters) {
+    public MethodSpec(List<TypeMirror> prefixTypes, ParameterSpec returnType, List<ParameterSpec> parameters) {
+        this.implicitTypes = prefixTypes;
         this.returnType = returnType;
         this.parameters = parameters;
     }
 
+    public List<TypeMirror> getImplicitTypes() {
+        return implicitTypes;
+    }
+
     public ParameterSpec getReturnType() {
         return returnType;
     }
@@ -41,4 +50,14 @@
     public List<ParameterSpec> getParameters() {
         return parameters;
     }
+
+    public ParameterSpec findParameterSpec(String name) {
+        for (ParameterSpec spec : parameters) {
+            if (spec.getName().equals(name)) {
+                return spec;
+            }
+        }
+        return null;
+    }
+
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java	Tue Mar 12 11:38:52 2013 +0100
@@ -39,7 +39,8 @@
     private final String name;
     private final TypeMirror[] allowedTypes;
     private final boolean optional;
-    private final Cardinality cardinality;
+    private Cardinality cardinality;
+    private boolean indexed;
 
     public ParameterSpec(String name, TypeMirror[] allowedTypes, boolean optional, Cardinality cardinality) {
         this.allowedTypes = allowedTypes;
@@ -63,6 +64,18 @@
         this(name, nodeTypeMirrors(nodeData), optional, cardinality);
     }
 
+    public boolean isIndexed() {
+        return indexed;
+    }
+
+    public void setIndexed(boolean indexed) {
+        this.indexed = indexed;
+    }
+
+    public void setCardinality(Cardinality cardinality) {
+        this.cardinality = cardinality;
+    }
+
     private static TypeMirror[] nodeTypeMirrors(NodeData nodeData) {
         Set<TypeMirror> typeMirrors = new LinkedHashSet<>();
 
@@ -95,6 +108,7 @@
         for (int i = 0; i < allowedTypes.length; i++) {
             TypeMirror mirror = allowedTypes[i];
             if (Utils.typeEquals(actualType, mirror)) {
+
                 return true;
             }
         }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java	Tue Mar 12 11:38:52 2013 +0100
@@ -32,15 +32,21 @@
 public abstract class Template {
 
     private final TypeElement templateType;
+    private final String templateMethodName;
     private final AnnotationMirror annotation;
 
     private List<? extends WritableElement> extensionElements;
 
-    public Template(TypeElement templateType, AnnotationMirror annotation) {
+    public Template(TypeElement templateType, String templateMethodName, AnnotationMirror annotation) {
         this.templateType = templateType;
+        this.templateMethodName = templateMethodName;
         this.annotation = annotation;
     }
 
+    public String getTemplateMethodName() {
+        return templateMethodName;
+    }
+
     public TypeElement getTemplateType() {
         return templateType;
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Tue Mar 12 11:38:52 2013 +0100
@@ -22,24 +22,32 @@
  */
 package com.oracle.truffle.codegen.processor.template;
 
+import java.util.*;
+
 import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+
+import com.oracle.truffle.codegen.processor.*;
 
 public class TemplateMethod {
 
+    private String id;
     private final Template template;
     private final MethodSpec specification;
     private final ExecutableElement method;
     private final AnnotationMirror markerAnnotation;
     private final ActualParameter returnType;
-    private final ActualParameter[] parameters;
+    private final List<ActualParameter> parameters;
 
-    public TemplateMethod(Template template, MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType, ActualParameter[] parameters) {
+    public TemplateMethod(String id, Template template, MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType,
+                    List<ActualParameter> parameters) {
         this.template = template;
         this.specification = specification;
         this.method = method;
         this.markerAnnotation = markerAnnotation;
         this.returnType = returnType;
         this.parameters = parameters;
+        this.id = id;
 
         if (parameters != null) {
             for (ActualParameter param : parameters) {
@@ -49,7 +57,15 @@
     }
 
     public TemplateMethod(TemplateMethod method) {
-        this(method.template, method.specification, method.method, method.markerAnnotation, method.returnType, method.parameters);
+        this(method.id, method.template, method.specification, method.method, method.markerAnnotation, method.returnType, method.parameters);
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getId() {
+        return id;
     }
 
     public Template getTemplate() {
@@ -64,28 +80,40 @@
         return returnType;
     }
 
-    public ActualParameter[] getParameters() {
+    public List<ActualParameter> getParameters() {
         return parameters;
     }
 
     public ActualParameter findParameter(String valueName) {
         for (ActualParameter param : getParameters()) {
-            if (param.getSpecification().getName().equals(valueName)) {
+            if (param.getName().equals(valueName)) {
                 return param;
             }
         }
         return null;
     }
 
+    public List<ActualParameter> getReturnTypeAndParameters() {
+        List<ActualParameter> allParameters = new ArrayList<>(getParameters().size() + 1);
+        allParameters.add(getReturnType());
+        allParameters.addAll(getParameters());
+        return Collections.unmodifiableList(allParameters);
+    }
+
     public ActualParameter findParameter(ParameterSpec spec) {
         for (ActualParameter param : getParameters()) {
-            if (param.getSpecification() == spec) {
+            if (param.getSpecification().getName().equals(spec.getName())) {
                 return param;
             }
         }
         return null;
     }
 
+    public boolean canBeAccessedByInstanceOf(TypeMirror type) {
+        TypeMirror methodType = Utils.findNearestEnclosingType(getMethod()).asType();
+        return Utils.isAssignable(type, methodType) || Utils.isAssignable(methodType, type);
+    }
+
     public ExecutableElement getMethod() {
         return method;
     }
@@ -100,7 +128,7 @@
 
     @Override
     public String toString() {
-        return getClass().getSimpleName() + " [method = " + method + "]";
+        return "id = " + getId() + ", " + getClass().getSimpleName() + " [method = " + getMethod() + "]";
     }
 
     public ActualParameter getPreviousParam(ActualParameter searchParam) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Tue Mar 12 11:38:52 2013 +0100
@@ -31,6 +31,7 @@
 import javax.lang.model.type.*;
 import javax.lang.model.util.*;
 
+import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
 
@@ -95,7 +96,7 @@
                 mirror = Utils.findAnnotationMirror(getContext().getEnvironment(), method, annotationType);
             }
 
-            if (method.getModifiers().contains(Modifier.PRIVATE)) {
+            if (method.getModifiers().contains(Modifier.PRIVATE) && emitErrors) {
                 getContext().getLog().error(method, "Method must not be private.");
                 valid = false;
                 continue;
@@ -126,7 +127,7 @@
         List<ParameterSpec> parameterSpecs = new ArrayList<>();
         parameterSpecs.addAll(methodSpecification.getParameters());
 
-        ActualParameter returnTypeMirror = resolveTypeMirror(returnTypeSpec, method.getReturnType(), template);
+        ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, method.getReturnType(), template, 0, false);
         if (returnTypeMirror == null) {
             if (isEmitErrors()) {
                 String expectedReturnType = createTypeSignature(returnTypeSpec, typeDefs, true);
@@ -140,88 +141,101 @@
             return null;
         }
 
-        Iterator<? extends VariableElement> variableIterator = method.getParameters().iterator();
+        List<TypeMirror> parameterTypes = new ArrayList<>();
+        parameterTypes.addAll(methodSpecification.getImplicitTypes());
+        for (VariableElement var : method.getParameters()) {
+            parameterTypes.add(var.asType());
+        }
+
+        List<ActualParameter> parameters = parseParameters(parameterTypes, parameterSpecs, methodSpecification.getImplicitTypes().size());
+        if (parameters == null) {
+            if (isEmitErrors()) {
+                String message = String.format("Method signature %s does not match to the expected signature: \n%s", createActualSignature(methodSpecification, method),
+                                createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs));
+                context.getLog().error(method, annotation, message);
+            }
+            return null;
+        }
+
+        String id = method.getSimpleName().toString();
+        AnnotationMirror idAnnotation = Utils.findAnnotationMirror(context.getEnvironment(), method, NodeId.class);
+        if (idAnnotation != null) {
+            id = Utils.getAnnotationValue(String.class, idAnnotation, "value");
+        }
+
+        return create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, parameters));
+    }
+
+    private static String createActualSignature(MethodSpec spec, ExecutableElement method) {
+        List<String> types = new ArrayList<>();
+        for (TypeMirror implicitType : spec.getImplicitTypes()) {
+            types.add("implicit " + Utils.getSimpleName(implicitType));
+        }
+        for (VariableElement var : method.getParameters()) {
+            types.add(Utils.getSimpleName(var.asType()));
+        }
+
+        StringBuilder b = new StringBuilder("(");
+        for (Iterator<String> iterator = types.iterator(); iterator.hasNext();) {
+            b.append(iterator.next());
+            if (iterator.hasNext()) {
+                b.append(", ");
+            }
+        }
+        b.append(")");
+        return b.toString();
+    }
+
+    private List<ActualParameter> parseParameters(List<TypeMirror> types, List<ParameterSpec> parameterSpecs, int hiddenCount) {
+        Iterator<? extends TypeMirror> parameterIterator = types.iterator();
         Iterator<? extends ParameterSpec> specificationIterator = parameterSpecs.iterator();
 
-        List<ActualParameter> resolvedMirrors = new ArrayList<>();
-        VariableElement parameter = null;
-        ParameterSpec specification = null;
-        while (specificationIterator.hasNext() || specification != null) {
-            if (specification == null) {
-                specification = specificationIterator.next();
-            }
-
-            if (parameter == null && variableIterator.hasNext()) {
-                parameter = variableIterator.next();
-            }
-
-            if (parameter == null) {
-                if (specification.getCardinality() == Cardinality.MULTIPLE) {
-                    specification = null;
-                    continue;
-                } else if (!specification.isOptional()) {
-                    if (isEmitErrors()) {
-                        // non option type specification found -> argument missing
-                        String expectedType = createTypeSignature(specification, typeDefs, false);
-
-                        String message = String.format("Missing argument \"%s\".\nExpected signature: \n %s", expectedType,
-                                        createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs));
+        TypeMirror parameter = parameterIterator.hasNext() ? parameterIterator.next() : null;
+        ParameterSpec specification = specificationIterator.hasNext() ? specificationIterator.next() : null;
 
-                        context.getLog().error(method, message);
-                    }
-                    return null;
-                } else {
-                    // specification is optional -> continue
-                    specification = null;
+        int globalParameterIndex = 0;
+        int specificationParameterIndex = 0;
+        List<ActualParameter> resolvedParameters = new ArrayList<>();
+        while (parameter != null || specification != null) {
+            if (parameter == null || specification == null) {
+                if (specification != null && (specification.isOptional() || specification.getCardinality() == Cardinality.MULTIPLE)) {
+                    specification = specificationIterator.hasNext() ? specificationIterator.next() : null;
+                    specificationParameterIndex = 0;
                     continue;
                 }
-            }
-
-            ActualParameter resolvedMirror = resolveTypeMirror(specification, parameter.asType(), template);
-
-            if (resolvedMirror == null) {
-                if (specification.isOptional()) {
-                    specification = null;
-                    continue;
-                }
-
-                if (isEmitErrors()) {
-                    String expectedReturnType = createTypeSignature(specification, typeDefs, false);
-                    String actualReturnType = Utils.getSimpleName(parameter.asType()) + " " + parameter.getSimpleName();
-
-                    String message = String.format("The provided argument type \"%s\" does not match expected type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType,
-                                    createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs));
-
-                    context.getLog().error(parameter, message);
-                }
                 return null;
             }
 
-            resolvedMirrors.add(resolvedMirror);
-            parameter = null; // consume parameter
+            boolean hidden = globalParameterIndex < hiddenCount;
+            ActualParameter resolvedParameter = matchParameter(specification, parameter, template, specificationParameterIndex, hidden);
+            if (resolvedParameter == null) {
+                // mismatch
+                if (specification.isOptional()) {
+                    specification = specificationIterator.hasNext() ? specificationIterator.next() : null;
+                    specificationParameterIndex = 0;
+                } else {
+                    return null;
+                }
+            } else {
+                resolvedParameters.add(resolvedParameter);
 
-            if (specification.getCardinality() != Cardinality.MULTIPLE) {
-                specification = null;
+                // match
+                if (specification.getCardinality() == Cardinality.ONE) {
+                    parameter = parameterIterator.hasNext() ? parameterIterator.next() : null;
+                    specification = specificationIterator.hasNext() ? specificationIterator.next() : null;
+                    globalParameterIndex++;
+                    specificationParameterIndex = 0;
+                } else if (specification.getCardinality() == Cardinality.MULTIPLE) {
+                    parameter = parameterIterator.hasNext() ? parameterIterator.next() : null;
+                    globalParameterIndex++;
+                    specificationParameterIndex++;
+                }
             }
         }
-
-        if (variableIterator.hasNext()) {
-            parameter = variableIterator.next();
-            if (isEmitErrors()) {
-                String actualReturnType = Utils.getSimpleName(parameter.asType()) + " " + parameter.getSimpleName();
-                String message = String.format("No argument expected but found \"%s\".\nExpected signature: \n %s", actualReturnType,
-                                createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs));
-
-                context.getLog().error(parameter, message);
-            }
-            return null;
-        }
-
-        ActualParameter[] paramMirrors = resolvedMirrors.toArray(new ActualParameter[resolvedMirrors.size()]);
-        return create(new TemplateMethod(template, methodSpecification, method, annotation, returnTypeMirror, paramMirrors));
+        return resolvedParameters;
     }
 
-    private ActualParameter resolveTypeMirror(ParameterSpec specification, TypeMirror mirror, Template typeSystem) {
+    private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template typeSystem, int index, boolean hidden) {
         TypeMirror resolvedType = mirror;
         if (hasError(resolvedType)) {
             resolvedType = context.resolveNotYetCompiledType(mirror, typeSystem);
@@ -230,7 +244,7 @@
         if (!specification.matches(resolvedType)) {
             return null;
         }
-        return new ActualParameter(specification, resolvedType);
+        return new ActualParameter(specification, resolvedType, index, hidden);
     }
 
     protected List<TypeDef> createTypeDefinitions(ParameterSpec returnType, List<? extends ParameterSpec> parameters) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java	Tue Mar 12 11:38:52 2013 +0100
@@ -26,15 +26,8 @@
 
 public class GuardData extends TemplateMethod {
 
-    private final Template origin;
-
-    public GuardData(TemplateMethod method, Template origin) {
+    public GuardData(TemplateMethod method) {
         super(method);
-        this.origin = origin;
-    }
-
-    public Template getOrigin() {
-        return origin;
     }
 
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java	Tue Mar 12 11:38:52 2013 +0100
@@ -26,8 +26,8 @@
 import java.util.*;
 
 import javax.lang.model.element.*;
+import javax.lang.model.type.*;
 
-import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
 import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
@@ -39,6 +39,8 @@
     public GuardParser(ProcessorContext context, Template template, TypeSystemData typeSystem) {
         super(context, template);
         this.typeSystem = typeSystem;
+        setEmitErrors(false);
+        setParseNullOnError(false);
     }
 
     @Override
@@ -46,22 +48,22 @@
         List<ParameterSpec> specs = new ArrayList<>();
         specs.add(new ParameterSpec("valueN", typeSystem, false, Cardinality.MULTIPLE));
         ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), false);
-        return new MethodSpec(returnTypeSpec, specs);
+        return new MethodSpec(Collections.<TypeMirror> emptyList(), returnTypeSpec, specs);
     }
 
     @Override
     public boolean isParsable(ExecutableElement method) {
-        return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null;
+        return true;
     }
 
     @Override
     public GuardData create(TemplateMethod method) {
-        return new GuardData(method, template);
+        return new GuardData(method);
     }
 
     @Override
     public Class<? extends Annotation> getAnnotationType() {
-        return GuardCheck.class;
+        return null;
     }
 
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java	Tue Mar 12 11:38:52 2013 +0100
@@ -26,6 +26,7 @@
 import java.util.*;
 
 import javax.lang.model.element.*;
+import javax.lang.model.type.*;
 
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
@@ -47,14 +48,14 @@
         List<ParameterSpec> specs = new ArrayList<>();
         specs.add(new ParameterSpec("value", getTypeSystem(), false, Cardinality.ONE));
         ParameterSpec returnTypeSpec = new ParameterSpec("returnType", targetType.getPrimitiveType(), false);
-        MethodSpec spec = new MethodSpec(returnTypeSpec, specs);
+        MethodSpec spec = new MethodSpec(Collections.<TypeMirror> emptyList(), returnTypeSpec, specs);
         return spec;
     }
 
     @Override
     public TypeCastData create(TemplateMethod method) {
         TypeData targetType = findTypeByMethodName(method.getMethod(), method.getMarkerAnnotation(), "as");
-        ActualParameter parameter = method.findParameter("value");
+        ActualParameter parameter = method.findParameter("valueValue");
         return new TypeCastData(method, parameter.getActualTypeData(getTypeSystem()), targetType);
     }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java	Tue Mar 12 11:38:52 2013 +0100
@@ -26,6 +26,7 @@
 import java.util.*;
 
 import javax.lang.model.element.*;
+import javax.lang.model.type.*;
 
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
@@ -47,7 +48,7 @@
         List<ParameterSpec> specs = new ArrayList<>();
         specs.add(new ParameterSpec("value", getTypeSystem(), false, Cardinality.ONE));
         ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), false);
-        MethodSpec spec = new MethodSpec(returnTypeSpec, specs);
+        MethodSpec spec = new MethodSpec(Collections.<TypeMirror> emptyList(), returnTypeSpec, specs);
         return spec;
     }
 
@@ -55,7 +56,7 @@
     public TypeCheckData create(TemplateMethod method) {
         TypeData checkedType = findTypeByMethodName(method.getMethod(), method.getMarkerAnnotation(), "is");
         assert checkedType != null;
-        ActualParameter parameter = method.findParameter("value");
+        ActualParameter parameter = method.findParameter("valueValue");
         assert parameter != null;
         return new TypeCheckData(method, checkedType, parameter.getActualTypeData(getTypeSystem()));
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java	Tue Mar 12 11:38:52 2013 +0100
@@ -40,7 +40,7 @@
     private final List<TypeCheckData> typeChecks = new ArrayList<>();
 
     public TypeData(TypeElement templateType, AnnotationMirror annotation, TypeMirror primitiveType, TypeMirror boxedType) {
-        super(templateType, annotation);
+        super(templateType, null, annotation);
         this.primitiveType = primitiveType;
         this.boxedType = boxedType;
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java	Tue Mar 12 11:38:52 2013 +0100
@@ -41,7 +41,7 @@
     private final TypeData voidType;
 
     public TypeSystemData(TypeElement templateType, AnnotationMirror annotation, TypeData[] types, TypeMirror genericType, TypeData voidType) {
-        super(templateType, annotation);
+        super(templateType, null, annotation);
         this.types = types;
         this.genericType = genericType;
         this.voidType = voidType;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java	Tue Mar 12 11:38:52 2013 +0100
@@ -145,7 +145,7 @@
     }
 
     private TypeData[] parseTypes(TypeElement templateType, AnnotationMirror templateTypeAnnotation) {
-        List<TypeMirror> typeMirrors = Utils.getAnnotationValueList(templateTypeAnnotation, "value");
+        List<TypeMirror> typeMirrors = Utils.getAnnotationValueList(TypeMirror.class, templateTypeAnnotation, "value");
         if (typeMirrors.size() == 0) {
             log.error(templateType, templateTypeAnnotation, "At least one type must be defined.");
             return null;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java	Tue Mar 12 11:38:52 2013 +0100
@@ -37,11 +37,6 @@
         super(node);
     }
 
-    @Generic
-    public Object doGeneric(Object left, Object right) {
-        throw new RuntimeException("Arithmetic not defined for types " + left.getClass().getSimpleName() + ", " + right.getClass().getSimpleName());
-    }
-
     public abstract static class AddNode extends ArithmeticNode {
 
         public AddNode(TypedNode left, TypedNode right) {
@@ -52,9 +47,8 @@
             super(node);
         }
 
-        @Specialization
-        @SpecializationThrows(javaClass = ArithmeticException.class, transitionTo = "doBigInteger")
-        int doInteger(int left, int right) {
+        @Specialization(rewriteOn = ArithmeticException.class)
+        int doInt(int left, int right) {
             return ExactMath.addExact(left, right);
         }
 
@@ -64,15 +58,19 @@
         }
 
         @Specialization
-        String doStringDirect(String left, String right) {
+        String doString(String left, String right) {
             return left + right;
         }
 
-        @Specialization
-        @SpecializationGuard(methodName = "isString")
-        String doString(Object left, Object right) {
+        @Specialization(guards = "isString")
+        String add(Object left, Object right) {
             return left.toString() + right.toString();
         }
+
+        @Generic
+        public Object addGeneric(Object left, Object right) {
+            throw new RuntimeException("Arithmetic not defined for types " + left.getClass().getSimpleName() + ", " + right.getClass().getSimpleName());
+        }
     }
 
     public abstract static class SubNode extends ArithmeticNode {
@@ -85,16 +83,20 @@
             super(node);
         }
 
-        @Specialization
-        @SpecializationThrows(javaClass = ArithmeticException.class, transitionTo = "doBigInteger")
-        int doInteger(int left, int right) {
+        @Specialization(rewriteOn = ArithmeticException.class)
+        int sub(int left, int right) {
             return ExactMath.subtractExact(left, right);
         }
 
         @Specialization
-        BigInteger doBigInteger(BigInteger left, BigInteger right) {
+        BigInteger sub(BigInteger left, BigInteger right) {
             return left.subtract(right);
         }
+
+        @Generic
+        public Object sub(Object left, Object right) {
+            throw new RuntimeException("Arithmetic not defined for types " + left.getClass().getSimpleName() + ", " + right.getClass().getSimpleName());
+        }
     }
 
     public abstract static class DivNode extends ArithmeticNode {
@@ -107,16 +109,20 @@
             super(node);
         }
 
-        @Specialization
-        @SpecializationThrows(javaClass = ArithmeticException.class, transitionTo = "doBigInteger")
-        int doInteger(int left, int right) {
+        @Specialization(rewriteOn = ArithmeticException.class)
+        int div(int left, int right) {
             return left / right;
         }
 
         @Specialization
-        BigInteger doBigInteger(BigInteger left, BigInteger right) {
+        BigInteger div(BigInteger left, BigInteger right) {
             return left.divide(right);
         }
+
+        @Generic
+        public Object div(Object left, Object right) {
+            throw new RuntimeException("Arithmetic not defined for types " + left.getClass().getSimpleName() + ", " + right.getClass().getSimpleName());
+        }
     }
 
     public abstract static class MulNode extends ArithmeticNode {
@@ -129,16 +135,20 @@
             super(node);
         }
 
-        @Specialization
-        @SpecializationThrows(javaClass = ArithmeticException.class, transitionTo = "doBigInteger")
-        int doInteger(int left, int right) {
+        @Specialization(rewriteOn = ArithmeticException.class)
+        int mul(int left, int right) {
             return ExactMath.multiplyExact(left, right);
         }
 
         @Specialization
-        BigInteger doBigInteger(BigInteger left, BigInteger right) {
+        BigInteger mul(BigInteger left, BigInteger right) {
             return left.multiply(right);
         }
+
+        @Generic
+        public Object mul(Object left, Object right) {
+            throw new RuntimeException("Arithmetic not defined for types " + left.getClass().getSimpleName() + ", " + right.getClass().getSimpleName());
+        }
     }
 
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LessThanNode.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LessThanNode.java	Tue Mar 12 11:38:52 2013 +0100
@@ -46,8 +46,7 @@
         return left.compareTo(right) < 0;
     }
 
-    @Specialization
-    @SpecializationGuard(methodName = "isString")
+    @Specialization(guards = "isString")
     public boolean doString(Object left, Object right) {
         return left.toString().compareTo(right.toString()) < 0;
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TypedNode.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TypedNode.java	Tue Mar 12 11:38:52 2013 +0100
@@ -24,7 +24,6 @@
 
 import java.math.*;
 
-import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 
@@ -49,7 +48,6 @@
 
     public abstract Object executeGeneric(VirtualFrame frame);
 
-    @GuardCheck
     public boolean isString(Object a, Object b) {
         return a instanceof String || b instanceof String;
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java	Tue Mar 12 10:02:20 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java	Tue Mar 12 11:38:52 2013 +0100
@@ -41,31 +41,31 @@
     }
 
     @Specialization
-    public int doInteger(VirtualFrame frame, int right) {
+    public int write(VirtualFrame frame, int right) {
         frame.setInt(slot, right);
         return right;
     }
 
     @Specialization
-    public BigInteger doBigInteger(VirtualFrame frame, BigInteger right) {
+    public BigInteger write(VirtualFrame frame, BigInteger right) {
         frame.setObject(slot, right);
         return right;
     }
 
     @Specialization
-    public boolean doBoolean(VirtualFrame frame, boolean right) {
+    public boolean write(VirtualFrame frame, boolean right) {
         frame.setBoolean(slot, right);
         return right;
     }
 
     @Specialization
-    public String doString(VirtualFrame frame, String right) {
+    public String write(VirtualFrame frame, String right) {
         frame.setObject(slot, right);
         return right;
     }
 
     @Generic
-    public Object doGeneric(VirtualFrame frame, Object right) {
+    public Object write(VirtualFrame frame, Object right) {
         frame.setObject(slot, right);
         return right;
     }
--- a/mx/projects	Tue Mar 12 10:02:20 2013 +0100
+++ b/mx/projects	Tue Mar 12 11:38:52 2013 +0100
@@ -366,10 +366,18 @@
 # truffle.api.codegen
 project@com.oracle.truffle.api.codegen@subDir=graal
 project@com.oracle.truffle.api.codegen@sourceDirs=src
-project@com.oracle.truffle.api.codegen@dependencies=
+project@com.oracle.truffle.api.codegen@dependencies=com.oracle.truffle.api
 project@com.oracle.truffle.api.codegen@checkstyle=com.oracle.graal.graph
 project@com.oracle.truffle.api.codegen@javaCompliance=1.7
 
+# truffle.api.codegen.test
+project@com.oracle.truffle.api.codegen.test@subDir=graal
+project@com.oracle.truffle.api.codegen.test@sourceDirs=src
+project@com.oracle.truffle.api.codegen.test@dependencies=com.oracle.truffle.api.codegen,JUNIT,com.oracle.truffle.api.test
+project@com.oracle.truffle.api.codegen.test@checkstyle=com.oracle.graal.graph
+project@com.oracle.truffle.api.codegen.test@javaCompliance=1.7
+project@com.oracle.truffle.api.codegen.test@annotationProcessors=com.oracle.truffle.codegen.processor
+
 # truffle.codegen.processor
 project@com.oracle.truffle.codegen.processor@subDir=graal
 project@com.oracle.truffle.codegen.processor@sourceDirs=src