changeset 8274:ff91c7101ed0

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Thu, 14 Mar 2013 01:09:43 +0100
parents 53683dc2815e (current diff) 1d40b7e8823b (diff)
children db00ce461a51
files graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GuardCheck.java graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationGuard.java graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/SpecializationThrows.java
diffstat 83 files changed, 2765 insertions(+), 1310 deletions(-) [+]
line wrap: on
line diff
--- a/GRAAL_AUTHORS	Thu Mar 14 01:09:32 2013 +0100
+++ b/GRAAL_AUTHORS	Thu Mar 14 01:09:43 2013 +0100
@@ -1,9 +1,12 @@
 Gilles Duboscq (gdub)
 Peter Hofer
+Christian Haeubl (chaeubl)
+Christian Humer (chumer)
+Roland Schatz
+Doug Simon (dnsimon)
+Lukas Stadler (lstadler)
 Alexander Stipsits
 Katrin Strassl
-Christian Humer (chumer)
 Christian Wimmer (cwimmer)
-Doug Simon (dnsimon)
-Lukas Stadler (lstadler)
+Andreas Woess (aw)
 Thomas Wuerthinger (thomaswue)
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Thu Mar 14 01:09:43 2013 +0100
@@ -221,7 +221,7 @@
         return method.invoke(receiver, args);
     }
 
-    static class Result {
+    protected static class Result {
 
         final Object returnValue;
         final Throwable exception;
@@ -263,7 +263,10 @@
         before();
         Object[] executeArgs = argsWithReceiver(receiver, args);
 
-        InstalledCode compiledMethod = getCode(runtime.lookupJavaMethod(method), parse(method));
+        ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(method);
+        checkArgs(javaMethod, executeArgs);
+
+        InstalledCode compiledMethod = getCode(javaMethod, parse(method));
         try {
             return new Result(compiledMethod.executeVarargs(executeArgs), null);
         } catch (Throwable e) {
@@ -273,6 +276,25 @@
         }
     }
 
+    protected void checkArgs(ResolvedJavaMethod method, Object[] args) {
+        JavaType[] sig = MetaUtil.signatureToTypes(method);
+        Assert.assertEquals(sig.length, args.length);
+        for (int i = 0; i < args.length; i++) {
+            JavaType javaType = sig[i];
+            Kind kind = javaType.getKind();
+            Object arg = args[i];
+            if (kind == Kind.Object) {
+                if (arg != null && javaType instanceof ResolvedJavaType) {
+                    ResolvedJavaType resolvedJavaType = (ResolvedJavaType) javaType;
+                    Assert.assertTrue(resolvedJavaType + " from " + runtime.lookupJavaType(arg.getClass()), resolvedJavaType.isAssignableFrom(runtime.lookupJavaType(arg.getClass())));
+                }
+            } else {
+                Assert.assertNotNull(arg);
+                Assert.assertEquals(kind.toBoxedJavaClass(), arg.getClass());
+            }
+        }
+    }
+
     /**
      * Prepends a non-null receiver argument to a given list or args.
      * 
@@ -296,16 +318,28 @@
         Method method = getMethod(name);
         Object receiver = Modifier.isStatic(method.getModifiers()) ? null : this;
 
+        test(method, receiver, args);
+    }
+
+    protected void test(Method method, Object receiver, Object... args) {
         Result expect = executeExpected(method, receiver, args);
         if (runtime == null) {
             return;
         }
+        test(method, expect, receiver, args);
+    }
+
+    protected void test(Method method, Result expect, Object receiver, Object... args) {
         Result actual = executeActual(method, receiver, args);
 
         if (expect.exception != null) {
             Assert.assertTrue("expected " + expect.exception, actual.exception != null);
             Assert.assertEquals(expect.exception.getClass(), actual.exception.getClass());
         } else {
+            if (actual.exception != null) {
+                actual.exception.printStackTrace();
+                Assert.fail("expected " + expect.returnValue + " but got an exception");
+            }
             assertEquals(expect.returnValue, actual.returnValue);
         }
     }
@@ -360,8 +394,7 @@
                 GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL);
                 phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
                 editPhasePlan(method, graph, phasePlan);
-                CompilationResult compResult = GraalCompiler.compileMethod(runtime(), backend, runtime().getTarget(), method, graph, null, phasePlan, OptimisticOptimizations.ALL,
-                                new SpeculationLog());
+                CompilationResult compResult = GraalCompiler.compileMethod(runtime(), backend, runtime().getTarget(), method, graph, null, phasePlan, OptimisticOptimizations.ALL, new SpeculationLog());
                 if (printCompilation) {
                     TTY.println(String.format("@%-6d Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, compResult.getTargetCodeSize()));
                 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/alloc/LinearScan.java	Thu Mar 14 01:09:43 2013 +0100
@@ -282,7 +282,6 @@
      * @return the created interval
      */
     Interval createInterval(Value operand) {
-        assert isProcessed(operand);
         assert isLegal(operand);
         int operandNumber = operandNumber(operand);
         Interval interval = new Interval(operand, operandNumber);
@@ -1951,12 +1950,6 @@
                 throw new GraalInternalError("");
             }
 
-            if (!isProcessed(i1.location())) {
-                TTY.println("Can not have an Interval for an ignored register " + i1.location());
-                TTY.println(i1.logString(this));
-                throw new GraalInternalError("");
-            }
-
             if (i1.first() == Range.EndMarker) {
                 TTY.println("Interval %d has no Range", i1.operandNumber);
                 TTY.println(i1.logString(this));
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotRegisterConfig.java	Thu Mar 14 01:09:43 2013 +0100
@@ -33,15 +33,12 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.phases.*;
 
 // @formatter:off
 public class AMD64HotSpotRegisterConfig implements RegisterConfig {
 
-    private final Register[] allocatable = {
-        rax, rbx, rcx, rdx, /*rsp,*/ rbp, rsi, rdi, r8, r9, /* r10, */r11, r12, r13, r14, /*r15, */
-        xmm0, xmm1, xmm2,  xmm3,  xmm4,  xmm5,  xmm6,  xmm7,
-        xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15
-    };
+    private final Register[] allocatable = initAllocatable();
 
     private final EnumMap<RegisterFlag, Register[]> categorized = Register.categorize(allocatable);
 
@@ -68,6 +65,34 @@
 
     private final CalleeSaveLayout csl;
 
+    private static Register findRegister(String name, Register[] all) {
+        for (Register reg : all) {
+            if (reg.name.equals(name)) {
+                return reg;
+            }
+        }
+        throw new IllegalArgumentException("register " + name + " is not allocatable");
+    }
+
+    private static Register[] initAllocatable() {
+        Register[] allocatable = {
+                        rax, rbx, rcx, rdx, /*rsp,*/ rbp, rsi, rdi, r8, r9, /* r10, */r11, r12, r13, r14, /*r15, */
+                        xmm0, xmm1, xmm2,  xmm3,  xmm4,  xmm5,  xmm6,  xmm7,
+                        xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15
+                    };
+
+        if (GraalOptions.RegisterPressure != null) {
+            String[] names = GraalOptions.RegisterPressure.split(",");
+            Register[] regs = new Register[names.length];
+            for (int i = 0; i < names.length; i++) {
+                regs[i] = findRegister(names[i], allocatable);
+            }
+            return regs;
+        }
+
+        return allocatable;
+    }
+
     public AMD64HotSpotRegisterConfig(HotSpotVMConfig config, boolean globalStubConfig) {
         if (config.windowsOs) {
             javaGeneralParameterRegisters = new Register[] {rdx, r8, r9, rdi, rsi, rcx};
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java	Thu Mar 14 01:09:43 2013 +0100
@@ -41,11 +41,6 @@
 
     public static final Descriptor UNWIND_EXCEPTION = new Descriptor("unwindException", true, void.class, Object.class);
 
-    /**
-     * Vtable stubs expect the metaspace Method in RBX.
-     */
-    public static final Register METHOD = AMD64.rbx;
-
     @Use({REG}) protected AllocatableValue exception;
     @Temp private RegisterValue framePointer;
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Mar 14 01:09:43 2013 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.java;
 
+import static com.oracle.graal.api.code.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.bytecode.Bytecodes.*;
 import static java.lang.reflect.Modifier.*;
 
@@ -52,7 +54,7 @@
 /**
  * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph.
  */
-public final class GraphBuilderPhase extends Phase {
+public class GraphBuilderPhase extends Phase {
 
     public static final class RuntimeCalls {
 
@@ -72,7 +74,7 @@
      */
     public static final int TRACELEVEL_STATE = 2;
 
-    private StructuredGraph currentGraph;
+    protected StructuredGraph currentGraph;
 
     private final MetaAccessProvider runtime;
     private ConstantPool constantPool;
@@ -82,7 +84,7 @@
 
     private BytecodeStream stream;           // the bytecode stream
 
-    private FrameStateBuilder frameState;          // the current execution state
+    protected FrameStateBuilder frameState;          // the current execution state
     private Block currentBlock;
 
     private ValueNode methodSynchronizedObject;
@@ -279,7 +281,7 @@
      * @param type the unresolved type of the constant
      */
     protected void handleUnresolvedLoadConstant(JavaType type) {
-        append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved)));
+        append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)));
         frameState.push(Kind.Object, append(ConstantNode.forObject(null, runtime, currentGraph)));
     }
 
@@ -288,7 +290,7 @@
      * @param object the object value whose type is being checked against {@code type}
      */
     protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) {
-        append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(object)), DeoptimizationReason.Unresolved, DeoptimizationAction.InvalidateRecompile)));
+        append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(object)), Unresolved, InvalidateRecompile)));
         frameState.apush(appendConstant(Constant.NULL_OBJECT));
     }
 
@@ -298,7 +300,7 @@
      */
     protected void handleUnresolvedInstanceOf(JavaType type, ValueNode object) {
         BlockPlaceholderNode successor = currentGraph.add(new BlockPlaceholderNode());
-        DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved));
+        DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved));
         IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new IsNullNode(object)), successor, deopt, 1));
         append(ifNode);
         lastInstr = successor;
@@ -309,7 +311,7 @@
      * @param type the type being instantiated
      */
     protected void handleUnresolvedNewInstance(JavaType type) {
-        append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved)));
+        append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)));
         frameState.apush(appendConstant(Constant.NULL_OBJECT));
     }
 
@@ -318,7 +320,7 @@
      * @param length the length of the array
      */
     protected void handleUnresolvedNewObjectArray(JavaType type, ValueNode length) {
-        append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved)));
+        append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)));
         frameState.apush(appendConstant(Constant.NULL_OBJECT));
     }
 
@@ -327,7 +329,7 @@
      * @param dims the dimensions for the multi-array
      */
     protected void handleUnresolvedNewMultiArray(JavaType type, ValueNode[] dims) {
-        append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved)));
+        append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)));
         frameState.apush(appendConstant(Constant.NULL_OBJECT));
     }
 
@@ -337,7 +339,7 @@
      */
     protected void handleUnresolvedLoadField(JavaField field, ValueNode receiver) {
         Kind kind = field.getKind();
-        append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved)));
+        append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)));
         frameState.push(kind.getStackKind(), append(ConstantNode.defaultForKind(kind, currentGraph)));
     }
 
@@ -347,7 +349,7 @@
      * @param receiver the object containing the field or {@code null} if {@code field} is static
      */
     protected void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver) {
-        append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved)));
+        append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)));
     }
 
     /**
@@ -355,12 +357,12 @@
      * @param type
      */
     protected void handleUnresolvedExceptionType(Representation representation, JavaType type) {
-        append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved)));
+        append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)));
     }
 
     protected void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind) {
         boolean withReceiver = invokeKind != InvokeKind.Static;
-        append(currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.Unresolved)));
+        append(currentGraph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)));
         frameState.popArguments(javaMethod.getSignature().getParameterSlots(withReceiver), javaMethod.getSignature().getParameterCount(withReceiver));
         Kind kind = javaMethod.getSignature().getReturnKind();
         if (kind != Kind.Void) {
@@ -733,8 +735,7 @@
 
     private void genThrow() {
         ValueNode exception = frameState.apop();
-        FixedGuardNode node = currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), DeoptimizationReason.NullCheckException, DeoptimizationAction.InvalidateReprofile,
-                        true));
+        FixedGuardNode node = currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true));
         append(node);
         append(handleException(exception, bci()));
     }
@@ -826,7 +827,7 @@
     /**
      * Gets the kind of array elements for the array type code that appears in a
      * {@link Bytecodes#NEWARRAY} bytecode.
-     * 
+     *
      * @param code the array type code
      * @return the kind from the array type code
      */
@@ -1109,7 +1110,7 @@
     private void appendInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args) {
         Kind resultType = targetMethod.getSignature().getReturnKind();
         if (GraalOptions.DeoptALot) {
-            DeoptimizeNode deoptimize = currentGraph.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint));
+            DeoptimizeNode deoptimize = currentGraph.add(new DeoptimizeNode(DeoptimizationAction.None, RuntimeConstraint));
             append(deoptimize);
             frameState.pushReturn(resultType, ConstantNode.defaultForKind(resultType, currentGraph));
             return;
@@ -1190,8 +1191,7 @@
         ValueNode local = frameState.loadLocal(localIndex);
         JsrScope scope = currentBlock.jsrScope;
         int retAddress = scope.nextReturnAddress();
-        append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new IntegerEqualsNode(local, ConstantNode.forInt(retAddress, currentGraph))), DeoptimizationReason.JavaSubroutineMismatch,
-                        DeoptimizationAction.InvalidateReprofile)));
+        append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new IntegerEqualsNode(local, ConstantNode.forInt(retAddress, currentGraph))), JavaSubroutineMismatch, InvalidateReprofile)));
         if (!successor.jsrScope.equals(scope.pop())) {
             throw new JsrNotSupportedBailout("unstructured control flow (ret leaves more than one scope)");
         }
@@ -1224,7 +1224,7 @@
 
     /**
      * Helper function that sums up the probabilities of all keys that lead to a specific successor.
-     * 
+     *
      * @return an array of size successorCount with the accumulated probability for each successor.
      */
     private static double[] successorProbabilites(int successorCount, int[] keySuccessors, double[] keyProbabilities) {
@@ -1391,7 +1391,7 @@
     private FixedNode createTarget(double probability, Block block, FrameStateBuilder stateAfter) {
         assert probability >= 0 && probability <= 1.01 : probability;
         if (isNeverExecutedCode(probability)) {
-            return currentGraph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.UnreachedCode));
+            return currentGraph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode));
         } else {
             assert block != null;
             return createTarget(block, stateAfter);
@@ -1553,7 +1553,10 @@
     private void createUnwind() {
         assert frameState.stackSize() == 1 : frameState;
         synchronizedEpilogue(FrameState.AFTER_EXCEPTION_BCI);
-        UnwindNode unwindNode = currentGraph.add(new UnwindNode(frameState.apop()));
+        ValueNode exception = frameState.apop();
+        FixedGuardNode guard = currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), NullCheckException, InvalidateReprofile, true));
+        append(guard);
+        UnwindNode unwindNode = currentGraph.add(new UnwindNode(exception));
         append(unwindNode);
     }
 
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Thu Mar 14 01:09:43 2013 +0100
@@ -48,6 +48,10 @@
      */
     Object[] argsToBind;
 
+    public JTTTest() {
+        Assert.assertNotNull(runtime);
+    }
+
     @Override
     protected StructuredGraph parse(Method m) {
         StructuredGraph graph = super.parse(m);
@@ -89,10 +93,14 @@
     }
 
     protected void runTest(String name, Object... args) {
-        // System.out.println(getClass().getSimpleName() + "." + name);
-        super.test(name, args);
+        Method method = getMethod(name);
+        Object receiver = Modifier.isStatic(method.getModifiers()) ? null : this;
+
+        Result expect = executeExpected(method, receiver, args);
+
+        test(method, expect, receiver, args);
         this.argsToBind = args;
-        super.test(name, args);
+        test(method, expect, receiver, args);
         this.argsToBind = null;
     }
 }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Except_Synchronized05.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/Except_Synchronized05.java	Thu Mar 14 01:09:43 2013 +0100
