changeset 9239:6aea59f0965c

Merge.
author Christian Haeubl <haeubl@ssw.jku.at>
date Tue, 23 Apr 2013 08:44:07 +0200
parents 8f01fe16e473 (current diff) 374ece5ff845 (diff)
children 3370b7abcc6e
files
diffstat 85 files changed, 2339 insertions(+), 1341 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationReason.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationReason.java	Tue Apr 23 08:44:07 2013 +0200
@@ -25,7 +25,6 @@
 /**
  * Enumeration of reasons for why a deoptimization is happening.
  */
-// @formatter:off
 public enum DeoptimizationReason {
     None,
     NullCheckException,
--- a/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodSubstitution.java	Tue Apr 23 08:44:07 2013 +0200
@@ -59,7 +59,7 @@
      * Determines if this method should be substituted in all cases, even if inlining thinks it is
      * not important.
      * 
-     * Not that this is still depending on whether inlining sees the correct call target, so it's
+     * Note that this is still depending on whether inlining sees the correct call target, so it's
      * only a hard guarantee for static and special invocations.
      */
     boolean forced() default false;
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Tue Apr 23 08:44:07 2013 +0200
@@ -156,23 +156,15 @@
         append(createMove(dst, src));
     }
 
-    private AMD64AddressValue prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) {
+    private AMD64AddressValue prepareAddress(Kind kind, Value base, long displacement, Value index, int scale) {
         AllocatableValue baseRegister;
-        int finalDisp = displacement;
+        long finalDisp = displacement;
         if (isConstant(base)) {
             if (asConstant(base).isNull()) {
                 baseRegister = AllocatableValue.UNUSED;
-            } else if (asConstant(base).getKind() != Kind.Object) {
-                long newDisplacement = displacement + asConstant(base).asLong();
-                if (NumUtil.isInt(newDisplacement)) {
-                    assert !runtime.needsDataPatch(asConstant(base));
-                    finalDisp = (int) newDisplacement;
-                    baseRegister = AllocatableValue.UNUSED;
-                } else {
-                    Variable newBase = newVariable(Kind.Long);
-                    emitMove(newBase, base);
-                    baseRegister = newBase;
-                }
+            } else if (asConstant(base).getKind() != Kind.Object && !runtime.needsDataPatch(asConstant(base))) {
+                finalDisp += asConstant(base).asLong();
+                baseRegister = AllocatableValue.UNUSED;
             } else {
                 baseRegister = load(base);
             }
@@ -187,19 +179,8 @@
         if (index != Value.ILLEGAL && scale != 0) {
             scaleEnum = Scale.fromInt(scale);
             if (isConstant(index)) {
-                long newDisplacement = finalDisp + asConstant(index).asLong() * scale;
-                // only use the constant index if the resulting displacement fits into a 32 bit
-                // offset
-                if (NumUtil.isInt(newDisplacement)) {
-                    finalDisp = (int) newDisplacement;
-                    indexRegister = AllocatableValue.UNUSED;
-                } else {
-                    // create a temporary variable for the index, the pointer load cannot handle a
-                    // constant index
-                    Variable newIndex = newVariable(Kind.Long);
-                    emitMove(newIndex, index);
-                    indexRegister = newIndex;
-                }
+                finalDisp += asConstant(index).asLong() * scale;
+                indexRegister = AllocatableValue.UNUSED;
             } else {
                 indexRegister = asAllocatable(index);
             }
@@ -208,11 +189,27 @@
             scaleEnum = Scale.Times1;
         }
 
-        return new AMD64AddressValue(kind, baseRegister, indexRegister, scaleEnum, finalDisp);
+        int displacementInt;
+        if (NumUtil.isInt(finalDisp)) {
+            displacementInt = (int) finalDisp;
+        } else {
+            displacementInt = 0;
+            AllocatableValue displacementRegister = load(Constant.forLong(finalDisp));
+            if (baseRegister == AllocatableValue.UNUSED) {
+                baseRegister = displacementRegister;
+            } else if (indexRegister == AllocatableValue.UNUSED) {
+                indexRegister = displacementRegister;
+                scaleEnum = Scale.Times1;
+            } else {
+                baseRegister = emitAdd(baseRegister, displacementRegister);
+            }
+        }
+
+        return new AMD64AddressValue(kind, baseRegister, indexRegister, scaleEnum, displacementInt);
     }
 
     @Override
-    public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, DeoptimizingNode deopting) {
+    public Variable emitLoad(Kind kind, Value base, long displacement, Value index, int scale, DeoptimizingNode deopting) {
         AMD64AddressValue loadAddress = prepareAddress(kind, base, displacement, index, scale);
         Variable result = newVariable(loadAddress.getKind());
         append(new LoadOp(result, loadAddress, deopting != null ? state(deopting) : null));
@@ -220,7 +217,7 @@
     }
 
     @Override
-    public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, DeoptimizingNode deopting) {
+    public void emitStore(Kind kind, Value base, long displacement, Value index, int scale, Value inputVal, DeoptimizingNode deopting) {
         AMD64AddressValue storeAddress = prepareAddress(kind, base, displacement, index, scale);
         LIRFrameState state = deopting != null ? state(deopting) : null;
 
@@ -237,7 +234,7 @@
     }
 
     @Override
-    public Variable emitLea(Value base, int displacement, Value index, int scale) {
+    public Variable emitLea(Value base, long displacement, Value index, int scale) {
         Variable result = newVariable(target().wordKind);
         AMD64AddressValue address = prepareAddress(result.getKind(), base, displacement, index, scale);
         append(new LeaOp(result, address));
--- a/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXLIRGenerator.java	Tue Apr 23 08:44:07 2013 +0200
@@ -137,7 +137,7 @@
         }
     }
 
-    private PTXAddressValue prepareAddress(Kind kind, Value base, int displacement, Value index, int scale) {
+    private PTXAddressValue prepareAddress(Kind kind, Value base, long displacement, Value index, int scale) {
         AllocatableValue baseRegister;
         long finalDisp = displacement;
         if (isConstant(base)) {
@@ -181,7 +181,7 @@
     }
 
     @Override
-    public Variable emitLoad(Kind kind, Value base, int displacement, Value index, int scale, DeoptimizingNode deopting) {
+    public Variable emitLoad(Kind kind, Value base, long displacement, Value index, int scale, DeoptimizingNode deopting) {
         PTXAddressValue loadAddress = prepareAddress(kind, base, displacement, index, scale);
         Variable result = newVariable(loadAddress.getKind());
         append(new LoadOp(result, loadAddress, deopting != null ? state(deopting) : null));
@@ -189,14 +189,14 @@
     }
 
     @Override
-    public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value inputVal, DeoptimizingNode deopting) {
+    public void emitStore(Kind kind, Value base, long displacement, Value index, int scale, Value inputVal, DeoptimizingNode deopting) {
         PTXAddressValue storeAddress = prepareAddress(kind, base, displacement, index, scale);
         Variable input = load(inputVal);
         append(new StoreOp(storeAddress, input, deopting != null ? state(deopting) : null));
     }
 
     @Override
-    public Variable emitLea(Value base, int displacement, Value index, int scale) {
+    public Variable emitLea(Value base, long displacement, Value index, int scale) {
         throw new InternalError("NYI");
     }
 
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Tue Apr 23 08:44:07 2013 +0200
@@ -214,19 +214,19 @@
     }
 
     @Override
-    public Value emitLoad(Kind kind, Value base, int displacement, Value index, int scale, DeoptimizingNode canTrap) {
+    public Value emitLoad(Kind kind, Value base, long displacement, Value index, int scale, DeoptimizingNode canTrap) {
         // SPARC: Auto-generated method stub
         return null;
     }
 
     @Override
-    public void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value input, DeoptimizingNode canTrap) {
+    public void emitStore(Kind kind, Value base, long displacement, Value index, int scale, Value input, DeoptimizingNode canTrap) {
         // SPARC: Auto-generated method stub
 
     }
 
     @Override
-    public Value emitLea(Value base, int displacement, Value index, int scale) {
+    public Value emitLea(Value base, long displacement, Value index, int scale) {
         // SPARC: Auto-generated method stub
         return null;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Apr 23 08:44:07 2013 +0200
@@ -363,6 +363,7 @@
     public long logPrimitiveStub;
     public long logObjectStub;
     public long logPrintfStub;
+    public long stubPrintfStub;
     public int deoptReasonNone;
     public long threadIsInterruptedStub;
     public long identityHashCodeStub;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Tue Apr 23 08:44:07 2013 +0200
@@ -262,6 +262,14 @@
                         /* arg2:     value */                       Kind.Long,
                         /* arg3:     value */                       Kind.Long));
 
+        addRuntimeCall(Stub.STUB_PRINTF, config.stubPrintfStub,
+                        /*           temps */ null,
+                        /*             ret */ ret(Kind.Void),
+                        /* arg0:    format */ javaCallingConvention(Kind.Long,
+                        /* arg1:     value */                       Kind.Long,
+                        /* arg2:     value */                       Kind.Long,
+                        /* arg3:     value */                       Kind.Long));
+
         addRuntimeCall(LOG_OBJECT, config.logObjectStub,
                         /*           temps */ null,
                         /*             ret */ ret(Kind.Void),
@@ -507,7 +515,7 @@
         if (n instanceof ArrayLengthNode) {
             ArrayLengthNode arrayLengthNode = (ArrayLengthNode) n;
             ValueNode array = arrayLengthNode.array();
-            ReadNode arrayLengthRead = graph.add(new ReadNode(array, LocationNode.create(LocationNode.FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt()));
+            ReadNode arrayLengthRead = graph.add(new ReadNode(array, ConstantLocationNode.create(LocationNode.FINAL_LOCATION, Kind.Int, config.arrayLengthOffset, graph), StampFactory.positiveInt()));
             arrayLengthRead.dependencies().add(tool.createNullCheckGuard(array));
             graph.replaceFixedWithFixed(arrayLengthNode, arrayLengthRead);
         } else if (n instanceof Invoke) {
@@ -533,8 +541,9 @@
                             // as HotSpot does not guarantee they are final values.
                             assert vtableEntryOffset > 0;
                             LoadHubNode hub = graph.add(new LoadHubNode(receiver, wordKind));
-                            ReadNode metaspaceMethod = graph.add(new ReadNode(hub, LocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph), StampFactory.forKind(wordKind())));
-                            ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, LocationNode.create(LocationNode.ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph),
+                            ReadNode metaspaceMethod = graph.add(new ReadNode(hub, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, vtableEntryOffset, graph),
+                                            StampFactory.forKind(wordKind())));
+                            ReadNode compiledEntry = graph.add(new ReadNode(metaspaceMethod, ConstantLocationNode.create(LocationNode.ANY_LOCATION, wordKind, config.methodCompiledEntryOffset, graph),
                                             StampFactory.forKind(wordKind())));
 
                             loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters, invoke.asNode().stamp(), signature, callTarget.targetMethod(),
@@ -558,7 +567,7 @@
             HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) loadField.field();
             ValueNode object = loadField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : loadField.object();
             assert loadField.kind() != Kind.Illegal;
-            ReadNode memoryRead = graph.add(new ReadNode(object, LocationNode.create(field, field.getKind(), field.offset(), graph), loadField.stamp()));
+            ReadNode memoryRead = graph.add(new ReadNode(object, ConstantLocationNode.create(field, field.getKind(), field.offset(), graph), loadField.stamp()));
             memoryRead.dependencies().add(tool.createNullCheckGuard(object));
 
             graph.replaceFixedWithFixed(loadField, memoryRead);
@@ -573,7 +582,7 @@
             StoreFieldNode storeField = (StoreFieldNode) n;
             HotSpotResolvedJavaField field = (HotSpotResolvedJavaField) storeField.field();
             ValueNode object = storeField.isStatic() ? ConstantNode.forObject(field.getDeclaringClass().mirror(), this, graph) : storeField.object();
-            LocationNode location = LocationNode.create(field, field.getKind(), field.offset(), graph);
+            LocationNode location = ConstantLocationNode.create(field, field.getKind(), field.offset(), graph);
             WriteBarrierType barrierType = getFieldStoreBarrierType(storeField);
             WriteNode memoryWrite = graph.add(new WriteNode(object, storeField.value(), location, barrierType));
             memoryWrite.dependencies().add(tool.createNullCheckGuard(object));
@@ -621,7 +630,7 @@
                     }
                 } else {
                     LoadHubNode arrayClass = graph.add(new LoadHubNode(array, wordKind));
-                    LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph);
+                    LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.arrayClassElementOffset, graph);
                     FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, location, null, StampFactory.forKind(wordKind())));
                     CheckCastDynamicNode checkcast = graph.add(new CheckCastDynamicNode(arrayElementKlass, value));
                     graph.addBeforeFixed(storeIndexed, checkcast);
@@ -656,7 +665,7 @@
         } else if (n instanceof LoadHubNode) {
             LoadHubNode loadHub = (LoadHubNode) n;
             assert loadHub.kind() == wordKind;
-            LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph);
+            LocationNode location = ConstantLocationNode.create(LocationNode.FINAL_LOCATION, wordKind, config.hubOffset, graph);
             ValueNode object = loadHub.object();
             assert !object.isConstant() || object.asConstant().isNull();
             ValueNode guard = tool.createNullCheckGuard(object);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -0,0 +1,61 @@
+/*
+ * 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.graal.hotspot.nodes;
+
+import static com.oracle.graal.graph.UnsafeAccess.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Converts a compile-time constant Java string into a malloc'ed C string. The malloc'ed string is
+ * never reclaimed so this should only be used for strings in permanent code such as compiled stubs.
+ */
+public final class CStringNode extends FloatingNode implements Lowerable {
+
+    private final String string;
+
+    public CStringNode(String string) {
+        super(StampFactory.forWord());
+        this.string = string;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        byte[] formatBytes = string.getBytes();
+        long cstring = unsafe.allocateMemory(formatBytes.length + 1);
+        for (int i = 0; i < formatBytes.length; i++) {
+            unsafe.putByte(cstring + i, formatBytes[i]);
+        }
+        unsafe.putByte(cstring + formatBytes.length, (byte) 0);
+        StructuredGraph graph = (StructuredGraph) graph();
+        ConstantNode replacement = ConstantNode.forLong(cstring, graph);
+        graph.replaceFloating(this, replacement);
+    }
+
+    @NodeIntrinsic
+    public static native Word cstring(@ConstantNodeParameter String string);
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/NewInstanceStub.java	Tue Apr 23 08:44:07 2013 +0200
@@ -208,40 +208,4 @@
     private static boolean forceSlowPath() {
         return Boolean.getBoolean("graal.newInstanceStub.forceSlowPath");
     }
-
-    static void log(boolean enabled, String format, long value) {
-        if (enabled) {
-            Log.printf(format, value);
-        }
-    }
-
-    static void log(boolean enabled, String format, WordBase value) {
-        if (enabled) {
-            Log.printf(format, value.rawValue());
-        }
-    }
-
-    static void log(boolean enabled, String format, long v1, long v2) {
-        if (enabled) {
-            Log.printf(format, v1, v2);
-        }
-    }
-
-    static void log(boolean enabled, String format, Word v1, long v2) {
-        if (enabled) {
-            Log.printf(format, v1.rawValue(), v2);
-        }
-    }
-
-    static void log(boolean enabled, String format, Word v1, Word v2) {
-        if (enabled) {
-            Log.printf(format, v1.rawValue(), v2.rawValue());
-        }
-    }
-
-    static void log(boolean enabled, String format, long v1, long v2, long v3) {
-        if (enabled) {
-            Log.printf(format, v1, v2, v3);
-        }
-    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Tue Apr 23 08:44:07 2013 +0200
@@ -22,19 +22,25 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
+import static com.oracle.graal.hotspot.nodes.CStringNode.*;
+
 import java.util.*;
 import java.util.concurrent.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.RuntimeCallTarget.Descriptor;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.target.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.internal.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.PhasePlan.PhasePosition;
@@ -43,6 +49,7 @@
 import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
 import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
+import com.oracle.graal.word.*;
 
 /**
  * Base class for implementing some low level code providing the out-of-line slow path for a
@@ -156,4 +163,52 @@
         }
         return code;
     }
+
+    static void log(boolean enabled, String format, long value) {
+        if (enabled) {
+            printf(format, value);
+        }
+    }
+
+    static void log(boolean enabled, String format, WordBase value) {
+        if (enabled) {
+            printf(format, value.rawValue());
+        }
+    }
+
+    static void log(boolean enabled, String format, Word v1, long v2) {
+        if (enabled) {
+            printf(format, v1.rawValue(), v2);
+        }
+    }
+
+    static void log(boolean enabled, String format, Word v1, Word v2) {
+        if (enabled) {
+            printf(format, v1.rawValue(), v2.rawValue());
+        }
+    }
+
+    public static final Descriptor STUB_PRINTF = new Descriptor("stubPrintf", false, void.class, Word.class, long.class, long.class, long.class);
+
+    @NodeIntrinsic(RuntimeCallNode.class)
+    private static native void printf(@ConstantNodeParameter Descriptor stubPrintf, Word format, long v1, long v2, long v3);
+
+    /**
+     * Prints a formatted string to the log stream.
+     * 
+     * @param format a C style printf format value that can contain at most one conversion specifier
+     *            (i.e., a sequence of characters starting with '%').
+     * @param value the value associated with the conversion specifier
+     */
+    public static void printf(String format, long value) {
+        printf(STUB_PRINTF, cstring(format), value, 0L, 0L);
+    }
+
+    public static void printf(String format, long v1, long v2) {
+        printf(STUB_PRINTF, cstring(format), v1, v2, 0L);
+    }
+
+    public static void printf(String format, long v1, long v2, long v3) {
+        printf(STUB_PRINTF, cstring(format), v1, v2, v3);
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Apr 23 08:44:07 2013 +0200
@@ -285,7 +285,7 @@
         ValueNode value;
         if (kind == Kind.Object) {
             value = frameState.xpop();
-            // astore and astore_<n> may be used to store a returnAddress (jsr) see JVMS par. 6.5.astore
+            // astore and astore_<n> may be used to store a returnAddress (jsr)
             assert value.kind() == Kind.Object || value.kind() == Kind.Int;
         } else {
             value = frameState.pop(kind);
@@ -1169,7 +1169,7 @@
         createInvokeNode(callTarget, resultType);
     }
 
-    protected Invoke createInvokeNode(MethodCallTargetNode callTarget, Kind resultType) {
+    protected Invoke createInvokeNode(CallTargetNode callTarget, Kind resultType) {
         // be conservative if information was not recorded (could result in endless recompiles
         // otherwise)
         if (graphBuilderConfig.omitAllExceptionEdges() || (optimisticOpts.useExceptionProbability() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE)) {
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_idea.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotpath/HP_idea.java	Tue Apr 23 08:44:07 2013 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.jtt.*;
 import org.junit.*;
 
-//@formatter:off
 public class HP_idea extends JTTTest {
 
     public boolean test() {
@@ -60,7 +59,7 @@
 
     /*
      * buildTestData
-     *
+     * 
      * Builds the data used for the test -- each time the test is run.
      */
 
@@ -115,10 +114,11 @@
 
     /*
      * calcEncryptKey
-     *
-     * Builds the 52 16-bit encryption subkeys Z[] from the user key and stores in 32-bit int array. The routing
-     * corrects an error in the source code in the Schnier book. Basically, the sense of the 7- and 9-bit shifts are
-     * reversed. It still works reversed, but would encrypted code would not decrypt with someone else's IDEA code.
+     * 
+     * Builds the 52 16-bit encryption subkeys Z[] from the user key and stores in 32-bit int array.
+     * The routing corrects an error in the source code in the Schnier book. Basically, the sense of
+     * the 7- and 9-bit shifts are reversed. It still works reversed, but would encrypted code would
+     * not decrypt with someone else's IDEA code.
      */
 
     private void calcEncryptKey() {
@@ -168,9 +168,9 @@
 
     /*
      * calcDecryptKey
-     *
-     * Builds the 52 16-bit encryption subkeys DK[] from the encryption- subkeys Z[]. DK[] is a 32-bit int array holding
-     * 16-bit values as unsigned.
+     * 
+     * Builds the 52 16-bit encryption subkeys DK[] from the encryption- subkeys Z[]. DK[] is a
+     * 32-bit int array holding 16-bit values as unsigned.
      */
 
     private void calcDecryptKey() {
@@ -215,12 +215,14 @@
 
     /*
      * cipher_idea
-     *
-     * IDEA encryption/decryption algorithm. It processes plaintext in 64-bit blocks, one at a time, breaking the block
-     * into four 16-bit unsigned subblocks. It goes through eight rounds of processing using 6 new subkeys each time,
-     * plus four for last step. The source text is in array text1, the destination text goes into array text2 The
-     * routine represents 16-bit subblocks and subkeys as type int so that they can be treated more easily as unsigned.
-     * Multiplication modulo 0x10001 interprets a zero sub-block as 0x10000; it must to fit in 16 bits.
+     * 
+     * IDEA encryption/decryption algorithm. It processes plaintext in 64-bit blocks, one at a time,
+     * breaking the block into four 16-bit unsigned subblocks. It goes through eight rounds of
+     * processing using 6 new subkeys each time, plus four for last step. The source text is in
+     * array text1, the destination text goes into array text2 The routine represents 16-bit
+     * subblocks and subkeys as type int so that they can be treated more easily as unsigned.
+     * Multiplication modulo 0x10001 interprets a zero sub-block as 0x10000; it must to fit in 16
+     * bits.
      */
 
     @SuppressWarnings("static-method")
@@ -356,35 +358,40 @@
 
     /*
      * mul
-     *
-     * Performs multiplication, modulo (2**16)+1. This code is structured on the assumption that untaken branches are
-     * cheaper than taken branches, and that the compiler doesn't schedule branches. Java: Must work with 32-bit int and
-     * one 64-bit long to keep 16-bit values and their products "unsigned." The routine assumes that both a and b could
-     * fit in 16 bits even though they come in as 32-bit ints. Lots of "& 0xFFFF" masks here to keep things 16-bit.
-     * Also, because the routine stores mod (2**16)+1 results in a 2**16 space, the result is truncated to zero whenever
-     * the result would zero, be 2**16. And if one of the multiplicands is 0, the result is not zero, but (2**16) + 1
-     * minus the other multiplicand (sort of an additive inverse mod 0x10001).
-     *
-     * NOTE: The java conversion of this routine works correctly, but is half the speed of using Java's modulus division
-     * function (%) on the multiplication with a 16-bit masking of the result--running in the Symantec Caje IDE. So it's
-     * not called for now; the test uses Java % instead.
+     * 
+     * Performs multiplication, modulo (2**16)+1. This code is structured on the assumption that
+     * untaken branches are cheaper than taken branches, and that the compiler doesn't schedule
+     * branches. Java: Must work with 32-bit int and one 64-bit long to keep 16-bit values and their
+     * products "unsigned." The routine assumes that both a and b could fit in 16 bits even though
+     * they come in as 32-bit ints. Lots of "& 0xFFFF" masks here to keep things 16-bit. Also,
+     * because the routine stores mod (2**16)+1 results in a 2**16 space, the result is truncated to
+     * zero whenever the result would zero, be 2**16. And if one of the multiplicands is 0, the
+     * result is not zero, but (2**16) + 1 minus the other multiplicand (sort of an additive inverse
+     * mod 0x10001).
+     * 
+     * NOTE: The java conversion of this routine works correctly, but is half the speed of using
+     * Java's modulus division function (%) on the multiplication with a 16-bit masking of the
+     * result--running in the Symantec Caje IDE. So it's not called for now; the test uses Java %
+     * instead.
      */
 
     /*
-     * private int mul(int a, int b) throws ArithmeticException { long p; // Large enough to catch 16-bit multiply //
-     * without hitting sign bit. if (a != 0) { if (b != 0) { p = (long) a * b; b = (int) p & 0xFFFF; // Lower 16 bits. a
-     * = (int) p >>> 16; // Upper 16 bits.
-     *
-     * return (b - a + (b < a ? 1 : 0) & 0xFFFF); } else return ((1 - a) & 0xFFFF); // If b = 0, then same as // 0x10001
-     * - a. } else // If a = 0, then return return((1 - b) & 0xFFFF); // same as 0x10001 - b. }
+     * private int mul(int a, int b) throws ArithmeticException { long p; // Large enough to catch
+     * 16-bit multiply // without hitting sign bit. if (a != 0) { if (b != 0) { p = (long) a * b; b
+     * = (int) p & 0xFFFF; // Lower 16 bits. a = (int) p >>> 16; // Upper 16 bits.
+     * 
+     * return (b - a + (b < a ? 1 : 0) & 0xFFFF); } else return ((1 - a) & 0xFFFF); // If b = 0,
+     * then same as // 0x10001 - a. } else // If a = 0, then return return((1 - b) & 0xFFFF); //
+     * same as 0x10001 - b. }
      */
 
     /*
      * inv
-     *
-     * Compute multiplicative inverse of x, modulo (2**16)+1 using extended Euclid's GCD (greatest common divisor)
-     * algorithm. It is unrolled twice to avoid swapping the meaning of the registers. And some subtracts are changed to
-     * adds. Java: Though it uses signed 32-bit ints, the interpretation of the bits within is strictly unsigned 16-bit.
+     * 
+     * Compute multiplicative inverse of x, modulo (2**16)+1 using extended Euclid's GCD (greatest
+     * common divisor) algorithm. It is unrolled twice to avoid swapping the meaning of the
+     * registers. And some subtracts are changed to adds. Java: Though it uses signed 32-bit ints,
+     * the interpretation of the bits within is strictly unsigned 16-bit.
      */
 
     @SuppressWarnings("static-method")
@@ -432,7 +439,7 @@
 
     /*
      * freeTestData
-     *
+     * 
      * Nulls arrays and forces garbage collection to free up memory.
      */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2013, 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.graal.nodes.extended;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * Location node that is the sum of two other location nodes. Can represent locations in the form of
+ * [(base + x) + y] where base is a node and x and y are location nodes.
+ */
+@NodeInfo(nameTemplate = "AddLoc {p#locationIdentity/s}")
+public final class AddLocationNode extends LocationNode implements Canonicalizable {
+
+    @Input private ValueNode x;
+    @Input private ValueNode y;
+
+    public LocationNode getX() {
+        return (LocationNode) x;
+    }
+
+    public LocationNode getY() {
+        return (LocationNode) y;
+    }
+
+    public static AddLocationNode create(LocationNode x, LocationNode y, Graph graph) {
+        assert x.getValueKind().equals(y.getValueKind()) && x.locationIdentity() == y.locationIdentity();
+        return graph.unique(new AddLocationNode(x.locationIdentity(), x.getValueKind(), x, y));
+    }
+
+    private AddLocationNode(Object identity, Kind kind, ValueNode x, ValueNode y) {
+        super(identity, kind);
+        this.x = x;
+        this.y = y;
+    }
+
+    @Override
+    protected LocationNode addDisplacement(long displacement) {
+        LocationNode added = getX().addDisplacement(displacement);
+        return graph().unique(new AddLocationNode(locationIdentity(), getValueKind(), added, getY()));
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (x instanceof ConstantLocationNode) {
+            return getY().addDisplacement(((ConstantLocationNode) x).displacement());
+        }
+        if (y instanceof ConstantLocationNode) {
+            return getX().addDisplacement(((ConstantLocationNode) y).displacement());
+        }
+
+        if (x instanceof IndexedLocationNode && y instanceof IndexedLocationNode) {
+            IndexedLocationNode xIdx = (IndexedLocationNode) x;
+            IndexedLocationNode yIdx = (IndexedLocationNode) y;
+            if (xIdx.indexScaling() == yIdx.indexScaling()) {
+                long displacement = xIdx.displacement() + yIdx.displacement();
+                ValueNode index = IntegerArithmeticNode.add(xIdx.index(), yIdx.index());
+                return IndexedLocationNode.create(locationIdentity(), getValueKind(), displacement, index, graph(), xIdx.indexScaling());
+            }
+        }
+
+        return this;
+    }
+
+    @Override
+    public Value generateLea(LIRGeneratorTool gen, Value base) {
+        Value xAddr = getX().generateLea(gen, base);
+        return getY().generateLea(gen, xAddr);
+    }
+
+    @Override
+    public Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting) {
+        Value xAddr = getX().generateLea(gen, base);
+        return getY().generateLoad(gen, xAddr, deopting);
+    }
+
+    @Override
+    public void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting) {
+        Value xAddr = getX().generateLea(gen, base);
+        getY().generateStore(gen, xAddr, value, deopting);
+    }
+
+    @NodeIntrinsic
+    public static native Location addLocation(@ConstantNodeParameter Object identity, @ConstantNodeParameter Kind kind, Location x, Location y);
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -49,7 +49,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        Value addr = getLocation().generateLea(gen, getObject());
+        Value addr = getLocation().generateLea(gen, gen.operand(getObject()));
         gen.setResult(this, addr);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2011, 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.graal.nodes.extended;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * Location node that has a constant displacement. Can represent addresses of the form [base + disp]
+ * where base is a node and disp is a constant.
+ */
+@NodeInfo(nameTemplate = "Loc {p#locationIdentity/s}")
+public class ConstantLocationNode extends LocationNode {
+
+    private final long displacement;
+
+    public long displacement() {
+        return displacement;
+    }
+
+    public static ConstantLocationNode create(Object identity, Kind kind, long displacement, Graph graph) {
+        return graph.unique(new ConstantLocationNode(identity, kind, displacement));
+    }
+
+    protected ConstantLocationNode(Object identity, Kind kind, long displacement) {
+        super(identity, kind);
+        this.displacement = displacement;
+    }
+
+    @Override
+    protected ConstantLocationNode addDisplacement(long x) {
+        return create(locationIdentity(), getValueKind(), displacement + x, graph());
+    }
+
+    @Override
+    public Value generateLea(LIRGeneratorTool gen, Value base) {
+        return gen.emitLea(base, displacement(), Value.ILLEGAL, 0);
+    }
+
+    @Override
+    public Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting) {
+        return gen.emitLoad(getValueKind(), base, displacement(), Value.ILLEGAL, 0, deopting);
+    }
+
+    @Override
+    public void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting) {
+        gen.emitStore(getValueKind(), base, displacement(), Value.ILLEGAL, 0, value, deopting);
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -53,7 +53,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        gen.setResult(this, location().generateLoad(gen, object(), this));
+        gen.setResult(this, location().generateLoad(gen, gen.operand(object()), this));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -28,13 +28,15 @@
 import com.oracle.graal.nodes.spi.*;
 
 /**
- * Extension of a {@linkplain LocationNode location} to include a scaled index. Can represent
- * locations in the form of [base + index * scale + disp] where base and index are nodes and scale
- * and disp are integer constants.
+ * Location node that has a displacement and a scaled index. Can represent locations in the form of
+ * [base + index * scale + disp] where base and index are nodes and scale and disp are integer
+ * constants.
  */
+@NodeInfo(nameTemplate = "IdxLoc {p#locationIdentity/s}")
 public final class IndexedLocationNode extends LocationNode implements Canonicalizable {
 
     @Input private ValueNode index;
+    private final long displacement;
     private final int indexScaling;
 
     /**
@@ -44,8 +46,8 @@
         return index;
     }
 
-    public static Object getArrayLocation(Kind elementKind) {
-        return elementKind;
+    public long displacement() {
+        return displacement;
     }
 
     /**
@@ -55,43 +57,53 @@
         return indexScaling;
     }
 
-    public static IndexedLocationNode create(Object identity, Kind kind, int displacement, ValueNode index, Graph graph, int indexScaling) {
-        return graph.unique(new IndexedLocationNode(identity, kind, index, displacement, indexScaling));
+    public static IndexedLocationNode create(Object identity, Kind kind, long displacement, ValueNode index, Graph graph, int indexScaling) {
+        return graph.unique(new IndexedLocationNode(identity, kind, displacement, index, indexScaling));
+    }
+
+    private IndexedLocationNode(Object identity, Kind kind, ValueNode index, int indexScaling) {
+        this(identity, kind, 0, index, indexScaling);
     }
 
-    private IndexedLocationNode(Object identity, Kind kind, ValueNode index, int displacement, int indexScaling) {
-        super(identity, kind, displacement);
+    private IndexedLocationNode(Object identity, Kind kind, long displacement, ValueNode index, int indexScaling) {
+        super(identity, kind);
         this.index = index;
+        this.displacement = displacement;
         this.indexScaling = indexScaling;
     }
 
     @Override
+    protected LocationNode addDisplacement(long x) {
+        return create(locationIdentity(), getValueKind(), displacement + x, index, graph(), indexScaling);
+    }
+
+    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         Constant constantIndex = index.asConstant();
         if (constantIndex != null) {
             long constantIndexLong = constantIndex.asLong();
             constantIndexLong *= indexScaling;
-            constantIndexLong += displacement();
-            int constantIndexInt = (int) constantIndexLong;
-            if (constantIndexLong == constantIndexInt) {
-                return LocationNode.create(locationIdentity(), getValueKind(), constantIndexInt, graph());
-            }
+            constantIndexLong += displacement;
+            return ConstantLocationNode.create(locationIdentity(), getValueKind(), constantIndexLong, graph());
         }
         return this;
     }
 
     @Override
-    public Value generateLea(LIRGeneratorTool gen, ValueNode base) {
-        return gen.emitLea(gen.operand(base), displacement(), gen.operand(index()), indexScaling());
+    public Value generateLea(LIRGeneratorTool gen, Value base) {
+        return gen.emitLea(base, displacement, gen.operand(index()), indexScaling());
     }
 
     @Override
-    public Value generateLoad(LIRGeneratorTool gen, ValueNode base, DeoptimizingNode deopting) {
-        return gen.emitLoad(getValueKind(), gen.operand(base), displacement(), gen.operand(index()), indexScaling(), deopting);
+    public Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting) {
+        return gen.emitLoad(getValueKind(), base, displacement, gen.operand(index()), indexScaling(), deopting);
     }
 
     @Override
-    public void generateStore(LIRGeneratorTool gen, ValueNode base, ValueNode value, DeoptimizingNode deopting) {
-        gen.emitStore(getValueKind(), gen.operand(base), displacement(), gen.operand(index()), indexScaling(), gen.operand(value), deopting);
+    public void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting) {
+        gen.emitStore(getValueKind(), base, displacement, gen.operand(index()), indexScaling(), value, deopting);
     }
+
+    @NodeIntrinsic
+    public static native Location indexedLocation(@ConstantNodeParameter Object identity, @ConstantNodeParameter Kind kind, int index, @ConstantNodeParameter int indexScaling);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -23,7 +23,6 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ValueNumberable;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -31,14 +30,12 @@
 import com.oracle.graal.nodes.type.*;
 
 /**
- * A location for a memory access in terms of the kind of value accessed and how to access it. The
- * base version can represent addresses of the form [base + disp] where base is a node and disp is a
- * constant.
+ * A location for a memory access in terms of the kind of value accessed and how to access it. All
+ * locations have the form [base + location], where base is a node and location is defined by
+ * subclasses of the {@link LocationNode}.
  */
-@NodeInfo(nameTemplate = "Loc {p#locationIdentity/s}")
-public class LocationNode extends FloatingNode implements LIRLowerable, ValueNumberable {
+public abstract class LocationNode extends FloatingNode implements LIRLowerable, ValueNumberable {
 
-    private int displacement;
     private Kind valueKind;
     private Object locationIdentity;
 
@@ -70,22 +67,19 @@
      */
     public static final Object FINAL_LOCATION = createLocation("FINAL_LOCATION");
 
+    /**
+     * Marker interface for locations in snippets.
+     */
+    public interface Location {
+    }
+
     public static Object getArrayLocation(Kind elementKind) {
         return elementKind;
     }
 
-    public int displacement() {
-        return displacement;
-    }
-
-    public static LocationNode create(Object identity, Kind kind, int displacement, Graph graph) {
-        return graph.unique(new LocationNode(identity, kind, displacement));
-    }
-
-    protected LocationNode(Object identity, Kind kind, int displacement) {
+    protected LocationNode(Object identity, Kind kind) {
         super(StampFactory.extension());
         assert kind != Kind.Illegal && kind != Kind.Void;
-        this.displacement = displacement;
         this.valueKind = kind;
         this.locationIdentity = identity;
     }
@@ -98,20 +92,16 @@
         return locationIdentity;
     }
 
+    protected abstract LocationNode addDisplacement(long displacement);
+
     @Override
     public void generate(LIRGeneratorTool generator) {
         // nothing to do...
     }
 
-    public Value generateLea(LIRGeneratorTool gen, ValueNode base) {
-        return gen.emitLea(gen.operand(base), displacement(), Value.ILLEGAL, 0);
-    }
+    public abstract Value generateLea(LIRGeneratorTool gen, Value base);
 
-    public Value generateLoad(LIRGeneratorTool gen, ValueNode base, DeoptimizingNode deopting) {
-        return gen.emitLoad(getValueKind(), gen.operand(base), displacement(), Value.ILLEGAL, 0, deopting);
-    }
+    public abstract Value generateLoad(LIRGeneratorTool gen, Value base, DeoptimizingNode deopting);
 
-    public void generateStore(LIRGeneratorTool gen, ValueNode base, ValueNode value, DeoptimizingNode deopting) {
-        gen.emitStore(getValueKind(), gen.operand(base), displacement(), Value.ILLEGAL, 0, gen.operand(value), deopting);
-    }
+    public abstract void generateStore(LIRGeneratorTool gen, Value base, Value value, DeoptimizingNode deopting);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -44,7 +44,7 @@
     }
 
     private ReadNode(ValueNode object, int displacement, Object locationIdentity, Kind kind) {
-        super(object, object.graph().add(new LocationNode(locationIdentity, kind, displacement)), StampFactory.forKind(kind));
+        super(object, ConstantLocationNode.create(locationIdentity, kind, displacement, object.graph()), StampFactory.forKind(kind));
     }
 
     private ReadNode(ValueNode object, ValueNode location, ValueNode dependency) {
@@ -57,7 +57,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        gen.setResult(this, location().generateLoad(gen, object(), this));
+        gen.setResult(this, location().generateLoad(gen, gen.operand(object()), this));
     }
 
     @Override
@@ -73,8 +73,8 @@
     public static ValueNode canonicalizeRead(ValueNode read, LocationNode location, ValueNode object, CanonicalizerTool tool) {
         MetaAccessProvider runtime = tool.runtime();
         if (runtime != null && object != null && object.isConstant()) {
-            if (location.locationIdentity() == LocationNode.FINAL_LOCATION && location.getClass() == LocationNode.class) {
-                long displacement = location.displacement();
+            if (location.locationIdentity() == LocationNode.FINAL_LOCATION && location instanceof ConstantLocationNode) {
+                long displacement = ((ConstantLocationNode) location).displacement();
                 Kind kind = location.getValueKind();
                 if (object.kind() == Kind.Object) {
                     Object base = object.asConstant().asObject();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -84,7 +84,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        location().generateStore(gen, object(), value(), this);
+        location().generateStore(gen, gen.operand(object()), gen.operand(value()), this);
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Tue Apr 23 08:44:07 2013 +0200
@@ -57,11 +57,11 @@
 
     public abstract void emitMove(Value dst, Value src);
 
-    public abstract Value emitLoad(Kind kind, Value base, int displacement, Value index, int scale, DeoptimizingNode deopting);
+    public abstract Value emitLoad(Kind kind, Value base, long displacement, Value index, int scale, DeoptimizingNode deopting);
 
-    public abstract void emitStore(Kind kind, Value base, int displacement, Value index, int scale, Value input, DeoptimizingNode deopting);
+    public abstract void emitStore(Kind kind, Value base, long displacement, Value index, int scale, Value input, DeoptimizingNode deopting);
 
-    public abstract Value emitLea(Value base, int displacement, Value index, int scale);
+    public abstract Value emitLea(Value base, long displacement, Value index, int scale);
 
     public abstract Value emitLea(StackSlot slot);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MacroSubstitution.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/MacroSubstitution.java	Tue Apr 23 08:44:07 2013 +0200
@@ -78,7 +78,7 @@
      * Determines if this method should be substituted in all cases, even if inlining thinks it is
      * not important.
      * 
-     * Not that this is still depending on whether inlining sees the correct call target, so it's
+     * Note that this is still depending on whether inlining sees the correct call target, so it's
      * only a hard guarantee for static and special invocations.
      */
     boolean forced() default false;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/GenericStamp.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/GenericStamp.java	Tue Apr 23 08:44:07 2013 +0200
@@ -33,7 +33,7 @@
     private final GenericStampType type;
 
     protected GenericStamp(GenericStampType type) {
-        super(Kind.Void);
+        super(type == GenericStampType.Void ? Kind.Void : Kind.Illegal);
         this.type = type;
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Tue Apr 23 08:44:07 2013 +0200
@@ -218,6 +218,10 @@
     }
 
     private boolean isImplicitNullCheck(LocationNode location) {
-        return !(location instanceof IndexedLocationNode) && location.displacement() < target.implicitNullCheckLimit;
+        if (location instanceof ConstantLocationNode) {
+            return ((ConstantLocationNode) location).displacement() < target.implicitNullCheckLimit;
+        } else {
+            return false;
+        }
     }
 }
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryNodeTest.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BinaryNodeTest.java	Tue Apr 23 08:44:07 2013 +0200
@@ -22,6 +22,9 @@
  */
 package com.oracle.truffle.api.codegen.test;
 
+import static com.oracle.truffle.api.codegen.test.TestHelper.*;
+import static org.junit.Assert.*;
+
 import org.junit.*;
 
 import com.oracle.truffle.api.codegen.*;
@@ -29,9 +32,6 @@
 import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode;
 import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode;
 
-import static junit.framework.Assert.*;
-import static com.oracle.truffle.api.codegen.test.TestHelper.*;
-
 public class BinaryNodeTest {
 
     @Test
@@ -49,31 +49,12 @@
         executeWith(node, new Object(), new Object());
     }
 
+    @NodeChildren({@NodeChild("left"), @NodeChild("right")})
     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);
-        }
     }
 
     abstract static class AddNode extends BinaryNode {
 
-        public AddNode(ValueNode left, ValueNode right) {
-            super(left, right);
-        }
-
-        public AddNode(AddNode prev) {
-            super(prev);
-        }
-
         @Specialization
         int add(int left, int right) {
             return left + right;
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/BuiltinTest.java	Tue Apr 23 08:44:07 2013 +0200
@@ -23,7 +23,7 @@
 package com.oracle.truffle.api.codegen.test;
 
 import static com.oracle.truffle.api.codegen.test.TestHelper.*;
-import static junit.framework.Assert.*;
+import static org.junit.Assert.*;
 
 import org.junit.*;
 
@@ -32,7 +32,6 @@
 import com.oracle.truffle.api.codegen.test.BuiltinTestFactory.StrFactory.StrConcatFactory;
 import com.oracle.truffle.api.codegen.test.BuiltinTestFactory.StrFactory.StrLengthFactory;
 import com.oracle.truffle.api.codegen.test.BuiltinTestFactory.StrFactory.StrSubstrFactory;
-import com.oracle.truffle.api.codegen.test.TypeSystemTest.ChildrenNode;
 import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode;
 import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode;
 
@@ -97,7 +96,7 @@
         assertSame(context, executeWith(node));
     }
 
-    @NodeClass(BuiltinNode.class)
+    @NodeClass(value = BuiltinNode.class, splitByMethodName = true)
     static class Str {
 
         private final String internal;
@@ -162,23 +161,22 @@
         }
     }
 
-    abstract static class BuiltinNode extends ChildrenNode {
+    @NodeChild(value = "children", type = ValueNode[].class)
+    abstract static class BuiltinNode extends ValueNode {
 
         protected final Context context;
 
         public BuiltinNode(BuiltinNode node) {
-            this(node.context, node.children);
+            this(node.context);
         }
 
-        public BuiltinNode(Context context, ValueNode... children) {
-            super(children);
+        public BuiltinNode(Context context) {
             this.context = context;
         }
 
         public Context getContext() {
             return context;
         }
-
     }
 
     static class Context {
--- /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/ExecuteEvaluatedTest.java	Tue Apr 23 08:44:07 2013 +0200
@@ -0,0 +1,69 @@
+/*
+ * 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.*;
+import com.oracle.truffle.api.codegen.*;
+import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode;
+import com.oracle.truffle.api.frame.*;
+
+public class ExecuteEvaluatedTest {
+
+    /* Represents target[element] */
+    @NodeChildren({@NodeChild("target"), @NodeChild("element")})
+    abstract static class ReadElementNode extends ValueNode {
+
+        @Specialization
+        int getInt(Object[] target, int element) {
+            return (int) target[element];
+        }
+
+        public abstract Object executeWith(VirtualFrame frame, Object targetValue);
+    }
+
+    /* Represents target[element]() */
+    @NodeChildren({@NodeChild("target"), @NodeChild(value = "element", type = ReadElementNode.class, executeWith = "target")})
+    abstract static class ElementCallNode extends ValueNode {
+
+        @Specialization
+        Object call(Object receiver, Object callTarget) {
+            return ((CallTarget) callTarget).call(new TestArguments(receiver));
+        }
+
+    }
+
+    public static class TestArguments extends Arguments {
+
+        private final Object receiver;
+
+        public TestArguments(Object receiver) {
+            this.receiver = receiver;
+        }
+
+        public Object getReceiver() {
+            return receiver;
+        }
+
+    }
+
+}
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/GuardsTest.java	Tue Apr 23 08:44:07 2013 +0200
@@ -23,14 +23,13 @@
 package com.oracle.truffle.api.codegen.test;
 
 import static com.oracle.truffle.api.codegen.test.TestHelper.*;
-import static junit.framework.Assert.*;
 
 import org.junit.*;
+import static org.junit.Assert.*;
 
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.api.codegen.test.GuardsTestFactory.GlobalFlagGuardFactory;
 import com.oracle.truffle.api.codegen.test.GuardsTestFactory.InvocationGuardFactory;
-import com.oracle.truffle.api.codegen.test.TypeSystemTest.ChildrenNode;
 import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode;
 import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode;
 
@@ -52,19 +51,12 @@
         assertEquals(1, InvocationGuard.genericInvocations);
     }
 
-    public abstract static class InvocationGuard extends ChildrenNode {
+    @NodeChildren({@NodeChild("value0"), @NodeChild("value1")})
+    public abstract static class InvocationGuard extends ValueNode {
 
         static int specializedInvocations = 0;
         static int genericInvocations = 0;
 
-        public InvocationGuard(ValueNode... children) {
-            super(children);
-        }
-
-        public InvocationGuard(InvocationGuard node) {
-            super(node);
-        }
-
         boolean guard(int value0, int value1) {
             return value0 != Integer.MAX_VALUE;
         }
@@ -95,18 +87,11 @@
         assertEquals(42, executeWith(root, NULL));
     }
 
-    public abstract static class GlobalFlagGuard extends ChildrenNode {
+    @NodeChild("expression")
+    public abstract static class GlobalFlagGuard extends ValueNode {
 
         static boolean globalFlag = false;
 
-        public GlobalFlagGuard(ValueNode... children) {
-            super(children);
-        }
-
-        public GlobalFlagGuard(GlobalFlagGuard node) {
-            super(node);
-        }
-
         static boolean globalFlagGuard() {
             return globalFlag;
         }
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TestHelper.java	Tue Apr 23 08:44:07 2013 +0200
@@ -26,6 +26,7 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.codegen.*;
+import com.oracle.truffle.api.codegen.test.BuiltinTest.*;
 import com.oracle.truffle.api.codegen.test.TypeSystemTest.*;
 
 /**
@@ -46,7 +47,7 @@
 
         List<Object> argumentList = new ArrayList<>();
         argumentList.addAll(Arrays.asList(constants));
-        if (ChildrenNode.class.isAssignableFrom(factory.getNodeClass())) {
+        if (ChildrenNode.class.isAssignableFrom(factory.getNodeClass()) || BuiltinNode.class.isAssignableFrom(factory.getNodeClass())) {
             argumentList.add(argumentNodes);
         } else {
             argumentList.addAll(Arrays.asList(argumentNodes));
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/TypeSystemTest.java	Tue Apr 23 08:44:07 2013 +0200
@@ -30,41 +30,40 @@
 
 public class TypeSystemTest {
 
-    @TypeSystem({int.class, Str.class})
+    @TypeSystem({int.class, Str.class, CallTarget.class, Object[].class})
     static class SimpleTypes {
     }
 
     @TypeSystemReference(SimpleTypes.class)
-    abstract static class ValueNode extends Node {
+    public abstract static class ValueNode extends Node {
 
-        int executeInt(VirtualFrame frame) throws UnexpectedResultException {
+        public int executeInt(VirtualFrame frame) throws UnexpectedResultException {
             return SimpleTypesGen.SIMPLETYPES.expectInteger(execute(frame));
         }
 
-        Str executeStr(VirtualFrame frame) throws UnexpectedResultException {
+        public Str executeStr(VirtualFrame frame) throws UnexpectedResultException {
             return SimpleTypesGen.SIMPLETYPES.expectStr(execute(frame));
         }
 
-        abstract Object execute(VirtualFrame frame);
+        public Object[] executeIntArray(VirtualFrame frame) throws UnexpectedResultException {
+            return SimpleTypesGen.SIMPLETYPES.expectObjectArray(execute(frame));
+        }
+
+        public abstract Object execute(VirtualFrame frame);
+
+        @Override
+        public ValueNode copy() {
+            return (ValueNode) super.copy();
+        }
     }
 
-    @TypeSystemReference(SimpleTypes.class)
-    abstract static class ChildrenNode extends ValueNode {
-
-        @Children protected ValueNode[] children;
-
-        public ChildrenNode(ValueNode... children) {
-            this.children = adoptChildren(children);
-        }
-
-        public ChildrenNode(ChildrenNode node) {
-            this(node.children);
-        }
+    @NodeChild(value = "children", type = ValueNode[].class)
+    public abstract static class ChildrenNode extends ValueNode {
 
     }
 
     @TypeSystemReference(SimpleTypes.class)
-    static class TestRootNode<E extends ValueNode> extends RootNode {
+    public static class TestRootNode<E extends ValueNode> extends RootNode {
 
         @Child private E node;
 
@@ -82,7 +81,7 @@
         }
     }
 
-    static class TestArguments extends Arguments {
+    public static class TestArguments extends Arguments {
 
         private final Object[] values;
 
@@ -100,7 +99,7 @@
 
     }
 
-    static class ArgumentNode extends ValueNode {
+    public static class ArgumentNode extends ValueNode {
 
         final int index;
 
@@ -109,7 +108,7 @@
         }
 
         @Override
-        Object execute(VirtualFrame frame) {
+        public Object execute(VirtualFrame frame) {
             return ((TestArguments) frame.getArguments()).get(index);
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChild.java	Tue Apr 23 08:44:07 2013 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.codegen;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.TYPE})
+public @interface NodeChild {
+
+    String value() default "";
+
+    Class<?> type() default NodeClass.InheritNode.class;
+
+    String[] executeWith() default {};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeChildren.java	Tue Apr 23 08:44:07 2013 +0200
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.codegen;
+
+import java.lang.annotation.*;
+
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.TYPE})
+public @interface NodeChildren {
+
+    NodeChild[] value() default {};
+
+}
--- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeClass.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/NodeClass.java	Tue Apr 23 08:44:07 2013 +0200
@@ -30,6 +30,11 @@
 @Target({ElementType.TYPE})
 public @interface NodeClass {
 
-    Class<? extends Node> value();
+    public static final class InheritNode extends Node {
+    }
+
+    Class<? extends Node> value() default InheritNode.class;
+
+    boolean splitByMethodName() default false;
 
 }
--- a/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeCast.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/TypeCast.java	Tue Apr 23 08:44:07 2013 +0200
@@ -24,11 +24,6 @@
 
 import java.lang.annotation.*;
 
-/**
- *
- *
- *
- */
 @Retention(RetentionPolicy.CLASS)
 @Target({ElementType.METHOD})
 public @interface TypeCast {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AbstractParser.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/AbstractParser.java	Tue Apr 23 08:44:07 2013 +0200
@@ -27,6 +27,7 @@
 
 import javax.annotation.processing.*;
 import javax.lang.model.element.*;
+import javax.tools.Diagnostic.Kind;
 
 import com.oracle.truffle.codegen.processor.template.*;
 
@@ -49,6 +50,7 @@
 
     public final M parse(RoundEnvironment env, Element element) {
         this.roundEnv = env;
+        M model = null;
         try {
             AnnotationMirror mirror = null;
             if (getAnnotationType() != null) {
@@ -58,13 +60,16 @@
             if (!context.getTruffleTypes().verify(context, element, mirror)) {
                 return null;
             }
-            M model = parse(element, mirror);
+            model = parse(element, mirror);
             if (model == null) {
                 return null;
             }
 
             model.emitMessages((TypeElement) element, log);
             return filterErrorElements(model);
+        } catch (CompileErrorException e) {
+            log.message(Kind.WARNING, element, null, null, "The truffle processor could not parse class due to error: %s", e.getMessage());
+            return null;
         } finally {
             this.roundEnv = null;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/CompileErrorException.java	Tue Apr 23 08:44:07 2013 +0200
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+public class CompileErrorException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    public CompileErrorException(String message) {
+        super(message);
+    }
+
+}
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ProcessorContext.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ProcessorContext.java	Tue Apr 23 08:44:07 2013 +0200
@@ -29,7 +29,9 @@
 import javax.annotation.processing.*;
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
+import javax.lang.model.util.*;
 
+import com.oracle.truffle.codegen.processor.ast.*;
 import com.oracle.truffle.codegen.processor.ast.CodeTypeMirror.ArrayCodeTypeMirror;
 import com.oracle.truffle.codegen.processor.template.*;
 
@@ -185,4 +187,26 @@
 
     }
 
+    public TypeMirror reloadTypeElement(TypeElement type) {
+        return getType(type.getQualifiedName().toString());
+    }
+
+    public TypeMirror reloadType(TypeMirror type) {
+        if (type instanceof CodeTypeMirror) {
+            return type;
+        } else if (type.getKind().isPrimitive()) {
+            return type;
+        }
+        Types types = getEnvironment().getTypeUtils();
+
+        switch (type.getKind()) {
+            case ARRAY:
+                return types.getArrayType(reloadType(((ArrayType) type).getComponentType()));
+            case WILDCARD:
+                return types.getWildcardType(((WildcardType) type).getExtendsBound(), ((WildcardType) type).getSuperBound());
+            case DECLARED:
+                return reloadTypeElement((TypeElement) (((DeclaredType) type).asElement()));
+        }
+        return type;
+    }
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/TruffleTypes.java	Tue Apr 23 08:44:07 2013 +0200
@@ -43,8 +43,8 @@
     private final TypeMirror nodeArray;
     private final TypeMirror unexpectedValueException;
     private final TypeMirror frame;
-    private final TypeMirror stableAnnotation;
-    private final TypeMirror contentStableAnnotation;
+    private final DeclaredType childAnnotation;
+    private final DeclaredType childrenAnnotation;
     private final TypeMirror typeConversion;
     private final TypeMirror truffleIntrinsics;
 
@@ -55,8 +55,8 @@
         nodeArray = context.getEnvironment().getTypeUtils().getArrayType(node);
         unexpectedValueException = getRequired(context, UnexpectedResultException.class);
         frame = getRequired(context, VirtualFrame.class);
-        stableAnnotation = getRequired(context, Child.class);
-        contentStableAnnotation = getRequired(context, Children.class);
+        childAnnotation = getRequired(context, Child.class);
+        childrenAnnotation = getRequired(context, Children.class);
         typeConversion = getRequired(context, TypeConversion.class);
         truffleIntrinsics = getRequired(context, TruffleIntrinsics.class);
     }
@@ -73,12 +73,12 @@
         return false;
     }
 
-    private TypeMirror getRequired(ProcessorContext context, Class clazz) {
+    private DeclaredType getRequired(ProcessorContext context, Class clazz) {
         TypeMirror type = context.getType(clazz);
         if (type == null) {
             errors.add(String.format("Could not find required type: %s", clazz.getSimpleName()));
         }
-        return type;
+        return (DeclaredType) type;
     }
 
     public TypeMirror getTruffleIntrinsics() {
@@ -105,11 +105,11 @@
         return unexpectedValueException;
     }
 
-    public TypeMirror getStableAnnotation() {
-        return stableAnnotation;
+    public DeclaredType getChildAnnotation() {
+        return childAnnotation;
     }
 
-    public TypeMirror getContentStableAnnotation() {
-        return contentStableAnnotation;
+    public DeclaredType getChildrenAnnotation() {
+        return childrenAnnotation;
     }
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java	Tue Apr 23 08:44:07 2013 +0200
@@ -32,6 +32,7 @@
 import javax.lang.model.util.*;
 
 import com.oracle.truffle.codegen.processor.ast.*;
+import com.oracle.truffle.codegen.processor.ast.CodeTypeMirror.DeclaredCodeTypeMirror;
 import com.oracle.truffle.codegen.processor.compiler.*;
 
 /**
@@ -63,17 +64,20 @@
         return types;
     }
 
+    public static DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) {
+        return new DeclaredCodeTypeMirror(typeElem, Arrays.asList(typeArgs));
+    }
+
     public static List<AnnotationMirror> collectAnnotations(ProcessorContext context, AnnotationMirror markerAnnotation, String elementName, Element element,
                     Class<? extends Annotation> annotationClass) {
-        List<AnnotationMirror> result = Utils.getAnnotationValueList(AnnotationMirror.class, markerAnnotation, elementName);
+        List<AnnotationMirror> result = new ArrayList<>();
+        if (markerAnnotation != null) {
+            result.addAll(Utils.getAnnotationValueList(AnnotationMirror.class, markerAnnotation, elementName));
+        }
         AnnotationMirror explicit = Utils.findAnnotationMirror(context.getEnvironment(), element, annotationClass);
         if (explicit != null) {
             result.add(explicit);
         }
-
-        for (AnnotationMirror mirror : result) {
-            assert Utils.typeEquals(mirror.getAnnotationType(), context.getType(annotationClass));
-        }
         return result;
     }
 
@@ -141,33 +145,100 @@
         }
     }
 
-    /**
-     * True if t1 is assignable to t2.
-     */
-    public static boolean isAssignable(TypeMirror t1, TypeMirror t2) {
-        if (typeEquals(t1, t2)) {
+    public static boolean isAssignable(ProcessorContext context, TypeMirror from, TypeMirror to) {
+        if (!(from instanceof CodeTypeMirror) && !(to instanceof CodeTypeMirror)) {
+            return context.getEnvironment().getTypeUtils().isAssignable(context.reloadType(from), context.reloadType(to));
+        } else {
+            return isAssignableImpl(context, from, to);
+        }
+    }
+
+    private static boolean isAssignableImpl(ProcessorContext context, TypeMirror from, TypeMirror to) {
+        // JLS 5.1.1 identity conversion
+        if (Utils.typeEquals(from, to)) {
             return true;
         }
-        if (isPrimitive(t1) || isPrimitive(t2)) {
-            // non-equal primitive types
+
+        // JLS 5.1.2 widening primitives
+        if (Utils.isPrimitive(from) && Utils.isPrimitive(to)) {
+            TypeKind fromKind = from.getKind();
+            TypeKind toKind = to.getKind();
+            switch (fromKind) {
+                case BYTE:
+                    switch (toKind) {
+                        case SHORT:
+                        case INT:
+                        case LONG:
+                        case FLOAT:
+                        case DOUBLE:
+                            return true;
+                    }
+                    break;
+                case SHORT:
+                    switch (toKind) {
+                        case INT:
+                        case LONG:
+                        case FLOAT:
+                        case DOUBLE:
+                            return true;
+                    }
+                    break;
+                case CHAR:
+                    switch (toKind) {
+                        case INT:
+                        case LONG:
+                        case FLOAT:
+                        case DOUBLE:
+                            return true;
+                    }
+                    break;
+                case INT:
+                    switch (toKind) {
+                        case LONG:
+                        case FLOAT:
+                        case DOUBLE:
+                            return true;
+                    }
+                    break;
+                case LONG:
+                    switch (toKind) {
+                        case FLOAT:
+                        case DOUBLE:
+                            return true;
+                    }
+                    break;
+                case FLOAT:
+                    switch (toKind) {
+                        case DOUBLE:
+                            return true;
+                    }
+                    break;
+
+            }
             return false;
-        }
-        if (t1 instanceof ArrayType && t2 instanceof ArrayType) {
-            return isAssignable(((ArrayType) t1).getComponentType(), ((ArrayType) t2).getComponentType());
-        }
-
-        TypeElement e1 = fromTypeMirror(t1);
-        TypeElement e2 = fromTypeMirror(t2);
-        if (e1 == null || e2 == null) {
+        } else if (Utils.isPrimitive(from) || Utils.isPrimitive(to)) {
             return false;
         }
 
-        List<TypeElement> superTypes = getSuperTypes(e1);
+        if (from instanceof ArrayType && to instanceof ArrayType) {
+            return isAssignable(context, ((ArrayType) from).getComponentType(), ((ArrayType) to).getComponentType());
+        }
+
+        TypeElement fromType = Utils.fromTypeMirror(from);
+        TypeElement toType = Utils.fromTypeMirror(to);
+        if (fromType == null || toType == null) {
+            return false;
+        }
+        // JLS 5.1.6 narrowing reference conversion
+
+        List<TypeElement> superTypes = Utils.getSuperTypes(fromType);
         for (TypeElement superType : superTypes) {
-            if (typeEquals(superType.asType(), t2)) {
+            if (Utils.typeEquals(superType.asType(), to)) {
                 return true;
             }
         }
+
+        // TODO more spec
         return false;
     }
 
@@ -210,6 +281,8 @@
                 return b.toString();
             case TYPEVAR:
                 return "Any";
+            case ERROR:
+                throw new CompileErrorException("Type error " + mirror);
             default:
                 throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror);
         }
@@ -247,6 +320,8 @@
                 return getWildcardName((WildcardType) mirror);
             case TYPEVAR:
                 return "?";
+            case ERROR:
+                throw new CompileErrorException("Type error " + mirror);
             default:
                 throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror);
         }
@@ -313,6 +388,10 @@
                 return "void";
             case TYPEVAR:
                 return getSimpleName(mirror);
+            case ERROR:
+                throw new CompileErrorException("Type error " + mirror);
+            case NONE:
+                return "$none";
             default:
                 throw new RuntimeException("Unknown type specified " + mirror + " mirror: " + mirror);
         }
@@ -326,6 +405,10 @@
         return mirror.getKind().isPrimitive();
     }
 
+    public static boolean isPrimitiveOrVoid(TypeMirror mirror) {
+        return isPrimitive(mirror) || isVoid(mirror);
+    }
+
     public static List<String> getQualifiedSuperTypeNames(TypeElement element) {
         List<TypeElement> types = getSuperTypes(element);
         List<String> qualifiedNames = new ArrayList<>();
@@ -361,7 +444,7 @@
         return null;
     }
 
-    private static List<Element> getElementHierarchy(Element e) {
+    public static List<Element> getElementHierarchy(Element e) {
         List<Element> elements = new ArrayList<>();
         elements.add(e);
 
@@ -579,7 +662,7 @@
 
         @Override
         public Object visitEnumConstant(VariableElement c, Void p) {
-            return c.getConstantValue();
+            return c;
         }
 
         @Override
@@ -762,11 +845,7 @@
 
     public static Modifier getVisibility(Set<Modifier> modifier) {
         for (Modifier mod : modifier) {
-            if (mod == Modifier.PUBLIC) {
-                return mod;
-            } else if (mod == Modifier.PRIVATE) {
-                return mod;
-            } else if (mod == Modifier.PROTECTED) {
+            if (mod == Modifier.PUBLIC || mod == Modifier.PRIVATE || mod == Modifier.PROTECTED) {
                 return mod;
             }
         }
@@ -803,4 +882,20 @@
         return getQualifiedName(actualType).equals("java.lang.Object");
     }
 
+    public static boolean isFieldAccessible(Element element, VariableElement variable) {
+        TypeElement type = Utils.findNearestEnclosingType(element);
+        TypeElement varType = Utils.findNearestEnclosingType(variable);
+
+        while (type != null) {
+            if (typeEquals(type.asType(), varType.asType())) {
+                return true;
+            }
+            if (type.getSuperclass() != null) {
+                type = Utils.fromTypeMirror(type.getSuperclass());
+            } else {
+                type = null;
+            }
+        }
+        return false;
+    }
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeExecutableElement.java	Tue Apr 23 08:44:07 2013 +0200
@@ -215,7 +215,7 @@
             copy.addAnnotationMirror(mirror);
         }
         for (VariableElement var : method.getParameters()) {
-            copy.addParameter(var);
+            copy.addParameter(CodeVariableElement.clone(var));
         }
         for (Element element : method.getEnclosedElements()) {
             copy.add(element);
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java	Tue Apr 23 08:44:07 2013 +0200
@@ -46,6 +46,11 @@
         this.parent = parent;
     }
 
+    @Override
+    public String toString() {
+        return root.toString();
+    }
+
     public int getTreeCount() {
         return treeCount;
     }
@@ -277,7 +282,13 @@
     }
 
     public CodeTreeBuilder tree(CodeTree treeToAdd) {
-        return push((BuilderCodeTree) treeToAdd).end();
+        if (treeToAdd instanceof BuilderCodeTree) {
+            return push((BuilderCodeTree) treeToAdd).end();
+        } else {
+            BuilderCodeTree tree = new BuilderCodeTree(GROUP, null, null);
+            tree.add(treeToAdd);
+            return push(tree).end();
+        }
     }
 
     public CodeTreeBuilder string(String chunk1, String chunk2, String chunk3, String chunk4, String... chunks) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeVariable.java	Tue Apr 23 08:44:07 2013 +0200
@@ -0,0 +1,60 @@
+/*
+ * 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.ast;
+
+public class CodeTreeVariable extends CodeTree {
+
+    private final String name;
+
+    private CodeTree value;
+
+    public CodeTreeVariable() {
+        super(CodeTreeKind.GROUP, null, null);
+        this.name = "";
+    }
+
+    public CodeTreeVariable(String name) {
+        super(CodeTreeKind.GROUP, null, null);
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void set(CodeTree tree) {
+        if (value == tree) {
+            return;
+        }
+        if (this.value != null) {
+            remove(this.value);
+        }
+        this.value = tree;
+        add(tree);
+    }
+
+    public CodeTree get() {
+        return value;
+    }
+
+}
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTypeMirror.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTypeMirror.java	Tue Apr 23 08:44:07 2013 +0200
@@ -64,11 +64,17 @@
 
     public static class DeclaredCodeTypeMirror extends CodeTypeMirror implements DeclaredType {
 
-        private final CodeTypeElement clazz;
+        private final TypeElement clazz;
+        private final List<? extends TypeMirror> typeArguments;
 
-        public DeclaredCodeTypeMirror(CodeTypeElement clazz) {
+        public DeclaredCodeTypeMirror(TypeElement clazz) {
+            this(clazz, Collections.<TypeMirror> emptyList());
+        }
+
+        public DeclaredCodeTypeMirror(TypeElement clazz, List<? extends TypeMirror> typeArguments) {
             super(TypeKind.DECLARED);
             this.clazz = clazz;
+            this.typeArguments = typeArguments;
         }
 
         @Override
@@ -83,7 +89,7 @@
 
         @Override
         public List<? extends TypeMirror> getTypeArguments() {
-            return Collections.emptyList();
+            return typeArguments;
         }
 
         @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/AbstractCodeWriter.java	Tue Apr 23 08:44:07 2013 +0200
@@ -123,9 +123,9 @@
         writeClassImpl(e);
     }
 
-    private String useImport(TypeMirror type) {
+    private String useImport(Element enclosedType, TypeMirror type) {
         if (imports != null) {
-            return imports.useImport(type);
+            return imports.createTypeReference(enclosedType, type);
         } else {
             return Utils.getSimpleName(type);
         }
@@ -133,7 +133,7 @@
 
     private void writeClassImpl(CodeTypeElement e) {
         for (AnnotationMirror annotation : e.getAnnotationMirrors()) {
-            visitAnnotation(annotation);
+            visitAnnotation(e, annotation);
             writeLn();
         }
 
@@ -145,12 +145,12 @@
         }
         write(e.getSimpleName());
         if (e.getSuperclass() != null && !getQualifiedName(e.getSuperclass()).equals("java.lang.Object")) {
-            write(" extends ").write(useImport(e.getSuperclass()));
+            write(" extends ").write(useImport(e, e.getSuperclass()));
         }
         if (e.getImplements().size() > 0) {
             write(" implements ");
             for (int i = 0; i < e.getImplements().size(); i++) {
-                write(useImport(e.getImplements().get(i)));
+                write(useImport(e, e.getImplements().get(i)));
                 if (i < e.getImplements().size() - 1) {
                     write(", ");
                 }
@@ -255,8 +255,8 @@
         Element parent = f.getEnclosingElement();
 
         for (AnnotationMirror annotation : f.getAnnotationMirrors()) {
-            visitAnnotation(annotation);
-            writeLn();
+            visitAnnotation(f, annotation);
+            write(" ");
         }
 
         CodeTree init = null;
@@ -275,7 +275,7 @@
             }
         } else {
             writeModifiers(f.getModifiers());
-            write(useImport(f.asType()));
+            write(useImport(f, f.asType()));
 
             if (f.getEnclosingElement().getKind() == ElementKind.METHOD) {
                 ExecutableElement method = (ExecutableElement) f.getEnclosingElement();
@@ -294,8 +294,8 @@
         return null;
     }
 
-    public void visitAnnotation(AnnotationMirror e) {
-        write("@").write(useImport(e.getAnnotationType()));
+    public void visitAnnotation(Element enclosedElement, AnnotationMirror e) {
+        write("@").write(useImport(enclosedElement, e.getAnnotationType()));
 
         if (!e.getElementValues().isEmpty()) {
             write("(");
@@ -303,7 +303,7 @@
 
             Map<? extends ExecutableElement, ? extends AnnotationValue> values = e.getElementValues();
             if (defaultElement != null && values.size() == 1 && values.get(defaultElement) != null) {
-                visitAnnotationValue(values.get(defaultElement));
+                visitAnnotationValue(enclosedElement, values.get(defaultElement));
             } else {
                 Set<? extends ExecutableElement> methodsSet = values.keySet();
                 List<ExecutableElement> methodsList = new ArrayList<>();
@@ -327,7 +327,7 @@
                     AnnotationValue value = values.get(method);
                     write(method.getSimpleName().toString());
                     write(" = ");
-                    visitAnnotationValue(value);
+                    visitAnnotationValue(enclosedElement, value);
 
                     if (i < methodsList.size() - 1) {
                         write(", ");
@@ -339,12 +339,18 @@
         }
     }
 
-    public void visitAnnotationValue(AnnotationValue e) {
-        e.accept(new AnnotationValueWriterVisitor(), null);
+    public void visitAnnotationValue(Element enclosedElement, AnnotationValue e) {
+        e.accept(new AnnotationValueWriterVisitor(enclosedElement), null);
     }
 
     private class AnnotationValueWriterVisitor extends AbstractAnnotationValueVisitor7<Void, Void> {
 
+        private final Element enclosedElement;
+
+        public AnnotationValueWriterVisitor(Element enclosedElement) {
+            this.enclosedElement = enclosedElement;
+        }
+
         @Override
         public Void visitBoolean(boolean b, Void p) {
             write(Boolean.toString(b));
@@ -403,14 +409,14 @@
 
         @Override
         public Void visitType(TypeMirror t, Void p) {
-            write(useImport(t));
+            write(useImport(enclosedElement, t));
             write(".class");
             return null;
         }
 
         @Override
         public Void visitEnumConstant(VariableElement c, Void p) {
-            write(useImport(c.asType()));
+            write(useImport(enclosedElement, c.asType()));
             write(".");
             write(c.getSimpleName().toString());
             return null;
@@ -418,7 +424,7 @@
 
         @Override
         public Void visitAnnotation(AnnotationMirror a, Void p) {
-            AbstractCodeWriter.this.visitAnnotation(a);
+            AbstractCodeWriter.this.visitAnnotation(enclosedElement, a);
             return null;
         }
 
@@ -427,7 +433,7 @@
             write("{");
             for (int i = 0; i < vals.size(); i++) {
                 AnnotationValue value = vals.get(i);
-                AbstractCodeWriter.this.visitAnnotationValue(value);
+                AbstractCodeWriter.this.visitAnnotationValue(enclosedElement, value);
                 if (i < vals.size() - 1) {
                     write(", ");
                 }
@@ -459,14 +465,14 @@
     @Override
     public Void visitExecutable(CodeExecutableElement e, Void p) {
         for (AnnotationMirror annotation : e.getAnnotationMirrors()) {
-            visitAnnotation(annotation);
+            visitAnnotation(e, annotation);
             writeLn();
         }
 
         writeModifiers(e.getModifiers());
 
         if (e.getReturnType() != null) {
-            write(useImport(e.getReturnType()));
+            write(useImport(e, e.getReturnType()));
             write(" ");
         }
         write(e.getSimpleName());
@@ -485,7 +491,7 @@
         if (throwables.size() > 0) {
             write(" throws ");
             for (int i = 0; i < throwables.size(); i++) {
-                write(useImport(throwables.get(i)));
+                write(useImport(e, throwables.get(i)));
                 if (i < throwables.size() - 1) {
                     write(", ");
                 }
@@ -549,20 +555,20 @@
                 break;
             case STATIC_FIELD_REFERENCE:
                 if (e.getString() != null) {
-                    write(imports.useStaticFieldImport(e.getType(), e.getString()));
+                    write(imports.createStaticFieldReference(e, e.getType(), e.getString()));
                 } else {
                     write("null");
                 }
                 break;
             case STATIC_METHOD_REFERENCE:
                 if (e.getString() != null) {
-                    write(imports.useStaticMethodImport(e.getType(), e.getString()));
+                    write(imports.createStaticMethodReference(e, e.getType(), e.getString()));
                 } else {
                     write("null");
                 }
                 break;
             case TYPE:
-                write(useImport(e.getType()));
+                write(useImport(e, e.getType()));
                 break;
             default:
                 assert false;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java	Tue Apr 23 08:44:07 2013 +0200
@@ -35,8 +35,7 @@
 
 public final class OrganizedImports {
 
-    private final Map<TypeMirror, Integer> importUsage = new HashMap<>();
-    private final Map<TypeMirror, Integer> staticImportUsage = new HashMap<>();
+    private final Set<TypeMirror> staticImportUsage = new HashSet<>();
 
     private final Map<String, TypeMirror> simpleNamesUsed = new HashMap<>();
 
@@ -53,16 +52,33 @@
 
     public static OrganizedImports organize(CodeTypeElement topLevelClass) {
         OrganizedImports organized = new OrganizedImports(topLevelClass);
-
-        OrganizedImports.ReferenceCollector reference = new ReferenceCollector();
-        topLevelClass.accept(reference, null);
-
-        OrganizedImports.ImportResolver resolver = new ImportResolver(reference, organized);
-        topLevelClass.accept(resolver, null);
+        organized.organizeImpl();
         return organized;
     }
 
-    public String useImport(TypeMirror type) {
+    private void organizeImpl() {
+        ImportTypeReferenceVisitor reference = new ImportTypeReferenceVisitor();
+        topLevelClass.accept(reference, null);
+
+        processStaticImports(topLevelClass);
+        List<TypeElement> types = Utils.getSuperTypes(topLevelClass);
+        for (TypeElement typeElement : types) {
+            processStaticImports(typeElement);
+        }
+
+        for (TypeMirror type : staticImportUsage) {
+            TypeElement element = fromTypeMirror(type);
+            if (element != null) {
+                // already processed by supertype
+                if (types.contains(element)) {
+                    continue;
+                }
+                processStaticImports(element);
+            }
+        }
+    }
+
+    public String createTypeReference(Element enclosedElement, TypeMirror type) {
         switch (type.getKind()) {
             case BOOLEAN:
             case BYTE:
@@ -75,11 +91,11 @@
             case VOID:
                 return Utils.getSimpleName(type);
             case DECLARED:
-                return createDeclaredTypeName((DeclaredType) type);
+                return createDeclaredTypeName(enclosedElement, (DeclaredType) type);
             case ARRAY:
-                return useImport(((ArrayType) type).getComponentType()) + "[]";
+                return createTypeReference(enclosedElement, ((ArrayType) type).getComponentType()) + "[]";
             case WILDCARD:
-                return createWildcardName((WildcardType) type);
+                return createWildcardName(enclosedElement, (WildcardType) type);
             case TYPEVAR:
                 return "?";
             default:
@@ -87,29 +103,50 @@
         }
     }
 
-    private String createWildcardName(WildcardType type) {
+    public String createStaticFieldReference(Element enclosedElement, TypeMirror type, String fieldName) {
+        return createStaticReference(enclosedElement, type, fieldName, ambiguousStaticFields, declaredStaticFields);
+    }
+
+    public String createStaticMethodReference(Element enclosedElement, TypeMirror type, String methodName) {
+        return createStaticReference(enclosedElement, type, methodName, ambiguousStaticMethods, declaredStaticMethods);
+    }
+
+    private String createStaticReference(Element enclosedElement, TypeMirror type, String name, Set<String> ambiguousSymbols, Set<String> declaredSymbols) {
+        if (ambiguousSymbols.contains(name)) {
+            // ambiguous import
+            return createTypeReference(enclosedElement, type) + "." + name;
+        } else if (!declaredSymbols.contains(name)) {
+            // not imported at all
+            return createTypeReference(enclosedElement, type) + "." + name;
+        } else {
+            // import declared and not ambiguous
+            return name;
+        }
+    }
+
+    private String createWildcardName(Element enclosedElement, WildcardType type) {
         StringBuilder b = new StringBuilder();
         if (type.getExtendsBound() != null) {
-            b.append("? extends ").append(useImport(type.getExtendsBound()));
+            b.append("? extends ").append(createTypeReference(enclosedElement, type.getExtendsBound()));
         } else if (type.getSuperBound() != null) {
-            b.append("? super ").append(useImport(type.getExtendsBound()));
+            b.append("? super ").append(createTypeReference(enclosedElement, type.getExtendsBound()));
         }
         return b.toString();
     }
 
-    private String createDeclaredTypeName(DeclaredType type) {
+    private String createDeclaredTypeName(Element enclosedElement, DeclaredType type) {
         String name = type.asElement().getSimpleName().toString();
 
-        TypeMirror usedByType = simpleNamesUsed.get(name);
-        if (usedByType == null) {
-            simpleNamesUsed.put(name, type);
-            usedByType = type;
-        }
+        if (needsImport(enclosedElement, type)) {
+            TypeMirror usedByType = simpleNamesUsed.get(name);
+            if (usedByType == null) {
+                simpleNamesUsed.put(name, type);
+                usedByType = type;
+            }
 
-        if (typeEquals(type, usedByType)) {
-            addUsage(type, importUsage);
-        } else {
-            name = getQualifiedName(type);
+            if (!typeEquals(type, usedByType)) {
+                name = getQualifiedName(type);
+            }
         }
 
         if (type.getTypeArguments().size() == 0) {
@@ -120,7 +157,7 @@
         b.append("<");
         if (type.getTypeArguments().size() > 0) {
             for (int i = 0; i < type.getTypeArguments().size(); i++) {
-                b.append(useImport(type.getTypeArguments().get(i)));
+                b.append(createTypeReference(enclosedElement, type.getTypeArguments().get(i)));
                 if (i < type.getTypeArguments().size() - 1) {
                     b.append(", ");
                 }
@@ -130,44 +167,15 @@
         return b.toString();
     }
 
-    public String useStaticFieldImport(TypeMirror type, String fieldName) {
-        return useStaticImport(type, fieldName, ambiguousStaticFields, declaredStaticFields);
-    }
-
-    public String useStaticMethodImport(TypeMirror type, String methodName) {
-        return useStaticImport(type, methodName, ambiguousStaticMethods, declaredStaticMethods);
-    }
-
-    private String useStaticImport(TypeMirror type, String name, Set<String> ambiguousSymbols, Set<String> declaredSymbols) {
-        if (ambiguousSymbols.contains(name)) {
-            // ambiguous import
-            return useImport(type) + "." + name;
-        } else if (!declaredSymbols.contains(name)) {
-            // not imported at all
-            return useImport(type) + "." + name;
-        } else {
-            // import declared and not ambiguous
-            addUsage(type, staticImportUsage);
-            return name;
-        }
-    }
-
     public Set<CodeImport> generateImports() {
         Set<CodeImport> imports = new HashSet<>();
 
-        imports.addAll(generateImports(topLevelClass, importUsage.keySet()));
-        imports.addAll(generateStaticImports(topLevelClass, staticImportUsage.keySet()));
+        imports.addAll(generateImports(simpleNamesUsed.values()));
+        imports.addAll(generateStaticImports(staticImportUsage));
 
         return imports;
     }
 
-    void clearStaticImports() {
-        declaredStaticFields.clear();
-        declaredStaticMethods.clear();
-        ambiguousStaticFields.clear();
-        ambiguousStaticMethods.clear();
-    }
-
     boolean processStaticImports(TypeElement element) {
         Set<String> importedMethods = new HashSet<>();
         List<ExecutableElement> methods = ElementFilter.methodsIn(element.getEnclosedElements());
@@ -217,37 +225,39 @@
         return allAmbiguous;
     }
 
-    private static Set<CodeImport> generateImports(CodeTypeElement e, Set<TypeMirror> toGenerate) {
-        Set<String> autoImportedTypes = new HashSet<>();
+    private boolean needsImport(Element enclosedElement, TypeMirror importType) {
+        String importPackagName = getPackageName(importType);
+        if (importPackagName == null) {
+            return false;
+        } else if (importPackagName.equals("java.lang")) {
+            return false;
+        } else if (importPackagName.equals(getPackageName(topLevelClass)) && Utils.isTopLevelClass(importType)) {
+            return false; // same package name -> no import
+        }
+
+        List<Element> elements = Utils.getElementHierarchy(enclosedElement);
 
-        // if type is declared inside a super type of this class -> no import
-        collectSuperTypeImports(e, autoImportedTypes);
-        collectInnerTypeImports(e, autoImportedTypes);
+        Set<String> autoImportedTypes = new HashSet<>();
+        for (Element element : elements) {
+            if (element.getKind().isClass()) {
+                collectSuperTypeImports((TypeElement) element, autoImportedTypes);
+                collectInnerTypeImports((TypeElement) element, autoImportedTypes);
+            }
+        }
 
+        String qualifiedName = getQualifiedName(importType);
+        if (autoImportedTypes.contains(qualifiedName)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    private static Set<CodeImport> generateImports(Collection<TypeMirror> toGenerate) {
         TreeSet<CodeImport> importObjects = new TreeSet<>();
         for (TypeMirror importType : toGenerate) {
-            String importTypePackageName = getPackageName(importType);
-            if (importTypePackageName == null) {
-                continue; // no package name -> no import
-            }
-
-            if (importTypePackageName.equals("java.lang")) {
-                continue; // java.lang is automatically imported
-            }
-
-            if (importTypePackageName.equals(getPackageName(e)) && Utils.isTopLevelClass(importType)) {
-                continue; // same package name -> no import
-            }
-
-            String qualifiedName = getQualifiedName(importType);
-
-            if (autoImportedTypes.contains(qualifiedName)) {
-                continue;
-            }
-
             importObjects.add(new CodeImport(importType, getQualifiedName(importType), false));
         }
-
         return importObjects;
     }
 
@@ -268,12 +278,12 @@
         }
     }
 
-    private static Set<CodeImport> generateStaticImports(CodeTypeElement e, Set<TypeMirror> toGenerate) {
+    private Set<CodeImport> generateStaticImports(Set<TypeMirror> toGenerate) {
         Set<String> autoImportedStaticTypes = new HashSet<>();
 
         // if type is declared inside a super type of this class -> no import
-        autoImportedStaticTypes.add(getQualifiedName(e));
-        autoImportedStaticTypes.addAll(getQualifiedSuperTypeNames(e));
+        autoImportedStaticTypes.add(getQualifiedName(topLevelClass));
+        autoImportedStaticTypes.addAll(getQualifiedSuperTypeNames(topLevelClass));
 
         TreeSet<CodeImport> importObjects = new TreeSet<>();
         for (TypeMirror importType : toGenerate) {
@@ -292,73 +302,52 @@
         return importObjects;
     }
 
-    private static void addUsage(TypeMirror type, Map<TypeMirror, Integer> usageMap) {
-        if (type != null) {
-            Integer value = usageMap.get(type);
-            if (value == null) {
-                usageMap.put(type, 1);
-            } else {
-                usageMap.put(type, value + 1);
-            }
-        }
-    }
-
-    private static class ReferenceCollector extends CodeElementScanner<Void, Void> {
-
-        final Map<TypeMirror, Integer> typeReferences = new HashMap<>();
-        final Map<TypeMirror, Integer> staticTypeReferences = new HashMap<>();
+    private abstract static class TypeReferenceVisitor extends CodeElementScanner<Void, Void> {
 
         @Override
         public void visitTree(CodeTree e, Void p) {
             if (e.getCodeKind() == CodeTreeKind.STATIC_FIELD_REFERENCE) {
-                addStaticImport(e.getType());
+                visitStaticFieldReference(e, e.getType(), e.getString());
             } else if (e.getCodeKind() == CodeTreeKind.STATIC_METHOD_REFERENCE) {
-                addStaticImport(e.getType());
-            } else {
-                addImport(e.getType());
+                visitStaticMethodReference(e, e.getType(), e.getString());
+            } else if (e.getType() != null) {
+                visitTypeReference(e, e.getType());
             }
             super.visitTree(e, p);
         }
 
         @Override
         public Void visitExecutable(CodeExecutableElement e, Void p) {
-            visitAnnotations(e.getAnnotationMirrors());
+            visitAnnotations(e, e.getAnnotationMirrors());
             if (e.getReturnType() != null) {
-                addImport(e.getReturnType());
+                visitTypeReference(e, e.getReturnType());
             }
             for (TypeMirror type : e.getThrownTypes()) {
-                addImport(type);
+                visitTypeReference(e, type);
             }
             return super.visitExecutable(e, p);
         }
 
         @Override
         public Void visitType(CodeTypeElement e, Void p) {
-            visitAnnotations(e.getAnnotationMirrors());
+            visitAnnotations(e, e.getAnnotationMirrors());
 
-            addImport(e.getSuperclass());
+            visitTypeReference(e, e.getSuperclass());
             for (TypeMirror type : e.getImplements()) {
-                addImport(type);
+                visitTypeReference(e, type);
             }
 
             return super.visitType(e, p);
         }
 
-        @Override
-        public Void visitVariable(VariableElement f, Void p) {
-            visitAnnotations(f.getAnnotationMirrors());
-            addImport(f.asType());
-            return super.visitVariable(f, p);
-        }
-
-        private void visitAnnotations(List<? extends AnnotationMirror> mirrors) {
+        private void visitAnnotations(Element enclosingElement, List<? extends AnnotationMirror> mirrors) {
             for (AnnotationMirror mirror : mirrors) {
-                visitAnnotation(mirror);
+                visitAnnotation(enclosingElement, mirror);
             }
         }
 
-        public void visitAnnotation(AnnotationMirror e) {
-            addImport(e.getAnnotationType());
+        public void visitAnnotation(Element enclosingElement, AnnotationMirror e) {
+            visitTypeReference(enclosingElement, e.getAnnotationType());
             if (!e.getElementValues().isEmpty()) {
                 Map<? extends ExecutableElement, ? extends AnnotationValue> values = e.getElementValues();
                 Set<? extends ExecutableElement> methodsSet = values.keySet();
@@ -372,17 +361,23 @@
 
                 for (int i = 0; i < methodsList.size(); i++) {
                     AnnotationValue value = values.get(methodsList.get(i));
-                    visitAnnotationValue(value);
+                    visitAnnotationValue(enclosingElement, value);
                 }
             }
         }
 
-        public void visitAnnotationValue(AnnotationValue e) {
-            e.accept(new AnnotationValueReferenceVisitor(), null);
+        public void visitAnnotationValue(Element enclosingElement, AnnotationValue e) {
+            e.accept(new AnnotationValueReferenceVisitor(enclosingElement), null);
         }
 
         private class AnnotationValueReferenceVisitor extends AbstractAnnotationValueVisitor7<Void, Void> {
 
+            private final Element enclosingElement;
+
+            public AnnotationValueReferenceVisitor(Element enclosedElement) {
+                this.enclosingElement = enclosedElement;
+            }
+
             @Override
             public Void visitBoolean(boolean b, Void p) {
                 return null;
@@ -430,95 +425,67 @@
 
             @Override
             public Void visitType(TypeMirror t, Void p) {
-                addImport(t);
+                visitTypeReference(enclosingElement, t);
                 return null;
             }
 
             @Override
             public Void visitEnumConstant(VariableElement c, Void p) {
-                addImport(c.asType());
+                visitTypeReference(enclosingElement, c.asType());
                 return null;
             }
 
             @Override
             public Void visitAnnotation(AnnotationMirror a, Void p) {
-                ReferenceCollector.this.visitAnnotation(a);
+                TypeReferenceVisitor.this.visitAnnotation(enclosingElement, 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));
+                    TypeReferenceVisitor.this.visitAnnotationValue(enclosingElement, vals.get(i));
                 }
                 return null;
             }
         }
 
         @Override
+        public Void visitVariable(VariableElement f, Void p) {
+            visitAnnotations(f, f.getAnnotationMirrors());
+            visitTypeReference(f, f.asType());
+            return super.visitVariable(f, p);
+        }
+
+        @Override
         public void visitImport(CodeImport e, Void p) {
         }
 
-        private void addStaticImport(TypeMirror type) {
-            addUsage(type, staticTypeReferences);
+        public abstract void visitTypeReference(Element enclosedType, TypeMirror type);
+
+        public abstract void visitStaticMethodReference(Element enclosedType, TypeMirror type, String elementName);
+
+        public abstract void visitStaticFieldReference(Element enclosedType, TypeMirror type, String elementName);
+
+    }
+
+    private class ImportTypeReferenceVisitor extends TypeReferenceVisitor {
+
+        @Override
+        public void visitStaticFieldReference(Element enclosedType, TypeMirror type, String elementName) {
+            staticImportUsage.add(type);
         }
 
-        private void addImport(TypeMirror type) {
-            addUsage(type, typeReferences);
+        @Override
+        public void visitStaticMethodReference(Element enclosedType, TypeMirror type, String elementName) {
+            staticImportUsage.add(type);
+        }
+
+        @Override
+        public void visitTypeReference(Element enclosedType, TypeMirror type) {
+            createTypeReference(enclosedType, type);
         }
 
     }
 
-    private static class ImportResolver extends CodeElementScanner<Void, Void> {
-
-        private final ReferenceCollector collector;
-        private final OrganizedImports organizedImports;
-
-        public ImportResolver(OrganizedImports.ReferenceCollector collector, OrganizedImports organizedImports) {
-            this.collector = collector;
-            this.organizedImports = organizedImports;
-        }
-
-        @Override
-        public Void visitType(CodeTypeElement e, Void p) {
-            if (e.isTopLevelClass()) {
-                organizedImports.clearStaticImports();
-
-                organizedImports.processStaticImports(e);
-                List<TypeElement> types = Utils.getSuperTypes(e);
-                for (TypeElement typeElement : types) {
-                    organizedImports.processStaticImports(typeElement);
-                }
-
-                for (TypeMirror type : collector.staticTypeReferences.keySet()) {
-                    TypeElement element = fromTypeMirror(type);
-                    if (element != null) {
-                        // already processed by supertype
-                        if (types.contains(element)) {
-                            continue;
-                        }
-                        organizedImports.processStaticImports(element);
-                    }
-                }
-
-                for (TypeMirror imp : collector.typeReferences.keySet()) {
-                    organizedImports.useImport(imp);
-                }
-            }
-            return super.visitType(e, p);
-        }
-
-        @Override
-        public void visitTree(CodeTree e, Void p) {
-            if (e.getCodeKind() == CodeTreeKind.TYPE) {
-                organizedImports.useImport(e.getType());
-            } else if (e.getCodeKind() == CodeTreeKind.STATIC_FIELD_REFERENCE) {
-                organizedImports.useStaticFieldImport(e.getType(), e.getString());
-            } else if (e.getCodeKind() == CodeTreeKind.STATIC_METHOD_REFERENCE) {
-                organizedImports.useStaticMethodImport(e.getType(), e.getString());
-            }
-            super.visitTree(e, p);
-        }
-    }
-
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeData.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeData.java	Tue Apr 23 08:44:07 2013 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.codegen.processor.node;
 
+import java.util.*;
+
 import javax.lang.model.element.*;
 
 import com.oracle.truffle.codegen.processor.*;
@@ -59,6 +61,47 @@
         return getMethod().getModifiers().contains(Modifier.FINAL);
     }
 
+    public boolean isAbstract() {
+        return getMethod().getModifiers().contains(Modifier.ABSTRACT);
+    }
+
+    public int getEvaluatedCount() {
+        int count = 0;
+        for (ActualParameter parameter : getParameters()) {
+            if (parameter.getSpecification().isSignature()) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    public boolean startsWithSignature(TemplateMethod method) {
+        for (ActualParameter param : getParameters()) {
+            if (!param.getSpecification().isSignature()) {
+                continue;
+            }
+            ActualParameter foundParam = method.findParameter(param.getLocalName());
+            if (foundParam != null) {
+                TypeData actualType = param.getTypeSystemType();
+                TypeData foundType = foundParam.getTypeSystemType();
+                if (actualType == null || foundType == null || !actualType.equalsType(foundType)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    public boolean hasGenericSignature() {
+        List<TypeData> types = getSignature();
+        for (TypeData typeData : types) {
+            if (!typeData.isGeneric()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     @Override
     public int hashCode() {
         return type.hashCode();
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java	Tue Apr 23 08:44:07 2013 +0200
@@ -29,6 +29,7 @@
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.codegen.processor.*;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality;
 import com.oracle.truffle.codegen.processor.template.*;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
@@ -42,27 +43,37 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-
-        List<TypeMirror> types = new ArrayList<>();
-        types.addAll(getNode().getTypeSystem().getPrimitiveTypeMirrors());
-        types.add(getContext().getType(void.class));
-
-        ParameterSpec returnTypeSpec = new ParameterSpec("executedValue", types);
-        returnTypeSpec.setSignature(true);
-        MethodSpec spec = new MethodSpec(returnTypeSpec);
-        spec.addOptional(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame()));
+        MethodSpec spec = createDefaultMethodSpec(method, mirror, false, null);
+        spec.setVariableRequiredArguments(true);
+        ParameterSpec other = new ParameterSpec("other", nodeTypeMirrors(getNode()));
+        other.setCardinality(Cardinality.MANY);
+        other.setSignature(true);
+        other.setIndexed(true);
+        spec.addRequired(other);
         return spec;
     }
 
     @Override
     public final boolean isParsable(ExecutableElement method) {
-        boolean parsable = method.getSimpleName().toString().startsWith("execute");
-        return parsable;
+        if (method.getModifiers().contains(Modifier.STATIC)) {
+            return false;
+        } else if (method.getModifiers().contains(Modifier.NATIVE)) {
+            return false;
+        }
+        return method.getSimpleName().toString().startsWith("execute");
+    }
+
+    @Override
+    protected List<TypeMirror> nodeTypeMirrors(NodeData nodeData) {
+        // executable types not yet available
+        List<TypeMirror> types = new ArrayList<>(nodeData.getTypeSystem().getPrimitiveTypeMirrors());
+        types.add(nodeData.getTypeSystem().getVoidType().getPrimitiveType());
+        return types;
     }
 
     @Override
     public ExecutableTypeData create(TemplateMethod method) {
-        TypeData resolvedType = method.getReturnType().getActualTypeData(getNode().getTypeSystem());
+        TypeData resolvedType = method.getReturnType().getTypeSystemType();
         return new ExecutableTypeData(method, getNode().getTypeSystem(), resolvedType);
     }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Tue Apr 23 08:44:07 2013 +0200
@@ -40,7 +40,7 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        return createDefaultMethodSpec(method, mirror, null);
+        return createDefaultMethodSpec(method, mirror, true, null);
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java	Tue Apr 23 08:44:07 2013 +0200
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.codegen.processor.node;
+
+import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+
+import com.oracle.truffle.codegen.processor.template.*;
+
+public class NodeChildData extends MessageContainer {
+
+    public enum Cardinality {
+        ONE, MANY;
+
+        public boolean isMany() {
+            return this == MANY;
+        }
+
+        public boolean isOne() {
+            return this == ONE;
+        }
+    }
+
+    public enum ExecutionKind {
+        DEFAULT, SHORT_CIRCUIT
+    }
+
+    private final Element sourceElement;
+    private final AnnotationMirror sourceAnnotationMirror;
+
+    private final String name;
+    private final TypeMirror type;
+    private final Element accessElement;
+
+    private final Cardinality cardinality;
+    private final ExecutionKind executionKind;
+    private NodeData nodeData;
+
+    public NodeChildData(Element sourceElement, AnnotationMirror sourceMirror, String name, TypeMirror nodeType, Element accessElement, Cardinality cardinality, ExecutionKind executionKind) {
+        this.sourceElement = sourceElement;
+        this.sourceAnnotationMirror = sourceMirror;
+        this.name = name;
+        this.type = nodeType;
+        this.accessElement = accessElement;
+        this.cardinality = cardinality;
+        this.executionKind = executionKind;
+    }
+
+    @Override
+    public Element getMessageElement() {
+        return sourceElement;
+    }
+
+    @Override
+    public AnnotationMirror getMessageAnnotation() {
+        return sourceAnnotationMirror;
+    }
+
+    public boolean isShortCircuit() {
+        return executionKind == ExecutionKind.SHORT_CIRCUIT;
+    }
+
+    void setNode(NodeData nodeData) {
+        this.nodeData = nodeData;
+        if (nodeData != null) {
+            getMessages().addAll(nodeData.collectMessages());
+        }
+    }
+
+    public Element getAccessElement() {
+        return accessElement;
+    }
+
+    public TypeMirror getNodeType() {
+        return type;
+    }
+
+    public Cardinality getCardinality() {
+        return cardinality;
+    }
+
+    public ExecutionKind getExecutionKind() {
+        return executionKind;
+    }
+
+    public NodeData getNodeData() {
+        return nodeData;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String toString() {
+        return "NodeFieldData[name=" + getName() + ", kind=" + cardinality + ", execution=" + executionKind + ", node=" + getNodeData() + "]";
+    }
+
+}
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Tue Apr 23 08:44:07 2013 +0200
@@ -34,8 +34,8 @@
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.ast.*;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.FieldKind;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.ExecutionKind;
 import com.oracle.truffle.codegen.processor.template.*;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
@@ -88,11 +88,12 @@
                 continue;
             }
 
-            method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(parameter)));
+            method.addParameter(new CodeVariableElement(parameter.getType(), valueName(parameter)));
         }
     }
 
-    private static void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, boolean includeImplicit) {
+    private static void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame,
+                    boolean includeImplicit) {
         if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) {
             builder.string("frameValue");
         }
@@ -109,15 +110,34 @@
                 continue;
             }
 
+            ActualParameter sourceParameter = source.findParameter(parameter.getLocalName());
+
             if (unexpectedValueName != null && parameter.getLocalName().equals(unexpectedValueName)) {
-                builder.cast(parameter.getActualType(), CodeTreeBuilder.singleString("ex.getResult()"));
+                builder.cast(parameter.getType(), CodeTreeBuilder.singleString("ex.getResult()"));
+            } else if (sourceParameter != null) {
+                builder.string(valueName(sourceParameter, parameter));
             } else {
                 builder.string(valueName(parameter));
             }
         }
     }
 
-    private static CodeTree createTemplateMethodCall(CodeTreeBuilder parent, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) {
+    private static String valueName(ActualParameter sourceParameter, ActualParameter targetParameter) {
+        if (sourceParameter != null) {
+            if (!sourceParameter.getSpecification().isSignature()) {
+                return valueName(targetParameter);
+            } else if (sourceParameter.getTypeSystemType() != null && targetParameter.getTypeSystemType() != null) {
+                if (sourceParameter.getTypeSystemType().needsCastTo(targetParameter.getTypeSystemType())) {
+                    return castValueName(targetParameter);
+                }
+            }
+            return valueName(targetParameter);
+        } else {
+            return valueName(targetParameter);
+        }
+    }
+
+    private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) {
         CodeTreeBuilder builder = parent.create();
 
         boolean castedValues = sourceMethod != targetMethod;
@@ -129,9 +149,8 @@
         }
         TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement());
         NodeData node = (NodeData) targetMethod.getTemplate();
-        TypeSystemData typeSystem = node.getTypeSystem();
 
-        boolean accessible = targetMethod.canBeAccessedByInstanceOf(node.getNodeType());
+        boolean accessible = targetMethod.canBeAccessedByInstanceOf(getContext(), node.getNodeType());
         if (accessible) {
             if (builder.findMethod().getModifiers().contains(STATIC)) {
                 if (method.getModifiers().contains(STATIC)) {
@@ -140,7 +159,11 @@
                     builder.string(THIS_NODE_LOCAL_VAR_NAME);
                 }
             } else {
-                builder.string("super");
+                if (targetMethod instanceof ExecutableTypeData) {
+                    builder.string("this");
+                } else {
+                    builder.string("super");
+                }
             }
         } else {
             if (method.getModifiers().contains(STATIC)) {
@@ -156,17 +179,8 @@
                 ActualParameter sourceParameter = sourceMethod.findParameter(parameter.getLocalName());
                 assert parameter != null;
 
-                if (castedValues) {
-                    NodeFieldData field = node.findField(parameter.getSpecification().getName());
-                    if (field == null) {
-                        builder.string(valueName(parameter));
-                    } else {
-                        if (Utils.typeEquals(sourceParameter.getActualType(), parameter.getActualType())) {
-                            builder.string(valueName(parameter));
-                        } else {
-                            builder.string(castValueName(parameter));
-                        }
-                    }
+                if (castedValues && sourceParameter != null) {
+                    builder.string(valueName(sourceParameter, parameter));
                 } else {
                     builder.string(valueName(parameter));
                 }
@@ -180,7 +194,7 @@
             if (valueParameter == null) {
                 valueParameter = targetParameter;
             }
-            TypeData targetType = targetParameter.getActualTypeData(typeSystem);
+            TypeData targetType = targetParameter.getTypeSystemType();
 
             if (targetParameter.isImplicit() || valueParameter.isImplicit()) {
                 continue;
@@ -188,7 +202,7 @@
 
             TypeData valueType = null;
             if (valueParameter != null) {
-                valueType = valueParameter.getActualTypeData(typeSystem);
+                valueType = valueParameter.getTypeSystemType();
             }
 
             if (targetParameter.getSpecification().isLocal()) {
@@ -203,7 +217,15 @@
             } else if (unexpectedValueName != null && targetParameter.getLocalName().equals(unexpectedValueName)) {
                 builder.string("ex.getResult()");
             } else if (targetType == null || targetType.isGeneric() || (valueType != null && valueType.equalsType(targetType))) {
+                builder.startGroup();
+
+                if (valueType != null && sourceMethod.getMethodName().equals(targetMethod.getMethodName()) && !valueType.isGeneric() && targetType.isGeneric()) {
+                    builder.string("(");
+                    builder.type(targetType.getPrimitiveType());
+                    builder.string(") ");
+                }
                 builder.string(valueName(targetParameter));
+                builder.end();
             } else {
                 builder.string(castValueName(targetParameter));
             }
@@ -214,8 +236,14 @@
         return builder.getRoot();
     }
 
-    private static String genClassName(Template operation) {
-        return getSimpleName(operation.getTemplateType()) + "Gen";
+    private static String genClassName(NodeData node) {
+        String nodeid = node.getNodeId();
+        if (nodeid.endsWith("Node") && !nodeid.equals("Node")) {
+            nodeid = nodeid.substring(0, nodeid.length() - 4);
+        }
+        String name = Utils.firstLetterUpperCase(nodeid);
+        name += "GenNode";
+        return name;
     }
 
     private String generatedGenericMethodName(SpecializationData specialization) {
@@ -243,10 +271,10 @@
         return prefix;
     }
 
-    private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, String value) {
+    private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, CodeTree value) {
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
         startCallTypeSystemMethod(context, builder, node, methodName);
-        builder.string(value);
+        builder.tree(value);
         builder.end().end();
         return builder.getRoot();
     }
@@ -277,11 +305,11 @@
             valuesNeedsCast = new HashSet<>();
             for (GuardData guard : targetSpecialization.getGuards()) {
                 for (ActualParameter parameter : guard.getParameters()) {
-                    NodeFieldData field = node.findField(parameter.getSpecification().getName());
+                    NodeChildData field = node.findChild(parameter.getSpecification().getName());
                     if (field == null) {
                         continue;
                     }
-                    TypeData typeData = parameter.getActualTypeData(node.getTypeSystem());
+                    TypeData typeData = parameter.getTypeSystemType();
                     if (typeData != null && !typeData.isGeneric()) {
                         valuesNeedsCast.add(parameter.getLocalName());
                     }
@@ -325,7 +353,7 @@
         return builder.getRoot();
     }
 
-    private static CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) {
+    private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) {
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
         String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
         if (guardedSpecialization.getGuards().size() > 0) {
@@ -344,8 +372,8 @@
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
         // Implict guards based on method signature
         for (ActualParameter guardedParam : guardedSpecialization.getParameters()) {
-            NodeFieldData field = guardedSpecialization.getNode().findField(guardedParam.getSpecification().getName());
-            if (field == null || field.getKind() == FieldKind.FIELD) {
+            NodeChildData field = guardedSpecialization.getNode().findChild(guardedParam.getSpecification().getName());
+            if (field == null) {
                 continue;
             }
             ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName());
@@ -369,8 +397,8 @@
         // Implict guards based on method signature
         String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
         for (ActualParameter guardedParam : guardedSpecialization.getParameters()) {
-            NodeFieldData field = guardedSpecialization.getNode().findField(guardedParam.getSpecification().getName());
-            if (field == null || field.getKind() == FieldKind.FIELD) {
+            NodeChildData field = guardedSpecialization.getNode().findChild(guardedParam.getSpecification().getName());
+            if (field == null) {
                 continue;
             }
             ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName());
@@ -388,12 +416,12 @@
         return builder.isEmpty() ? null : builder.getRoot();
     }
 
-    private CodeTree createImplicitGuard(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) {
+    private CodeTree createImplicitGuard(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, ActualParameter target) {
         NodeData node = field.getNodeData();
         CodeTreeBuilder builder = new CodeTreeBuilder(parent);
 
-        TypeData targetType = target.getActualTypeData(node.getTypeSystem());
-        TypeData sourceType = source.getActualTypeData(node.getTypeSystem());
+        TypeData targetType = target.getTypeSystemType();
+        TypeData sourceType = source.getTypeSystemType();
 
         if (targetType.equalsType(sourceType) || targetType.isGeneric()) {
             return null;
@@ -409,7 +437,7 @@
             builder.string(" || ");
         }
 
-        startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(target.getActualTypeData(node.getTypeSystem())));
+        startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(target.getTypeSystemType()));
         builder.string(valueName(source));
         builder.end().end(); // call
 
@@ -422,14 +450,12 @@
         return builder.getRoot();
     }
 
-    private CodeTree createCast(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) {
+    private CodeTree createCast(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, ActualParameter target) {
         NodeData node = field.getNodeData();
-        TypeSystemData typeSystem = node.getTypeSystem();
+        TypeData sourceType = source.getTypeSystemType();
+        TypeData targetType = target.getTypeSystemType();
 
-        TypeData sourceType = source.getActualTypeData(typeSystem);
-        TypeData targetType = target.getActualTypeData(typeSystem);
-
-        if (targetType.equalsType(sourceType) || targetType.isGeneric()) {
+        if (!sourceType.needsCastTo(targetType)) {
             return null;
         }
 
@@ -440,9 +466,9 @@
             condition = CodeTreeBuilder.singleString(valueName(shortCircuit));
         }
 
-        CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), valueName(target));
+        CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), CodeTreeBuilder.singleString(valueName(target)));
 
-        return createLazyAssignment(parent, castValueName(target), target.getActualType(), condition, value);
+        return createLazyAssignment(parent, castValueName(target), target.getType(), condition, value);
     }
 
     /**
@@ -483,22 +509,49 @@
         builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end();
     }
 
+    private static List<ExecutableElement> findUserConstructors(TypeMirror nodeType) {
+        List<ExecutableElement> constructors = new ArrayList<>();
+        for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(nodeType).getEnclosedElements())) {
+            if (constructor.getModifiers().contains(PRIVATE)) {
+                continue;
+            }
+            if (isCopyConstructor(constructor)) {
+                continue;
+            }
+            constructors.add(constructor);
+        }
+
+        if (constructors.isEmpty()) {
+            constructors.add(new CodeExecutableElement(null, Utils.getSimpleName(nodeType)));
+        }
+
+        return constructors;
+    }
+
+    private static boolean isCopyConstructor(ExecutableElement element) {
+        if (element.getParameters().size() != 1) {
+            return false;
+        }
+        VariableElement var = element.getParameters().get(0);
+        TypeElement type = Utils.findNearestEnclosingType(var);
+
+        if (!Utils.typeEquals(var.asType(), type.asType())) {
+            return false;
+        }
+        return true;
+    }
+
     @Override
     protected void createChildren(NodeData node) {
         Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>();
-        if (node.getDeclaredChildren() != null && !node.getDeclaredChildren().isEmpty()) {
-            for (NodeData nodeChild : node.getDeclaredChildren()) {
+        if (node.getDeclaredNodes() != null && !node.getDeclaredNodes().isEmpty()) {
+            for (NodeData nodeChild : node.getDeclaredNodes()) {
                 NodeCodeGenerator generator = new NodeCodeGenerator(getContext());
                 childTypes.put(nodeChild, generator.process(null, nodeChild).getEnclosedElements());
             }
         }
 
-        if (node.getExtensionElements() != null && !node.getExtensionElements().isEmpty()) {
-            NodeGenFactory factory = new NodeGenFactory(context);
-            add(factory, node);
-        }
-
-        if (node.needsFactory() || node.getNodeChildren().size() > 0) {
+        if (node.needsFactory() || node.getNodeDeclaringChildren().size() > 0) {
             add(new NodeFactoryFactory(context, childTypes), node);
         }
     }
@@ -511,36 +564,138 @@
 
         @Override
         protected CodeTypeElement create(NodeData node) {
-            CodeTypeElement clazz = createClass(node, modifiers(PUBLIC, ABSTRACT), genClassName(node), node.getTemplateType().asType(), false);
+            CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), genClassName(node), node.getNodeType(), false);
 
-            for (ExecutableElement executable : ElementFilter.constructorsIn(node.getTemplateType().getEnclosedElements())) {
-                CodeExecutableElement superConstructor = createSuperConstructor(clazz, executable);
+            for (NodeChildData child : node.getChildren()) {
+                clazz.add(createChildField(child));
 
-                if (superConstructor != null) {
-                    if (superConstructor.getParameters().size() == 1 && Utils.typeEquals(superConstructor.getParameters().get(0).asType(), node.getTemplateType().asType())) {
-                        String originalName = superConstructor.getParameters().get(0).getSimpleName().toString();
-                        superConstructor.getParameters().clear();
-                        superConstructor.getParameters().add(new CodeVariableElement(clazz.asType(), originalName));
-                    }
-                    clazz.add(superConstructor);
+                if (child.getAccessElement() != null && child.getAccessElement().getModifiers().contains(Modifier.ABSTRACT)) {
+                    ExecutableElement getter = (ExecutableElement) child.getAccessElement();
+                    CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), getter);
+                    method.getModifiers().remove(Modifier.ABSTRACT);
+                    method.createBuilder().startReturn().string("this.").string(child.getName()).end();
+                    clazz.add(method);
                 }
             }
 
+            createConstructors(node, clazz);
+
             if (node.getExtensionElements() != null) {
                 clazz.getEnclosedElements().addAll(node.getExtensionElements());
             }
 
-            node.setNodeType(clazz.asType());
-
             return clazz;
         }
 
+        private void createConstructors(NodeData node, CodeTypeElement clazz) {
+            List<ExecutableElement> signatureConstructors = new ArrayList<>();
+            ExecutableElement copyConstructor = null;
+            List<? extends ExecutableElement> constructors = ElementFilter.constructorsIn(Utils.fromTypeMirror(node.getNodeType()).getEnclosedElements());
+            for (ExecutableElement constructor : constructors) {
+                if (constructor.getModifiers().contains(Modifier.PRIVATE) || constructor.getParameters().isEmpty()) {
+                    continue;
+                }
+
+                if (isCopyConstructor(constructor)) {
+                    assert copyConstructor == null;
+                    copyConstructor = createConstructor(clazz, constructor, true);
+                } else {
+                    signatureConstructors.add(createConstructor(clazz, constructor, false));
+                }
+            }
+
+            if (copyConstructor == null && node.needsRewrites(getContext())) {
+                clazz.add(createConstructor(clazz, null, true));
+            } else if (copyConstructor != null) {
+                clazz.add(copyConstructor);
+            }
+
+            if (signatureConstructors.isEmpty() && !node.getChildren().isEmpty()) {
+                clazz.add(createConstructor(clazz, null, false));
+            } else {
+                clazz.getEnclosedElements().addAll(signatureConstructors);
+            }
+        }
+
+        private CodeExecutableElement createConstructor(CodeTypeElement type, ExecutableElement superConstructor, boolean copyConstructor) {
+            CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString());
+            CodeTreeBuilder builder = method.createBuilder();
+            if (!copyConstructor) {
+                if (superConstructor != null) {
+                    for (VariableElement param : superConstructor.getParameters()) {
+                        method.getParameters().add(CodeVariableElement.clone(param));
+                    }
+                }
+                for (NodeChildData child : getModel().getChildren()) {
+                    method.getParameters().add(new CodeVariableElement(child.getNodeType(), child.getName()));
+                }
+            } else {
+                if (!(superConstructor == null && getModel().getChildren().isEmpty())) {
+                    method.getParameters().add(new CodeVariableElement(type.asType(), "copy"));
+                }
+            }
+
+            if (superConstructor != null) {
+                builder.startStatement();
+                builder.startSuperCall();
+                if (copyConstructor) {
+                    builder.string("copy");
+                } else {
+                    for (VariableElement param : superConstructor.getParameters()) {
+                        builder.string(param.getSimpleName().toString());
+                    }
+                }
+                builder.end();
+                builder.end();
+            }
+
+            for (NodeChildData child : getModel().getChildren()) {
+
+                builder.startStatement();
+                builder.string("this.").string(child.getName()).string(" = ");
+
+                if (child.getCardinality() == Cardinality.MANY) {
+                    builder.startCall("adoptChildren");
+                } else {
+                    builder.startCall("adoptChild");
+                }
+
+                builder.startGroup();
+                if (copyConstructor) {
+                    builder.string("copy.");
+                }
+                builder.string(child.getName());
+                builder.end();
+
+                builder.end();
+                builder.end();
+
+            }
+
+            return method;
+        }
+
+        private CodeVariableElement createChildField(NodeChildData child) {
+            DeclaredType annotationType;
+            if (child.getCardinality() == Cardinality.MANY) {
+                annotationType = getContext().getTruffleTypes().getChildrenAnnotation();
+            } else {
+                annotationType = getContext().getTruffleTypes().getChildAnnotation();
+            }
+
+            CodeVariableElement var = new CodeVariableElement(child.getNodeType(), child.getName());
+            var.getModifiers().add(Modifier.PROTECTED);
+            var.getAnnotationMirrors().add(new CodeAnnotationMirror(annotationType));
+            return var;
+        }
     }
 
     private class NodeFactoryFactory extends ClassElementFactory<NodeData> {
 
         private final Map<NodeData, List<TypeElement>> childTypes;
 
+        private CodeTypeElement generatedNode;
+
         public NodeFactoryFactory(ProcessorContext context, Map<NodeData, List<TypeElement>> childElements) {
             super(context);
             this.childTypes = childElements;
@@ -565,6 +720,10 @@
             Modifier createVisibility = Utils.getVisibility(clazz.getModifiers());
 
             if (node.needsFactory()) {
+                NodeGenFactory factory = new NodeGenFactory(context);
+                add(factory, node);
+                generatedNode = factory.getElement();
+
                 createFactoryMethods(node, clazz, createVisibility);
 
                 if (node.getSpecializations().size() > 1) {
@@ -583,15 +742,15 @@
                 }
 
                 for (SpecializationData specialization : node.getSpecializations()) {
-                    add(new SpecializedNodeFactory(context), specialization);
+                    add(new SpecializedNodeFactory(context, generatedNode), specialization);
                 }
 
-                TypeMirror nodeFactory = getContext().getEnvironment().getTypeUtils().getDeclaredType(Utils.fromTypeMirror(getContext().getType(NodeFactory.class)), node.getNodeType());
+                TypeMirror nodeFactory = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getType(NodeFactory.class)), node.getNodeType());
                 clazz.getImplements().add(nodeFactory);
                 clazz.add(createCreateNodeMethod(node));
                 clazz.add(createCreateNodeSpecializedMethod(node));
                 clazz.add(createGetNodeClassMethod(node));
-                clazz.add(createGetNodeSignaturesMethod(node));
+                clazz.add(createGetNodeSignaturesMethod());
                 clazz.add(createGetChildrenSignatureMethod(node));
                 clazz.add(createGetInstanceMethod(node, createVisibility));
                 clazz.add(createInstanceConstant(node, clazz.asType()));
@@ -616,7 +775,7 @@
                 }
             }
 
-            List<NodeData> children = node.getNodeChildren();
+            List<NodeData> children = node.getNodeDeclaringChildren();
             if (node.getParent() == null && children.size() > 0) {
                 clazz.add(createGetFactories(node));
             }
@@ -624,24 +783,22 @@
         }
 
         private CodeExecutableElement createGetNodeClassMethod(NodeData node) {
-            Types types = getContext().getEnvironment().getTypeUtils();
-            TypeMirror returnType = types.getDeclaredType(Utils.fromTypeMirror(getContext().getType(Class.class)), node.getNodeType());
+            TypeMirror returnType = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getType(Class.class)), node.getNodeType());
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeClass");
             CodeTreeBuilder builder = method.createBuilder();
             builder.startReturn().typeLiteral(node.getNodeType()).end();
             return method;
         }
 
-        private CodeExecutableElement createGetNodeSignaturesMethod(NodeData node) {
-            Types types = getContext().getEnvironment().getTypeUtils();
+        private CodeExecutableElement createGetNodeSignaturesMethod() {
             TypeElement listType = Utils.fromTypeMirror(getContext().getType(List.class));
             TypeMirror classType = getContext().getType(Class.class);
-            TypeMirror returnType = types.getDeclaredType(listType, types.getDeclaredType(listType, classType));
+            TypeMirror returnType = Utils.getDeclaredType(listType, Utils.getDeclaredType(listType, classType));
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeSignatures");
             CodeTreeBuilder builder = method.createBuilder();
             builder.startReturn();
             builder.startStaticCall(getContext().getType(Arrays.class), "asList");
-            List<ExecutableElement> constructors = findUserConstructors(node);
+            List<ExecutableElement> constructors = findUserConstructors(generatedNode.asType());
             for (ExecutableElement constructor : constructors) {
                 builder.tree(createAsList(builder, Utils.asTypeMirrors(constructor.getParameters()), classType));
             }
@@ -656,8 +813,8 @@
             TypeMirror classType = getContext().getType(Class.class);
             TypeMirror nodeType = getContext().getTruffleTypes().getNode();
             TypeMirror wildcardNodeType = types.getWildcardType(nodeType, null);
-            classType = types.getDeclaredType(Utils.fromTypeMirror(classType), wildcardNodeType);
-            TypeMirror returnType = types.getDeclaredType(listType, classType);
+            classType = Utils.getDeclaredType(Utils.fromTypeMirror(classType), wildcardNodeType);
+            TypeMirror returnType = Utils.getDeclaredType(listType, classType);
 
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getExecutionSignature");
             CodeTreeBuilder builder = method.createBuilder();
@@ -667,16 +824,16 @@
             SpecializationData data = node.getSpecializations().get(0);
             for (ActualParameter parameter : data.getParameters()) {
                 ParameterSpec spec = parameter.getSpecification();
-                NodeFieldData field = node.findField(spec.getName());
-                if (field == null || field.getKind() == FieldKind.FIELD) {
+                NodeChildData field = node.findChild(spec.getName());
+                if (field == null) {
                     continue;
                 }
 
                 TypeMirror type;
-                if (field.getKind() == FieldKind.CHILDREN && field.getType().getKind() == TypeKind.ARRAY) {
-                    type = ((ArrayType) field.getType()).getComponentType();
+                if (field.getCardinality() == Cardinality.MANY && field.getNodeType().getKind() == TypeKind.ARRAY) {
+                    type = ((ArrayType) field.getNodeType()).getComponentType();
                 } else {
-                    type = field.getType();
+                    type = field.getNodeType();
                 }
 
                 signatureTypes.add(type);
@@ -706,7 +863,7 @@
             method.addParameter(arguments);
 
             CodeTreeBuilder builder = method.createBuilder();
-            List<ExecutableElement> signatures = findUserConstructors(node);
+            List<ExecutableElement> signatures = findUserConstructors(generatedNode.asType());
             boolean ifStarted = false;
 
             for (ExecutableElement element : signatures) {
@@ -785,9 +942,8 @@
         }
 
         private ExecutableElement createGetInstanceMethod(NodeData node, Modifier visibility) {
-            Types types = getContext().getEnvironment().getTypeUtils();
             TypeElement nodeFactoryType = Utils.fromTypeMirror(getContext().getType(NodeFactory.class));
-            TypeMirror returnType = types.getDeclaredType(nodeFactoryType, node.getNodeType());
+            TypeMirror returnType = Utils.getDeclaredType(nodeFactoryType, node.getNodeType());
 
             CodeExecutableElement method = new CodeExecutableElement(modifiers(), returnType, "getInstance");
             if (visibility != null) {
@@ -830,7 +986,7 @@
         }
 
         private ExecutableElement createGetFactories(NodeData node) {
-            List<NodeData> children = node.getNodeChildren();
+            List<NodeData> children = node.getNodeDeclaringChildren();
             if (node.needsFactory()) {
                 children.add(node);
             }
@@ -851,11 +1007,11 @@
             TypeMirror factoryType = getContext().getType(NodeFactory.class);
             TypeMirror baseType;
             if (allSame) {
-                baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), commonNodeSuperType);
+                baseType = Utils.getDeclaredType(Utils.fromTypeMirror(factoryType), commonNodeSuperType);
             } else {
-                baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null));
+                baseType = Utils.getDeclaredType(Utils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null));
             }
-            TypeMirror listType = types.getDeclaredType(Utils.fromTypeMirror(getContext().getType(List.class)), baseType);
+            TypeMirror listType = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getType(List.class)), baseType);
 
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), listType, "getFactories");
 
@@ -884,28 +1040,12 @@
         }
 
         private void createFactoryMethods(NodeData node, CodeTypeElement clazz, Modifier createVisibility) {
-            List<ExecutableElement> constructors = findUserConstructors(node);
+            List<ExecutableElement> constructors = findUserConstructors(generatedNode.asType());
             for (ExecutableElement constructor : constructors) {
                 clazz.add(createCreateMethod(node, createVisibility, constructor));
             }
         }
 
-        private List<ExecutableElement> findUserConstructors(NodeData node) {
-            List<ExecutableElement> constructors = new ArrayList<>();
-            for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(node.getNodeType()).getEnclosedElements())) {
-                if (constructor.getModifiers().contains(PRIVATE)) {
-                    continue;
-                }
-
-                // skip node rewrite constructor
-                if (constructor.getParameters().size() == 1 && typeEquals(constructor.getParameters().get(0).asType(), node.getNodeType())) {
-                    continue;
-                }
-                constructors.add(constructor);
-            }
-            return constructors;
-        }
-
         private CodeExecutableElement createCreateMethod(NodeData node, Modifier visibility, ExecutableElement constructor) {
             CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), constructor);
             method.setSimpleName(CodeNames.of("create"));
@@ -942,6 +1082,12 @@
             method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "specializationClass"));
 
             CodeTreeBuilder body = method.createBuilder();
+
+            body.startStatement();
+            body.type(generatedNode.asType()).string(" ").string(THIS_NODE_LOCAL_VAR_NAME + "Cast");
+            body.string(" = ").string("(").type(generatedNode.asType()).string(") ").string(THIS_NODE_LOCAL_VAR_NAME);
+            body.end();
+
             boolean first = true;
             for (TypeData type : node.getTypeSystem().getTypes()) {
                 SpecializationData specialization = node.findUniqueSpecialization(type);
@@ -954,21 +1100,21 @@
                     }
                     body.string("specializationClass == ").type(type.getBoxedType()).string(".class").end().startBlock();
                     body.startReturn().startNew(nodeSpecializationClassName(specialization));
-                    body.string(THIS_NODE_LOCAL_VAR_NAME);
+                    body.string(THIS_NODE_LOCAL_VAR_NAME + "Cast");
                     body.end().end(); // new, return
 
                     body.end(); // if
                 }
             }
             body.startReturn().startNew(nodeSpecializationClassName(node.getGenericSpecialization()));
-            body.string(THIS_NODE_LOCAL_VAR_NAME);
+            body.string(THIS_NODE_LOCAL_VAR_NAME + "Cast");
             body.end().end();
             return method;
         }
 
         private CodeExecutableElement createSpecializeMethod(NodeData node) {
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), node.getNodeType(), "specialize");
-            method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME));
+            method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME));
             method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
             addInternalValueParameters(method, node.getGenericSpecialization(), true);
 
@@ -992,7 +1138,7 @@
         }
 
         private List<CodeExecutableElement> createGeneratedGenericMethod(NodeData node) {
-            TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getActualType();
+            TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType();
             if (node.needsRewrites(context)) {
                 List<CodeExecutableElement> methods = new ArrayList<>();
 
@@ -1037,7 +1183,7 @@
 
                 nextBuilder.startReturn().startCall(generatedGenericMethodName(next));
                 nextBuilder.string(THIS_NODE_LOCAL_VAR_NAME);
-                addInternalValueParameterNames(nextBuilder, next, null, true, true);
+                addInternalValueParameterNames(nextBuilder, next, next, null, true, true);
                 nextBuilder.end().end();
 
                 invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, true, invokeMethod, nextBuilder.getRoot());
@@ -1069,7 +1215,7 @@
 
                     builder.startReturn().startCall(generatedGenericMethodName(exception.getTransitionTo()));
                     builder.string(THIS_NODE_LOCAL_VAR_NAME);
-                    addInternalValueParameterNames(builder, exception.getTransitionTo(), null, true, true);
+                    addInternalValueParameterNames(builder, exception.getTransitionTo(), exception.getTransitionTo(), null, true, true);
                     builder.end().end();
                 }
                 builder.end();
@@ -1080,14 +1226,21 @@
 
     private class SpecializedNodeFactory extends ClassElementFactory<SpecializationData> {
 
-        public SpecializedNodeFactory(ProcessorContext context) {
+        private final CodeTypeElement nodeGen;
+
+        public SpecializedNodeFactory(ProcessorContext context, CodeTypeElement nodeGen) {
             super(context);
+            this.nodeGen = nodeGen;
         }
 
         @Override
         public CodeTypeElement create(SpecializationData specialization) {
             NodeData node = specialization.getNode();
-            CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), node.getNodeType(), false);
+            TypeMirror baseType = node.getNodeType();
+            if (nodeGen != null) {
+                baseType = nodeGen.asType();
+            }
+            CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), baseType, false);
             return clazz;
         }
 
@@ -1108,20 +1261,14 @@
                 if (execType.isFinal()) {
                     continue;
                 }
-                CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod());
-                if (method.getParameters().size() == 1) {
-                    CodeVariableElement var = CodeVariableElement.clone(method.getParameters().get(0));
-                    var.setName("frameValue");
-                    method.getParameters().set(0, var);
-                }
-                method.getModifiers().remove(Modifier.ABSTRACT);
-                clazz.add(method);
-
-                TypeData primaryType = specialization.getReturnType().getActualTypeData(node.getTypeSystem());
-                if (primaryType == execType.getType()) {
-                    buildFunctionalExecuteMethod(method.createBuilder(), specialization);
+                CodeExecutableElement executeMethod = createExecutableTypeOverride(execType);
+                clazz.add(executeMethod);
+                CodeTreeBuilder builder = executeMethod.createBuilder();
+                CodeTree result = createExecuteBody(builder, specialization, execType);
+                if (result != null) {
+                    builder.tree(result);
                 } else {
-                    buildCastingExecuteMethod(method.createBuilder(), specialization, execType.getType());
+                    clazz.remove(executeMethod);
                 }
             }
 
@@ -1130,23 +1277,111 @@
             }
         }
 
-        private void buildCastingExecuteMethod(CodeTreeBuilder builder, SpecializationData specialization, TypeData type) {
+        private CodeTree createExecuteBody(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData execType) {
+            TypeData primaryType = specialization.getReturnType().getTypeSystemType();
+
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+
+            ExecutableTypeData foundEvaluatedPrimaryType = findFunctionalExecutableType(specialization, execType.getEvaluatedCount());
+
+            if (execType == foundEvaluatedPrimaryType || foundEvaluatedPrimaryType == null) {
+                builder.tree(createFunctionalExecute(builder, specialization, execType));
+            } else if (needsCastingExecuteMethod(execType, primaryType)) {
+                builder.tree(createCastingExecute(builder, specialization, execType, foundEvaluatedPrimaryType));
+            } else {
+                return null;
+            }
+
+            return builder.getRoot();
+        }
+
+        private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType) {
+            CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod());
+
+            int i = 0;
+            for (VariableElement param : method.getParameters()) {
+                CodeVariableElement var = CodeVariableElement.clone(param);
+                var.setName(valueName(execType.getParameters().get(i)));
+                method.getParameters().set(i, var);
+                i++;
+            }
+
+            method.getAnnotationMirrors().clear();
+            method.getModifiers().remove(Modifier.ABSTRACT);
+            return method;
+        }
+
+        private boolean needsCastingExecuteMethod(ExecutableTypeData execType, TypeData primaryType) {
+            if (execType.isAbstract()) {
+                return true;
+            }
+            if (Utils.isPrimitiveOrVoid(primaryType.getPrimitiveType()) && Utils.isPrimitiveOrVoid(execType.getType().getPrimitiveType())) {
+                return true;
+            }
+            if (execType.getType().isGeneric()) {
+                return true;
+            }
+            return false;
+        }
+
+        private ExecutableTypeData findFunctionalExecutableType(SpecializationData specialization, int evaluatedCount) {
+            TypeData primaryType = specialization.getReturnType().getTypeSystemType();
+            List<ExecutableTypeData> otherTypes = specialization.getNode().getExecutableTypes(evaluatedCount);
+
+            List<ExecutableTypeData> filteredTypes = new ArrayList<>();
+            for (ExecutableTypeData compareType : otherTypes) {
+                if (!Utils.typeEquals(compareType.getType().getPrimitiveType(), primaryType.getPrimitiveType())) {
+                    continue;
+                }
+                filteredTypes.add(compareType);
+            }
+
+            for (ExecutableTypeData compareType : filteredTypes) {
+                if (compareType.startsWithSignature(specialization)) {
+                    return compareType;
+                }
+            }
+
+            for (ExecutableTypeData compareType : otherTypes) {
+                if (compareType.startsWithSignature(specialization)) {
+                    return compareType;
+                }
+            }
+
+            return null;
+        }
+
+        private CodeTree createCastingExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable, ExecutableTypeData castExecutable) {
+            TypeData type = executable.getType();
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             NodeData node = specialization.getNode();
-            TypeSystemData typeSystem = node.getTypeSystem();
 
             ExecutableTypeData castedType = node.findExecutableType(type);
-            TypeData primaryType = specialization.getReturnType().getActualTypeData(typeSystem);
-            ExecutableTypeData execType = specialization.getNode().findExecutableType(primaryType);
+            TypeData primaryType = castExecutable.getType();
 
-            boolean needsTry = execType.hasUnexpectedValue(getContext());
+            boolean needsTry = castExecutable.hasUnexpectedValue(getContext());
             boolean returnVoid = type.isVoid();
 
-            CodeTree primaryExecuteCall = null;
+            List<ActualParameter> executeParameters = new ArrayList<>();
+            for (ActualParameter sourceParameter : executable.getParameters()) {
+                NodeChildData field = specialization.getNode().findChild(sourceParameter.getSpecification().getName());
+                if (field == null) {
+                    continue;
+                }
 
-            CodeTreeBuilder executeBuilder = CodeTreeBuilder.createBuilder();
-            buildExecute(executeBuilder, null, null, execType);
-            primaryExecuteCall = executeBuilder.getRoot();
+                ActualParameter targetParameter = castExecutable.findParameter(sourceParameter.getLocalName());
+                if (targetParameter != null) {
+                    TypeData sourceType = sourceParameter.getTypeSystemType();
+                    TypeData targetType = targetParameter.getTypeSystemType();
+                    if (sourceType.needsCastTo(targetType)) {
+                        executeParameters.add(targetParameter);
+                    }
+                }
+            }
 
+            builder.tree(createExecuteChildren(builder, executable, specialization, executeParameters, null, true));
+
+            CodeTree primaryExecuteCall = createTemplateMethodCall(builder, executable, castExecutable, null);
             if (needsTry) {
                 if (!returnVoid) {
                     builder.declaration(primaryType.getPrimitiveType(), "value");
@@ -1186,6 +1421,8 @@
                     builder.end();
                 }
             }
+
+            return builder.getRoot();
         }
 
         private CodeTree createExpectType(NodeData node, ExecutableTypeData castedType, CodeTree value) {
@@ -1211,25 +1448,28 @@
             return builder.getRoot();
         }
 
-        private void buildFunctionalExecuteMethod(CodeTreeBuilder builder, SpecializationData specialization) {
+        private CodeTree createFunctionalExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable) {
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             if (specialization.isUninitialized()) {
                 builder.tree(createDeoptimize(builder));
             }
 
-            builder.tree(createExecuteChildren(builder, specialization));
+            builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null, false));
 
             CodeTree executeNode;
             if (specialization.isUninitialized()) {
-                builder.tree(createSpecializeCall(builder, specialization));
+                builder.tree(createSpecializeCall(builder, executable, specialization));
             }
-            executeNode = createExecute(builder, specialization);
+            executeNode = createExecute(builder, executable, specialization);
 
             SpecializationData next = specialization.findNextSpecialization();
             CodeTree returnSpecialized = null;
             if (next != null) {
-                returnSpecialized = createReturnSpecializeAndExecute(builder, next, null);
+                returnSpecialized = createReturnSpecializeAndExecute(builder, executable, next, null);
             }
             builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized));
+
+            return builder.getRoot();
         }
 
         private CodeTree createDeoptimize(CodeTreeBuilder parent) {
@@ -1240,7 +1480,7 @@
             return builder.getRoot();
         }
 
-        private CodeTree createSpecializeCall(CodeTreeBuilder parent, SpecializationData specialization) {
+        private CodeTree createSpecializeCall(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) {
             NodeData node = specialization.getNode();
 
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
@@ -1252,7 +1492,7 @@
                 builder.startCall(factoryClassName(node), "specialize");
                 builder.string("this");
                 builder.typeLiteral(builder.findMethod().getEnclosingElement().asType());
-                addInternalValueParameterNames(builder, specialization, null, true, true);
+                addInternalValueParameterNames(builder, executable, specialization, null, true, true);
                 builder.end(); // call replace, call specialize
             } else {
                 builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end();
@@ -1261,19 +1501,20 @@
             return builder.getRoot();
         }
 
-        private CodeTree createExecute(CodeTreeBuilder parent, SpecializationData specialization) {
+        private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) {
             NodeData node = specialization.getNode();
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             if (!specialization.getExceptions().isEmpty()) {
                 builder.startTryBlock();
             }
 
+            CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent);
             if (specialization.isUninitialized()) {
                 String genericMethodName = generatedGenericMethodName(null);
-                builder.startReturn().startCall(factoryClassName(node), genericMethodName);
-                builder.string("this");
-                addInternalValueParameterNames(builder, specialization, null, true, true);
-                builder.end().end();
+                returnBuilder.startCall(factoryClassName(node), genericMethodName);
+                returnBuilder.string("this");
+                addInternalValueParameterNames(returnBuilder, executable, specialization, null, true, true);
+                returnBuilder.end();
             } else if (specialization.getMethod() == null && !node.needsRewrites(context)) {
                 emitEncounteredSynthetic(builder);
             } else if (specialization.isGeneric()) {
@@ -1284,36 +1525,81 @@
                     genericMethodName = generatedGenericMethodName(null);
                 }
 
-                builder.startReturn().startCall(factoryClassName(node), genericMethodName);
-                builder.string("this");
-                addInternalValueParameterNames(builder, specialization, null, true, true);
-                builder.end().end();
+                returnBuilder.startCall(factoryClassName(node), genericMethodName);
+                returnBuilder.string("this");
+                addInternalValueParameterNames(returnBuilder, executable, specialization, null, true, true);
+                returnBuilder.end();
             } else {
+                returnBuilder.tree(createTemplateMethodCall(returnBuilder, executable, specialization, null));
+            }
+
+            if (!returnBuilder.isEmpty()) {
                 builder.startReturn();
-                builder.tree(createTemplateMethodCall(builder, specialization, specialization, null));
-                builder.end(); // return
+
+                TypeData targetType = node.getTypeSystem().findTypeData(builder.findMethod().getReturnType());
+                TypeData sourceType = specialization.getReturnType().getTypeSystemType();
+
+                if (targetType == null || sourceType == null) {
+                    builder.tree(returnBuilder.getRoot());
+                } else if (sourceType.needsCastTo(targetType)) {
+                    builder.tree(createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.expectTypeMethodName(targetType), returnBuilder.getRoot()));
+                } else {
+                    builder.tree(returnBuilder.getRoot());
+                }
+                builder.end();
             }
 
             if (!specialization.getExceptions().isEmpty()) {
                 for (SpecializationThrowsData exception : specialization.getExceptions()) {
                     builder.end().startCatchBlock(exception.getJavaClass(), "ex");
-                    builder.tree(createReturnSpecializeAndExecute(parent, exception.getTransitionTo(), null));
+                    builder.tree(createReturnSpecializeAndExecute(parent, executable, exception.getTransitionTo(), null));
                 }
                 builder.end();
             }
             return builder.getRoot();
         }
 
-        private CodeTree createExecuteChildren(CodeTreeBuilder parent, SpecializationData specialization) {
+        private CodeTree createExecuteChildren(CodeTreeBuilder parent, ExecutableTypeData sourceExecutable, SpecializationData specialization, List<ActualParameter> targetParameters,
+                        ActualParameter unexpectedParameter, boolean cast) {
+            NodeData sourceNode = specialization.getNode();
+
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
 
-            for (ActualParameter parameter : specialization.getParameters()) {
-                NodeFieldData field = specialization.getNode().findField(parameter.getSpecification().getName());
-                if (field == null || field.getKind() == FieldKind.FIELD) {
+            for (ActualParameter targetParameter : targetParameters) {
+                NodeChildData field = sourceNode.findChild(targetParameter.getSpecification().getName());
+                if (field == null) {
                     continue;
                 }
+                TypeData targetType = targetParameter.getTypeSystemType();
 
-                buildFieldExecute(builder, specialization, parameter, field, null);
+                ExecutableTypeData targetExecutable = field.getNodeData().findExecutableType(targetType);
+
+                ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName());
+
+                String targetVariableName = null;
+                CodeTree executionExpression = null;
+                if (cast || sourceParameter != null) {
+                    TypeData sourceType = sourceParameter.getTypeSystemType();
+                    if (!sourceType.needsCastTo(targetType)) {
+                        if (field.isShortCircuit() && sourceParameter != null) {
+                            builder.tree(createShortCircuitValue(builder, sourceExecutable, specialization, field, targetParameter.getPreviousParameter(), unexpectedParameter));
+                        }
+                        continue;
+                    }
+                    executionExpression = createExpectType(sourceNode, targetExecutable, CodeTreeBuilder.singleString(valueName(targetParameter)));
+                    targetVariableName = castValueName(targetParameter);
+                } else if (sourceParameter == null) {
+                    targetVariableName = valueName(targetParameter);
+                    executionExpression = createExecuteChildExpression(builder, field, targetParameter);
+                }
+
+                CodeTreeVariable executionVar = new CodeTreeVariable();
+                CodeTree shortCircuitTree = createShortCircuitTree(builder, executionVar, targetVariableName, sourceExecutable, specialization, targetParameter, unexpectedParameter);
+                CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpression, targetVariableName, specialization, sourceExecutable, targetExecutable, targetParameter,
+                                shortCircuitTree != executionVar);
+
+                executionVar.set(unexpectedTree);
+                builder.tree(shortCircuitTree);
             }
             return builder.getRoot();
         }
@@ -1326,62 +1612,66 @@
             }
         }
 
-        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());
+        private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ExecutableTypeData currentExecutable,
+                        ExecutableTypeData targetExecutable, ActualParameter param, boolean shortCircuit) {
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+            boolean unexpected = targetExecutable.hasUnexpectedValue(getContext());
+            builder.startStatement();
 
-            if (!shortCircuit && unexpected) {
-                builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).end();
+            if (!shortCircuit) {
+                builder.type(param.getType()).string(" ").string(targetVariableName);
             }
 
             if (unexpected) {
+                if (!shortCircuit) {
+                    builder.end();
+                }
                 builder.startTryBlock();
+                builder.startStatement();
+                builder.string(targetVariableName);
+            } else if (shortCircuit) {
+                builder.startStatement();
+                builder.string(targetVariableName);
             }
-
-            if (!shortCircuit && !unexpected) {
-                builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).string(" = ");
-            } else {
-                builder.startStatement().string(valueName(param)).string(" = ");
-            }
-            buildExecute(builder, param, field, execType);
+            builder.string(" = ");
+            builder.tree(body);
             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 || field.getKind() == FieldKind.FIELD) {
-                        continue;
-                    }
-                    if (execute) {
-                        buildFieldExecute(builder, specialization.getNode().getGenericSpecialization(), exParam, exField, param);
-                    } else if (exParam.getLocalName().equals(param.getLocalName())) {
-                        execute = true;
-                    }
-                }
-                builder.tree(createReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param));
+                ActualParameter genericParameter = generic.findParameter(param.getLocalName());
+
+                List<ActualParameter> genericParameters = generic.getParametersAfter(genericParameter);
+                builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter, false));
+                builder.tree(createReturnSpecializeAndExecute(builder, currentExecutable, specialization.findNextSpecialization(), param));
                 builder.end(); // catch block
             }
 
-            endShortCircuit(builder, shortCircuit);
-            builder.newLine();
+            return builder.getRoot();
         }
 
-        private void buildExecute(CodeTreeBuilder builder, ActualParameter parameter, NodeFieldData field, ExecutableTypeData execType) {
-            if (field != null) {
-                Element accessElement = field.getAccessElement();
-                if (accessElement.getKind() == ElementKind.METHOD) {
-                    builder.startCall(accessElement.getSimpleName().toString()).end();
+        private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData targetField, ActualParameter sourceParameter) {
+            TypeData type = sourceParameter.getTypeSystemType();
+            ExecutableTypeData execType = targetField.getNodeData().findExecutableType(type);
+
+            /*
+             * FIXME Temporary deactivated due to partial evaluation failure else if
+             * (accessElement.getKind() == ElementKind.METHOD) {
+             * builder.startCall(accessElement.getSimpleName().toString()).end(); }
+             */
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+            if (targetField != null) {
+                Element accessElement = targetField.getAccessElement();
+                if (accessElement == null || accessElement.getKind() == ElementKind.METHOD) {
+                    builder.string("this.").string(targetField.getName());
                 } else if (accessElement.getKind() == ElementKind.FIELD) {
                     builder.string("this.").string(accessElement.getSimpleName().toString());
                 } else {
                     throw new AssertionError();
                 }
-                if (parameter.getSpecification().isIndexed()) {
-                    builder.string("[" + parameter.getIndex() + "]");
+                if (sourceParameter.getSpecification().isIndexed()) {
+                    builder.string("[" + sourceParameter.getIndex() + "]");
                 }
                 builder.string(".");
             }
@@ -1390,22 +1680,40 @@
                 builder.string("frameValue");
             }
             builder.end();
+            return builder.getRoot();
         }
 
-        private boolean startShortCircuit(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter parameter, ActualParameter exceptionParam) {
-            NodeFieldData forField = specialization.getNode().findField(parameter.getSpecification().getName());
+        private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, ExecutableTypeData currentExecutable, SpecializationData specialization,
+                        ActualParameter parameter, ActualParameter exceptionParam) {
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+
+            NodeChildData forField = specialization.getNode().findChild(parameter.getSpecification().getName());
             if (forField == null) {
-                return false;
+                return body;
             }
 
             if (forField.getExecutionKind() != ExecutionKind.SHORT_CIRCUIT) {
-                return false;
+                return body;
             }
 
             ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter);
 
+            builder.tree(createShortCircuitValue(builder, currentExecutable, specialization, forField, shortCircuitParam, exceptionParam));
+
+            builder.declaration(parameter.getType(), targetVariableName, CodeTreeBuilder.createBuilder().defaultValue(parameter.getType()));
+            builder.startIf().string(shortCircuitParam.getLocalName()).end();
+            builder.startBlock();
+            builder.tree(body);
+            builder.end();
+
+            return builder.getRoot();
+        }
+
+        private CodeTree createShortCircuitValue(CodeTreeBuilder parent, ExecutableTypeData currentExecutable, SpecializationData specialization, NodeChildData forField,
+                        ActualParameter shortCircuitParam, ActualParameter exceptionParam) {
+            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             int shortCircuitIndex = 0;
-            for (NodeFieldData field : specialization.getNode().getFields()) {
+            for (NodeChildData field : specialization.getNode().getChildren()) {
                 if (field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) {
                     if (field == forField) {
                         break;
@@ -1414,51 +1722,36 @@
                 }
             }
 
-            builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(shortCircuitParam)).string(" = ");
+            builder.startStatement().type(shortCircuitParam.getType()).string(" ").string(valueName(shortCircuitParam)).string(" = ");
             ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex);
-
-            builder.tree(createTemplateMethodCall(builder, shortCircuitData, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null));
-
+            builder.tree(createTemplateMethodCall(builder, currentExecutable, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null));
             builder.end(); // statement
 
-            builder.declaration(parameter.getActualType(), valueName(parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getActualType()));
-            builder.startIf().string(shortCircuitParam.getLocalName()).end();
-            builder.startBlock();
-
-            return true;
+            return builder.getRoot();
         }
 
-        private void endShortCircuit(CodeTreeBuilder builder, boolean shortCircuit) {
-            if (shortCircuit) {
-                builder.end();
-            }
-        }
-
-        private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, SpecializationData nextSpecialization, ActualParameter exceptionParam) {
+        private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam) {
             CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent);
             specializeCall.startCall("specializeAndExecute");
             specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class");
-            addInternalValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, true);
+            addInternalValueParameterNames(specializeCall, executable, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true,
+                            true);
             specializeCall.end().end();
 
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
             builder.startReturn();
-            builder.tree(specializeCall.getRoot());
+            builder.tree(createExpectType(nextSpecialization.getNode(), executable, specializeCall.getRoot()));
             builder.end();
+
             return builder.getRoot();
         }
 
         private void buildSpecializeAndExecute(CodeTypeElement clazz, SpecializationData specialization) {
             NodeData node = specialization.getNode();
-            TypeData returnType = specialization.getReturnType().getActualTypeData(node.getTypeSystem());
-            ExecutableTypeData returnExecutableType = node.findExecutableType(returnType);
-            boolean canThrowUnexpected = returnExecutableType == null ? true : returnExecutableType.hasUnexpectedValue(getContext());
+            TypeData returnType = node.getGenericSpecialization().getReturnType().getTypeSystemType();
 
             CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), returnType.getPrimitiveType(), "specializeAndExecute");
             method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
-            if (canThrowUnexpected) {
-                method.addThrownType(getUnexpectedValueException());
-            }
             addInternalValueParameters(method, specialization.getNode().getGenericSpecialization(), true);
             clazz.add(method);
 
@@ -1470,7 +1763,7 @@
             builder.startStatement();
             builder.startCall("replace");
             builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState");
-            addInternalValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, true, true);
+            addInternalValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), specialization.getNode().getGenericSpecialization(), null, true, true);
             builder.end();
             builder.end(); // call replace
             builder.end(); // statement
@@ -1486,10 +1779,10 @@
             CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder();
             genericExecute.startCall(factoryClassName(specialization.getNode()), generatedMethodName);
             genericExecute.string("this");
-            addInternalValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), null, true, true);
+            addInternalValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), specialization.getNode().getGenericSpecialization(), null, true, true);
             genericExecute.end(); // call generated generic
 
-            CodeTree genericInvocation = createExpectType(node, returnExecutableType, genericExecute.getRoot());
+            CodeTree genericInvocation = genericExecute.getRoot();
 
             if (generatedGeneric != null && Utils.isVoid(generatedGeneric.getReturnType())) {
                 builder.statement(genericInvocation);
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Tue Apr 23 08:44:07 2013 +0200
@@ -28,8 +28,7 @@
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.FieldKind;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.ExecutionKind;
 import com.oracle.truffle.codegen.processor.template.*;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
@@ -37,17 +36,18 @@
 
     private final String nodeId;
     private NodeData declaringNode;
-    private List<NodeData> declaredChildren = new ArrayList<>();
+    private List<NodeData> declaredNodes = new ArrayList<>();
+    private boolean splitByMethodName;
 
     private TypeSystemData typeSystem;
+    private List<NodeChildData> children;
     private List<NodeFieldData> fields;
     private TypeMirror nodeType;
     private ParameterSpec instanceParameterSpec;
 
     private List<SpecializationData> specializations;
     private List<SpecializationListenerData> specializationListeners;
-    private List<GuardData> guards;
-    private List<ExecutableTypeData> executableTypes;
+    private Map<Integer, List<ExecutableTypeData>> executableTypes;
     private List<ShortCircuitData> shortCircuits;
 
     public NodeData(TypeElement type, String id) {
@@ -59,53 +59,69 @@
         super(splitSource.getTemplateType(), templateMethodName, null);
         this.nodeId = nodeId;
         this.declaringNode = splitSource.declaringNode;
-        this.declaredChildren = splitSource.declaredChildren;
+        this.declaredNodes = splitSource.declaredNodes;
         this.typeSystem = splitSource.typeSystem;
         this.nodeType = splitSource.nodeType;
         this.specializations = splitSource.specializations;
         this.specializationListeners = splitSource.specializationListeners;
-        this.guards = splitSource.guards;
         this.executableTypes = splitSource.executableTypes;
         this.shortCircuits = splitSource.shortCircuits;
         this.fields = splitSource.fields;
+        this.children = splitSource.children;
+    }
+
+    public boolean isSplitByMethodName() {
+        return splitByMethodName;
     }
 
     void setTypeSystem(TypeSystemData typeSystem) {
         this.typeSystem = typeSystem;
     }
 
+    void setFields(List<NodeFieldData> fields) {
+        this.fields = fields;
+    }
+
+    public List<NodeFieldData> getFields() {
+        return fields;
+    }
+
+    void setSplitByMethodName(boolean splitByMethodName) {
+        this.splitByMethodName = splitByMethodName;
+    }
+
     @Override
     protected List<MessageContainer> findChildContainers() {
-        List<MessageContainer> children = new ArrayList<>();
-        if (declaredChildren != null) {
-            children.addAll(declaredChildren);
+        List<MessageContainer> containerChildren = new ArrayList<>();
+        if (declaredNodes != null) {
+            containerChildren.addAll(declaredNodes);
         }
         if (typeSystem != null) {
-            children.add(typeSystem);
+            containerChildren.add(typeSystem);
         }
         if (specializations != null) {
             for (MessageContainer specialization : specializations) {
                 if (specialization.getMessageElement() != null) {
-                    children.add(specialization);
+                    containerChildren.add(specialization);
                 }
             }
         }
         if (specializationListeners != null) {
-            children.addAll(specializationListeners);
-        }
-        if (guards != null) {
-            children.addAll(guards);
+            containerChildren.addAll(specializationListeners);
         }
         if (executableTypes != null) {
-            children.addAll(executableTypes);
+            containerChildren.addAll(getExecutableTypes());
         }
         if (shortCircuits != null) {
-            children.addAll(shortCircuits);
+            containerChildren.addAll(shortCircuits);
+        }
+        if (children != null) {
+            containerChildren.addAll(children);
         }
         if (fields != null) {
-            children.addAll(fields);
+            containerChildren.addAll(fields);
         }
-        return children;
+        return containerChildren;
     }
 
     public ParameterSpec getInstanceParameterSpec() {
@@ -131,6 +147,10 @@
         if (specializations == null) {
             return false;
         }
+        if (getTemplateType().getModifiers().contains(Modifier.PRIVATE)) {
+            return false;
+        }
+
         boolean noSpecialization = true;
         for (SpecializationData specialization : specializations) {
             noSpecialization = noSpecialization && specialization.isGeneric() || specialization.isUninitialized();
@@ -139,27 +159,29 @@
     }
 
     public boolean supportsFrame() {
-        for (ExecutableTypeData execType : executableTypes) {
-            if (execType.findParameter("frameValue") == null) {
-                return false;
+        if (executableTypes != null) {
+            for (ExecutableTypeData execType : getExecutableTypes(-1)) {
+                if (execType.findParameter("frameValue") == null) {
+                    return false;
+                }
             }
         }
         return true;
     }
 
-    public List<NodeData> getNodeChildren() {
-        List<NodeData> children = new ArrayList<>();
-        for (NodeData child : getDeclaredChildren()) {
+    public List<NodeData> getNodeDeclaringChildren() {
+        List<NodeData> nodeChildren = new ArrayList<>();
+        for (NodeData child : getDeclaredNodes()) {
             if (child.needsFactory()) {
-                children.add(child);
+                nodeChildren.add(child);
             }
-            children.addAll(child.getNodeChildren());
+            nodeChildren.addAll(child.getNodeDeclaringChildren());
         }
-        return children;
+        return nodeChildren;
     }
 
-    void setDeclaredChildren(List<NodeData> declaredChildren) {
-        this.declaredChildren = declaredChildren;
+    void setDeclaredNodes(List<NodeData> declaredChildren) {
+        this.declaredNodes = declaredChildren;
 
         for (NodeData child : declaredChildren) {
             child.declaringNode = this;
@@ -170,8 +192,8 @@
         return declaringNode;
     }
 
-    public List<NodeData> getDeclaredChildren() {
-        return declaredChildren;
+    public List<NodeData> getDeclaredNodes() {
+        return declaredNodes;
     }
 
     public void setNodeType(TypeMirror nodeType) {
@@ -218,9 +240,21 @@
         return null;
     }
 
+    public List<ExecutableTypeData> getExecutableTypes(int evaluatedCount) {
+        if (evaluatedCount == -1) {
+            List<ExecutableTypeData> typeData = new ArrayList<>();
+            for (int currentEvaluationCount : executableTypes.keySet()) {
+                typeData.addAll(executableTypes.get(currentEvaluationCount));
+            }
+            return typeData;
+        } else {
+            return executableTypes.get(evaluatedCount);
+        }
+    }
+
     public List<ExecutableTypeData> findGenericExecutableTypes(ProcessorContext context) {
         List<ExecutableTypeData> types = new ArrayList<>();
-        for (ExecutableTypeData type : executableTypes) {
+        for (ExecutableTypeData type : getExecutableTypes(0)) {
             if (!type.hasUnexpectedValue(context)) {
                 types.add(type);
             }
@@ -229,7 +263,7 @@
     }
 
     public ExecutableTypeData findExecutableType(TypeData prmitiveType) {
-        for (ExecutableTypeData type : executableTypes) {
+        for (ExecutableTypeData type : getExecutableTypes(0)) {
             if (Utils.typeEquals(type.getType().getPrimitiveType(), prmitiveType.getPrimitiveType())) {
                 return type;
             }
@@ -240,7 +274,7 @@
     public SpecializationData findUniqueSpecialization(TypeData type) {
         SpecializationData result = null;
         for (SpecializationData specialization : specializations) {
-            if (specialization.getReturnType().getActualTypeData(getTypeSystem()) == type) {
+            if (specialization.getReturnType().getTypeSystemType() == type) {
                 if (result != null) {
                     // Result not unique;
                     return null;
@@ -251,33 +285,14 @@
         return result;
     }
 
-    public List<TypeMirror> getExecutablePrimitiveTypeMirrors() {
-        List<TypeMirror> typeMirrors = new ArrayList<>();
-        for (ExecutableTypeData executableType : executableTypes) {
-            typeMirrors.add(executableType.getType().getPrimitiveType());
-        }
-        return typeMirrors;
-    }
-
-    public NodeFieldData[] filterFields(FieldKind fieldKind, ExecutionKind usage) {
-        List<NodeFieldData> filteredFields = new ArrayList<>();
-        for (NodeFieldData field : getFields()) {
+    public NodeChildData[] filterFields(ExecutionKind usage) {
+        List<NodeChildData> filteredFields = new ArrayList<>();
+        for (NodeChildData field : getChildren()) {
             if (usage == null || field.getExecutionKind() == usage) {
-                if (fieldKind == null || field.getKind() == fieldKind) {
-                    filteredFields.add(field);
-                }
+                filteredFields.add(field);
             }
         }
-        return filteredFields.toArray(new NodeFieldData[filteredFields.size()]);
-    }
-
-    public boolean hasUnexpectedExecutableTypes(ProcessorContext context) {
-        for (ExecutableTypeData type : getExecutableTypes()) {
-            if (type.hasUnexpectedValue(context)) {
-                return true;
-            }
-        }
-        return false;
+        return filteredFields.toArray(new NodeChildData[filteredFields.size()]);
     }
 
     public boolean needsRewrites(ProcessorContext context) {
@@ -321,13 +336,13 @@
 
         dumpProperty(builder, indent, "templateClass", Utils.getQualifiedName(getTemplateType()));
         dumpProperty(builder, indent, "typeSystem", getTypeSystem());
-        dumpProperty(builder, indent, "fields", getFields());
+        dumpProperty(builder, indent, "fields", getChildren());
         dumpProperty(builder, indent, "executableTypes", getExecutableTypes());
         dumpProperty(builder, indent, "specializations", getSpecializations());
         dumpProperty(builder, indent, "messages", collectMessages());
-        if (getDeclaredChildren().size() > 0) {
+        if (getDeclaredNodes().size() > 0) {
             builder.append(String.format("\n%s  children = [", indent));
-            for (NodeData node : getDeclaredChildren()) {
+            for (NodeData node : getDeclaredNodes()) {
                 builder.append("\n");
                 builder.append(node.dump(level + 1));
             }
@@ -373,8 +388,8 @@
         return b.toString();
     }
 
-    public NodeFieldData findField(String name) {
-        for (NodeFieldData field : getFields()) {
+    public NodeChildData findChild(String name) {
+        for (NodeChildData field : getChildren()) {
             if (field.getName().equals(name)) {
                 return field;
             }
@@ -382,12 +397,12 @@
         return null;
     }
 
-    public List<NodeFieldData> getFields() {
-        return fields;
+    public List<NodeChildData> getChildren() {
+        return children;
     }
 
-    void setFields(List<NodeFieldData> fields) {
-        this.fields = fields;
+    void setChildren(List<NodeChildData> fields) {
+        this.children = fields;
     }
 
     public List<SpecializationData> getSpecializations() {
@@ -412,12 +427,8 @@
         return specializationListeners;
     }
 
-    public List<GuardData> getGuards() {
-        return guards;
-    }
-
     public List<ExecutableTypeData> getExecutableTypes() {
-        return executableTypes;
+        return getExecutableTypes(-1);
     }
 
     public List<ShortCircuitData> getShortCircuits() {
@@ -437,11 +448,7 @@
         this.specializationListeners = specializationListeners;
     }
 
-    void setGuards(List<GuardData> guards) {
-        this.guards = guards;
-    }
-
-    void setExecutableTypes(List<ExecutableTypeData> executableTypes) {
+    void setExecutableTypes(Map<Integer, List<ExecutableTypeData>> executableTypes) {
         this.executableTypes = executableTypes;
     }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Tue Apr 23 08:44:07 2013 +0200
@@ -29,88 +29,27 @@
 
 public class NodeFieldData extends MessageContainer {
 
-    public enum FieldKind {
-        CHILD, CHILDREN, FIELD
-    }
-
-    public enum ExecutionKind {
-        DEFAULT, IGNORE, SHORT_CIRCUIT
-    }
-
-    private final VariableElement fieldElement;
-    private final Element accessElement;
-    private final AnnotationMirror childAnnotationMirror;
-
-    private final FieldKind fieldKind;
-    private final ExecutionKind executionKind;
-    private NodeData nodeData;
+    private VariableElement variable;
 
-    public NodeFieldData(VariableElement fieldElement, Element accessElement, AnnotationMirror childAnnotationMirror, FieldKind fieldKind, ExecutionKind executionKind) {
-        this.fieldElement = fieldElement;
-        this.accessElement = accessElement;
-        this.childAnnotationMirror = childAnnotationMirror;
-        this.fieldKind = fieldKind;
-        this.executionKind = executionKind;
-    }
-
-    NodeFieldData(NodeFieldData field) {
-        this.fieldElement = field.fieldElement;
-        this.accessElement = field.accessElement;
-        this.childAnnotationMirror = field.childAnnotationMirror;
-        this.fieldKind = field.fieldKind;
-        this.executionKind = field.executionKind;
-        this.nodeData = field.nodeData;
+    public NodeFieldData(VariableElement var) {
+        this.variable = var;
     }
 
     @Override
     public Element getMessageElement() {
-        return fieldElement;
-    }
-
-    public boolean isShortCircuit() {
-        return executionKind == ExecutionKind.SHORT_CIRCUIT;
+        return variable;
     }
 
-    void setNode(NodeData nodeData) {
-        this.nodeData = nodeData;
-        getMessages().addAll(nodeData.collectMessages());
-    }
-
-    public VariableElement getFieldElement() {
-        return fieldElement;
-    }
-
-    public Element getAccessElement() {
-        return accessElement;
-    }
-
-    public AnnotationMirror getChildAnnotationMirror() {
-        return childAnnotationMirror;
+    public String getName() {
+        return variable.getSimpleName().toString();
     }
 
     public TypeMirror getType() {
-        return fieldElement.asType();
-    }
-
-    public FieldKind getKind() {
-        return fieldKind;
-    }
-
-    public ExecutionKind getExecutionKind() {
-        return executionKind;
+        return variable.asType();
     }
 
-    public NodeData getNodeData() {
-        return nodeData;
-    }
-
-    public String getName() {
-        return fieldElement.getSimpleName().toString();
-    }
-
-    @Override
-    public String toString() {
-        return "NodeFieldData[name=" + getName() + ", kind=" + fieldKind + ", execution=" + executionKind + ", node=" + getNodeData() + "]";
+    public VariableElement getVariable() {
+        return variable;
     }
 
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java	Tue Apr 23 08:44:07 2013 +0200
@@ -28,9 +28,9 @@
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.*;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.ExecutionKind;
 import com.oracle.truffle.codegen.processor.template.*;
-import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
 
 public abstract class NodeMethodParser<E extends TemplateMethod> extends TemplateMethodParser<NodeData, E> {
 
@@ -48,7 +48,7 @@
         return spec;
     }
 
-    private static List<TypeMirror> nodeTypeMirrors(NodeData nodeData) {
+    protected List<TypeMirror> nodeTypeMirrors(NodeData nodeData) {
         Set<TypeMirror> typeMirrors = new LinkedHashSet<>();
 
         for (ExecutableTypeData typeData : nodeData.getExecutableTypes()) {
@@ -66,11 +66,15 @@
 
     @Override
     public boolean isParsable(ExecutableElement method) {
-        return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null;
+        if (getAnnotationType() != null) {
+            return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null;
+        }
+
+        return true;
     }
 
     @SuppressWarnings("unused")
-    protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, String shortCircuitName) {
+    protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, boolean shortCircuitsEnabled, String shortCircuitName) {
         MethodSpec methodSpec = new MethodSpec(createReturnParameterSpec());
 
         if (getNode().supportsFrame()) {
@@ -80,35 +84,36 @@
         resolveAndAddImplicitThis(methodSpec, method);
 
         for (NodeFieldData field : getNode().getFields()) {
-            if (field.getKind() == FieldKind.FIELD) {
+            if (!Utils.isFieldAccessible(method, field.getVariable())) {
                 ParameterSpec spec = new ParameterSpec(field.getName(), field.getType());
                 spec.setLocal(true);
                 methodSpec.addOptional(spec);
             }
         }
 
-        for (NodeFieldData field : getNode().getFields()) {
-            if (field.getExecutionKind() == ExecutionKind.IGNORE) {
-                continue;
-            }
+        // children are null when parsing executable types
+        if (getNode().getChildren() != null) {
+            for (NodeChildData child : getNode().getChildren()) {
+                if (child.getExecutionKind() == ExecutionKind.DEFAULT) {
+                    ParameterSpec spec = createValueParameterSpec(child.getName(), child.getNodeData());
+                    if (child.getCardinality().isMany()) {
+                        spec.setCardinality(Cardinality.MANY);
+                        spec.setIndexed(true);
+                    }
+                    methodSpec.addRequired(spec);
+                } else if (child.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) {
+                    String valueName = child.getName();
+                    if (shortCircuitName != null && valueName.equals(shortCircuitName)) {
+                        break;
+                    }
 
-            if (field.getExecutionKind() == ExecutionKind.DEFAULT) {
-                ParameterSpec spec = createValueParameterSpec(field.getName(), field.getNodeData());
-                if (field.getKind() == FieldKind.CHILDREN) {
-                    spec.setCardinality(Cardinality.MULTIPLE);
-                    spec.setIndexed(true);
+                    if (shortCircuitsEnabled) {
+                        methodSpec.addRequired(new ParameterSpec(shortCircuitValueName(valueName), getContext().getType(boolean.class)));
+                    }
+                    methodSpec.addRequired(createValueParameterSpec(valueName, child.getNodeData()));
+                } else {
+                    assert false;
                 }
-                methodSpec.addRequired(spec);
-            } else if (field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) {
-                String valueName = field.getName();
-                if (shortCircuitName != null && valueName.equals(shortCircuitName)) {
-                    break;
-                }
-
-                methodSpec.addRequired(new ParameterSpec(shortCircuitValueName(valueName), getContext().getType(boolean.class)));
-                methodSpec.addRequired(createValueParameterSpec(valueName, field.getNodeData()));
-            } else {
-                assert false;
             }
         }
 
@@ -118,7 +123,7 @@
     protected void resolveAndAddImplicitThis(MethodSpec methodSpec, ExecutableElement method) {
         TypeMirror declaredType = Utils.findNearestEnclosingType(method).asType();
 
-        if (!method.getModifiers().contains(Modifier.STATIC) && !Utils.isAssignable(declaredType, getContext().getTruffleTypes().getNode())) {
+        if (!method.getModifiers().contains(Modifier.STATIC) && !Utils.isAssignable(getContext(), declaredType, getContext().getTruffleTypes().getNode())) {
             methodSpec.addImplicitRequiredType(getNode().getTemplateType().asType());
         }
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Tue Apr 23 08:44:07 2013 +0200
@@ -31,18 +31,17 @@
 import javax.tools.Diagnostic.Kind;
 
 import com.oracle.truffle.api.codegen.*;
-import com.oracle.truffle.api.nodes.Node.Child;
-import com.oracle.truffle.api.nodes.Node.Children;
+import com.oracle.truffle.api.codegen.NodeClass.InheritNode;
 import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.FieldKind;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.ExecutionKind;
 import com.oracle.truffle.codegen.processor.template.*;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
 public class NodeParser extends TemplateParser<NodeData> {
 
     public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, SpecializationListener.class,
-                    ExecuteChildren.class, NodeClass.class, NodeId.class);
+                    ExecuteChildren.class, NodeClass.class, NodeChild.class, NodeChildren.class, NodeId.class);
 
     private Map<String, NodeData> parsedNodes;
 
@@ -73,7 +72,7 @@
 
     @Override
     protected NodeData filterErrorElements(NodeData model) {
-        for (Iterator<NodeData> iterator = model.getDeclaredChildren().iterator(); iterator.hasNext();) {
+        for (Iterator<NodeData> iterator = model.getDeclaredNodes().iterator(); iterator.hasNext();) {
             NodeData node = filterErrorElements(iterator.next());
             if (node == null) {
                 iterator.remove();
@@ -114,87 +113,97 @@
         parsedNodes.put(typeName, rootNode);
 
         if (rootNode != null) {
-            children.addAll(rootNode.getDeclaredChildren());
-            rootNode.setDeclaredChildren(children);
+            children.addAll(rootNode.getDeclaredNodes());
+            rootNode.setDeclaredNodes(children);
         }
 
         return rootNode;
     }
 
-    private NodeData parseNode(TypeElement type) {
-        if (Utils.findAnnotationMirror(processingEnv, type, GeneratedBy.class) != null) {
+    private NodeData parseNode(TypeElement originalTemplateType) {
+        // reloading the type elements is needed for ecj
+        TypeElement templateType = Utils.fromTypeMirror(context.reloadTypeElement(originalTemplateType));
+
+        if (Utils.findAnnotationMirror(processingEnv, originalTemplateType, GeneratedBy.class) != null) {
             // generated nodes should not get called again.
             return null;
         }
 
-        AnnotationMirror methodNodes = Utils.findAnnotationMirror(processingEnv, type, NodeClass.class);
+        List<TypeElement> lookupTypes = findSuperClasses(new ArrayList<TypeElement>(), templateType);
+        Collections.reverse(lookupTypes);
 
-        if (methodNodes == null && !Utils.isAssignable(type.asType(), context.getTruffleTypes().getNode())) {
-            return null; // not a node
+        AnnotationMirror nodeClass = findFirstAnnotation(lookupTypes, NodeClass.class);
+        TypeMirror nodeType = null;
+        if (Utils.isAssignable(context, templateType.asType(), context.getTruffleTypes().getNode())) {
+            nodeType = templateType.asType();
         }
-
-        if (type.getModifiers().contains(Modifier.PRIVATE)) {
-            // TODO error message here!?
-            return null; // not visible, not a node
+        if (nodeClass != null) {
+            nodeType = inheritType(nodeClass, "value", nodeType);
         }
 
-        TypeElement nodeType;
-        boolean needsSplit;
-        if (methodNodes != null) {
-            needsSplit = methodNodes != null;
-            nodeType = Utils.fromTypeMirror(Utils.getAnnotationValue(TypeMirror.class, methodNodes, "value"));
-        } else {
-            needsSplit = false;
-            nodeType = type;
+        if (nodeType == null) {
+            if (nodeClass == null) {
+                // no node
+                return null;
+            } else {
+                // FIXME nodeType not specified error
+                return null;
+            }
         }
 
-        NodeData nodeData = parseNodeData(type, nodeType);
+        Set<Element> elementSet = new HashSet<>(context.getEnvironment().getElementUtils().getAllMembers(templateType));
+        if (!Utils.typeEquals(templateType.asType(), nodeType)) {
+            elementSet.addAll(context.getEnvironment().getElementUtils().getAllMembers(Utils.fromTypeMirror(nodeType)));
 
-        if (nodeData.hasErrors()) {
-            return nodeData; // error sync point
-        }
+            List<TypeElement> nodeLookupTypes = findSuperClasses(new ArrayList<TypeElement>(), Utils.fromTypeMirror(nodeType));
+            Collections.reverse(nodeLookupTypes);
+            lookupTypes.addAll(nodeLookupTypes);
 
-        if (Utils.typeEquals(nodeType.asType(), type.asType())) {
-            // filter fields if they were not split. (field are accessible anyway)
-            for (ListIterator<NodeFieldData> iterator = nodeData.getFields().listIterator(); iterator.hasNext();) {
-                NodeFieldData field = iterator.next();
-                if (field.getKind() == FieldKind.FIELD) {
+            Set<TypeElement> types = new HashSet<>();
+            for (ListIterator<TypeElement> iterator = lookupTypes.listIterator(); iterator.hasNext();) {
+                TypeElement typeElement = iterator.next();
+                if (types.contains(typeElement)) {
                     iterator.remove();
+                } else {
+                    types.add(typeElement);
                 }
             }
         }
+        List<Element> elements = new ArrayList<>(elementSet);
 
-        List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type));
-        nodeData.setExtensionElements(getExtensionParser().parseAll(nodeData, elements));
-        if (nodeData.getExtensionElements() != null) {
-            elements.addAll(nodeData.getExtensionElements());
+        NodeData node = parseNodeData(templateType, nodeType, elements, lookupTypes);
+
+        if (node.hasErrors()) {
+            return node; // error sync point
         }
-        parseMethods(nodeData, elements);
+
+        parseMethods(node, elements);
 
-        if (nodeData.hasErrors()) {
-            return nodeData;
+        if (node.hasErrors()) {
+            return node;
         }
 
         List<NodeData> nodes;
-        if (needsSplit) {
-            nodes = splitNodeData(nodeData);
+
+        if (node.isSplitByMethodName()) {
+            nodes = splitNodeData(node);
         } else {
             nodes = new ArrayList<>();
-            nodes.add(nodeData);
+            nodes.add(node);
         }
 
         for (NodeData splittedNode : nodes) {
             finalizeSpecializations(elements, splittedNode);
-            verifyNode(splittedNode);
+            verifyNode(splittedNode, elements);
         }
 
-        if (needsSplit) {
-            nodeData.setDeclaredChildren(nodes);
-            nodeData.setSpecializationListeners(new ArrayList<SpecializationListenerData>());
-            nodeData.setSpecializations(new ArrayList<SpecializationData>());
-            return nodeData;
+        if (node.isSplitByMethodName()) {
+            node.setDeclaredNodes(nodes);
+            node.setSpecializationListeners(new ArrayList<SpecializationListenerData>());
+            node.setSpecializations(new ArrayList<SpecializationData>());
+            return node;
         } else {
-            return nodeData;
+            return node;
         }
     }
 
@@ -299,25 +308,30 @@
         } else if (node.needsRewrites(context)) {
             SpecializationData specialization = specializations.get(0);
             GenericParser parser = new GenericParser(context, node);
-            MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, null);
+            MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, true, null);
 
             ExecutableTypeData anyGenericReturnType = node.findAnyGenericExecutableType(context);
             assert anyGenericReturnType != null;
 
-            ActualParameter returnType = new ActualParameter(specification.getReturnType(), anyGenericReturnType.getType().getPrimitiveType(), 0, false);
+            ActualParameter returnType = new ActualParameter(specification.getReturnType(), anyGenericReturnType.getType(), 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 || field.getKind() == FieldKind.FIELD) {
-                    actualType = specializationParameter.getActualType();
+                NodeChildData child = node.findChild(parameterSpec.getName());
+                TypeData actualType;
+                if (child == null) {
+                    actualType = specializationParameter.getTypeSystemType();
                 } else {
-                    ExecutableTypeData paramType = field.getNodeData().findAnyGenericExecutableType(context);
+                    ExecutableTypeData paramType = child.getNodeData().findAnyGenericExecutableType(context);
                     assert paramType != null;
-                    actualType = paramType.getType().getPrimitiveType();
+                    actualType = paramType.getType();
                 }
-                parameters.add(new ActualParameter(parameterSpec, actualType, specializationParameter.getIndex(), specializationParameter.isImplicit()));
+
+                if (actualType != null) {
+                    parameters.add(new ActualParameter(parameterSpec, actualType, specializationParameter.getIndex(), specializationParameter.isImplicit()));
+                } else {
+                    parameters.add(new ActualParameter(parameterSpec, specializationParameter.getType(), specializationParameter.getIndex(), specializationParameter.isImplicit()));
+                }
             }
             TemplateMethod genericMethod = new TemplateMethod("Generic", node, specification, null, null, returnType, parameters);
             genericSpecialization = new SpecializationData(genericMethod, true, false);
@@ -328,18 +342,18 @@
         if (genericSpecialization != null) {
             if (genericSpecialization.isUseSpecializationsForGeneric()) {
                 for (ActualParameter parameter : genericSpecialization.getReturnTypeAndParameters()) {
-                    if (Utils.isObject(parameter.getActualType())) {
+                    if (Utils.isObject(parameter.getType())) {
                         continue;
                     }
                     Set<String> types = new HashSet<>();
                     for (SpecializationData specialization : specializations) {
                         ActualParameter actualParameter = specialization.findParameter(parameter.getLocalName());
                         if (actualParameter != null) {
-                            types.add(Utils.getQualifiedName(actualParameter.getActualType()));
+                            types.add(Utils.getQualifiedName(actualParameter.getType()));
                         }
                     }
                     if (types.size() > 1) {
-                        genericSpecialization.replaceParameter(parameter.getLocalName(), new ActualParameter(parameter, node.getTypeSystem().getGenericType()));
+                        genericSpecialization.replaceParameter(parameter.getLocalName(), new ActualParameter(parameter, node.getTypeSystem().getGenericTypeData()));
                     }
                 }
             }
@@ -364,9 +378,13 @@
                 needsId.add(specialization);
             }
         }
-        List<String> ids = calculateSpecializationIds(needsId);
-        for (int i = 0; i < ids.size(); i++) {
-            needsId.get(i).setId(ids.get(i));
+
+        // verify specialization parameter length
+        if (verifySpecializationParameters(node)) {
+            List<String> ids = calculateSpecializationIds(needsId);
+            for (int i = 0; i < ids.size(); i++) {
+                needsId.get(i).setId(ids.get(i));
+            }
         }
     }
 
@@ -403,12 +421,12 @@
                 continue;
             }
             List<String> paramIds = new LinkedList<>();
-            paramIds.add(Utils.getTypeId(other.getReturnType().getActualType()));
+            paramIds.add(Utils.getTypeId(other.getReturnType().getType()));
             for (ActualParameter param : other.getParameters()) {
-                if (other.getNode().findField(param.getSpecification().getName()) == null) {
+                if (other.getNode().findChild(param.getSpecification().getName()) == null) {
                     continue;
                 }
-                paramIds.add(Utils.getTypeId(param.getActualType()));
+                paramIds.add(Utils.getTypeId(param.getType()));
             }
             assert lastSize == -1 || lastSize == paramIds.size();
             if (lastSize != -1 && lastSize != paramIds.size()) {
@@ -507,64 +525,57 @@
         return signatures;
     }
 
-    private void verifyNode(NodeData nodeData) {
-        // verify specialization parameter length
-        verifySpecializationParameters(nodeData);
-
+    private void verifyNode(NodeData nodeData, List<? extends Element> elements) {
         // verify order is not ambiguous
         verifySpecializationOrder(nodeData);
 
-        verifyMissingAbstractMethods(nodeData);
+        verifyMissingAbstractMethods(nodeData, elements);
 
         assignShortCircuitsToSpecializations(nodeData);
 
         verifyConstructors(nodeData);
 
-// if (!verifyNamingConvention(specializations, "do")) {
-// return null;
-// }
-//
-// if (!verifyNamesUnique(specializations)) {
-// return null;
-// }
-
         verifyNamingConvention(nodeData.getShortCircuits(), "needs");
 
         verifySpecializationThrows(nodeData);
     }
 
-    private NodeData parseNodeData(TypeElement templateType, TypeElement nodeType) {
-        List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeType));
-        List<TypeElement> typeHierarchy = findSuperClasses(new ArrayList<TypeElement>(), nodeType);
-        Collections.reverse(typeHierarchy);
+    private NodeData parseNodeData(TypeElement templateType, TypeMirror nodeType, List<? extends Element> elements, List<TypeElement> lookupTypes) {
         NodeData nodeData = new NodeData(templateType, templateType.getSimpleName().toString());
 
-        AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class);
+        AnnotationMirror typeSystemMirror = findFirstAnnotation(lookupTypes, TypeSystemReference.class);
         if (typeSystemMirror == null) {
-            nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), nodeType.getQualifiedName().toString());
+            nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), Utils.getQualifiedName(nodeType));
             return nodeData;
         }
 
         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));
+            nodeData.addError("The used type system '%s' is invalid or not a Node.", Utils.getQualifiedName(typeSytemType));
             return nodeData;
         }
 
-        nodeData.setNodeType(nodeType.asType());
-        nodeData.setTypeSystem(typeSystem);
+        boolean splitByMethodName = false;
+        AnnotationMirror nodeClass = findFirstAnnotation(lookupTypes, NodeClass.class);
+        if (nodeClass != null) {
+            splitByMethodName = Utils.getAnnotationValue(Boolean.class, nodeClass, "splitByMethodName");
+        }
 
-        List<ExecutableTypeData> executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements));
-        nodeData.setExecutableTypes(executableTypes);
+        nodeData.setNodeType(nodeType);
+        nodeData.setSplitByMethodName(splitByMethodName);
+        nodeData.setTypeSystem(typeSystem);
+        nodeData.setFields(parseFields(elements));
+        nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements)));
         parsedNodes.put(Utils.getQualifiedName(templateType), nodeData);
 
-        nodeData.setFields(parseFields(elements, typeHierarchy));
+        // parseChildren invokes cyclic parsing.
+        nodeData.setChildren(parseChildren(templateType, elements, lookupTypes));
 
         return nodeData;
     }
 
-    private static void verifySpecializationParameters(NodeData nodeData) {
+    private static boolean verifySpecializationParameters(NodeData nodeData) {
         boolean valid = true;
         int args = -1;
         for (SpecializationData specializationData : nodeData.getSpecializations()) {
@@ -585,16 +596,17 @@
                 specialization.addError("All specializations must have the same number of arguments.");
             }
         }
+        return valid;
     }
 
-    private void verifyMissingAbstractMethods(NodeData nodeData) {
+    private static void verifyMissingAbstractMethods(NodeData nodeData, List<? extends Element> originalElements) {
         if (!nodeData.needsFactory()) {
             // missing abstract methods only needs to be implemented
             // if we need go generate factory for it.
             return;
         }
 
-        List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeData.getTemplateType()));
+        List<Element> elements = new ArrayList<>(originalElements);
 
         Set<Element> unusedElements = new HashSet<>(elements);
         for (TemplateMethod method : nodeData.getAllTemplateMethods()) {
@@ -604,6 +616,12 @@
             unusedElements.removeAll(nodeData.getExtensionElements());
         }
 
+        for (NodeChildData child : nodeData.getChildren()) {
+            if (child.getAccessElement() != null) {
+                unusedElements.remove(child.getAccessElement());
+            }
+        }
+
         for (ExecutableElement unusedMethod : ElementFilter.methodsIn(unusedElements)) {
             if (unusedMethod.getModifiers().contains(Modifier.ABSTRACT)) {
                 nodeData.addError("The type %s must implement the inherited abstract method %s.", Utils.getSimpleName(nodeData.getTemplateType()), Utils.getReadableSignature(unusedMethod));
@@ -618,8 +636,17 @@
         }
 
         TypeElement type = Utils.fromTypeMirror(nodeData.getNodeType());
+        List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());
 
-        List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());
+        boolean parametersFound = false;
+        for (ExecutableElement constructor : constructors) {
+            if (!constructor.getParameters().isEmpty()) {
+                parametersFound = true;
+            }
+        }
+        if (!parametersFound) {
+            return;
+        }
         for (ExecutableElement e : constructors) {
             if (e.getParameters().size() == 1) {
                 TypeMirror firstArg = e.getParameters().get(0).asType();
@@ -638,38 +665,23 @@
         nodeData.addError("Specialization constructor '%s(%s previousNode) { this(...); }' is required.", Utils.getSimpleName(type), Utils.getSimpleName(type));
     }
 
-    private static List<ExecutableTypeData> filterExecutableTypes(List<ExecutableTypeData> executableTypes) {
-        List<ExecutableTypeData> filteredExecutableTypes = new ArrayList<>();
-        for (ExecutableTypeData t1 : executableTypes) {
-            boolean add = true;
-            for (ExecutableTypeData t2 : executableTypes) {
-                if (t1 == t2) {
-                    continue;
-                }
-                if (Utils.typeEquals(t1.getType().getPrimitiveType(), t2.getType().getPrimitiveType())) {
-                    if (t1.isFinal() && !t2.isFinal()) {
-                        add = false;
-                    }
-                }
+    private static Map<Integer, List<ExecutableTypeData>> groupExecutableTypes(List<ExecutableTypeData> executableTypes) {
+        Map<Integer, List<ExecutableTypeData>> groupedTypes = new HashMap<>();
+        for (ExecutableTypeData type : executableTypes) {
+            int evaluatedCount = type.getEvaluatedCount();
+
+            List<ExecutableTypeData> types = groupedTypes.get(evaluatedCount);
+            if (types == null) {
+                types = new ArrayList<>();
+                groupedTypes.put(evaluatedCount, types);
             }
-            if (add) {
-                filteredExecutableTypes.add(t1);
-            }
+            types.add(type);
         }
 
-        Collections.sort(filteredExecutableTypes, new Comparator<ExecutableTypeData>() {
-
-            @Override
-            public int compare(ExecutableTypeData o1, ExecutableTypeData o2) {
-                int index1 = o1.getTypeSystem().findType(o1.getType());
-                int index2 = o2.getTypeSystem().findType(o2.getType());
-                if (index1 == -1 || index2 == -1) {
-                    return 0;
-                }
-                return index1 - index2;
-            }
-        });
-        return filteredExecutableTypes;
+        for (List<ExecutableTypeData> types : groupedTypes.values()) {
+            Collections.sort(types);
+        }
+        return groupedTypes;
     }
 
     private AnnotationMirror findFirstAnnotation(List<? extends Element> elements, Class<? extends Annotation> annotation) {
@@ -682,16 +694,20 @@
         return null;
     }
 
-    private List<NodeFieldData> parseFields(List<? extends Element> elements, final List<TypeElement> typeHierarchy) {
-        AnnotationMirror executionOrderMirror = findFirstAnnotation(typeHierarchy, ExecuteChildren.class);
-        List<String> executionDefinition = null;
-        if (executionOrderMirror != null) {
-            executionDefinition = new ArrayList<>();
-            for (String object : Utils.getAnnotationValueList(String.class, executionOrderMirror, "value")) {
-                executionDefinition.add(object);
+    private static List<NodeFieldData> parseFields(List<? extends Element> elements) {
+        List<NodeFieldData> fields = new ArrayList<>();
+        for (VariableElement field : ElementFilter.fieldsIn(elements)) {
+            if (field.getModifiers().contains(Modifier.STATIC)) {
+                continue;
+            }
+            if (field.getModifiers().contains(Modifier.PUBLIC) || field.getModifiers().contains(Modifier.PROTECTED)) {
+                fields.add(new NodeFieldData(field));
             }
         }
+        return fields;
+    }
 
+    private List<NodeChildData> parseChildren(TypeElement templateType, List<? extends Element> elements, final List<TypeElement> typeHierarchy) {
         Set<String> shortCircuits = new HashSet<>();
         for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
             AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class);
@@ -700,136 +716,113 @@
             }
         }
 
-        List<NodeFieldData> fields = new ArrayList<>();
-        for (VariableElement var : ElementFilter.fieldsIn(elements)) {
-            if (var.getModifiers().contains(Modifier.STATIC)) {
-                continue;
+        List<NodeChildData> parsedChildren = new ArrayList<>();
+        List<TypeElement> typeHierarchyReversed = new ArrayList<>(typeHierarchy);
+        Collections.reverse(typeHierarchyReversed);
+        for (TypeElement type : typeHierarchyReversed) {
+            AnnotationMirror nodeClassMirror = Utils.findAnnotationMirror(processingEnv, type, NodeClass.class);
+            AnnotationMirror nodeChildrenMirror = Utils.findAnnotationMirror(processingEnv, type, NodeChildren.class);
+
+            TypeMirror nodeClassType = type.getSuperclass();
+            if (!Utils.isAssignable(context, nodeClassType, context.getTruffleTypes().getNode())) {
+                nodeClassType = null;
             }
 
-            if (executionDefinition != null) {
-                if (!executionDefinition.contains(var.getSimpleName().toString())) {
-                    continue;
-                }
+            if (nodeClassMirror != null) {
+                nodeClassType = inheritType(nodeClassMirror, "value", nodeClassType);
             }
 
-            NodeFieldData field = parseField(var, shortCircuits);
-            if (field != null) {
-                fields.add(field);
-            }
-        }
-        sortByExecutionOrder(fields, executionDefinition == null ? Collections.<String> emptyList() : executionDefinition, typeHierarchy);
-        return fields;
-    }
+            List<AnnotationMirror> children = Utils.collectAnnotations(context, nodeChildrenMirror, "value", type, NodeChild.class);
+            for (AnnotationMirror childMirror : children) {
+                String name = Utils.getAnnotationValue(String.class, childMirror, "value");
+
+                Cardinality cardinality = Cardinality.ONE;
 
-    private NodeFieldData parseField(VariableElement var, Set<String> foundShortCircuits) {
-        AnnotationMirror childMirror = Utils.findAnnotationMirror(processingEnv, var, Child.class);
-        AnnotationMirror childrenMirror = Utils.findAnnotationMirror(processingEnv, var, Children.class);
-
-        FieldKind kind;
+                TypeMirror childType = inheritType(childMirror, "type", nodeClassType);
+                if (childType.getKind() == TypeKind.ARRAY) {
+                    cardinality = Cardinality.MANY;
+                }
 
-        ExecutionKind execution;
-        if (foundShortCircuits.contains(var.getSimpleName().toString())) {
-            execution = ExecutionKind.SHORT_CIRCUIT;
-        } else {
-            execution = ExecutionKind.DEFAULT;
-        }
-
-        AnnotationMirror mirror;
-        TypeMirror type;
+                Element getter = findGetter(elements, name, childType);
 
-        if (childMirror != null) {
-            mirror = childMirror;
-            type = var.asType();
-            kind = FieldKind.CHILD;
-        } else if (childrenMirror != null) {
-            mirror = childrenMirror;
-            type = getComponentType(var.asType());
-            kind = FieldKind.CHILDREN;
-        } else {
-            execution = ExecutionKind.IGNORE;
-            type = var.asType();
-            mirror = null;
-            kind = FieldKind.FIELD;
-        }
+                ExecutionKind kind = ExecutionKind.DEFAULT;
+                if (shortCircuits.contains(name)) {
+                    kind = ExecutionKind.SHORT_CIRCUIT;
+                }
+
+                NodeChildData nodeChild = new NodeChildData(templateType, childMirror, name, childType, getter, cardinality, kind);
+
+                parsedChildren.add(nodeChild);
 
-        NodeFieldData fieldData = new NodeFieldData(var, findAccessElement(var), mirror, kind, execution);
-        if (type != null && mirror != null) {
-            TypeElement typeElement = Utils.fromTypeMirror(type);
-            if (typeElement == null) {
-                return null;
-            }
-            NodeData fieldNodeData = resolveNode(typeElement);
-            fieldData.setNode(fieldNodeData);
+                verifyNodeChild(nodeChild);
+                if (nodeChild.hasErrors()) {
+                    continue;
+                }
 
-            if (fieldNodeData == null) {
-                fieldData.addError("Node type '%s' is invalid.", Utils.getQualifiedName(type));
-            } else if (fieldNodeData.findGenericExecutableTypes(context).isEmpty()) {
-                fieldData.addError("No executable generic types found for node '%s'.", Utils.getQualifiedName(type));
+                NodeData fieldNodeData = resolveNode(Utils.fromTypeMirror(childType));
+                nodeChild.setNode(fieldNodeData);
+                if (fieldNodeData == null) {
+                    nodeChild.addError("Node type '%s' is invalid or not a valid Node.", Utils.getQualifiedName(childType));
+                } else if (fieldNodeData.findGenericExecutableTypes(context).isEmpty()) {
+                    nodeChild.addError("No executable generic types found for node '%s'.", Utils.getQualifiedName(type));
+                }
             }
         }
 
-        if (fieldData.getAccessElement().getModifiers().contains(Modifier.PRIVATE)) {
-            return null;
+        List<NodeChildData> filteredChildren = new ArrayList<>();
+        Set<String> encounteredNames = new HashSet<>();
+        for (int i = parsedChildren.size() - 1; i >= 0; i--) {
+            NodeChildData child = parsedChildren.get(i);
+            if (!encounteredNames.contains(child.getName())) {
+                filteredChildren.add(0, child);
+                encounteredNames.add(child.getName());
+            }
         }
-
-        return fieldData;
+        return filteredChildren;
     }
 
-    private Element findAccessElement(VariableElement variableElement) {
-        Element enclosed = variableElement.getEnclosingElement();
-        if (!enclosed.getKind().isClass()) {
-            throw new IllegalArgumentException("Field must be enclosed in a class.");
-        }
-
-        String methodName;
-        if (Utils.typeEquals(variableElement.asType(), context.getType(boolean.class))) {
-            methodName = "is" + Utils.firstLetterUpperCase(variableElement.getSimpleName().toString());
-        } else {
-            methodName = "get" + Utils.firstLetterUpperCase(variableElement.getSimpleName().toString());
+    private static void verifyNodeChild(NodeChildData nodeChild) {
+        if (nodeChild.getNodeType() == null) {
+            nodeChild.addError("No valid node type could be resoleved.");
         }
+        // FIXME verify node child
+        // FIXME verify node type set
+    }
 
-        ExecutableElement getter = null;
-        for (ExecutableElement method : ElementFilter.methodsIn(enclosed.getEnclosedElements())) {
-            if (method.getSimpleName().toString().equals(methodName) && method.getParameters().size() == 0 && !Utils.typeEquals(method.getReturnType(), context.getType(void.class))) {
-                getter = method;
-                break;
-            }
-        }
-        if (getter != null && !getter.getModifiers().contains(Modifier.PRIVATE)) {
-            return getter;
+    private TypeMirror inheritType(AnnotationMirror annotation, String valueName, TypeMirror parentType) {
+        TypeMirror inhertNodeType = context.getType(InheritNode.class);
+        TypeMirror value = Utils.getAnnotationValue(TypeMirror.class, annotation, valueName);
+        if (Utils.typeEquals(inhertNodeType, value)) {
+            return parentType;
         } else {
-            return variableElement;
+            return value;
         }
     }
 
-    private static void sortByExecutionOrder(List<NodeFieldData> fields, final List<String> executionOrder, final List<TypeElement> typeHierarchy) {
-        Collections.sort(fields, new Comparator<NodeFieldData>() {
+    private Element findGetter(List<? extends Element> elements, String variableName, TypeMirror type) {
+        if (type == null) {
+            return null;
+        }
+        String methodName;
+        if (Utils.typeEquals(type, context.getType(boolean.class))) {
+            methodName = "is" + Utils.firstLetterUpperCase(variableName);
+        } else {
+            methodName = "get" + Utils.firstLetterUpperCase(variableName);
+        }
 
-            @Override
-            public int compare(NodeFieldData o1, NodeFieldData o2) {
-                // sort by execution order
-                int index1 = executionOrder.indexOf(o1.getName());
-                int index2 = executionOrder.indexOf(o2.getName());
-                if (index1 == -1 || index2 == -1) {
-                    // sort by type hierarchy
-                    index1 = typeHierarchy.indexOf(o1.getFieldElement().getEnclosingElement());
-                    index2 = typeHierarchy.indexOf(o2.getFieldElement().getEnclosingElement());
-
-                    // finally sort by name (will emit warning)
-                    if (index1 == -1 || index2 == -1) {
-                        return o1.getName().compareTo(o2.getName());
-                    }
-                }
-                return index1 - index2;
+        for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
+            if (method.getSimpleName().toString().equals(methodName) && method.getParameters().size() == 0 && Utils.typeEquals(method.getReturnType(), type)) {
+                return method;
             }
-        });
+        }
+        return null;
     }
 
     private void assignShortCircuitsToSpecializations(NodeData node) {
         Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits());
 
         boolean valid = true;
-        for (NodeFieldData field : node.filterFields(null, ExecutionKind.SHORT_CIRCUIT)) {
+        for (NodeChildData field : node.filterFields(ExecutionKind.SHORT_CIRCUIT)) {
             String valueName = field.getName();
             List<ShortCircuitData> availableCircuits = groupedShortCircuits.get(valueName);
 
@@ -880,7 +873,7 @@
             return;
         }
 
-        NodeFieldData[] fields = node.filterFields(null, ExecutionKind.SHORT_CIRCUIT);
+        NodeChildData[] fields = node.filterFields(ExecutionKind.SHORT_CIRCUIT);
         for (SpecializationData specialization : node.getSpecializations()) {
             List<ShortCircuitData> assignedShortCuts = new ArrayList<>(fields.length);
 
@@ -917,14 +910,14 @@
 
     private boolean isGenericShortCutMethod(NodeData node, TemplateMethod method) {
         for (ActualParameter parameter : method.getParameters()) {
-            NodeFieldData field = node.findField(parameter.getSpecification().getName());
-            if (field == null || field.getKind() == FieldKind.FIELD) {
+            NodeChildData field = node.findChild(parameter.getSpecification().getName());
+            if (field == null) {
                 continue;
             }
             ExecutableTypeData found = null;
             List<ExecutableTypeData> executableElements = field.getNodeData().findGenericExecutableTypes(context);
             for (ExecutableTypeData executable : executableElements) {
-                if (executable.getType().equalsType(parameter.getActualTypeData(node.getTypeSystem()))) {
+                if (executable.getType().equalsType(parameter.getTypeSystemType())) {
                     found = executable;
                     break;
                 }
@@ -949,13 +942,6 @@
         return group;
     }
 
-    private TypeMirror getComponentType(TypeMirror type) {
-        if (type instanceof ArrayType) {
-            return getComponentType(((ArrayType) type).getComponentType());
-        }
-        return type;
-    }
-
     private static List<TypeElement> findSuperClasses(List<TypeElement> collection, TypeElement element) {
         if (element.getSuperclass() != null) {
             TypeElement superElement = Utils.fromTypeMirror(element.getSuperclass());
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitData.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitData.java	Tue Apr 23 08:44:07 2013 +0200
@@ -62,7 +62,7 @@
 
         for (ActualParameter param : getParameters()) {
             ActualParameter specializationParam = specialization.findParameter(param.getLocalName());
-            if (!Utils.typeEquals(param.getActualType(), specializationParam.getActualType())) {
+            if (!Utils.typeEquals(param.getType(), specializationParam.getType())) {
                 return false;
             }
         }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java	Tue Apr 23 08:44:07 2013 +0200
@@ -29,7 +29,7 @@
 
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.ExecutionKind;
 import com.oracle.truffle.codegen.processor.template.*;
 
 public class ShortCircuitParser extends NodeMethodParser<ShortCircuitData> {
@@ -40,8 +40,8 @@
         super(context, node);
 
         shortCircuitValues = new HashSet<>();
-        NodeFieldData[] shortCircuitFields = node.filterFields(null, ExecutionKind.SHORT_CIRCUIT);
-        for (NodeFieldData field : shortCircuitFields) {
+        NodeChildData[] shortCircuitFields = node.filterFields(ExecutionKind.SHORT_CIRCUIT);
+        for (NodeChildData field : shortCircuitFields) {
             shortCircuitValues.add(field.getName());
         }
     }
@@ -49,7 +49,7 @@
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
         String shortCircuitValue = Utils.getAnnotationValue(String.class, mirror, "value");
-        return createDefaultMethodSpec(method, mirror, shortCircuitValue);
+        return createDefaultMethodSpec(method, mirror, true, shortCircuitValue);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Tue Apr 23 08:44:07 2013 +0200
@@ -26,7 +26,6 @@
 
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.*;
 import com.oracle.truffle.codegen.processor.template.*;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
@@ -83,11 +82,11 @@
             return true;
         }
         for (ActualParameter parameter : getParameters()) {
-            NodeFieldData field = getNode().findField(parameter.getSpecification().getName());
-            if (field == null || field.getKind() == FieldKind.FIELD) {
+            NodeChildData field = getNode().findChild(parameter.getSpecification().getName());
+            if (field == null) {
                 continue;
             }
-            ExecutableTypeData type = field.getNodeData().findExecutableType(parameter.getActualTypeData(field.getNodeData().getTypeSystem()));
+            ExecutableTypeData type = field.getNodeData().findExecutableType(parameter.getTypeSystemType());
             if (type.hasUnexpectedValue(context)) {
                 return true;
             }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java	Tue Apr 23 08:44:07 2013 +0200
@@ -38,7 +38,7 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        return createDefaultMethodSpec(method, mirror, null);
+        return createDefaultMethodSpec(method, mirror, true, null);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java	Tue Apr 23 08:44:07 2013 +0200
@@ -40,7 +40,7 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        return createDefaultMethodSpec(method, mirror, null);
+        return createDefaultMethodSpec(method, mirror, true, null);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java	Tue Apr 23 08:44:07 2013 +0200
@@ -29,15 +29,17 @@
 public class ActualParameter {
 
     private final ParameterSpec specification;
-    private final TypeMirror actualType;
+    private TypeData typeSystemType;
     private TemplateMethod method;
     private final String localName;
     private final int index;
     private final boolean implicit;
+    private final TypeMirror type;
 
     public ActualParameter(ParameterSpec specification, TypeMirror actualType, int index, boolean implicit) {
         this.specification = specification;
-        this.actualType = actualType;
+        this.type = actualType;
+        this.typeSystemType = null;
 
         this.index = index;
         this.implicit = implicit;
@@ -49,7 +51,12 @@
         this.localName = valueName;
     }
 
-    public ActualParameter(ActualParameter parameter, TypeMirror otherType) {
+    public ActualParameter(ParameterSpec specification, TypeData actualType, int index, boolean implicit) {
+        this(specification, actualType.getPrimitiveType(), index, implicit);
+        this.typeSystemType = actualType;
+    }
+
+    public ActualParameter(ActualParameter parameter, TypeData otherType) {
         this(parameter.specification, otherType, parameter.index, parameter.implicit);
     }
 
@@ -77,12 +84,12 @@
         return method;
     }
 
-    public TypeMirror getActualType() {
-        return actualType;
+    public TypeMirror getType() {
+        return type;
     }
 
-    public TypeData getActualTypeData(TypeSystemData typeSystem) {
-        return typeSystem.findTypeData(actualType);
+    public TypeData getTypeSystemType() {
+        return typeSystemType;
     }
 
     public ActualParameter getPreviousParameter() {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ClassElementFactory.java	Tue Apr 23 08:44:07 2013 +0200
@@ -75,7 +75,7 @@
             builder.string("this.");
             builder.string(fieldName);
             builder.string(" = ");
-            if (isAssignable(field.asType(), getContext().getTruffleTypes().getNode())) {
+            if (isAssignable(getContext(), field.asType(), getContext().getTruffleTypes().getNode())) {
                 builder.string("adoptChild(").string(fieldName).string(")");
             } else {
                 builder.string(fieldName);
@@ -99,7 +99,6 @@
         if (element.getModifiers().contains(Modifier.PRIVATE)) {
             return null;
         }
-
         CodeExecutableElement executable = CodeExecutableElement.clone(getContext().getEnvironment(), element);
         executable.setReturnType(null);
         executable.setSimpleName(CodeNames.of(type.getSimpleName().toString()));
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java	Tue Apr 23 08:44:07 2013 +0200
@@ -27,7 +27,7 @@
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality;
 
 public class MethodSpec {
 
@@ -60,8 +60,9 @@
         optional.add(spec);
     }
 
-    public void addRequired(ParameterSpec spec) {
+    public ParameterSpec addRequired(ParameterSpec spec) {
         required.add(spec);
+        return spec;
     }
 
     public List<TypeMirror> getImplicitRequiredTypes() {
@@ -80,10 +81,6 @@
         return optional;
     }
 
-    public void makeTypeDefinitions() {
-
-    }
-
     public List<ParameterSpec> getAll() {
         List<ParameterSpec> specs = new ArrayList<>();
         specs.add(getReturnType());
@@ -154,11 +151,11 @@
 
         for (ParameterSpec requiredSpec : getRequired()) {
             b.append(sep);
-            if (requiredSpec.getCardinality() == Cardinality.MULTIPLE) {
+            if (requiredSpec.getCardinality() == Cardinality.MANY) {
                 b.append("{");
             }
             b.append(createTypeSignature(requiredSpec, false));
-            if (requiredSpec.getCardinality() == Cardinality.MULTIPLE) {
+            if (requiredSpec.getCardinality() == Cardinality.MANY) {
                 b.append("}");
             }
             sep = ", ";
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ParameterSpec.java	Tue Apr 23 08:44:07 2013 +0200
@@ -27,14 +27,11 @@
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.codegen.processor.*;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality;
 import com.oracle.truffle.codegen.processor.template.MethodSpec.TypeDef;
 
 public class ParameterSpec {
 
-    public enum Cardinality {
-        ONE, MULTIPLE;
-    }
-
     private final String name;
     private final List<TypeMirror> allowedTypes;
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Tue Apr 23 08:44:07 2013 +0200
@@ -144,14 +144,16 @@
 
     public List<ActualParameter> getReturnTypeAndParameters() {
         List<ActualParameter> allParameters = new ArrayList<>(getParameters().size() + 1);
-        allParameters.add(getReturnType());
+        if (getReturnType() != null) {
+            allParameters.add(getReturnType());
+        }
         allParameters.addAll(getParameters());
         return Collections.unmodifiableList(allParameters);
     }
 
-    public boolean canBeAccessedByInstanceOf(TypeMirror type) {
+    public boolean canBeAccessedByInstanceOf(ProcessorContext context, TypeMirror type) {
         TypeMirror methodType = Utils.findNearestEnclosingType(getMethod()).asType();
-        return Utils.isAssignable(type, methodType) || Utils.isAssignable(methodType, type);
+        return Utils.isAssignable(context, type, methodType) || Utils.isAssignable(context, methodType, type);
     }
 
     public ExecutableElement getMethod() {
@@ -186,13 +188,17 @@
         return prev;
     }
 
-    public List<TypeData> getSignature(TypeSystemData typeSystem) {
+    public TypeData getReturnSignature() {
+        return getReturnType().getTypeSystemType();
+    }
+
+    public List<TypeData> getSignature() {
         List<TypeData> types = new ArrayList<>();
-        for (ActualParameter parameter : getReturnTypeAndParameters()) {
+        for (ActualParameter parameter : getParameters()) {
             if (!parameter.getSpecification().isSignature()) {
                 continue;
             }
-            TypeData typeData = parameter.getActualTypeData(typeSystem);
+            TypeData typeData = parameter.getTypeSystemType();
             if (typeData != null) {
                 types.add(typeData);
             }
@@ -220,14 +226,27 @@
         return compare;
     }
 
+    public List<ActualParameter> getParametersAfter(ActualParameter genericParameter) {
+        boolean found = false;
+        List<ActualParameter> foundParameters = new ArrayList<>();
+        for (ActualParameter param : getParameters()) {
+            if (param.getLocalName().equals(genericParameter.getLocalName())) {
+                found = true;
+            } else if (found) {
+                foundParameters.add(param);
+            }
+        }
+        return foundParameters;
+    }
+
     public int compareBySignature(TemplateMethod compareMethod) {
         TypeSystemData typeSystem = getTemplate().getTypeSystem();
         if (typeSystem != compareMethod.getTemplate().getTypeSystem()) {
             throw new IllegalStateException("Cannot compare two methods with different type systems.");
         }
 
-        List<TypeData> signature1 = getSignature(typeSystem);
-        List<TypeData> signature2 = compareMethod.getSignature(typeSystem);
+        List<TypeData> signature1 = getSignature();
+        List<TypeData> signature2 = compareMethod.getSignature();
         if (signature1.size() != signature2.size()) {
             return signature2.size() - signature1.size();
         }
@@ -242,6 +261,12 @@
                 return 0;
             }
         }
+        if (result == 0) {
+            TypeData returnSignature1 = getReturnSignature();
+            TypeData returnSignature2 = compareMethod.getReturnSignature();
+
+            result = compareActualParameter(typeSystem, returnSignature1, returnSignature2);
+        }
 
         return result;
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java	Tue Apr 23 08:44:07 2013 +0200
@@ -33,7 +33,8 @@
 
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
-import com.oracle.truffle.codegen.processor.template.ParameterSpec.Cardinality;
+import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality;
+import com.oracle.truffle.codegen.processor.typesystem.*;
 
 public abstract class TemplateMethodParser<T extends Template, E extends TemplateMethod> {
 
@@ -69,6 +70,10 @@
         return context;
     }
 
+    public TypeSystemData getTypeSystem() {
+        return template.getTypeSystem();
+    }
+
     public abstract MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror);
 
     public abstract E create(TemplateMethod method);
@@ -221,7 +226,7 @@
         ConsumableListIterator<ParameterSpec> required = new ConsumableListIterator<>(spec.getRequired());
         while (required.get() != null || types.get() != null) {
             if (required.get() == null || types.get() == null) {
-                if (required.get() != null && required.get().getCardinality() == Cardinality.MULTIPLE) {
+                if (required.get() != null && required.get().getCardinality() == Cardinality.MANY) {
                     required.consume();
                     specificationParameterIndex = 0;
                     continue;
@@ -231,7 +236,7 @@
             boolean implicit = types.getIndex() < spec.getImplicitRequiredTypes().size();
             ActualParameter resolvedParameter = matchParameter(required.get(), types.get(), template, specificationParameterIndex, implicit);
             if (resolvedParameter == null) {
-                if (required.get().getCardinality() == Cardinality.MULTIPLE) {
+                if (required.get().getCardinality() == Cardinality.MANY) {
                     required.consume();
                     continue;
                 }
@@ -243,7 +248,7 @@
                 if (required.get().getCardinality() == Cardinality.ONE) {
                     required.consume();
                     specificationParameterIndex = 0;
-                } else if (required.get().getCardinality() == Cardinality.MULTIPLE) {
+                } else if (required.get().getCardinality() == Cardinality.MANY) {
                     specificationParameterIndex++;
                 }
             }
@@ -263,16 +268,22 @@
         return parsedParams;
     }
 
-    private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template typeSystem, int index, boolean implicit) {
+    private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template originalTemplate, int index, boolean implicit) {
         TypeMirror resolvedType = mirror;
         if (hasError(resolvedType)) {
-            resolvedType = context.resolveNotYetCompiledType(mirror, typeSystem);
+            resolvedType = context.resolveNotYetCompiledType(mirror, originalTemplate);
         }
 
         if (!specification.matches(resolvedType)) {
             return null;
         }
-        return new ActualParameter(specification, resolvedType, index, implicit);
+
+        TypeData resolvedTypeData = getTypeSystem().findTypeData(resolvedType);
+        if (resolvedTypeData != null) {
+            return new ActualParameter(specification, resolvedTypeData, index, implicit);
+        } else {
+            return new ActualParameter(specification, resolvedType, index, implicit);
+        }
     }
 
     /* Helper class for parsing. */
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java	Tue Apr 23 08:44:07 2013 +0200
@@ -46,12 +46,12 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        MethodSpec spec = createDefaultMethodSpec(method, mirror, null);
+        MethodSpec spec = createDefaultMethodSpec(method, mirror, true, null);
         spec.setVariableRequiredArguments(true);
         spec.getRequired().clear();
 
         for (ActualParameter parameter : specialization.getRequiredParameters()) {
-            ParameterSpec paramSpec = new ParameterSpec(parameter.getLocalName(), parameter.getActualType(), getNode().getTypeSystem().getGenericType());
+            ParameterSpec paramSpec = new ParameterSpec(parameter.getLocalName(), parameter.getType(), getNode().getTypeSystem().getGenericType());
             paramSpec.setSignature(true);
             spec.addRequired(paramSpec);
         }
@@ -82,7 +82,7 @@
             if (specializationParameter == null) {
                 newParameters.add(parameter);
             } else {
-                newParameters.add(new ActualParameter(specializationParameter.getSpecification(), parameter.getActualType(), specializationParameter.getIndex(), parameter.isImplicit()));
+                newParameters.add(new ActualParameter(specializationParameter.getSpecification(), parameter.getTypeSystemType(), specializationParameter.getIndex(), parameter.isImplicit()));
             }
         }
         guard.setParameters(newParameters);
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java	Tue Apr 23 08:44:07 2013 +0200
@@ -51,7 +51,7 @@
     public TypeCastData create(TemplateMethod method) {
         TypeData targetType = findTypeByMethodName(method, "as");
         ActualParameter parameter = method.findParameter("valueValue");
-        return new TypeCastData(method, parameter.getActualTypeData(getTypeSystem()), targetType);
+        return new TypeCastData(method, parameter.getTypeSystemType(), targetType);
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java	Tue Apr 23 08:44:07 2013 +0200
@@ -53,7 +53,7 @@
         assert checkedType != null;
         ActualParameter parameter = method.findParameter("valueValue");
         assert parameter != null;
-        return new TypeCheckData(method, checkedType, parameter.getActualTypeData(getTypeSystem()));
+        return new TypeCheckData(method, checkedType, parameter.getTypeSystemType());
     }
 
     @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeData.java	Tue Apr 23 08:44:07 2013 +0200
@@ -110,4 +110,19 @@
         return Utils.typeEquals(boxedType, actualTypeData.boxedType);
     }
 
+    public boolean needsCastTo(TypeData targetType) {
+        if (this.equals(targetType)) {
+            return false;
+        } else if (targetType.isGeneric()) {
+            return false;
+        } else if (targetType.isVoid()) {
+            return false;
+        }
+        return true;
+    }
+
+    public boolean isPrimitive() {
+        return Utils.isPrimitive(getPrimitiveType());
+    }
+
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeSystemMethodParser.java	Tue Apr 23 08:44:07 2013 +0200
@@ -34,10 +34,6 @@
         super(context, typeSystem);
     }
 
-    public TypeSystemData getTypeSystem() {
-        return template;
-    }
-
     @Override
     public final boolean isParsable(ExecutableElement method) {
         return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/NodeFactory.java	Tue Apr 23 08:44:07 2013 +0200
@@ -74,7 +74,7 @@
         if (expressions.size() >= 1) {
             StatementNode[] nodes = new StatementNode[expressions.size() + 1];
             for (int i = 0; i < expressions.size(); i++) {
-                nodes[i] = PrintNodeFactory.create(expressions.get(i), printOutput);
+                nodes[i] = PrintNodeFactory.create(printOutput, expressions.get(i));
             }
             nodes[expressions.size()] = new PrintLineNode(printOutput);
             return new BlockNode(nodes);
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ArithmeticNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -29,24 +29,8 @@
 
 public abstract class ArithmeticNode extends BinaryNode {
 
-    public ArithmeticNode(TypedNode left, TypedNode right) {
-        super(left, right);
-    }
-
-    protected ArithmeticNode(ArithmeticNode node) {
-        super(node);
-    }
-
     public abstract static class AddNode extends ArithmeticNode {
 
-        public AddNode(TypedNode left, TypedNode right) {
-            super(left, right);
-        }
-
-        protected AddNode(AddNode node) {
-            super(node);
-        }
-
         @Specialization(rewriteOn = ArithmeticException.class)
         int doInt(int left, int right) {
             return ExactMath.addExact(left, right);
@@ -70,14 +54,6 @@
 
     public abstract static class SubNode extends ArithmeticNode {
 
-        public SubNode(TypedNode left, TypedNode right) {
-            super(left, right);
-        }
-
-        protected SubNode(SubNode node) {
-            super(node);
-        }
-
         @Specialization(rewriteOn = ArithmeticException.class)
         int sub(int left, int right) {
             return ExactMath.subtractExact(left, right);
@@ -92,14 +68,6 @@
 
     public abstract static class DivNode extends ArithmeticNode {
 
-        public DivNode(TypedNode left, TypedNode right) {
-            super(left, right);
-        }
-
-        protected DivNode(DivNode node) {
-            super(node);
-        }
-
         @Specialization(rewriteOn = ArithmeticException.class)
         int div(int left, int right) {
             return left / right;
@@ -113,14 +81,6 @@
 
     public abstract static class MulNode extends ArithmeticNode {
 
-        public MulNode(TypedNode left, TypedNode right) {
-            super(left, right);
-        }
-
-        protected MulNode(MulNode node) {
-            super(node);
-        }
-
         @Specialization(rewriteOn = ArithmeticException.class)
         int mul(int left, int right) {
             return ExactMath.multiplyExact(left, right);
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/BinaryNode.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/BinaryNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -24,20 +24,7 @@
 
 import com.oracle.truffle.api.codegen.*;
 
-@ExecuteChildren({"leftNode", "rightNode"})
+@NodeChildren({@NodeChild("leftNode"), @NodeChild("rightNode")})
 public abstract class BinaryNode extends TypedNode {
 
-    @Child protected TypedNode leftNode;
-
-    @Child protected TypedNode rightNode;
-
-    public BinaryNode(TypedNode left, TypedNode right) {
-        this.leftNode = adoptChild(left);
-        this.rightNode = adoptChild(right);
-    }
-
-    public BinaryNode(BinaryNode node) {
-        this(node.leftNode, node.rightNode);
-    }
-
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ConditionNode.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/ConditionNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -28,4 +28,9 @@
 
     public abstract boolean executeCondition(VirtualFrame frame);
 
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        executeCondition(frame);
+    }
+
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/IfNode.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/IfNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -25,23 +25,19 @@
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.api.frame.*;
 
-@ExecuteChildren("conditionNode")
+@NodeChild(value = "conditionNode", type = ConditionNode.class)
 public abstract class IfNode extends StatementNode {
 
-    @Child protected ConditionNode conditionNode;
-
     @Child private StatementNode thenPartNode;
-
     @Child private StatementNode elsePartNode;
 
-    public IfNode(ConditionNode condition, StatementNode thenPart, StatementNode elsePart) {
-        this.conditionNode = adoptChild(condition);
+    public IfNode(StatementNode thenPart, StatementNode elsePart) {
         this.thenPartNode = adoptChild(thenPart);
         this.elsePartNode = adoptChild(elsePart);
     }
 
     protected IfNode(IfNode node) {
-        this(node.conditionNode, node.thenPartNode, node.elsePartNode);
+        this(node.thenPartNode, node.elsePartNode);
     }
 
     @Specialization
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LessThanNode.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LessThanNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -28,14 +28,6 @@
 
 public abstract class LessThanNode extends BinaryNode {
 
-    public LessThanNode(TypedNode left, TypedNode right) {
-        super(left, right);
-    }
-
-    public LessThanNode(LessThanNode node) {
-        this(node.leftNode, node.rightNode);
-    }
-
     @Specialization
     public boolean doInteger(int left, int right) {
         return left < right;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LogicalAndNode.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/LogicalAndNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -27,14 +27,6 @@
 @SuppressWarnings("unused")
 public abstract class LogicalAndNode extends BinaryNode {
 
-    public LogicalAndNode(TypedNode leftNode, TypedNode rightNode) {
-        super(leftNode, rightNode);
-    }
-
-    public LogicalAndNode(LogicalAndNode node) {
-        this(node.leftNode, node.rightNode);
-    }
-
     @ShortCircuit("rightNode")
     public boolean needsRightNode(boolean left) {
         return left;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/PrintNode.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/PrintNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -26,19 +26,17 @@
 
 import com.oracle.truffle.api.codegen.*;
 
+@NodeChild(value = "expression", type = TypedNode.class)
 public abstract class PrintNode extends StatementNode {
 
-    @Child protected TypedNode expression;
-
     private final PrintStream output;
 
-    public PrintNode(TypedNode expression, PrintStream output) {
-        this.expression = adoptChild(expression);
+    public PrintNode(PrintStream output) {
         this.output = output;
     }
 
     public PrintNode(PrintNode node) {
-        this(node.expression, node.output);
+        this(node.output);
     }
 
     @Specialization
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TernaryNode.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TernaryNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -27,25 +27,9 @@
 import com.oracle.truffle.api.codegen.*;
 
 @SuppressWarnings("unused")
-@ExecuteChildren({"conditionNode", "ifPartNode", "elsePartNode"})
+@NodeChildren({@NodeChild(value = "conditionNode", type = ConditionNode.class), @NodeChild("ifPartNode"), @NodeChild("elsePartNode")})
 public abstract class TernaryNode extends TypedNode {
 
-    @Child protected ConditionNode conditionNode;
-
-    @Child protected TypedNode ifPartNode;
-
-    @Child protected TypedNode elsePartNode;
-
-    public TernaryNode(ConditionNode condition, TypedNode ifPart, TypedNode elsePart) {
-        this.conditionNode = adoptChild(condition);
-        this.ifPartNode = adoptChild(ifPart);
-        this.elsePartNode = adoptChild(elsePart);
-    }
-
-    public TernaryNode(TernaryNode condition) {
-        this(condition.conditionNode, condition.ifPartNode, condition.elsePartNode);
-    }
-
     @ShortCircuit("ifPartNode")
     public boolean needsIfPart(boolean condition) {
         return condition;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TypedNode.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/TypedNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -26,6 +26,7 @@
 
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.*;
 
 public abstract class TypedNode extends ConditionNode {
 
@@ -38,18 +39,46 @@
         }
     }
 
-    public abstract boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException;
+    public abstract Object executeGeneric(VirtualFrame frame);
 
-    public abstract int executeInteger(VirtualFrame frame) throws UnexpectedResultException;
+    public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException {
+        return SLTypesGen.SLTYPES.expectBoolean(executeGeneric(frame));
+    }
+
+    public int executeInteger(VirtualFrame frame) throws UnexpectedResultException {
+        return SLTypesGen.SLTYPES.expectInteger(executeGeneric(frame));
+    }
 
-    public abstract BigInteger executeBigInteger(VirtualFrame frame) throws UnexpectedResultException;
+    public BigInteger executeBigInteger(VirtualFrame frame) throws UnexpectedResultException {
+        return SLTypesGen.SLTYPES.expectBigInteger(executeGeneric(frame));
+    }
 
-    public abstract String executeString(VirtualFrame frame) throws UnexpectedResultException;
+    public String executeString(VirtualFrame frame) throws UnexpectedResultException {
+        return SLTypesGen.SLTYPES.expectString(executeGeneric(frame));
+    }
 
-    public abstract Object executeGeneric(VirtualFrame frame);
+    @Override
+    public void executeVoid(VirtualFrame frame) {
+        executeGeneric(frame);
+    }
 
     public boolean isString(Object a, Object b) {
         return a instanceof String || b instanceof String;
     }
 
+    @SuppressWarnings("unused")
+    public Object executeEvaluated(VirtualFrame frame, Object val1) {
+        return executeGeneric(frame);
+    }
+
+    @SuppressWarnings("unused")
+    public Object executeEvaluated(VirtualFrame frame, Object val1, Object val2) {
+        return executeEvaluated(frame, val1);
+    }
+
+    @SuppressWarnings("unused")
+    public Object executeEvaluated(VirtualFrame frame, Object val1, Object val2, Object val3) {
+        return executeEvaluated(frame, val1, val2);
+    }
+
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java	Mon Apr 22 17:49:13 2013 +0200
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/WriteLocalNode.java	Tue Apr 23 08:44:07 2013 +0200
@@ -27,17 +27,15 @@
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.api.frame.*;
 
+@NodeChild(value = "rightNode", type = TypedNode.class)
 public abstract class WriteLocalNode extends FrameSlotNode {
 
-    @Child protected TypedNode rightNode;
-
-    public WriteLocalNode(FrameSlot slot, TypedNode right) {
+    public WriteLocalNode(FrameSlot slot) {
         super(slot);
-        this.rightNode = adoptChild(right);
     }
 
     public WriteLocalNode(WriteLocalNode node) {
-        this(node.slot, node.rightNode);
+        this(node.slot);
     }
 
     @Specialization
--- a/src/cpu/x86/vm/graalRuntime_x86.cpp	Mon Apr 22 17:49:13 2013 +0200
+++ b/src/cpu/x86/vm/graalRuntime_x86.cpp	Tue Apr 23 08:44:07 2013 +0200
@@ -972,6 +972,18 @@
       break;
     }
 
+    case stub_printf_id: {
+      __ enter();
+      oop_maps = new OopMapSet();
+      OopMap* oop_map = save_live_registers(sasm, 4);
+      int call_offset = __ call_RT(noreg, noreg, (address)stub_printf, j_rarg0, j_rarg1, j_rarg2, j_rarg3);
+      oop_maps->add_gc_map(call_offset, oop_map);
+      restore_live_registers(sasm);
+      __ leave();
+      __ ret(0);
+      break;
+    }
+
     case log_primitive_id: {
       __ enter();
       oop_maps = new OopMapSet();
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Mon Apr 22 17:49:13 2013 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Tue Apr 23 08:44:07 2013 +0200
@@ -773,6 +773,7 @@
   set_stub("logPrimitiveStub", GraalRuntime::entry_for(GraalRuntime::log_primitive_id));
   set_stub("logObjectStub", GraalRuntime::entry_for(GraalRuntime::log_object_id));
   set_stub("logPrintfStub", GraalRuntime::entry_for(GraalRuntime::log_printf_id));
+  set_stub("stubPrintfStub", GraalRuntime::entry_for(GraalRuntime::stub_printf_id));
   set_stub("aescryptEncryptBlockStub", StubRoutines::aescrypt_encryptBlock());
   set_stub("aescryptDecryptBlockStub", StubRoutines::aescrypt_decryptBlock());
   set_stub("cipherBlockChainingEncryptAESCryptStub", StubRoutines::cipherBlockChaining_encryptAESCrypt());
--- a/src/share/vm/graal/graalRuntime.cpp	Mon Apr 22 17:49:13 2013 +0200
+++ b/src/share/vm/graal/graalRuntime.cpp	Tue Apr 23 08:44:07 2013 +0200
@@ -565,6 +565,12 @@
   tty->print(buf, v1, v2, v3);
 JRT_END
 
+JRT_LEAF(void, GraalRuntime::stub_printf(JavaThread* thread, jlong format, jlong v1, jlong v2, jlong v3))
+  ResourceMark rm;
+  char *buf = (char*) (address) format;
+  tty->print(buf, v1, v2, v3);
+JRT_END
+
 JRT_ENTRY(void, GraalRuntime::log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline))
   union {
       jlong l;
--- a/src/share/vm/graal/graalRuntime.hpp	Mon Apr 22 17:49:13 2013 +0200
+++ b/src/share/vm/graal/graalRuntime.hpp	Tue Apr 23 08:44:07 2013 +0200
@@ -98,6 +98,7 @@
   stub(create_out_of_bounds_exception) \
   stub(log_object)              \
   stub(log_printf)              \
+  stub(stub_printf)             \
   stub(log_primitive)           \
   stub(identity_hash_code)      \
   stub(thread_is_interrupted)   \
@@ -146,6 +147,7 @@
   static void monitorexit (JavaThread* thread, oopDesc* obj, BasicLock* lock);
   static void vm_error(JavaThread* thread, oop where, oop format, jlong value);
   static void log_printf(JavaThread* thread, oop format, jlong v1, jlong v2, jlong v3);
+  static void stub_printf(JavaThread* thread, jlong format, jlong v1, jlong v2, jlong v3);
   static void log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline);
   static void wb_pre_call(JavaThread* thread, oopDesc* obj);
   static void wb_post_call(JavaThread* thread, oopDesc* obj, void* card);