@@ -29,29 +29,11 @@
 
 public class Except_Synchronized05 extends JTTTest {
 
-    Object field;
-
-    public static int test(int arg) {
-        Except_Synchronized05 obj = new Except_Synchronized05();
-        int a = obj.bar(arg) != null ? 1 : 0;
-        int b = obj.baz(arg) != null ? 1 : 0;
-        return a + b;
-    }
+    static class Foo {
 
-    public synchronized Object bar(int arg) {
-        try {
-            String f = foo1(arg);
-            if (f == null) {
-                field = new Object();
-            }
-        } catch (NullPointerException e) {
-            // do nothing
-        }
-        return field;
-    }
+        Object field;
 
-    public Object baz(int arg) {
-        synchronized (this) {
+        public synchronized Object bar(int arg) {
             try {
                 String f = foo1(arg);
                 if (f == null) {
@@ -62,14 +44,36 @@
             }
             return field;
         }
+
+        public Object baz(int arg) {
+            synchronized (this) {
+                try {
+                    String f = foo1(arg);
+                    if (f == null) {
+                        field = new Object();
+                    }
+                } catch (NullPointerException e) {
+                    // do nothing
+                }
+                return field;
+            }
+        }
+
+        @SuppressWarnings("static-method")
+        private String foo1(int arg) {
+            if (arg == 0) {
+                throw null;
+            }
+            return null;
+        }
+
     }
 
-    @SuppressWarnings("static-method")
-    private String foo1(int arg) {
-        if (arg == 0) {
-            throw null;
-        }
-        return null;
+    public static int test(int arg) {
+        Foo obj = new Foo();
+        int a = obj.bar(arg) != null ? 1 : 0;
+        int b = obj.baz(arg) != null ? 1 : 0;
+        return a + b;
     }
 
     @Test
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Thu Mar 14 01:09:43 2013 +0100
@@ -59,12 +59,19 @@
                 BeginNode trueSuccessor;
                 BeginNode falseSuccessor;
                 DeoptimizeNode deopt = graph.add(new DeoptimizeNode(guard.action(), guard.reason()));
+                BeginNode deoptBranch = BeginNode.begin(deopt);
+                Loop loop = block.getLoop();
+                while (loop != null) {
+                    LoopExitNode exit = graph.add(new LoopExitNode(loop.loopBegin()));
+                    graph.addBeforeFixed(deopt, exit);
+                    loop = loop.parent;
+                }
                 if (guard.negated()) {
-                    trueSuccessor = BeginNode.begin(deopt);
+                    trueSuccessor = deoptBranch;
                     falseSuccessor = fastPath;
                 } else {
                     trueSuccessor = fastPath;
-                    falseSuccessor = BeginNode.begin(deopt);
+                    falseSuccessor = deoptBranch;
                 }
                 IfNode ifNode = graph.add(new IfNode(guard.condition(), trueSuccessor, falseSuccessor, trueSuccessor == fastPath ? 1 : 0));
                 guard.replaceAndDelete(fastPath);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Thu Mar 14 01:09:43 2013 +0100
@@ -1000,6 +1000,17 @@
         return count;
     }
 
+    static MonitorExitNode findPrecedingMonitorExit(UnwindNode unwind) {
+        Node pred = unwind.predecessor();
+        while (pred != null) {
+            if (pred instanceof MonitorExitNode) {
+                return (MonitorExitNode) pred;
+            }
+            pred = pred.predecessor();
+        }
+        return null;
+    }
+
     /**
      * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph.
      * 
@@ -1070,13 +1081,13 @@
         } else {
             if (unwindNode != null) {
                 UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
+                MonitorExitNode monitorExit = findPrecedingMonitorExit(unwindDuplicate);
                 DeoptimizeNode deoptimizeNode = new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler);
                 unwindDuplicate.replaceAndDelete(graph.add(deoptimizeNode));
                 // move the deopt upwards if there is a monitor exit that tries to use the
                 // "after exception" frame state
                 // (because there is no "after exception" frame state!)
-                if (deoptimizeNode.predecessor() instanceof MonitorExitNode) {
-                    MonitorExitNode monitorExit = (MonitorExitNode) deoptimizeNode.predecessor();
+                if (monitorExit != null) {
                     if (monitorExit.stateAfter() != null && monitorExit.stateAfter().bci == FrameState.AFTER_EXCEPTION_BCI) {
                         FrameState monitorFrameState = monitorExit.stateAfter();
                         graph.removeFixed(monitorExit);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Thu Mar 14 01:09:43 2013 +0100
@@ -148,6 +148,9 @@
     public static boolean ExitVMOnBailout                    = ____;
     public static boolean ExitVMOnException                  = true;
 
+    // Register allocator debugging
+    public static String  RegisterPressure                   = null;
+
     // Code generator settings
     public static boolean ConditionalElimination             = true;
     public static boolean CullFrameStates                    = ____;
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/GraphPrinterDumpHandler.java	Thu Mar 14 01:09:43 2013 +0100
@@ -82,16 +82,22 @@
         if (sdf == null) {
             sdf = new SimpleDateFormat("YYYY-MM-dd-HHmm");
         }
-        String fileName = "Graphs-" + Thread.currentThread().getName() + "-" + sdf.format(new Date()) + ext;
+        String prefix = "Graphs-" + Thread.currentThread().getName() + "-" + sdf.format(new Date());
+        String num = "";
+        File file;
+        int i = 0;
+        while ((file = new File(prefix + num + ext)).exists()) {
+            num = "-" + Integer.toString(++i);
+        }
         try {
             if (GraalOptions.PrintBinaryGraphs) {
-                printer = new BinaryGraphPrinter(FileChannel.open(new File(fileName).toPath(), StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW));
+                printer = new BinaryGraphPrinter(FileChannel.open(file.toPath(), StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW));
             } else {
-                printer = new IdealGraphPrinter(new FileOutputStream(fileName));
+                printer = new IdealGraphPrinter(new FileOutputStream(file));
             }
-            TTY.println("Dumping IGV graphs to %s", fileName);
+            TTY.println("Dumping IGV graphs to %s", file.getName());
         } catch (IOException e) {
-            TTY.println("Failed to open %s to dump IGV graphs : %s", fileName, e);
+            TTY.println("Failed to open %s to dump IGV graphs : %s", file.getName(), e);
             failuresCount++;
             printer = null;
         }
--- /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	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:43 2013 +0100
@@ -0,0 +1,159 @@
+/*
+ * 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	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:43 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 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/GeneratedBy.java	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 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	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeFactory.java	Thu Mar 14 01:09:43 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>> getExecutionSignature();
+
 }
--- /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	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/Specialization.java	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 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	Thu Mar 14 01:09:32 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeSystem.java	Thu Mar 14 01:09:43 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.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReturnTypeSpecializationTest.java	Thu Mar 14 01:09:43 2013 +0100
@@ -38,7 +38,7 @@
  * should be speculated on. When the speculation fails and the child node cannot return the
  * appropriate type of value, it can use an {@link UnexpectedResultException} to still pass the
  * result to the caller. In such a case, the caller must rewrite itself to a more general version in
- * oder to avoid future failures of this kind.
+ * order to avoid future failures of this kind.
  * </p>
  */
 public class ReturnTypeSpecializationTest {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AbstractParser.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AbstractParser.java	Thu Mar 14 01:09:43 2013 +0100
@@ -58,12 +58,22 @@
             if (!context.getTruffleTypes().verify(context, element, mirror)) {
                 return null;
             }
-            return parse(element, mirror);
+            M model = parse(element, mirror);
+            if (model == null) {
+                return null;
+            }
+
+            model.emitMessages((TypeElement) element, log);
+            return filterErrorElements(model);
         } finally {
             this.roundEnv = null;
         }
     }
 
+    protected M filterErrorElements(M model) {
+        return model.hasErrors() ? null : model;
+    }
+
     protected abstract M parse(Element element, AnnotationMirror mirror);
 
     public abstract Class<? extends Annotation> getAnnotationType();
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Log.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Log.java	Thu Mar 14 01:09:43 2013 +0100
@@ -41,30 +41,6 @@
         this.processingEnv = env;
     }
 
-    public void warning(Element element, String format, Object... args) {
-        message(Kind.WARNING, element, null, null, format, args);
-    }
-
-    public void warning(Element element, AnnotationMirror mirror, String format, Object... args) {
-        message(Kind.WARNING, element, mirror, null, format, args);
-    }
-
-    public void error(Element element, String format, Object... args) {
-        message(Kind.ERROR, element, null, null, format, args);
-    }
-
-    public void error(String format, Object... args) {
-        message(Kind.ERROR, null, null, null, format, args);
-    }
-
-    public void error(Element element, AnnotationMirror mirror, String format, Object... args) {
-        message(Kind.ERROR, element, mirror, null, format, args);
-    }
-
-    public void error(Element element, AnnotationMirror mirror, AnnotationValue value, String format, Object... args) {
-        message(Kind.ERROR, element, mirror, value, format, args);
-    }
-
     public void message(Kind kind, Element element, AnnotationMirror mirror, AnnotationValue value, String format, Object... args) {
         AnnotationMirror usedMirror = mirror;
         Element usedElement = element;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleProcessor.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleProcessor.java	Thu Mar 14 01:09:43 2013 +0100
@@ -28,6 +28,7 @@
 import javax.annotation.processing.*;
 import javax.lang.model.*;
 import javax.lang.model.element.*;
+import javax.tools.Diagnostic.*;
 
 import com.oracle.truffle.codegen.processor.ProcessorContext.ProcessCallback;
 import com.oracle.truffle.codegen.processor.node.*;
@@ -95,7 +96,7 @@
 
     private static void handleThrowable(AnnotationProcessor generator, Throwable t, Element e) {
         String message = "Uncaught error in " + generator.getClass().getSimpleName() + " while processing " + e;
-        generator.getContext().getLog().error(e, message + ": " + Utils.printException(t));
+        generator.getContext().getLog().message(Kind.ERROR, e, null, null, message + ": " + Utils.printException(t));
     }
 
     @SuppressWarnings("unchecked")
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java	Thu Mar 14 01:09:43 2013 +0100
@@ -26,6 +26,7 @@
 
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
+import javax.tools.Diagnostic.*;
 
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.intrinsics.*;
@@ -66,7 +67,7 @@
         }
 
         for (String error : errors) {
-            context.getLog().error(element, mirror, error);
+            context.getLog().message(Kind.ERROR, element, mirror, null, error);
         }
 
         return false;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java	Thu Mar 14 01:09:43 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);
     }
 
@@ -619,7 +748,7 @@
             return true;
         }
 
-        // search for any supertypes
+        // search for any super types
         TypeElement exceptionTypeElement = fromTypeMirror(exceptionType);
         List<TypeElement> superTypes = getSuperTypes(exceptionTypeElement);
         for (TypeElement typeElement : superTypes) {
@@ -648,7 +777,7 @@
         Set<String> typeSuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(type)));
         String typeName = getQualifiedName(type);
         if (!typeSuperSet.contains(Throwable.class.getCanonicalName()) && !typeName.equals(Throwable.class.getCanonicalName())) {
-            throw new IllegalArgumentException("Given does not extend Throwable.");
+            throw new IllegalArgumentException("Given type does not extend Throwable.");
         }
         return typeSuperSet.contains(RuntimeException.class.getCanonicalName()) || typeName.equals(RuntimeException.class.getCanonicalName());
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/compiler/AbstractCompiler.java	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ext/ExtensionParser.java	Thu Mar 14 01:09:43 2013 +0100
@@ -31,6 +31,7 @@
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.api.*;
 import com.oracle.truffle.codegen.processor.api.element.*;
+import com.oracle.truffle.codegen.processor.template.*;
 
 public class ExtensionParser {
 
@@ -45,25 +46,25 @@
         this.extensionContext = new ExtensionContextImpl(context.getEnvironment(), null, factory);
     }
 
-    public List<WritableElement> parseAll(TypeElement typeElement, List<? extends Element> elements) {
+    public List<WritableElement> parseAll(Template template, List<? extends Element> elements) {
         List<WritableElement> generatedMethods = new ArrayList<>();
-        parseElement(generatedMethods, typeElement);
+        parseElement(template, generatedMethods, template.getTemplateType());
 
         List<? extends ExecutableElement> methods = ElementFilter.methodsIn(elements);
         for (ExecutableElement method : methods) {
             for (VariableElement var : method.getParameters()) {
-                parseElement(generatedMethods, var);
+                parseElement(template, generatedMethods, var);
             }
-            parseElement(generatedMethods, method);
+            parseElement(template, generatedMethods, method);
         }
 
         return generatedMethods;
     }
 
-    private void parseElement(List<WritableElement> elements, Element element) {
+    private void parseElement(Template template, List<WritableElement> elements, Element element) {
         List<? extends AnnotationMirror> mirrors = element.getAnnotationMirrors();
         for (AnnotationMirror mirror : mirrors) {
-            ExtensionProcessor processor = findProcessor(element, mirror);
+            ExtensionProcessor processor = findProcessor(template, mirror);
             if (processor != null) {
                 try {
                     factory.generatorAnnotationMirror = mirror;
@@ -71,7 +72,7 @@
                     processor.process(extensionContext, mirror, element);
                     elements.addAll(extensionContext.returnElements());
                 } catch (Throwable e) {
-                    context.getLog().error(element, mirror, "Processor for '%s' failed with exception: \n\n%s.", Utils.getQualifiedName(mirror.getAnnotationType()), Utils.printException(e));
+                    template.addError("Processor for '%s' failed with exception: \n\n%s.", Utils.getQualifiedName(mirror.getAnnotationType()), Utils.printException(e));
                 } finally {
                     factory.generatorAnnotationMirror = null;
                     factory.generatorElement = null;
@@ -80,7 +81,7 @@
         }
     }
 
-    private ExtensionProcessor findProcessor(Element element, AnnotationMirror mirror) {
+    private ExtensionProcessor findProcessor(Template template, AnnotationMirror mirror) {
         String processorName = Utils.getQualifiedName(mirror.getAnnotationType());
         ExtensionProcessor processor = null;
         if (extensions.containsKey(processorName)) {
@@ -88,24 +89,24 @@
         } 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);
                 } catch (ClassNotFoundException e) {
-                    context.getLog().error(element, mirror, "Could not find processor class '%s' configured in '@%s'.", className, processorName);
+                    template.addError("Could not find processor class '%s' configured in '@%s'.", className, processorName);
                     return null;
                 }
                 try {
                     processor = (ExtensionProcessor) processorClass.newInstance();
                 } catch (InstantiationException e) {
-                    context.getLog().error(element, mirror, "Could not instantiate processor class '%s' configured in '@%s'.", className, processorName);
+                    template.addError("Could not instantiate processor class '%s' configured in '@%s'.", className, processorName);
                     return null;
                 } catch (IllegalAccessException e) {
-                    context.getLog().error(element, mirror, "Could not access processor class '%s' configured in '@%s'.", className, processorName);
+                    template.addError("Could not access processor class '%s' configured in '@%s'.", className, processorName);
                     return null;
                 } catch (ClassCastException e) {
-                    context.getLog().error(element, mirror, "Processor class '%s' configured in '@%s' does not implement '%s'.", className, processorName, ExtensionProcessor.class.getName());
+                    template.addError("Processor class '%s' configured in '@%s' does not implement '%s'.", className, processorName, ExtensionProcessor.class.getName());
                     return null;
                 }
             }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java	Thu Mar 14 01:09:43 2013 +0100
@@ -44,14 +44,14 @@
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
         List<TypeMirror> types = new ArrayList<>();
-        types.addAll(Arrays.asList(getNode().getTypeSystem().getPrimitiveTypeMirrors()));
+        types.addAll(getNode().getTypeSystem().getPrimitiveTypeMirrors());
         types.add(getContext().getType(void.class));
 
-        ParameterSpec returnTypeSpec = new ParameterSpec("executedValue", types.toArray(new TypeMirror[types.size()]), false, Cardinality.ONE);
+        ParameterSpec returnTypeSpec = new ParameterSpec("executedValue", types, false, Cardinality.ONE);
 
         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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Thu Mar 14 01:09:43 2013 +0100
@@ -41,7 +41,7 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        return createDefaultMethodSpec(null);
+        return createDefaultMethodSpec(method, mirror, null);
     }
 
     @Override
@@ -51,8 +51,7 @@
         for (ExecutableTypeData type : execTypes) {
             types.add(type.getType().getPrimitiveType());
         }
-        TypeMirror[] array = types.toArray(new TypeMirror[types.size()]);
-        return new ParameterSpec(valueName, array, false, Cardinality.ONE);
+        return new ParameterSpec(valueName, types, false, Cardinality.ONE);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Thu Mar 14 01:09:43 2013 +0100
@@ -35,6 +35,7 @@
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.ast.*;
 import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind;
+import com.oracle.truffle.codegen.processor.node.NodeFieldData.FieldKind;
 import com.oracle.truffle.codegen.processor.template.*;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
@@ -51,73 +52,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 +102,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 +114,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,31 +143,63 @@
         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();
+        if (method == null) {
+            throw new IllegalStateException("Cannot call synthtetic operation methods.");
+        }
+        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) {
+    private String generatedGenericMethodName(SpecializationData specialization) {
         final String prefix = "generic";
 
         if (specialization == null) {
             return prefix;
         }
 
+        if (!specialization.getNode().getGenericSpecialization().isUseSpecializationsForGeneric() || !specialization.getNode().needsRewrites(context)) {
+            return prefix;
+        }
+
         SpecializationData prev = null;
         for (SpecializationData current : specialization.getNode().getSpecializations()) {
             if (specialization == current) {
                 if (prev == null || prev.isUninitialized()) {
                     return prefix;
                 } else {
-                    return prefix + specializationId(current);
+                    return prefix + current.getId();
                 }
             }
             prev = current;
@@ -237,34 +254,32 @@
         }
 
         if (implicitGuards == null && explicitGuards == null && conditionPrefix != null && !conditionPrefix.isEmpty()) {
-            builder.startIf().string(conditionPrefix).end().startBlock();
+            builder.startIf();
+            builder.string(conditionPrefix);
+            builder.end().startBlock();
             ifCount++;
         }
 
         builder.tree(guardedStatements);
 
         builder.end(ifCount);
-        if (ifCount > 0 && elseStatements != null) {
-            builder.startElseBlock();
+        if (elseStatements != null && ifCount > 0) {
             builder.tree(elseStatements);
-            builder.end();
         }
-
         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) {
+        if (guardedSpecialization.getGuards().size() > 0) {
             // Explicitly specified guards
             for (SpecializationGuardData guard : guardedSpecialization.getGuards()) {
                 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 +291,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 +311,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 +356,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 +388,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);
     }
 
     /**
@@ -408,6 +425,10 @@
         return builder.getRoot();
     }
 
+    private void emitEncounteredSynthetic(CodeTreeBuilder builder) {
+        builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end();
+    }
+
     @Override
     protected void createChildren(NodeData node) {
         Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>();
@@ -492,13 +513,15 @@
             if (node.needsFactory()) {
                 createFactoryMethods(node, clazz, createVisibility);
 
-                if (node.getSpecializations().length > 1) {
+                if (node.getSpecializations().size() > 1) {
                     clazz.add(createCreateSpecializedMethod(node, createVisibility));
                 }
 
-                if (node.needsRewrites(getContext())) {
+                if (node.needsRewrites(context)) {
                     clazz.add(createSpecializeMethod(node));
+                }
 
+                if (node.getGenericSpecialization() != null) {
                     List<CodeExecutableElement> genericMethods = createGeneratedGenericMethod(node);
                     for (CodeExecutableElement method : genericMethods) {
                         clazz.add(method);
@@ -515,6 +538,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 +589,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, "getExecutionSignature");
+            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 +782,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 +864,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 +899,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 +916,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();
 
@@ -868,14 +939,14 @@
 
         private List<CodeExecutableElement> createGeneratedGenericMethod(NodeData node) {
             TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getActualType();
-            if (node.getGenericSpecialization().isUseSpecializationsForGeneric()) {
+            if (node.getGenericSpecialization().isUseSpecializationsForGeneric() && node.needsRewrites(context)) {
                 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 +954,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 +967,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);
             }
@@ -908,44 +979,51 @@
             CodeTree invokeMethod = invokeMethodBuilder.getRoot();
 
             if (next != null) {
-                invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, false, invokeMethod, null);
+                CodeTreeBuilder nextBuilder = builder.create();
+
+                nextBuilder.startReturn().startCall(generatedGenericMethodName(next));
+                nextBuilder.string(THIS_NODE_LOCAL_VAR_NAME);
+                addValueParameterNames(nextBuilder, next, null, true, true);
+                nextBuilder.end().end();
+
+                invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, false, invokeMethod, nextBuilder.getRoot());
             }
 
             builder.tree(invokeMethod);
 
             if (next != null) {
                 builder.end();
-
-                builder.startReturn().startCall(generatedGenericMethodName(next));
-                builder.string(THIS_NODE_LOCAL_VAR_NAME);
-                addValueParameterNames(builder, next, null, 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);
-            builder.end().end(); // start call operation
-            builder.end(); // return
+            if (specialization.getMethod() == null) {
+                emitEncounteredSynthetic(builder);
+            } else {
+                builder.startReturn();
+                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();
             }
         }
+
     }
 
     private class SpecializedNodeFactory extends ClassElementFactory<SpecializationData> {
@@ -957,7 +1035,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 +1059,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 +1074,7 @@
             }
 
             if (node.needsRewrites(getContext()) && !specialization.isGeneric() && !specialization.isUninitialized()) {
-                buildSpecializeStateMethod(clazz, specialization);
+                buildSpecializeAndExecute(clazz, specialization);
             }
         }
 
@@ -1014,7 +1092,7 @@
             CodeTree primaryExecuteCall = null;
 
             CodeTreeBuilder executeBuilder = CodeTreeBuilder.createBuilder();
-            buildExecute(executeBuilder, null, execType);
+            buildExecute(executeBuilder, null, null, execType);
             primaryExecuteCall = executeBuilder.getRoot();
 
             if (needsTry) {
@@ -1122,7 +1200,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 +1212,28 @@
         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())) {
+            if (specialization.getMethod() == null && !node.needsRewrites(context)) {
+                emitEncounteredSynthetic(builder);
+            } else if (specialization.isUninitialized() || specialization.isGeneric()) {
                 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());
-                } else {
-                    startCallOperationMethod(builder, specialization);
-                }
-                addValueParameterNames(builder, specialization, null, false);
+                startCallOperationMethod(builder, specialization, 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 +1245,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 +1260,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 +1321,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;
@@ -1294,16 +1356,16 @@
             }
 
             builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(shortCircuitParam)).string(" = ");
-            ShortCircuitData shortCircuitData = specialization.getShortCircuits()[shortCircuitIndex];
+            ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(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 +1377,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 +1391,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 +1402,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 +1413,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 +1424,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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Thu Mar 14 01:09:43 2013 +0100
@@ -35,22 +35,85 @@
 
 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 TypeSystemData typeSystem;
+    private List<NodeFieldData> fields;
+    private TypeMirror nodeType;
+    private ParameterSpec instanceParameterSpec;
+
+    private List<SpecializationData> specializations;
+    private List<SpecializationListenerData> specializationListeners;
+    private List<GuardData> guards;
+    private List<ExecutableTypeData> executableTypes;
+    private List<ShortCircuitData> shortCircuits;
 
-    private final TypeSystemData typeSystem;
+    public NodeData(TypeElement type, String id) {
+        super(type, null, null);
+        this.nodeId = id;
+    }
+
+    public NodeData(NodeData splitSource, String templateMethodName, String nodeId) {
+        super(splitSource.getTemplateType(), templateMethodName, null);
+        this.nodeId = nodeId;
+        this.declaringNode = splitSource.declaringNode;
+        this.declaredChildren = splitSource.declaredChildren;
+        this.typeSystem = splitSource.typeSystem;
+        this.nodeType = splitSource.nodeType;
+        this.specializations = splitSource.specializations;
+        this.specializationListeners = splitSource.specializationListeners;
+        this.guards = splitSource.guards;
+        this.executableTypes = splitSource.executableTypes;
+        this.shortCircuits = splitSource.shortCircuits;
+        this.fields = splitSource.fields;
+    }
+
+    void setTypeSystem(TypeSystemData typeSystem) {
+        this.typeSystem = typeSystem;
+    }
 
-    private NodeFieldData[] fields;
-    private SpecializationData[] specializations;
-    private TemplateMethod[] specializationListeners;
-    private GuardData[] guards;
-    private ExecutableTypeData[] executableTypes;
+    @Override
+    protected List<MessageContainer> findChildContainers() {
+        List<MessageContainer> sinks = new ArrayList<>();
+        if (declaredChildren != null) {
+            sinks.addAll(declaredChildren);
+        }
+        if (typeSystem != null) {
+            sinks.add(typeSystem);
+        }
+        if (specializations != null) {
+            sinks.addAll(specializations);
+        }
+        if (specializationListeners != null) {
+            sinks.addAll(specializationListeners);
+        }
+        if (guards != null) {
+            sinks.addAll(guards);
+        }
+        if (executableTypes != null) {
+            sinks.addAll(executableTypes);
+        }
+        if (shortCircuits != null) {
+            sinks.addAll(shortCircuits);
+        }
+        if (fields != null) {
+            sinks.addAll(fields);
+        }
+        return sinks;
+    }
 
-    private TypeMirror nodeType;
+    public ParameterSpec getInstanceParameterSpec() {
+        return instanceParameterSpec;
+    }
 
-    public NodeData(TypeElement type, TypeSystemData typeSystem) {
-        super(type, null);
-        this.typeSystem = typeSystem;
+    public void setInstanceParameterSpec(ParameterSpec instanceParameter) {
+        this.instanceParameterSpec = instanceParameter;
+    }
+
+    public String getNodeId() {
+        return nodeId;
     }
 
     public TypeMirror getNodeType() {
@@ -71,6 +134,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 +158,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() {
@@ -107,22 +179,16 @@
 
         for (SpecializationData specialization : getSpecializations()) {
             methods.add(specialization);
-            if (specialization.getShortCircuits() != null) {
-                methods.addAll(Arrays.asList(specialization.getShortCircuits()));
-            }
         }
 
-        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 +199,6 @@
         return foundGuards;
     }
 
-    public ExecutableTypeData[] getExecutableTypes() {
-        return executableTypes;
-    }
-
     public ExecutableTypeData findGenericExecutableType(ProcessorContext context, TypeData type) {
         List<ExecutableTypeData> types = findGenericExecutableTypes(context);
         for (ExecutableTypeData availableType : types) {
@@ -147,6 +209,14 @@
         return null;
     }
 
+    public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context) {
+        List<ExecutableTypeData> types = findGenericExecutableTypes(context);
+        if (!types.isEmpty()) {
+            return types.get(0);
+        }
+        return null;
+    }
+
     public List<ExecutableTypeData> findGenericExecutableTypes(ProcessorContext context) {
         List<ExecutableTypeData> types = new ArrayList<>();
         for (ExecutableTypeData type : executableTypes) {
@@ -180,47 +250,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);
                 }
             }
         }
@@ -238,18 +281,13 @@
 
     public boolean needsRewrites(ProcessorContext context) {
         boolean needsRewrites = false;
-        for (NodeFieldData field : getFields()) {
-            if (field.getExecutionKind() == ExecutionKind.DEFAULT || field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) {
-                if (!field.getNodeData().hasUnexpectedExecutableTypes(context)) {
-                    continue;
-                }
 
+        for (SpecializationData specialization : getSpecializations()) {
+            if (specialization.hasRewrite(context)) {
                 needsRewrites = true;
                 break;
             }
         }
-
-        needsRewrites &= specializations.length >= 2;
         return needsRewrites;
     }
 
@@ -263,37 +301,65 @@
     }
 
     public TypeSystemData getTypeSystem() {
-        if (typeSystem != null) {
-            return typeSystem;
+        return typeSystem;
+    }
+
+    public String dump() {
+        return dump(0);
+    }
+
+    private String dump(int level) {
+        String indent = "";
+        for (int i = 0; i < level; i++) {
+            indent += "  ";
+        }
+        StringBuilder builder = new StringBuilder();
+
+        builder.append(String.format("%s%s {", indent, toString()));
+
+        dumpProperty(builder, indent, "templateClass", Utils.getQualifiedName(getTemplateType()));
+        dumpProperty(builder, indent, "typeSystem", getTypeSystem());
+        dumpProperty(builder, indent, "fields", getFields());
+        dumpProperty(builder, indent, "executableTypes", getExecutableTypes());
+        dumpProperty(builder, indent, "specializations", getSpecializations());
+        dumpProperty(builder, indent, "guards", getGuards());
+        dumpProperty(builder, indent, "messages", collectMessages());
+        if (getDeclaredChildren().size() > 0) {
+            builder.append(String.format("\n%s  children = [", indent));
+            for (NodeData node : getDeclaredChildren()) {
+                builder.append("\n");
+                builder.append(node.dump(level + 1));
+            }
+            builder.append(String.format("\n%s  ]", indent));
+        }
+        builder.append(String.format("%s}", indent));
+        return builder.toString();
+    }
+
+    private static void dumpProperty(StringBuilder b, String indent, String propertyName, Object value) {
+        if (value instanceof List) {
+            List<?> list = (List<?>) value;
+            if (!list.isEmpty()) {
+                b.append(String.format("\n%s  %s = %s", indent, propertyName, dumpList((List<?>) value)));
+            }
         } else {
-            return null;
+            if (value != null) {
+                b.append(String.format("\n%s  %s = %s", indent, propertyName, value));
+            }
         }
     }
 
-    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)));
-        return b.toString();
-    }
-
-    private static String dumpList(Object[] array) {
+    private static String dumpList(List<?> array) {
         if (array == null) {
             return "null";
         }
 
+        if (array.isEmpty()) {
+            return "[]";
+        } else if (array.size() == 1) {
+            return "[" + array.get(0).toString() + "]";
+        }
+
         StringBuilder b = new StringBuilder();
         b.append("[");
         for (Object object : array) {
@@ -315,4 +381,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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Thu Mar 14 01:09:43 2013 +0100
@@ -25,10 +25,12 @@
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
 
-public class NodeFieldData {
+import com.oracle.truffle.codegen.processor.template.*;
+
+public class NodeFieldData extends MessageContainer {
 
     public enum FieldKind {
-        FIELD, CHILD, CHILDREN
+        CHILD, CHILDREN
     }
 
     public enum ExecutionKind {
@@ -41,21 +43,39 @@
 
     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) {
+    public NodeFieldData(VariableElement fieldElement, Element accessElement, AnnotationMirror childAnnotationMirror, FieldKind fieldKind, ExecutionKind executionKind) {
         this.fieldElement = fieldElement;
         this.accessElement = accessElement;
         this.childAnnotationMirror = childAnnotationMirror;
-        this.nodeData = typeNodeData;
         this.fieldKind = fieldKind;
         this.executionKind = executionKind;
     }
 
+    NodeFieldData(NodeFieldData field) {
+        this.fieldElement = field.fieldElement;
+        this.accessElement = field.accessElement;
+        this.childAnnotationMirror = field.childAnnotationMirror;
+        this.fieldKind = field.fieldKind;
+        this.executionKind = field.executionKind;
+        this.nodeData = field.nodeData;
+    }
+
+    @Override
+    public Element getMessageElement() {
+        return fieldElement;
+    }
+
     public boolean isShortCircuit() {
         return executionKind == ExecutionKind.SHORT_CIRCUIT;
     }
 
+    void setNode(NodeData nodeData) {
+        this.nodeData = nodeData;
+        getMessages().addAll(nodeData.collectMessages());
+    }
+
     public VariableElement getFieldElement() {
         return fieldElement;
     }
@@ -90,7 +110,7 @@
 
     @Override
     public String toString() {
-        return "NodeFieldData[name=" + getName() + ", kind=" + fieldKind + ", execution=" + executionKind + "]";
+        return "NodeFieldData[name=" + getName() + ", kind=" + fieldKind + ", execution=" + executionKind + ", node=" + getNodeData().toString() + "]";
     }
 
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Thu Mar 14 01:09:43 2013 +0100
@@ -28,6 +28,7 @@
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
 import javax.lang.model.util.*;
+import javax.tools.Diagnostic.*;
 
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.api.nodes.Node.Child;
@@ -41,11 +42,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 +53,37 @@
     @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);
-        } finally {
+            node = resolveNode((TypeElement) element);
             if (Log.DEBUG) {
-                NodeData parsed = parsedNodes.get(Utils.getQualifiedName(originalType));
-                if (parsed != null) {
+                NodeData parsed = parsedNodes.get(Utils.getQualifiedName((TypeElement) element));
+                if (node != null) {
                     String dump = parsed.dump();
-                    log.error("Node parsed: %s", dump);
-                    System.out.println("Parsed: " + dump);
+                    log.message(Kind.ERROR, null, null, null, dump);
+                    System.out.println(dump);
                 }
             }
+        } finally {
             parsedNodes = null;
-            originalType = null;
         }
+
+        return node;
+    }
+
+    @Override
+    protected NodeData filterErrorElements(NodeData model) {
+        for (Iterator<NodeData> iterator = model.getDeclaredChildren().iterator(); iterator.hasNext();) {
+            NodeData node = filterErrorElements(iterator.next());
+            if (node == null) {
+                iterator.remove();
+            }
+        }
+        if (model.hasErrors()) {
+            return null;
+        }
+        return model;
     }
 
     @Override
@@ -78,182 +91,426 @@
         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);
-        if (rootNode == null && children.size() > 0) {
-            rootNode = new NodeData(rootType, null);
+
+        NodeData rootNode = parseNode(rootType);
+        boolean hasErrors = rootNode != null ? rootNode.hasErrors() : false;
+        if ((rootNode == null || hasErrors) && children.size() > 0) {
+            rootNode = new NodeData(rootType, rootType.getSimpleName().toString());
         }
+
+        parsedNodes.put(typeName, rootNode);
+
         if (rootNode != null) {
+            children.addAll(rootNode.getDeclaredChildren());
             rootNode.setDeclaredChildren(children);
         }
 
         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
         }
 
         if (type.getModifiers().contains(Modifier.PRIVATE)) {
-            return null; // not visible
+            // TODO error message here!?
+            return null; // not visible, not a node
+        }
+
+        TypeElement nodeType;
+        boolean needsSplit;
+        if (methodNodes != null) {
+            needsSplit = methodNodes != null;
+            nodeType = Utils.fromTypeMirror(Utils.getAnnotationValue(TypeMirror.class, methodNodes, "value"));
+        } else {
+            needsSplit = false;
+            nodeType = type;
+        }
+
+        NodeData nodeData = parseNodeData(type, nodeType);
+        if (nodeData.hasErrors()) {
+            return nodeData; // error sync point
         }
 
         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());
-            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);
-
-        nodeData.setExtensionElements(getExtensionParser().parseAll(type, elements));
+        nodeData.setExtensionElements(getExtensionParser().parseAll(nodeData, elements));
         if (nodeData.getExtensionElements() != null) {
             elements.addAll(nodeData.getExtensionElements());
         }
+        parseMethods(nodeData, elements);
 
-        List<ExecutableTypeData> executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements));
-
-        nodeData.setExecutableTypes(executableTypes.toArray(new ExecutableTypeData[executableTypes.size()]));
+        if (nodeData.hasErrors()) {
+            return nodeData;
+        }
 
-        parsedNodes.put(Utils.getQualifiedName(type), nodeData);
+        List<NodeData> nodes;
+        if (needsSplit) {
+            nodes = splitNodeData(nodeData);
+        } else {
+            nodes = new ArrayList<>();
+            nodes.add(nodeData);
+        }
 
-        NodeFieldData[] fields = parseFields(nodeData, elements, typeHierarchy);
-        if (fields == null) {
-            return null;
+        for (NodeData splittedNode : nodes) {
+            finalizeSpecializations(splittedNode);
+            verifyNode(splittedNode);
+        }
+
+        if (needsSplit) {
+            nodeData.setDeclaredChildren(nodes);
+            nodeData.setSpecializationListeners(new ArrayList<SpecializationListenerData>());
+            nodeData.setSpecializations(new ArrayList<SpecializationData>());
+            return nodeData;
+        } else {
+            return nodeData;
         }
-        nodeData.setFields(fields);
+    }
+
+    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<>();
+            }
 
-        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()]));
+            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;
+    }
 
-        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);
+    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 void 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 (specializations == null || genericSpecializations == null || shortCircuits == null || listeners == null || guards == null) {
-            return null;
+        List<SpecializationData> allSpecializations = new ArrayList<>();
+        allSpecializations.addAll(generics);
+        allSpecializations.addAll(specializations);
+
+        node.setSpecializations(allSpecializations);
+    }
+
+    private void finalizeSpecializations(final NodeData node) {
+        List<SpecializationData> specializations = new ArrayList<>(node.getSpecializations());
+
+        if (specializations.isEmpty()) {
+            return;
+        }
+
+        List<SpecializationData> generics = new ArrayList<>();
+        for (SpecializationData spec : specializations) {
+            if (spec.isGeneric()) {
+                generics.add(spec);
+            }
+        }
+
+        if (generics.size() == 1 && specializations.size() == 1) {
+            for (SpecializationData generic : generics) {
+                generic.addError("@%s defined but no @%s.", Generic.class.getSimpleName(), Specialization.class.getSimpleName());
+            }
         }
 
         SpecializationData genericSpecialization = null;
-        if (genericSpecializations.size() > 1) {
-            for (SpecializationData generic : genericSpecializations) {
-                log.error(generic.getMethod(), "Only one method with @%s is allowed per operation.", Generic.class.getSimpleName());
+        if (generics.size() > 1) {
+            for (SpecializationData generic : generics) {
+                generic.addError("Only @%s is allowed per operation.", Generic.class.getSimpleName());
             }
-            return null;
-        } else if (genericSpecializations.size() == 1) {
-            genericSpecialization = genericSpecializations.get(0);
+            return;
+        } else if (generics.size() == 1) {
+            genericSpecialization = generics.get(0);
+        } else if (node.needsRewrites(context)) {
+            SpecializationData specialization = specializations.get(0);
+            GenericParser parser = new GenericParser(context, node);
+            MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, null);
+
+            ExecutableTypeData anyGenericReturnType = node.findAnyGenericExecutableType(context);
+            assert anyGenericReturnType != null;
+
+            ActualParameter returnType = new ActualParameter(specification.getReturnType(), anyGenericReturnType.getType().getPrimitiveType(), 0, false);
+            List<ActualParameter> parameters = new ArrayList<>();
+            for (ActualParameter specializationParameter : specialization.getParameters()) {
+                ParameterSpec parameterSpec = specification.findParameterSpec(specializationParameter.getSpecification().getName());
+                NodeFieldData field = node.findField(parameterSpec.getName());
+                TypeMirror actualType;
+                if (field == null) {
+                    actualType = specializationParameter.getActualType();
+                } else {
+                    ExecutableTypeData paramType = field.getNodeData().findAnyGenericExecutableType(context);
+                    assert paramType != null;
+                    actualType = paramType.getType().getPrimitiveType();
+                }
+                parameters.add(new ActualParameter(parameterSpec, actualType, specializationParameter.getIndex(), specializationParameter.isHidden()));
+            }
+            TemplateMethod genericMethod = new TemplateMethod("Generic", node, specification, null, null, returnType, parameters);
+            genericSpecialization = new SpecializationData(genericMethod, true, false);
+
+            specializations.add(genericSpecialization);
         }
 
-        if (specializations.size() > 1 && genericSpecialization == null) {
-            log.error(type, "Need a @%s method.", Generic.class.getSimpleName());
-            return null;
+        if (genericSpecialization != null) {
+            CodeExecutableElement uninitializedMethod = new CodeExecutableElement(Utils.modifiers(Modifier.PUBLIC), context.getType(void.class), "doUninitialized");
+            TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", 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);
+    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;
+    }
 
-        // verify order is not ambiguous
-        if (!verifySpecializationOrder(typeSystem, specializations)) {
-            return null;
+    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;
         }
 
-        nodeData.setSpecializations(allSpecializations.toArray(new SpecializationData[allSpecializations.size()]));
-        nodeData.setSpecializationListeners(listeners.toArray(new TemplateMethod[listeners.size()]));
+        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();
+        }
+    }
 
-        if (!verifyMissingAbstractMethods(nodeData, elements)) {
-            return null;
-        }
+    private void verifyNode(NodeData nodeData) {
+        // verify specialization parameter length
+        verifySpecializationParameters(nodeData);
+
+        // verify order is not ambiguous
+        verifySpecializationOrder(nodeData);
+
+        verifyMissingAbstractMethods(nodeData);
+
+        assignShortCircuitsToSpecializations(nodeData);
 
-        if (!assignShortCircuitsToSpecializations(nodeData, allSpecializations, shortCircuits)) {
-            return null;
-        }
+        verifyConstructors(nodeData);
+
+// if (!verifyNamingConvention(specializations, "do")) {
+// return null;
+// }
+//
+// if (!verifyNamesUnique(specializations)) {
+// return null;
+// }
+
+        verifyNamingConvention(nodeData.getShortCircuits(), "needs");
 
-        if (!verifyConstructors(nodeData)) {
-            return null;
+        verifySpecializationThrows(nodeData);
+    }
+
+    private NodeData parseNodeData(TypeElement templateType, TypeElement nodeType) {
+        List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeType));
+        List<TypeElement> typeHierarchy = findSuperClasses(new ArrayList<TypeElement>(), nodeType);
+        Collections.reverse(typeHierarchy);
+        NodeData nodeData = new NodeData(templateType, templateType.getSimpleName().toString());
+
+        AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class);
+        if (typeSystemMirror == null) {
+            nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), nodeType.getQualifiedName().toString());
+            return nodeData;
         }
 
-        if (!verifyNamingConvention(specializations, "do")) {
-            return null;
-        }
-
-        if (!verifyNamesUnique(specializations)) {
-            return null;
+        TypeMirror typeSytemType = Utils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value");
+        final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true);
+        if (typeSystem == null) {
+            nodeData.addError("The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType));
+            return nodeData;
         }
 
-        if (!verifyNamingConvention(shortCircuits, "needs")) {
-            return null;
-        }
+        nodeData.setNodeType(nodeType.asType());
+        nodeData.setTypeSystem(typeSystem);
 
-        if (!verifySpecializationThrows(typeSystem, specializations)) {
-            return null;
-        }
+        List<ExecutableTypeData> executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements));
+        nodeData.setExecutableTypes(executableTypes);
+        parsedNodes.put(Utils.getQualifiedName(templateType), nodeData);
+        nodeData.setFields(parseFields(nodeData, elements, typeHierarchy));
 
         return nodeData;
     }
 
-    private boolean verifyMissingAbstractMethods(NodeData nodeData, List<Element> elements) {
-        if (nodeData.needsFactory()) {
+    private static void 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()) {
+                specialization.addError("All specializations must have the same number of arguments.");
+            }
+        }
+    }
+
+    private void verifyMissingAbstractMethods(NodeData nodeData) {
+        if (!nodeData.needsFactory()) {
             // missing abstract methods only needs to be implemented
             // if we need go generate factory for it.
-            return true;
+            return;
         }
 
+        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());
@@ -262,24 +519,20 @@
             unusedElements.removeAll(nodeData.getExtensionElements());
         }
 
-        boolean valid = true;
         for (ExecutableElement unusedMethod : ElementFilter.methodsIn(unusedElements)) {
             if (unusedMethod.getModifiers().contains(Modifier.ABSTRACT)) {
-                context.getLog().error(nodeData.getTemplateType(), "The type %s must implement the inherited abstract method %s.", Utils.getSimpleName(nodeData.getTemplateType()),
-                                Utils.getReadableSignature(unusedMethod));
-                valid = false;
+                nodeData.addError("The type %s must implement the inherited abstract method %s.", Utils.getSimpleName(nodeData.getTemplateType()), Utils.getReadableSignature(unusedMethod));
             }
         }
+    }
+
+    private void verifyConstructors(NodeData nodeData) {
+        if (!nodeData.needsRewrites(context)) {
+            // no specialization constructor is needed if the node never rewrites.
+            return;
+        }
 
-        return valid;
-    }
-
-    private boolean verifyConstructors(NodeData nodeData) {
         TypeElement type = Utils.fromTypeMirror(nodeData.getNodeType());
-        if (!nodeData.needsRewrites(context)) {
-            // no specialization constructor is needed if the node never rewrites.
-            return true;
-        }
 
         List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());
         for (ExecutableElement e : constructors) {
@@ -287,20 +540,17 @@
                 TypeMirror firstArg = e.getParameters().get(0).asType();
                 if (Utils.typeEquals(firstArg, nodeData.getNodeType())) {
                     if (e.getModifiers().contains(Modifier.PRIVATE)) {
-                        context.getLog().error(e, "The specialization constructor must not be private.");
-                        return false;
+                        nodeData.addError("The specialization constructor must not be private.");
                     } else if (constructors.size() <= 1) {
-                        context.getLog().error(e, "The specialization constructor must not be the only constructor. The definition of an alternative constructor is required.");
-                        return false;
+                        nodeData.addError("The specialization constructor must not be the only constructor. The definition of an alternative constructor is required.");
                     }
-                    return true;
+                    return;
                 }
             }
         }
 
         // not found
-        context.getLog().error(type, "Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type));
-        return false;
+        nodeData.addError("Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type));
     }
 
     private static List<ExecutableTypeData> filterExecutableTypes(List<ExecutableTypeData> executableTypes) {
@@ -347,13 +597,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,12 +611,10 @@
         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"));
             }
         }
 
-        boolean valid = true;
-
         List<NodeFieldData> fields = new ArrayList<>();
         for (VariableElement var : ElementFilter.fieldsIn(elements)) {
             if (var.getModifiers().contains(Modifier.STATIC)) {
@@ -380,23 +628,12 @@
             }
 
             NodeFieldData field = parseField(nodeData, var, shortCircuits);
-            if (field != null) {
-                if (field.getExecutionKind() != ExecutionKind.IGNORE) {
-                    fields.add(field);
-                }
-            } else {
-                valid = false;
+            if (field.getExecutionKind() != ExecutionKind.IGNORE) {
+                fields.add(field);
             }
         }
-
-        // TODO parse getters
-        if (!valid) {
-            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,34 +661,29 @@
             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;
+        NodeFieldData fieldData = new NodeFieldData(var, findAccessElement(var), mirror, kind, execution);
         if (nodeType != null) {
-            fieldNodeData = resolveNode(Utils.fromTypeMirror(nodeType));
-            Element errorElement = Utils.typeEquals(parentNodeData.getTemplateType().asType(), var.getEnclosingElement().asType()) ? var : parentNodeData.getTemplateType();
+            NodeData fieldNodeData = resolveNode(Utils.fromTypeMirror(nodeType));
+            fieldData.setNode(fieldNodeData);
 
             if (fieldNodeData == null) {
-                // TODO redirect errors from resolve.
-                context.getLog().error(errorElement, "Node type '%s' is invalid.", Utils.getQualifiedName(nodeType));
-                return null;
+                fieldData.addError("Node type '%s' is invalid.", Utils.getQualifiedName(nodeType));
             } else if (fieldNodeData.findGenericExecutableTypes(context).isEmpty()) {
-                // TODO better error handling for (no or multiple?)
-                context.getLog().error(errorElement, "No executable generic types found for node '%s'.", Utils.getQualifiedName(nodeType));
-                return null;
+                fieldData.addError("No executable generic types found for node '%s'.", Utils.getQualifiedName(nodeType));
+            }
+
+            // 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);
+        return fieldData;
     }
 
     private Element findAccessElement(VariableElement variableElement) {
@@ -482,8 +714,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 +737,16 @@
         });
     }
 
-    private boolean assignShortCircuitsToSpecializations(NodeData nodeData, List<SpecializationData> specializations, List<ShortCircuitData> shortCircuits) {
-
-        Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(shortCircuits);
+    private void 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);
+                node.addError("@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName);
                 valid = false;
                 continue;
             }
@@ -531,7 +761,7 @@
 
             if (!sameMethodName) {
                 for (ShortCircuitData circuit : availableCircuits) {
-                    log.error(circuit.getMethod(), circuit.getMarkerAnnotation(), "All short circuits for short cut value '%s' must have the same method name.", valueName);
+                    circuit.addError("All short circuits for short cut value '%s' must have the same method name.", valueName);
                 }
                 valid = false;
                 continue;
@@ -539,14 +769,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);
+                node.addError("No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName);
                 valid = false;
                 continue;
             }
@@ -559,67 +789,48 @@
         }
 
         if (!valid) {
-            return valid;
+            return;
         }
 
-        NodeFieldData[] fields = nodeData.filterFields(null, ExecutionKind.SHORT_CIRCUIT);
-        for (SpecializationData specialization : specializations) {
-            ShortCircuitData[] assignedShortCuts = new ShortCircuitData[fields.length];
+        NodeFieldData[] fields = node.filterFields(null, ExecutionKind.SHORT_CIRCUIT);
+        for (SpecializationData specialization : node.getSpecializations()) {
+            List<ShortCircuitData> assignedShortCuts = new ArrayList<>(fields.length);
 
             for (int i = 0; i < fields.length; i++) {
                 List<ShortCircuitData> availableShortCuts = groupedShortCircuits.get(fields[i].getName());
 
                 ShortCircuitData genericShortCircuit = null;
+                ShortCircuitData compatibleShortCircuit = null;
                 for (ShortCircuitData circuit : availableShortCuts) {
                     if (circuit.isGeneric()) {
                         genericShortCircuit = circuit;
                     } else if (circuit.isCompatibleTo(specialization)) {
-                        assignedShortCuts[i] = circuit;
+                        compatibleShortCircuit = circuit;
                     }
                 }
 
-                if (assignedShortCuts[i] == null) {
-                    assignedShortCuts[i] = genericShortCircuit;
+                if (compatibleShortCircuit == null) {
+                    compatibleShortCircuit = genericShortCircuit;
                 }
+                assignedShortCuts.add(compatibleShortCircuit);
             }
             specialization.setShortCircuits(assignedShortCuts);
         }
-        return true;
     }
 
-    private boolean verifyNamingConvention(List<? extends TemplateMethod> methods, String prefix) {
-        boolean valid = true;
+    private static void verifyNamingConvention(List<? extends TemplateMethod> methods, String prefix) {
         for (int i = 0; i < methods.size(); i++) {
             TemplateMethod m1 = methods.get(i);
             if (m1.getMethodName().length() < 3 || !m1.getMethodName().startsWith(prefix)) {
-                log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Naming convention: method name must start with '%s'.", prefix);
-                valid = false;
+                m1.addError("Naming convention: method name must start with '%s'.", prefix);
             }
         }
-        return valid;
-    }
-
-    private boolean verifyNamesUnique(List<? extends TemplateMethod> methods) {
-        boolean valid = true;
-        for (int i = 0; i < methods.size(); i++) {
-            TemplateMethod m1 = methods.get(i);
-            for (int j = i + 1; j < methods.size(); j++) {
-                TemplateMethod m2 = methods.get(j);
-
-                if (m1.getMethodName().equalsIgnoreCase(m2.getMethodName())) {
-                    log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Method name '%s' used multiple times", m1.getMethodName());
-                    log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Method name '%s' used multiple times", m1.getMethodName());
-                    return false;
-                }
-            }
-        }
-        return valid;
     }
 
     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 +879,10 @@
         return collection;
     }
 
-    private boolean verifySpecializationOrder(TypeSystemData typeSystem, List<SpecializationData> specializations) {
+    private static void 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++) {
@@ -678,56 +892,39 @@
                 if (m1.getOrder() != Specialization.DEFAULT_ORDER && m2.getOrder() != Specialization.DEFAULT_ORDER) {
                     int specOrder = m1.getOrder() - m2.getOrder();
                     if (specOrder == 0) {
-                        log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Order value %d used multiple times", m1.getOrder());
-                        log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Order value %d used multiple times", m1.getOrder());
-                        return false;
+                        m1.addError("Order value %d used multiple times", m1.getOrder());
+                        m2.addError("Order value %d used multiple times", m1.getOrder());
+                        return;
                     } else if ((specOrder < 0 && inferredOrder > 0) || (specOrder > 0 && inferredOrder < 0)) {
-                        log.error(m1.getMethod(), m1.getMarkerAnnotation(), "Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder());
-                        log.error(m2.getMethod(), m2.getMarkerAnnotation(), "Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder());
-                        return false;
+                        m1.addError("Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder());
+                        m2.addError("Explicit order values %d and %d are inconsistent with type lattice ordering.", m1.getOrder(), m2.getOrder());
+                        return;
                     }
                 } else if (inferredOrder == 0) {
                     SpecializationData m = (m1.getOrder() == Specialization.DEFAULT_ORDER ? m1 : m2);
-                    log.error(m.getMethod(), m.getMarkerAnnotation(), "Cannot calculate a consistent order for this specialization. Define the order attribute to resolve this.");
-                    return false;
+                    m.addError("Cannot calculate a consistent order for this specialization. Define the order attribute to resolve this.");
+                    return;
                 }
             }
         }
-        return true;
     }
 
-    private boolean verifySpecializationThrows(TypeSystemData typeSystem, List<SpecializationData> specializations) {
+    private static void 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());
-                            valid = false;
+                            throwsData.addError("Duplicate exception type.");
                         }
                     }
                 }
             }
         }
-        return valid;
     }
 
     private static int compareSpecialization(TypeSystemData typeSystem, SpecializationData m1, SpecializationData m2) {
@@ -744,8 +941,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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitData.java	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java	Thu Mar 14 01:09:43 2013 +0100
@@ -48,14 +48,8 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        String shortCircuitValue = Utils.getAnnotationValueString(mirror, "value");
-
-        if (!shortCircuitValues.contains(shortCircuitValue)) {
-            getContext().getLog().error(method, mirror, "Invalid short circuit value %s.", shortCircuitValue);
-            return null;
-        }
-
-        return createDefaultMethodSpec(shortCircuitValue);
+        String shortCircuitValue = Utils.getAnnotationValue(String.class, mirror, "value");
+        return createDefaultMethodSpec(method, mirror, shortCircuitValue);
     }
 
     @Override
@@ -65,9 +59,12 @@
 
     @Override
     public ShortCircuitData create(TemplateMethod method) {
-        String shortCircuitValue = Utils.getAnnotationValueString(method.getMarkerAnnotation(), "value");
-        assert shortCircuitValue != null;
-        assert shortCircuitValues.contains(shortCircuitValue);
+        String shortCircuitValue = Utils.getAnnotationValue(String.class, method.getMarkerAnnotation(), "value");
+
+        if (!shortCircuitValues.contains(shortCircuitValue)) {
+            method.addError("Invalid short circuit value %s.", shortCircuitValue);
+        }
+
         return new ShortCircuitData(method, shortCircuitValue);
     }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Thu Mar 14 01:09:43 2013 +0100
@@ -22,7 +22,10 @@
  */
 package com.oracle.truffle.codegen.processor.node;
 
+import java.util.*;
+
 import com.oracle.truffle.api.codegen.*;
+import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
 
 public class SpecializationData extends TemplateMethod {
@@ -30,13 +33,13 @@
     private final int order;
     private final boolean generic;
     private final boolean uninitialized;
-    private final SpecializationThrowsData[] exceptions;
-    private SpecializationGuardData[] guards;
-    private ShortCircuitData[] shortCircuits;
+    private final List<SpecializationThrowsData> exceptions;
+    private List<SpecializationGuardData> guards;
+    private List<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,8 +56,40 @@
         this.order = Specialization.DEFAULT_ORDER;
         this.generic = generic;
         this.uninitialized = uninitialized;
-        this.exceptions = new SpecializationThrowsData[0];
-        this.guards = new SpecializationGuardData[0];
+        this.exceptions = Collections.emptyList();
+        this.guards = new ArrayList<>();
+    }
+
+    @Override
+    protected List<MessageContainer> findChildContainers() {
+        List<MessageContainer> sinks = new ArrayList<>();
+        if (exceptions != null) {
+            sinks.addAll(exceptions);
+        }
+        if (guards != null) {
+            sinks.addAll(guards);
+        }
+        return sinks;
+    }
+
+    public boolean hasRewrite(ProcessorContext context) {
+        if (!getExceptions().isEmpty()) {
+            return true;
+        }
+        if (!getGuards().isEmpty()) {
+            return true;
+        }
+        for (ActualParameter parameter : getParameters()) {
+            NodeFieldData field = getNode().findField(parameter.getSpecification().getName());
+            if (field == null) {
+                continue;
+            }
+            ExecutableTypeData type = field.getNodeData().findExecutableType(parameter.getActualTypeData(field.getNodeData().getTypeSystem()));
+            if (type.hasUnexpectedValue(context)) {
+                return true;
+            }
+        }
+        return false;
     }
 
     public NodeData getNode() {
@@ -65,7 +100,7 @@
         this.node = node;
     }
 
-    public void setGuards(SpecializationGuardData[] guards) {
+    public void setGuards(List<SpecializationGuardData> guards) {
         this.guards = guards;
     }
 
@@ -81,19 +116,19 @@
         return uninitialized;
     }
 
-    public SpecializationThrowsData[] getExceptions() {
+    public List<SpecializationThrowsData> getExceptions() {
         return exceptions;
     }
 
-    public SpecializationGuardData[] getGuards() {
+    public List<SpecializationGuardData> getGuards() {
         return guards;
     }
 
-    public void setShortCircuits(ShortCircuitData[] shortCircuits) {
+    public void setShortCircuits(List<ShortCircuitData> shortCircuits) {
         this.shortCircuits = shortCircuits;
     }
 
-    public ShortCircuitData[] getShortCircuits() {
+    public List<ShortCircuitData> getShortCircuits() {
         return shortCircuits;
     }
 
@@ -106,10 +141,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;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationGuardData.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationGuardData.java	Thu Mar 14 01:09:43 2013 +0100
@@ -22,20 +22,42 @@
  */
 package com.oracle.truffle.codegen.processor.node;
 
+import javax.lang.model.element.*;
+
+import com.oracle.truffle.codegen.processor.template.*;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
-public class SpecializationGuardData {
+public class SpecializationGuardData extends MessageContainer {
 
+    private final SpecializationData specialization;
+    private final AnnotationValue value;
     private final String guardMethod;
     private final boolean onSpecialization;
     private final boolean onExecution;
 
     private GuardData guardDeclaration;
 
-    public SpecializationGuardData(String guardMethod, boolean onSpecialization, boolean onExecution) {
+    public SpecializationGuardData(SpecializationData specialization, AnnotationValue value, String guardMethod, boolean onSpecialization, boolean onExecution) {
+        this.specialization = specialization;
         this.guardMethod = guardMethod;
         this.onSpecialization = onSpecialization;
         this.onExecution = onExecution;
+        this.value = value;
+    }
+
+    @Override
+    public Element getMessageElement() {
+        return specialization.getMessageElement();
+    }
+
+    @Override
+    public AnnotationMirror getMessageAnnotation() {
+        return specialization.getMessageAnnotation();
+    }
+
+    @Override
+    public AnnotationValue getMessageAnnotationValue() {
+        return value;
     }
 
     public String getGuardMethod() {
--- /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	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java	Thu Mar 14 01:09:43 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.");
+            method.addError("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);
-
-            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));
-                return null;
+        AnnotationValue rewriteValue = Utils.getAnnotationValue(method.getMarkerAnnotation(), "rewriteOn");
+        List<TypeMirror> exceptionTypes = Utils.getAnnotationValueList(TypeMirror.class, method.getMarkerAnnotation(), "rewriteOn");
+        List<SpecializationThrowsData> exceptionData = new ArrayList<>();
+        for (TypeMirror exceptionType : exceptionTypes) {
+            SpecializationThrowsData throwsData = new SpecializationThrowsData(method.getMarkerAnnotation(), rewriteValue, exceptionType);
+            if (!Utils.canThrowType(method.getMethod().getThrownTypes(), exceptionType)) {
+                throwsData.addError("Method must specify a throws clause with the exception type '%s'.", Utils.getQualifiedName(exceptionType));
             }
+            exceptionData.add(throwsData);
         }
 
-        Arrays.sort(exceptionData, new Comparator<SpecializationThrowsData>() {
+        Collections.sort(exceptionData, new Comparator<SpecializationThrowsData>() {
 
             @Override
             public int compare(SpecializationThrowsData o1, SpecializationThrowsData o2) {
@@ -87,26 +81,19 @@
         });
         SpecializationData specialization = new SpecializationData(method, order, exceptionData);
         boolean valid = true;
-        List<AnnotationMirror> guardDefs = Utils.collectAnnotations(getContext(), method.getMarkerAnnotation(), "guards", method.getMethod(), SpecializationGuard.class);
-        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");
+        AnnotationValue guardsValue = Utils.getAnnotationValue(method.getMarkerAnnotation(), "guards");
+        List<String> guardDefs = Utils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards");
+        List<SpecializationGuardData> guardData = new ArrayList<>(guardDefs.size());
+        for (int i = 0; i < guardDefs.size(); i++) {
+            String guardMethod = guardDefs.get(i);
 
-            if (!onSpecialization && !onExecution) {
-                String message = "Either onSpecialization, onExecution or both must be enabled.";
-                getContext().getLog().error(method.getMethod(), guardMirror, message);
-                valid = false;
-                continue;
-            }
+            SpecializationGuardData assignedGuard = new SpecializationGuardData(specialization, guardsValue, guardMethod, true, true);
+
+            guardData.add(assignedGuard);
 
-            guardData[i] = new SpecializationGuardData(guardMethod, onSpecialization, onExecution);
-
-            GuardData compatibleGuard = matchSpecializationGuard(guardMirror, specialization, guardData[i]);
+            GuardData compatibleGuard = matchSpecializationGuard(specialization, assignedGuard);
             if (compatibleGuard != null) {
-                guardData[i].setGuardDeclaration(compatibleGuard);
+                assignedGuard.setGuardDeclaration(compatibleGuard);
             } else {
                 valid = false;
             }
@@ -121,7 +108,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,16 +129,14 @@
             }
             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);
-            return null;
+            specializationGuard.addError("No guard with signature '%s' found in type system.", expectedSignature);
         }
 
         return compatibleGuard;
     }
 
     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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationThrowsData.java	Thu Mar 14 01:09:43 2013 +0100
@@ -25,23 +25,40 @@
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
 
-public class SpecializationThrowsData {
+import com.oracle.truffle.codegen.processor.template.*;
 
+public class SpecializationThrowsData extends MessageContainer {
+
+    private final AnnotationValue annotationValue;
     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, AnnotationValue value, TypeMirror javaClass) {
         this.annotationMirror = annotationMirror;
+        this.annotationValue = value;
         this.javaClass = javaClass;
-        this.transitionTo = transitionTo;
     }
 
     void setSpecialization(SpecializationData specialization) {
         this.specialization = specialization;
     }
 
+    @Override
+    public Element getMessageElement() {
+        return specialization.getMessageElement();
+    }
+
+    @Override
+    public AnnotationMirror getMessageAnnotation() {
+        return annotationMirror;
+    }
+
+    @Override
+    public AnnotationValue getMessageAnnotationValue() {
+        return annotationValue;
+    }
+
     public TypeMirror getJavaClass() {
         return javaClass;
     }
@@ -54,16 +71,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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.java	Thu Mar 14 01:09:43 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());
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MessageContainer.java	Thu Mar 14 01:09:43 2013 +0100
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.codegen.processor.template;
+
+import java.util.*;
+
+import javax.lang.model.element.*;
+import javax.tools.Diagnostic.Kind;
+
+import com.oracle.truffle.codegen.processor.*;
+
+public abstract class MessageContainer {
+
+    private final List<Message> messages = new ArrayList<>();
+
+    public final void addWarning(String text, Object... params) {
+        getMessages().add(new Message(this, String.format(text, params), Kind.WARNING));
+    }
+
+    public final void addError(String text, Object... params) {
+        getMessages().add(new Message(this, String.format(text, params), Kind.ERROR));
+    }
+
+    protected List<MessageContainer> findChildContainers() {
+        return Collections.emptyList();
+    }
+
+    public abstract Element getMessageElement();
+
+    public final void emitMessages(TypeElement baseElement, Log log) {
+        emitMessagesImpl(baseElement, log, new HashSet<MessageContainer>());
+    }
+
+    private void emitMessagesImpl(TypeElement baseElement, Log log, Set<MessageContainer> visitedSinks) {
+        for (Message message : getMessages()) {
+            emitDefault(baseElement, log, message);
+        }
+
+        for (MessageContainer sink : findChildContainers()) {
+            if (visitedSinks.contains(sink)) {
+                return;
+            }
+
+            visitedSinks.add(sink);
+            sink.emitMessagesImpl(baseElement, log, visitedSinks);
+        }
+    }
+
+    private void emitDefault(TypeElement baseType, Log log, Message message) {
+        if (Utils.typeEquals(baseType.asType(), Utils.findRootEnclosingType(getMessageElement()).asType()) && this == message.getOriginalContainer()) {
+            log.message(message.getKind(), getMessageElement(), getMessageAnnotation(), getMessageAnnotationValue(), message.getText());
+        } else {
+            MessageContainer original = message.getOriginalContainer();
+            log.message(message.getKind(), baseType, null, null, wrapText(original.getMessageElement(), original.getMessageAnnotation(), message.getText()));
+        }
+    }
+
+    private static String wrapText(Element element, AnnotationMirror mirror, String text) {
+        StringBuilder b = new StringBuilder();
+        if (element != null) {
+            b.append("Element " + element.toString());
+        }
+        if (mirror != null) {
+            b.append(" at annotation @" + Utils.getSimpleName(mirror.getAnnotationType()));
+        }
+
+        if (b.length() > 0) {
+            b.append(" is erroneous: ").append(text);
+            return b.toString();
+        } else {
+            return text;
+        }
+    }
+
+    public AnnotationMirror getMessageAnnotation() {
+        return null;
+    }
+
+    public AnnotationValue getMessageAnnotationValue() {
+        return null;
+    }
+
+    public final boolean hasErrors() {
+        return hasErrorsImpl(new HashSet<MessageContainer>());
+    }
+
+    public final List<Message> collectMessages() {
+        List<Message> collectedMessages = new ArrayList<>();
+        collectMessagesImpl(collectedMessages, new HashSet<MessageContainer>());
+        return collectedMessages;
+    }
+
+    private void collectMessagesImpl(List<Message> collectedMessages, Set<MessageContainer> visitedSinks) {
+        collectedMessages.addAll(getMessages());
+        for (MessageContainer sink : findChildContainers()) {
+            if (visitedSinks.contains(sink)) {
+                return;
+            }
+
+            visitedSinks.add(sink);
+            sink.collectMessagesImpl(collectedMessages, visitedSinks);
+        }
+    }
+
+    private boolean hasErrorsImpl(Set<MessageContainer> visitedSinks) {
+        for (Message msg : getMessages()) {
+            if (msg.getKind() == Kind.ERROR) {
+                return true;
+            }
+        }
+        for (MessageContainer sink : findChildContainers()) {
+            if (visitedSinks.contains(sink)) {
+                return false;
+            }
+
+            visitedSinks.add(sink);
+
+            if (sink.hasErrorsImpl(visitedSinks)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public List<Message> getMessages() {
+        return messages;
+    }
+
+    public static final class Message {
+
+        private final MessageContainer originalContainer;
+        private final String text;
+        private final Kind kind;
+
+        public Message(MessageContainer originalContainer, String text, Kind kind) {
+            this.originalContainer = originalContainer;
+            this.text = text;
+            this.kind = kind;
+        }
+
+        public MessageContainer getOriginalContainer() {
+            return originalContainer;
+        }
+
+        public String getText() {
+            return text;
+        }
+
+        public Kind getKind() {
+            return kind;
+        }
+
+        @Override
+        public String toString() {
+            return kind + ": " + text;
+        }
+
+    }
+
+}
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java	Thu Mar 14 01:09:43 2013 +0100
@@ -37,11 +37,12 @@
     }
 
     private final String name;
-    private final TypeMirror[] allowedTypes;
+    private final List<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) {
+    public ParameterSpec(String name, List<TypeMirror> allowedTypes, boolean optional, Cardinality cardinality) {
         this.allowedTypes = allowedTypes;
         this.name = name;
         this.optional = optional;
@@ -50,7 +51,7 @@
 
     /** Type constructor. */
     public ParameterSpec(String name, TypeMirror singleFixedType, boolean optional) {
-        this(name, new TypeMirror[]{singleFixedType}, optional, Cardinality.ONE);
+        this(name, Arrays.asList(singleFixedType), optional, Cardinality.ONE);
     }
 
     /** Type system value constructor. */
@@ -63,7 +64,19 @@
         this(name, nodeTypeMirrors(nodeData), optional, cardinality);
     }
 
-    private static TypeMirror[] nodeTypeMirrors(NodeData nodeData) {
+    public boolean isIndexed() {
+        return indexed;
+    }
+
+    public void setIndexed(boolean indexed) {
+        this.indexed = indexed;
+    }
+
+    public void setCardinality(Cardinality cardinality) {
+        this.cardinality = cardinality;
+    }
+
+    private static List<TypeMirror> nodeTypeMirrors(NodeData nodeData) {
         Set<TypeMirror> typeMirrors = new LinkedHashSet<>();
 
         for (ExecutableTypeData typeData : nodeData.getExecutableTypes()) {
@@ -72,7 +85,7 @@
 
         typeMirrors.add(nodeData.getTypeSystem().getGenericType());
 
-        return typeMirrors.toArray(new TypeMirror[typeMirrors.size()]);
+        return new ArrayList<>(typeMirrors);
     }
 
     public final String getName() {
@@ -87,13 +100,12 @@
         return cardinality;
     }
 
-    public TypeMirror[] getAllowedTypes() {
+    public List<TypeMirror> getAllowedTypes() {
         return allowedTypes;
     }
 
     public boolean matches(TypeMirror actualType) {
-        for (int i = 0; i < allowedTypes.length; i++) {
-            TypeMirror mirror = allowedTypes[i];
+        for (TypeMirror mirror : allowedTypes) {
             if (Utils.typeEquals(actualType, mirror)) {
                 return true;
             }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/Template.java	Thu Mar 14 01:09:43 2013 +0100
@@ -29,18 +29,34 @@
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.api.element.*;
 
-public abstract class Template {
+public abstract class Template extends MessageContainer {
 
     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;
     }
 
+    @Override
+    public Element getMessageElement() {
+        return templateType;
+    }
+
+    @Override
+    protected List<MessageContainer> findChildContainers() {
+        return Collections.emptyList();
+    }
+
+    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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Thu Mar 14 01:09:43 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.*;
 
-public class TemplateMethod {
+import com.oracle.truffle.codegen.processor.*;
 
+public class TemplateMethod extends MessageContainer {
+
+    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,31 @@
     }
 
     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);
+        getMessages().addAll(method.getMessages());
+    }
+
+    @Override
+    public Element getMessageElement() {
+        return method;
+    }
+
+    @Override
+    public AnnotationMirror getMessageAnnotation() {
+        return markerAnnotation;
+    }
+
+    @Override
+    protected List<MessageContainer> findChildContainers() {
+        return Collections.emptyList();
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getId() {
+        return id;
     }
 
     public Template getTemplate() {
@@ -64,34 +96,50 @@
         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;
     }
 
     public String getMethodName() {
-        return getMethod().getSimpleName().toString();
+        if (getMethod() != null) {
+            return getMethod().getSimpleName().toString();
+        } else {
+            return "$synthetic";
+        }
     }
 
     public AnnotationMirror getMarkerAnnotation() {
@@ -100,7 +148,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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Thu Mar 14 01:09:43 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,13 +96,14 @@
                 mirror = Utils.findAnnotationMirror(getContext().getEnvironment(), method, annotationType);
             }
 
-            if (method.getModifiers().contains(Modifier.PRIVATE)) {
-                getContext().getLog().error(method, "Method must not be private.");
+            E parsedMethod = parse(method, mirror);
+
+            if (method.getModifiers().contains(Modifier.PRIVATE) && emitErrors) {
+                parsedMethod.addError("Method must not be private.");
                 valid = false;
                 continue;
             }
 
-            E parsedMethod = parse(method, mirror);
             if (parsedMethod != null) {
                 parsedMethods.add(parsedMethod);
             } else {
@@ -120,108 +122,126 @@
             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");
+        }
+
         List<TypeDef> typeDefs = createTypeDefinitions(methodSpecification.getReturnType(), methodSpecification.getParameters());
 
         ParameterSpec returnTypeSpec = methodSpecification.getReturnType();
         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()) {
+            if (emitErrors) {
+                E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections.<ActualParameter> emptyList()));
                 String expectedReturnType = createTypeSignature(returnTypeSpec, typeDefs, true);
                 String actualReturnType = Utils.getSimpleName(method.getReturnType());
 
                 String message = String.format("The provided return type \"%s\" does not match expected return type \"%s\".\nExpected signature: \n %s", actualReturnType, expectedReturnType,
                                 createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs));
+                invalidMethod.addError(message);
+                return invalidMethod;
+            } else {
+                return null;
+            }
+        }
 
-                context.getLog().error(method, annotation, message);
+        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()) {
+                E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections.<ActualParameter> emptyList()));
+                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));
+                invalidMethod.addError(message);
+                return invalidMethod;
+            } else {
+                return null;
             }
-            return null;
         }
 
-        Iterator<? extends VariableElement> variableIterator = method.getParameters().iterator();
+        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 +250,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) {
@@ -242,12 +262,12 @@
 
         int defIndex = 0;
         for (ParameterSpec spec : allParams) {
-            TypeMirror[] allowedTypes = spec.getAllowedTypes();
-            TypeMirror[] types = spec.getAllowedTypes();
-            if (types != null && allowedTypes.length > 1) {
+            List<TypeMirror> allowedTypes = spec.getAllowedTypes();
+            List<TypeMirror> types = spec.getAllowedTypes();
+            if (types != null && allowedTypes.size() > 1) {
                 TypeDef foundDef = null;
                 for (TypeDef def : typeDefs) {
-                    if (Arrays.equals(allowedTypes, def.getTypes())) {
+                    if (allowedTypes.equals(def.getTypes())) {
                         foundDef = def;
                         break;
                     }
@@ -267,11 +287,11 @@
 
     protected static class TypeDef {
 
-        private final TypeMirror[] types;
+        private final List<TypeMirror> types;
         private final String name;
         private final List<ParameterSpec> parameters = new ArrayList<>();
 
-        public TypeDef(TypeMirror[] types, String name) {
+        public TypeDef(List<TypeMirror> types, String name) {
             this.types = types;
             this.name = name;
         }
@@ -280,7 +300,7 @@
             return parameters;
         }
 
-        public TypeMirror[] getTypes() {
+        public List<TypeMirror> getTypes() {
             return types;
         }
 
@@ -349,7 +369,7 @@
 
     private static String createTypeSignature(ParameterSpec spec, List<TypeDef> typeDefs, boolean typeOnly) {
         StringBuilder builder = new StringBuilder();
-        if (spec.getAllowedTypes().length > 1) {
+        if (spec.getAllowedTypes().size() > 1) {
             TypeDef foundTypeDef = null;
             for (TypeDef typeDef : typeDefs) {
                 if (typeDef.getParameters().contains(spec)) {
@@ -360,8 +380,8 @@
             if (foundTypeDef != null) {
                 builder.append("<" + foundTypeDef.getName() + ">");
             }
-        } else if (spec.getAllowedTypes().length == 1) {
-            builder.append(Utils.getSimpleName(spec.getAllowedTypes()[0]));
+        } else if (spec.getAllowedTypes().size() == 1) {
+            builder.append(Utils.getSimpleName(spec.getAllowedTypes().get(0)));
         } else {
             builder.append("void");
         }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateParser.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateParser.java	Thu Mar 14 01:09:43 2013 +0100
@@ -43,9 +43,8 @@
         return extensionParser;
     }
 
-    protected boolean verifyExclusiveMethodAnnotation(TypeElement type, Class<?>... annotationTypes) {
-        boolean valid = true;
-        List<ExecutableElement> methods = ElementFilter.methodsIn(type.getEnclosedElements());
+    protected void verifyExclusiveMethodAnnotation(Template template, Class<?>... annotationTypes) {
+        List<ExecutableElement> methods = ElementFilter.methodsIn(template.getTemplateType().getEnclosedElements());
         for (ExecutableElement method : methods) {
             List<AnnotationMirror> foundAnnotations = new ArrayList<>();
             for (int i = 0; i < annotationTypes.length; i++) {
@@ -61,34 +60,9 @@
                     annotationNames.add("@" + Utils.getSimpleName(mirror.getAnnotationType()));
                 }
 
-                for (AnnotationMirror mirror : foundAnnotations) {
-                    context.getLog().error(method, mirror, "Non exclusive usage of annotations %s.", annotationNames);
-                }
-                valid = false;
+                template.addError("Non exclusive usage of annotations %s.", annotationNames);
             }
         }
-        return valid;
-    }
-
-    protected boolean verifyTemplateType(TypeElement template, AnnotationMirror annotation) {
-        // annotation type on class path!?
-        boolean valid = true;
-        TypeElement annotationTypeElement = processingEnv.getElementUtils().getTypeElement(getAnnotationType().getCanonicalName());
-        if (annotationTypeElement == null) {
-            log.error(template, annotation, "Required class " + getAnnotationType().getName() + " is not on the classpath.");
-            valid = false;
-        }
-        if (template.getModifiers().contains(Modifier.PRIVATE)) {
-            log.error(template, annotation, "The annotated class must have at least package protected visibility.");
-            valid = false;
-        }
-
-        if (template.getModifiers().contains(Modifier.FINAL)) {
-            log.error(template, annotation, "The annotated class must not be final.");
-            valid = false;
-        }
-
-        return valid;
     }
 
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java	Thu Mar 14 01:09:43 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.*;
@@ -40,21 +41,21 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        TypeData targetType = findTypeByMethodName(method, mirror, "as");
+        TypeData targetType = findTypeByMethodName(method.getSimpleName().toString(), "as");
         if (targetType == null) {
             return null;
         }
         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");
+        TypeData targetType = findTypeByMethodName(method, "as");
+        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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java	Thu Mar 14 01:09:43 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.*;
@@ -40,22 +41,22 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        TypeData targetType = findTypeByMethodName(method, mirror, "is");
+        TypeData targetType = findTypeByMethodName(method.getSimpleName().toString(), "is");
         if (targetType == null) {
             return null;
         }
         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;
     }
 
     @Override
     public TypeCheckData create(TemplateMethod method) {
-        TypeData checkedType = findTypeByMethodName(method.getMethod(), method.getMarkerAnnotation(), "is");
+        TypeData checkedType = findTypeByMethodName(method, "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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java	Thu Mar 14 01:09:43 2013 +0100
@@ -30,21 +30,38 @@
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
 
-public class TypeData extends Template {
+public class TypeData extends MessageContainer {
 
-    protected TypeSystemData typeSystem;
+    private final TypeSystemData typeSystem;
+    private final AnnotationValue annotationValue;
     private final TypeMirror primitiveType;
     private final TypeMirror boxedType;
 
     private final List<TypeCastData> typeCasts = new ArrayList<>();
     private final List<TypeCheckData> typeChecks = new ArrayList<>();
 
-    public TypeData(TypeElement templateType, AnnotationMirror annotation, TypeMirror primitiveType, TypeMirror boxedType) {
-        super(templateType, annotation);
+    public TypeData(TypeSystemData typeSystem, AnnotationValue value, TypeMirror primitiveType, TypeMirror boxedType) {
+        this.typeSystem = typeSystem;
+        this.annotationValue = value;
         this.primitiveType = primitiveType;
         this.boxedType = boxedType;
     }
 
+    @Override
+    public Element getMessageElement() {
+        return typeSystem.getMessageElement();
+    }
+
+    @Override
+    public AnnotationMirror getMessageAnnotation() {
+        return typeSystem.getMessageAnnotation();
+    }
+
+    @Override
+    public AnnotationValue getMessageAnnotationValue() {
+        return annotationValue;
+    }
+
     void addTypeCast(TypeCastData typeCast) {
         this.typeCasts.add(typeCast);
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemCodeGenerator.java	Thu Mar 14 01:09:43 2013 +0100
@@ -167,8 +167,8 @@
 
             CodeTreeBuilder builder = method.createBuilder();
             builder.startReturn();
-            if (typeSystem.getTypes().length > 0) {
-                builder.typeLiteral(typeSystem.getTypes()[0].getBoxedType());
+            if (!typeSystem.getTypes().isEmpty()) {
+                builder.typeLiteral(typeSystem.getTypes().get(0).getBoxedType());
             } else {
                 builder.null_();
             }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemData.java	Thu Mar 14 01:09:43 2013 +0100
@@ -32,35 +32,42 @@
 
 public class TypeSystemData extends Template {
 
-    private final TypeData[] types;
-    private final TypeMirror[] primitiveTypeMirrors;
-    private final TypeMirror[] boxedTypeMirrors;
+    private List<TypeData> types;
+    private List<TypeMirror> primitiveTypeMirrors = new ArrayList<>();
+    private List<TypeMirror> boxedTypeMirrors = new ArrayList<>();
 
-    private final TypeMirror genericType;
+    private TypeMirror genericType;
+    private TypeData voidType;
+
+    public TypeSystemData(TypeElement templateType, AnnotationMirror annotation) {
+        super(templateType, null, annotation);
+    }
 
-    private final TypeData voidType;
+    void setTypes(List<TypeData> types) {
+        this.types = types;
+        if (types != null) {
+            for (TypeData typeData : types) {
+                primitiveTypeMirrors.add(typeData.getPrimitiveType());
+                boxedTypeMirrors.add(typeData.getBoxedType());
+            }
+        }
+    }
 
-    public TypeSystemData(TypeElement templateType, AnnotationMirror annotation, TypeData[] types, TypeMirror genericType, TypeData voidType) {
-        super(templateType, annotation);
-        this.types = types;
+    void setGenericType(TypeMirror genericType) {
         this.genericType = genericType;
+    }
+
+    void setVoidType(TypeData voidType) {
         this.voidType = voidType;
-        this.primitiveTypeMirrors = new TypeMirror[types.length];
-        for (int i = 0; i < types.length; i++) {
-            primitiveTypeMirrors[i] = types[i].getPrimitiveType();
-        }
+    }
 
-        this.boxedTypeMirrors = new TypeMirror[types.length];
-        for (int i = 0; i < types.length; i++) {
-            boxedTypeMirrors[i] = types[i].getBoxedType();
+    @Override
+    protected List<MessageContainer> findChildContainers() {
+        List<MessageContainer> sinks = new ArrayList<>();
+        if (types != null) {
+            sinks.addAll(types);
         }
-
-        for (TypeData type : types) {
-            type.typeSystem = this;
-        }
-        if (voidType != null) {
-            voidType.typeSystem = this;
-        }
+        return sinks;
     }
 
     public boolean isGeneric(TypeMirror type) {
@@ -71,16 +78,16 @@
         return voidType;
     }
 
-    public TypeData[] getTypes() {
-        return types;
+    public List<TypeMirror> getBoxedTypeMirrors() {
+        return boxedTypeMirrors;
     }
 
-    public TypeMirror[] getPrimitiveTypeMirrors() {
+    public List<TypeMirror> getPrimitiveTypeMirrors() {
         return primitiveTypeMirrors;
     }
 
-    public TypeMirror[] getBoxedTypeMirrors() {
-        return boxedTypeMirrors;
+    public List<TypeData> getTypes() {
+        return types;
     }
 
     public TypeMirror getGenericType() {
@@ -88,7 +95,7 @@
     }
 
     public TypeData getGenericTypeData() {
-        TypeData result = types[types.length - 1];
+        TypeData result = types.get(types.size() - 1);
         assert result.getBoxedType() == genericType;
         return result;
     }
@@ -111,7 +118,7 @@
         if (index == -1) {
             return null;
         }
-        return types[index];
+        return types.get(index);
     }
 
     public int findType(TypeData typeData) {
@@ -119,8 +126,8 @@
     }
 
     public int findType(TypeMirror type) {
-        for (int i = 0; i < types.length; i++) {
-            if (Utils.typeEquals(types[i].getPrimitiveType(), type)) {
+        for (int i = 0; i < types.size(); i++) {
+            if (Utils.typeEquals(types.get(i).getPrimitiveType(), type)) {
                 return i;
             }
         }
@@ -129,7 +136,7 @@
 
     @Override
     public String toString() {
-        return getClass().getSimpleName() + "[template = " + Utils.getSimpleName(getTemplateType()) + ", types = " + Arrays.toString(types) + "]";
+        return getClass().getSimpleName() + "[template = " + Utils.getSimpleName(getTemplateType()) + ", types = " + types + "]";
     }
 
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java	Thu Mar 14 01:09:43 2013 +0100
@@ -43,18 +43,24 @@
         return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null;
     }
 
-    protected TypeData findTypeByMethodName(ExecutableElement method, AnnotationMirror annotationMirror, String prefix) {
-        String methodName = method.getSimpleName().toString();
+    protected TypeData findTypeByMethodName(String methodName, String prefix) {
+        String typeName = methodName.substring(prefix.length(), methodName.length());
+        TypeData type = getTypeSystem().findType(typeName);
+        return type;
+    }
+
+    protected TypeData findTypeByMethodName(TemplateMethod method, String prefix) {
+        String methodName = method.getMethodName();
         if (!methodName.startsWith(prefix)) {
-            String annotationName = Utils.getSimpleName(annotationMirror.getAnnotationType());
-            getContext().getLog().error(method, "Methods annotated with %s must match the pattern '%s'.", annotationName, String.format("%s${typeName}", prefix));
+            String annotationName = Utils.getSimpleName(method.getMessageAnnotation().getAnnotationType());
+            method.addError("Methods annotated with %s must match the pattern '%s'.", annotationName, String.format("%s${typeName}", prefix));
             return null;
         }
         String typeName = methodName.substring(prefix.length(), methodName.length());
         TypeData type = getTypeSystem().findType(typeName);
         if (type == null) {
             String annotationName = TypeSystem.class.getSimpleName();
-            getContext().getLog().error(method, "Type '%s' is not declared in this @%s.", typeName, annotationName);
+            method.addError("Type '%s' is not declared in this @%s.", typeName, annotationName);
             return null;
         }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemParser.java	Thu Mar 14 01:09:43 2013 +0100
@@ -52,27 +52,39 @@
     protected TypeSystemData parse(Element element, AnnotationMirror mirror) {
         TypeElement templateType = (TypeElement) element;
         AnnotationMirror templateTypeAnnotation = mirror;
+        TypeSystemData typeSystem = new TypeSystemData(templateType, templateTypeAnnotation);
 
-        if (!verifyTemplateType(templateType, templateTypeAnnotation)) {
-            return null;
+        // annotation type on class path!?
+        TypeElement annotationTypeElement = processingEnv.getElementUtils().getTypeElement(getAnnotationType().getCanonicalName());
+        if (annotationTypeElement == null) {
+            typeSystem.addError("Required class %s is not on the classpath.", getAnnotationType().getName());
+        }
+        if (templateType.getModifiers().contains(Modifier.PRIVATE)) {
+            typeSystem.addError("A @%s must have at least package protected visibility.", getAnnotationType().getName());
         }
 
-        TypeData[] types = parseTypes(templateType, templateTypeAnnotation);
-        if (types == null) {
-            return null;
+        if (templateType.getModifiers().contains(Modifier.FINAL)) {
+            typeSystem.addError("The @%s must not be final.", getAnnotationType().getName());
+        }
+        if (typeSystem.hasErrors()) {
+            return typeSystem;
+        }
+
+        typeSystem.setTypes(parseTypes(typeSystem));
+        if (typeSystem.getTypes() == null) {
+            return typeSystem;
         }
 
         TypeMirror genericType = context.getType(Object.class);
-        TypeData voidType = new TypeData(templateType, templateTypeAnnotation, context.getType(void.class), context.getType(Void.class));
-
-        TypeSystemData typeSystem = new TypeSystemData(templateType, templateTypeAnnotation, types, genericType, voidType);
+        TypeData voidType = new TypeData(typeSystem, null, context.getType(void.class), context.getType(Void.class));
 
-        if (!verifyExclusiveMethodAnnotation(templateType, TypeCast.class, TypeCheck.class)) {
-            return null;
-        }
+        typeSystem.setGenericType(genericType);
+        typeSystem.setVoidType(voidType);
+
+        verifyExclusiveMethodAnnotation(typeSystem, TypeCast.class, TypeCheck.class);
 
         List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(templateType));
-        typeSystem.setExtensionElements(getExtensionParser().parseAll(templateType, elements));
+        typeSystem.setExtensionElements(getExtensionParser().parseAll(typeSystem, elements));
         if (typeSystem.getExtensionElements() != null) {
             elements.addAll(typeSystem.getExtensionElements());
         }
@@ -81,7 +93,7 @@
         List<TypeCheckData> checks = new TypeCheckParser(context, typeSystem).parse(elements);
 
         if (casts == null || checks == null) {
-            return null;
+            return typeSystem;
         }
 
         for (TypeCheckData check : checks) {
@@ -92,24 +104,15 @@
             cast.getTargetType().addTypeCast(cast);
         }
 
-        if (!verifyGenericTypeChecksAndCasts(types)) {
-            return null;
-        }
-
-        if (!verifyMethodSignatures(element, types)) {
-            return null;
-        }
-
-        if (!verifyNamesUnique(templateType, templateTypeAnnotation, types)) {
-            return null;
-        }
+        verifyGenericTypeChecksAndCasts(typeSystem);
+        verifyMethodSignatures(typeSystem);
+        verifyNamesUnique(typeSystem);
 
         return typeSystem;
     }
 
-    private boolean verifyGenericTypeChecksAndCasts(TypeData[] types) {
-        boolean valid = true;
-        for (TypeData type : types) {
+    private static void verifyGenericTypeChecksAndCasts(TypeSystemData typeSystem) {
+        for (TypeData type : typeSystem.getTypes()) {
             if (!type.getTypeChecks().isEmpty()) {
                 boolean hasGeneric = false;
                 for (TypeCheckData typeCheck : type.getTypeChecks()) {
@@ -119,10 +122,9 @@
                     }
                 }
                 if (!hasGeneric) {
-                    log.error(type.getTypeSystem().getTemplateType(), "No generic but specific @%s method %s for type %s specified. "
-                                    + "Specify a generic @%s method with parameter type %s to resolve this.", TypeCheck.class.getSimpleName(), TypeSystemCodeGenerator.isTypeMethodName(type),
-                                    Utils.getSimpleName(type.getBoxedType()), TypeCheck.class.getSimpleName(), Object.class.getSimpleName());
-                    valid = false;
+                    type.addError("No generic but specific @%s method %s for type %s specified. " + "Specify a generic @%s method with parameter type %s to resolve this.",
+                                    TypeCheck.class.getSimpleName(), TypeSystemCodeGenerator.isTypeMethodName(type), Utils.getSimpleName(type.getBoxedType()), TypeCheck.class.getSimpleName(),
+                                    Object.class.getSimpleName());
                 }
             }
             if (!type.getTypeCasts().isEmpty()) {
@@ -134,60 +136,55 @@
                     }
                 }
                 if (!hasGeneric) {
-                    log.error(type.getTypeSystem().getTemplateType(), "No generic but specific @%s method %s for type %s specified. "
-                                    + "Specify a generic @%s method with parameter type %s to resolve this.", TypeCast.class.getSimpleName(), TypeSystemCodeGenerator.asTypeMethodName(type),
-                                    Utils.getSimpleName(type.getBoxedType()), TypeCast.class.getSimpleName(), Object.class.getSimpleName());
-                    valid = false;
+                    type.addError("No generic but specific @%s method %s for type %s specified. " + "Specify a generic @%s method with parameter type %s to resolve this.",
+                                    TypeCast.class.getSimpleName(), TypeSystemCodeGenerator.asTypeMethodName(type), Utils.getSimpleName(type.getBoxedType()), TypeCast.class.getSimpleName(),
+                                    Object.class.getSimpleName());
                 }
             }
         }
-        return valid;
     }
 
-    private TypeData[] parseTypes(TypeElement templateType, AnnotationMirror templateTypeAnnotation) {
-        List<TypeMirror> typeMirrors = Utils.getAnnotationValueList(templateTypeAnnotation, "value");
-        if (typeMirrors.size() == 0) {
-            log.error(templateType, templateTypeAnnotation, "At least one type must be defined.");
-            return null;
+    private List<TypeData> parseTypes(TypeSystemData typeSystem) {
+        List<TypeData> types = new ArrayList<>();
+        List<TypeMirror> typeMirrors = Utils.getAnnotationValueList(TypeMirror.class, typeSystem.getTemplateTypeAnnotation(), "value");
+        if (typeMirrors.isEmpty()) {
+            typeSystem.addError("At least one type must be defined.");
+            return types;
         }
 
-        final AnnotationValue annotationValue = Utils.getAnnotationValue(templateTypeAnnotation, "value");
+        final AnnotationValue annotationValue = Utils.getAnnotationValue(typeSystem.getTemplateTypeAnnotation(), "value");
         final TypeMirror objectType = context.getType(Object.class);
 
-        List<TypeData> types = new ArrayList<>();
         for (TypeMirror primitiveType : typeMirrors) {
+            TypeMirror boxedType = Utils.boxType(context, primitiveType);
+            TypeData typeData = new TypeData(typeSystem, annotationValue, primitiveType, boxedType);
 
             if (isPrimitiveWrapper(primitiveType)) {
-                log.error(templateType, templateTypeAnnotation, annotationValue, "Types must not contain primitive wrapper types.");
-                continue;
+                typeData.addError("Types must not contain primitive wrapper types.");
             }
 
-            TypeMirror boxedType = Utils.boxType(context, primitiveType);
-
             if (Utils.typeEquals(boxedType, objectType)) {
-                log.error(templateType, templateTypeAnnotation, annotationValue, "Types must not contain the generic type java.lang.Object.");
-                continue;
+                typeData.addError("Types must not contain the generic type java.lang.Object.");
             }
 
-            types.add(new TypeData(templateType, templateTypeAnnotation, primitiveType, boxedType));
+            types.add(typeData);
         }
 
-        verifyTypeOrder(templateType, templateTypeAnnotation, annotationValue, types);
+        verifyTypeOrder(types);
 
-        types.add(new TypeData(templateType, templateTypeAnnotation, objectType, objectType));
+        types.add(new TypeData(typeSystem, annotationValue, objectType, objectType));
 
-        return types.toArray(new TypeData[types.size()]);
+        return types;
     }
 
-    private void verifyTypeOrder(TypeElement templateType, AnnotationMirror templateTypeAnnotation, AnnotationValue annotationValue, List<TypeData> types) {
+    private static void verifyTypeOrder(List<TypeData> types) {
         Map<String, List<String>> invalidTypes = new HashMap<>();
 
         for (int i = types.size() - 1; i >= 0; i--) {
             TypeData typeData = types.get(i);
             TypeMirror type = typeData.getBoxedType();
             if (invalidTypes.containsKey(Utils.getQualifiedName(type))) {
-                log.error(templateType, templateTypeAnnotation, annotationValue, "Invalid type order. The type(s) %s are inherited from a earlier defined type %s.",
-                                invalidTypes.get(Utils.getQualifiedName(type)), Utils.getQualifiedName(type));
+                typeData.addError("Invalid type order. The type(s) %s are inherited from a earlier defined type %s.", invalidTypes.get(Utils.getQualifiedName(type)), Utils.getQualifiedName(type));
             }
             List<String> nextInvalidTypes = Utils.getQualifiedSuperTypeNames(Utils.fromTypeMirror(type));
             nextInvalidTypes.add(getQualifiedName(type));
@@ -216,19 +213,18 @@
         return false;
     }
 
-    private boolean verifyMethodSignatures(Element element, TypeData[] types) {
+    private void verifyMethodSignatures(TypeSystemData typeSystem) {
         Set<String> generatedIsMethodNames = new HashSet<>();
         Set<String> generatedAsMethodNames = new HashSet<>();
         Set<String> generatedExpectMethodNames = new HashSet<>();
 
-        for (TypeData typeData : types) {
+        for (TypeData typeData : typeSystem.getTypes()) {
             generatedIsMethodNames.add(TypeSystemCodeGenerator.isTypeMethodName(typeData));
             generatedAsMethodNames.add(TypeSystemCodeGenerator.asTypeMethodName(typeData));
             generatedExpectMethodNames.add(TypeSystemCodeGenerator.expectTypeMethodName(typeData));
         }
 
-        boolean valid = true;
-        List<ExecutableElement> methods = ElementFilter.methodsIn(element.getEnclosedElements());
+        List<ExecutableElement> methods = ElementFilter.methodsIn(typeSystem.getTemplateType().getEnclosedElements());
         for (ExecutableElement method : methods) {
             if (method.getModifiers().contains(Modifier.PRIVATE)) {
                 // will not conflict overridden methods
@@ -238,51 +234,48 @@
             }
             String methodName = method.getSimpleName().toString();
             if (generatedIsMethodNames.contains(methodName)) {
-                valid &= verifyIsMethod(method);
+                verifyIsMethod(typeSystem, method);
             } else if (generatedAsMethodNames.contains(methodName)) {
-                valid &= verifyAsMethod(method);
+                verifyAsMethod(typeSystem, method);
             } else if (generatedExpectMethodNames.contains(methodName)) {
-                valid &= verifyExpectMethod(method);
+                verifyExpectMethod(typeSystem);
             }
         }
-        return valid;
     }
 
-    private boolean verifyIsMethod(ExecutableElement method) {
+    private boolean verifyIsMethod(TypeSystemData typeSystem, ExecutableElement method) {
         AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, TypeCheck.class);
         if (mirror == null) {
-            log.error(method, "Method starting with the pattern is${typeName} must be annotated with @%s.", TypeCheck.class.getSimpleName());
+            typeSystem.addError("Method starting with the pattern is${typeName} must be annotated with @%s.", TypeCheck.class.getSimpleName());
             return false;
         }
         return true;
     }
 
-    private boolean verifyAsMethod(ExecutableElement method) {
+    private boolean verifyAsMethod(TypeSystemData typeSystem, ExecutableElement method) {
         AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, TypeCast.class);
         if (mirror == null) {
-            log.error(method, "Method starting with the pattern as${typeName} must be annotated with @%s.", TypeCast.class.getSimpleName());
+            typeSystem.addError("Method starting with the pattern as${typeName} must be annotated with @%s.", TypeCast.class.getSimpleName());
             return false;
         }
         return true;
     }
 
-    private boolean verifyExpectMethod(ExecutableElement method) {
-        log.error(method, "Method starting with the pattern expect${typeName} must not be declared manually.");
+    private static boolean verifyExpectMethod(TypeSystemData typeSystem) {
+        typeSystem.addError("Method starting with the pattern expect${typeName} must not be declared manually.");
         return false;
     }
 
-    private boolean verifyNamesUnique(TypeElement templateType, AnnotationMirror templateTypeAnnotation, TypeData[] types) {
-        boolean valid = true;
-        for (int i = 0; i < types.length; i++) {
-            for (int j = i + 1; j < types.length; j++) {
-                String name1 = Utils.getSimpleName(types[i].getBoxedType());
-                String name2 = Utils.getSimpleName(types[j].getBoxedType());
+    private static void verifyNamesUnique(TypeSystemData typeSystem) {
+        List<TypeData> types = typeSystem.getTypes();
+        for (int i = 0; i < types.size(); i++) {
+            for (int j = i + 1; j < types.size(); j++) {
+                String name1 = Utils.getSimpleName(types.get(i).getBoxedType());
+                String name2 = Utils.getSimpleName(types.get(j).getBoxedType());
                 if (name1.equalsIgnoreCase(name2)) {
-                    log.error(templateType, templateTypeAnnotation, "Two types result in the same name: %s, %s.", name1, name2);
-                    valid = false;
+                    typeSystem.addError("Two types result in the same name: %s, %s.", name1, name2);
                 }
             }
         }
-        return valid;
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java	Thu Mar 14 01:09:43 2013 +0100
@@ -27,8 +27,11 @@
 import java.util.*;
 
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.sl.nodes.ArithmeticNodeFactory.AddNodeFactory;
+import com.oracle.truffle.sl.nodes.ArithmeticNodeFactory.DivNodeFactory;
+import com.oracle.truffle.sl.nodes.ArithmeticNodeFactory.MulNodeFactory;
+import com.oracle.truffle.sl.nodes.ArithmeticNodeFactory.SubNodeFactory;
 import com.oracle.truffle.sl.nodes.*;
-import com.oracle.truffle.sl.nodes.ArithmeticNodeFactory.*;
 
 public class NodeFactory {
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLTypes.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLTypes.java	Thu Mar 14 01:09:43 2013 +0100
@@ -41,7 +41,7 @@
             return (int) value;
         } else {
             int result = ((BigInteger) value).intValue();
-            assert BigInteger.valueOf(result).equals(value) : "Loosing precision";
+            assert BigInteger.valueOf(result).equals(value) : "Losing precision";
             return result;
         }
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java	Thu Mar 14 01:09:43 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,13 +58,12 @@
         }
 
         @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();
         }
     }
@@ -85,16 +78,16 @@
             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);
         }
+
     }
 
     public abstract static class DivNode extends ArithmeticNode {
@@ -107,14 +100,13 @@
             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);
         }
     }
@@ -129,16 +121,16 @@
             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);
         }
+
     }
 
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LessThanNode.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LessThanNode.java	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TypedNode.java	Thu Mar 14 01:09:43 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	Thu Mar 14 01:09:32 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java	Thu Mar 14 01:09:43 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 writeGeneric(VirtualFrame frame, Object right) {
         frame.setObject(slot, right);
         return right;
     }
--- a/make/build-graal.xml	Thu Mar 14 01:09:32 2013 +0100
+++ b/make/build-graal.xml	Thu Mar 14 01:09:43 2013 +0100
@@ -34,7 +34,7 @@
 
   <target name="compile">
     <mkdir dir="${classes.dir}"/>
-    <javac srcdir="${src.dir}" destdir="${classes.dir}" debug="on">
+    <javac srcdir="${src.dir}" destdir="${classes.dir}" debug="on" includeantruntime="false">
       <include name="com.oracle.graal.*/**"/>
       <exclude name="com.oracle.graal.test/**"/>
       <exclude name="com.oracle.graal.*.test/**"/>
--- a/make/windows/makefiles/projectcreator.make	Thu Mar 14 01:09:32 2013 +0100
+++ b/make/windows/makefiles/projectcreator.make	Thu Mar 14 01:09:43 2013 +0100
@@ -145,8 +145,10 @@
  -ignorePath_TARGET c1_
 
 ProjectCreatorIDEOptionsIgnoreGraal=\
- -ignorePath_TARGET graal
- 
+ -ignorePath_TARGET src/share/vm/graal \
+ -ignorePath_TARGET graal/generated \
+ -ignorePath_TARGET vm/graal
+
 ProjectCreatorIDEOptionsIgnoreCompiler2=\
  -ignorePath_TARGET compiler2 \
  -ignorePath_TARGET tiered \
@@ -175,7 +177,6 @@
 ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \
  -define_compiler1 COMPILER1 \
  -ignorePath_compiler1 core \
- -ignorePath_compiler1 src/share/vm/graal \
  $(ProjectCreatorIDEOptionsIgnoreGraal:TARGET=compiler1) \
  $(ProjectCreatorIDEOptionsIgnoreCompiler2:TARGET=compiler1)
 
@@ -185,7 +186,6 @@
 ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \
  -define_graal GRAAL \
  -ignorePath_graal core \
- -ignorePath_graal src/share/vm/c1 \
  $(ProjectCreatorIDEOptionsIgnoreCompiler1:TARGET=graal) \
  $(ProjectCreatorIDEOptionsIgnoreCompiler2:TARGET=graal)
 
@@ -195,8 +195,9 @@
 #NOTE! This list must be kept in sync with GENERATED_NAMES in adlc.make.
 ProjectCreatorIDEOptions=$(ProjectCreatorIDEOptions) \
  -define_compiler2 COMPILER2 \
+ -define_compiler2 GRAAL \
  -ignorePath_compiler2 core \
- -ignorePath_compiler2 src/share/vm/graal \
+ -ignorePath_compiler2 graal/generated \
  -additionalFile_compiler2 $(Platform_arch_model).ad \
  -additionalFile_compiler2 ad_$(Platform_arch_model).cpp \
  -additionalFile_compiler2 ad_$(Platform_arch_model).hpp \
@@ -209,7 +210,6 @@
  -additionalFile_compiler2 ad_$(Platform_arch_model)_pipeline.cpp \
  -additionalFile_compiler2 adGlobals_$(Platform_arch_model).hpp \
  -additionalFile_compiler2 dfa_$(Platform_arch_model).cpp \
- $(ProjectCreatorIDEOptionsIgnoreGraal:TARGET=compiler2) \
  $(ProjectCreatorIDEOptionsIgnoreCompiler1:TARGET=compiler2)
 
 # Add in the jvmti (JSR-163) options
--- a/mx/commands.py	Thu Mar 14 01:09:32 2013 +0100
+++ b/mx/commands.py	Thu Mar 14 01:09:43 2013 +0100
@@ -316,7 +316,7 @@
         return join(jdk, 'jre', 'lib', _arch(), 'jvm.cfg')
     return join(_vmLibDirInJdk(jdk), 'jvm.cfg')
 
-def _jdk(build='product', create=False):
+def _jdk(build='product', vmToCheck=None, create=False):
     """
     Get the JDK into which Graal is installed, creating it first if necessary.
     """
@@ -344,7 +344,6 @@
             if not exists(jvmCfg):
                 mx.abort(jvmCfg + ' does not exist')
 
-            lines = []
             defaultVM = None
             with open(jvmCfg) as f:
                 for line in f:
@@ -353,17 +352,14 @@
                         assert len(parts) == 2, parts
                         assert parts[1] == 'KNOWN', parts[1]
                         defaultVM = parts[0][1:]
-                        lines.append('-' + defaultVM + '0 KNOWN\n')
-                    lines.append(line)
 
             assert defaultVM is not None, 'Could not find default VM in ' + jvmCfg
             if mx.get_os() != 'windows':
                 chmodRecursive(jdk, 0755)
             shutil.copytree(join(_vmLibDirInJdk(jdk), defaultVM), join(_vmLibDirInJdk(jdk), defaultVM + '0'))
 
-            with open(jvmCfg, 'w') as f:
-                for line in lines:
-                    f.write(line)
+            with open(jvmCfg, 'w') as fp:
+                print >> fp, '-' + defaultVM + '0 KNOWN'
 
             # Install a copy of the disassembler library
             try:
@@ -372,10 +368,21 @@
                 pass
     else:
         if not exists(jdk):
-            mx.abort('The ' + build + ' VM has not been created - run \'mx clean; mx build ' + build + '\'')
+            mx.abort('The ' + build + ' VM has not been created - run "mx build ' + build + '"')
             
     _installGraalJarInJdks(mx.distribution('GRAAL'))
     
+    if vmToCheck is not None:
+        jvmCfg = _vmCfgInJdk(jdk)
+        found = False
+        with open(jvmCfg) as f:
+            for line in f:
+                if line.strip() == '-' + vmToCheck + ' KNOWN':
+                    found = True
+                    break
+        if not found:
+            mx.abort('The ' + build + ' ' + vmToCheck + ' VM has not been created - run "mx --vm ' + vmToCheck + ' build ' + build + '"')
+        
     return jdk
 
 def _installGraalJarInJdks(graalDist):
@@ -588,23 +595,18 @@
             mx.abort(jvmCfg + ' does not exist')
 
         prefix = '-' + vm
-        vmKnown = prefix + ' KNOWN\n'
-        lines = []
+        vmKnown = prefix + ' KNOWN'
         with open(jvmCfg) as f:
             for line in f:
-                if vmKnown in line:
+                if vmKnown == line.strip():
                     found = True
                     break
-                if not line.startswith(prefix):
-                    lines.append(line)
         if not found:
             mx.log('Appending "' + prefix + ' KNOWN" to ' + jvmCfg)
-            lines.append(vmKnown)
             if mx.get_os() != 'windows':
                 os.chmod(jvmCfg, 0755)
-            with open(jvmCfg, 'w') as f:
-                for line in lines:
-                    f.write(line)
+            with open(jvmCfg, 'a') as f:
+                print >> f, vmKnown
 
         if exists(timestampFile):
             os.utime(timestampFile, None)
@@ -626,7 +628,7 @@
         vm = _vm
 
     build = vmbuild if vmbuild is not None else _vmbuild if _vmSourcesAvailable else 'product'
-    jdk = _jdk(build)
+    jdk = _jdk(build, vmToCheck=vm)
     mx.expand_project_in_args(args)
     if _make_eclipse_launch:
         mx.make_eclipse_launch(args, 'graal-' + build, name=None, deps=mx.project('com.oracle.graal.hotspot').all_deps([], True))
@@ -818,6 +820,10 @@
         tasks.append(t.stop())
 
         _vmbuild = 'product'
+        t = Task('BootstrapWithRegisterPressure:product')
+        vm(['-G:RegisterPressure=rbx,r11,r14,xmm3,xmm11,xmm14', '-esa', '-version'])
+        tasks.append(t.stop())
+        
         originalVm = _vm
         _vm = 'server' # hosted mode
         t = Task('UnitTests:hosted-product')
--- a/mx/projects	Thu Mar 14 01:09:32 2013 +0100
+++ b/mx/projects	Thu Mar 14 01:09:43 2013 +0100
@@ -366,21 +366,29 @@
 # 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
+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
-project@com.oracle.truffle.codegen.processor@dependencies=com.oracle.truffle.api.codegen,com.oracle.truffle.api
+project@com.oracle.truffle.codegen.processor@dependencies=com.oracle.truffle.api.codegen
 project@com.oracle.truffle.codegen.processor@checkstyle=com.oracle.graal.graph
 project@com.oracle.truffle.codegen.processor@javaCompliance=1.7
 
 # truffle.sl
 project@com.oracle.truffle.sl@subDir=graal
 project@com.oracle.truffle.sl@sourceDirs=src
-project@com.oracle.truffle.sl@dependencies=com.oracle.truffle.api.codegen,com.oracle.truffle.api
+project@com.oracle.truffle.sl@dependencies=com.oracle.truffle.api.codegen
 project@com.oracle.truffle.sl@checkstyle=com.oracle.graal.graph
 project@com.oracle.truffle.sl@javaCompliance=1.7
 project@com.oracle.truffle.sl@annotationProcessors=com.oracle.truffle.codegen.processor
--- a/src/cpu/x86/vm/graalRuntime_x86.cpp	Thu Mar 14 01:09:32 2013 +0100
+++ b/src/cpu/x86/vm/graalRuntime_x86.cpp	Thu Mar 14 01:09:43 2013 +0100
@@ -925,19 +925,6 @@
       __ movptr(rsp, rbp);
       __ pop(rbp);
 
-      Label nonNullExceptionOop;
-      __ testptr(rax, rax);
-      __ jcc(Assembler::notZero, nonNullExceptionOop);
-      {
-        __ enter();
-        oop_maps = new OopMapSet();
-        OopMap* oop_map = save_live_registers(sasm, 0);
-        int call_offset = __ call_RT(rax, noreg, (address)create_null_exception, 0);
-        oop_maps->add_gc_map(call_offset, oop_map);
-        __ leave();
-      }
-      __ bind(nonNullExceptionOop);
-
       __ set_info("unwind_exception", dont_gc_arguments);
       // note: no stubframe since we are about to leave the current
       //       activation and we are calling a leaf VM function only.
--- a/src/cpu/x86/vm/macroAssembler_x86.cpp	Thu Mar 14 01:09:32 2013 +0100
+++ b/src/cpu/x86/vm/macroAssembler_x86.cpp	Thu Mar 14 01:09:43 2013 +0100
@@ -2058,7 +2058,7 @@
 }
 
 // !defined(COMPILER2) is because of stupid core builds
-#if !defined(_LP64) || defined(COMPILER1) || !defined(COMPILER2)
+#if !defined(_LP64) || defined(COMPILER1) || !defined(COMPILER2) || defined(GRAAL)
 void MacroAssembler::empty_FPU_stack() {
   if (VM_Version::supports_mmx()) {
     emms();
--- a/src/share/tools/ProjectCreator/FileTreeCreatorVC10.java	Thu Mar 14 01:09:32 2013 +0100
+++ b/src/share/tools/ProjectCreator/FileTreeCreatorVC10.java	Thu Mar 14 01:09:43 2013 +0100
@@ -50,7 +50,8 @@
                if (addFile.equals(fileName)) {
                   // supress any ignore
                   // TODO - may need some adjustments
-                  if (file.toAbsolutePath().toString().contains(cfg.get("Flavour"))) {
+                  String relativePath = startDir.toUri().relativize(file.toUri()).getPath();
+                  if (relativePath.contains(cfg.get("Flavour"))) {
                      currentFileAttr.removeFromIgnored(cfg);
                   }
                }