changeset 20982:23d6b95bd687

Merge
author Tom Rodriguez <tom.rodriguez@oracle.com>
date Wed, 15 Apr 2015 11:03:04 -0700
parents 92fc95e8667d (current diff) 018c536858cc (diff)
children b99da6d86cfe
files graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemNodeFactory.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeData.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GenericParser.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedDispatchNode.java
diffstat 121 files changed, 3568 insertions(+), 2938 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGELOG.md	Wed Apr 15 10:09:13 2015 -0700
+++ b/CHANGELOG.md	Wed Apr 15 11:03:04 2015 -0700
@@ -36,6 +36,10 @@
 * Changed syntax and semantics of Specialization#assumptions and Specialization#guards. They now use a Java like expression syntax.
 * Changed guard expressions that do not bind any dynamic parameter are invoked just once per specialization instantiation. They are now asserted to be true on the fast path.
 * Renamed @ImportGuards to @ImportStatic.
+* Changed declaring a @TypeSystemReference for a node that contains specializations is not mandatory anymore.
+* Changed types used in specializations are not restricted on types declared in the type system anymore.
+* Changed nodes that declare all execute methods with the same number of evaluated arguments as specialization arguments do not require @NodeChild annotations anymore.
+* Changed types used in checks and casts are not mandatory to be declared in the type system.
 
 ## Version 0.6
 19-Dec-2014, [Repository Revision](http://hg.openjdk.java.net/graal/graal/shortlog/graal-0.6)
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Wed Apr 15 11:03:04 2015 -0700
@@ -1790,4 +1790,8 @@
     public void fpadd32(Register rs1, Register rs2, Register rd) {
         op3(Impdep1, Fpadd32, rs1, rs2, rd);
     }
+
+    public boolean isCbcond(int i) {
+        return (i & 0xC1C00000) == 0xC00000;
+    }
 }
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java	Wed Apr 15 11:03:04 2015 -0700
@@ -87,7 +87,7 @@
             case Bpr:
                 boolean isCBcond = (inst & CBCOND_MASK) != 0;
                 if (isCBcond) {
-                    assert isSimm10(disp);
+                    assert isSimm10(disp) : String.format("%d: instruction: 0x%x", disp, inst);
                     int d10Split = 0;
                     d10Split |= (disp & 0b11_0000_0000) << D10HI_SHIFT - 8;
                     d10Split |= (disp & 0b00_1111_1111) << D10LO_SHIFT;
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java	Wed Apr 15 11:03:04 2015 -0700
@@ -44,6 +44,13 @@
     }
 
     /**
+     * Determines if this plugin can only be used when inlining the method is it associated with.
+     */
+    default boolean inlineOnly() {
+        return isSignaturePolymorphic();
+    }
+
+    /**
      * Handles invocation of a signature polymorphic method.
      *
      * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodSubstitutionPlugin.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/MethodSubstitutionPlugin.java	Wed Apr 15 11:03:04 2015 -0700
@@ -62,6 +62,11 @@
         this.originalIsStatic = parameters.length == 0 || parameters[0] != Receiver.class;
     }
 
+    public boolean inlineOnly() {
+        // Conservatively assume MacroNodes may be used in a substitution
+        return true;
+    }
+
     /**
      * Gets the substitute method, resolving it first if necessary.
      */
@@ -121,8 +126,7 @@
                 return m;
             }
         }
-        throw new GraalInternalError("No method found in %s compatible with \"%s(%s)\"", declaringClass.getName(), name, Arrays.asList(parameters).stream().map(c -> c.getSimpleName()).collect(
-                        Collectors.joining(", ")));
+        throw new GraalInternalError("No method found specified by %s", this);
     }
 
     /**
@@ -165,4 +169,10 @@
         }
         throw new GraalInternalError("could not find method named \"execute\" in " + c.getName());
     }
+
+    @Override
+    public String toString() {
+        return String.format("%s[%s.%s(%s)]", getClass().getSimpleName(), declaringClass.getName(), name,
+                        Arrays.asList(parameters).stream().map(c -> c.getSimpleName()).collect(Collectors.joining(", ")));
+    }
 }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/CompileTheWorldTest.java	Wed Apr 15 11:03:04 2015 -0700
@@ -40,7 +40,7 @@
         boolean originalSetting = ExitVMOnException.getValue();
         // Compile a couple classes in rt.jar
         String file = System.getProperty("java.home") + "/lib/rt.jar";
-        new CompileTheWorld(file, new Config(null), 1, 5, null, false).compile();
+        new CompileTheWorld(file, new Config(null), 1, 5, null, null, false).compile();
         ExitVMOnException.setValue(originalSetting);
     }
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Wed Apr 15 11:03:04 2015 -0700
@@ -126,7 +126,7 @@
             Method method = lookup(className, methodName);
             if (method != null) {
                 ResolvedJavaMethod installedCodeOwner = getMetaAccess().lookupJavaMethod(method);
-                StructuredGraph subst = getReplacements().getSubstitution(installedCodeOwner);
+                StructuredGraph subst = getReplacements().getSubstitution(installedCodeOwner, 0);
                 ResolvedJavaMethod substMethod = subst == null ? null : subst.method();
                 if (substMethod != null) {
                     StructuredGraph graph = new StructuredGraph(substMethod, AllowAssumptions.YES);
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/MemoryUsageBenchmark.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/MemoryUsageBenchmark.java	Wed Apr 15 11:03:04 2015 -0700
@@ -180,7 +180,7 @@
         compileAndTime("complex");
         if (CompileTheWorldClasspath.getValue() != SUN_BOOT_CLASS_PATH) {
             CompileTheWorld ctw = new CompileTheWorld(CompileTheWorldClasspath.getValue(), new Config(CompileTheWorldConfig.getValue()), CompileTheWorldStartAt.getValue(),
-                            CompileTheWorldStopAt.getValue(), CompileTheWorldMethodFilter.getValue(), CompileTheWorldVerbose.getValue());
+                            CompileTheWorldStopAt.getValue(), CompileTheWorldMethodFilter.getValue(), CompileTheWorldExcludeMethodFilter.getValue(), CompileTheWorldVerbose.getValue());
             try {
                 ctw.compile();
             } catch (Throwable e) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Wed Apr 15 11:03:04 2015 -0700
@@ -70,6 +70,8 @@
         public static final OptionValue<Integer> CompileTheWorldIterations = new OptionValue<>(1);
         @Option(help = "Only compile methods matching this filter", type = OptionType.Debug)
         public static final OptionValue<String> CompileTheWorldMethodFilter = new OptionValue<>(null);
+        @Option(help = "Exclude methods matching this filter from compilation", type = OptionType.Debug)
+        public static final OptionValue<String> CompileTheWorldExcludeMethodFilter = new OptionValue<>(null);
         @Option(help = "First class to consider when using -XX:+CompileTheWorld", type = OptionType.Debug)
         public static final OptionValue<Integer> CompileTheWorldStartAt = new OptionValue<>(1);
         @Option(help = "Last class to consider when using -XX:+CompileTheWorld", type = OptionType.Debug)
@@ -158,6 +160,9 @@
     /** Only compile methods matching one of the filters in this array if the array is non-null. */
     private final MethodFilter[] methodFilters;
 
+    /** Exclude methods matching one of the filters in this array if the array is non-null. */
+    private final MethodFilter[] excludeMethodFilters;
+
     // Counters
     private int classFileCounter = 0;
     private AtomicLong compiledMethodsCounter = new AtomicLong();
@@ -180,12 +185,15 @@
      * @param files {@link File#pathSeparator} separated list of Zip/Jar files to compile
      * @param startAt index of the class file to start compilation at
      * @param stopAt index of the class file to stop compilation at
+     * @param methodFilters
+     * @param excludeMethodFilters
      */
-    public CompileTheWorld(String files, Config config, int startAt, int stopAt, String methodFilters, boolean verbose) {
+    public CompileTheWorld(String files, Config config, int startAt, int stopAt, String methodFilters, String excludeMethodFilters, boolean verbose) {
         this.files = files;
         this.startAt = startAt;
         this.stopAt = stopAt;
         this.methodFilters = methodFilters == null || methodFilters.isEmpty() ? null : MethodFilter.parse(methodFilters);
+        this.excludeMethodFilters = excludeMethodFilters == null || excludeMethodFilters.isEmpty() ? null : MethodFilter.parse(excludeMethodFilters);
         this.verbose = verbose;
         this.config = config;
 
@@ -292,8 +300,12 @@
                 if (methodFilters == null || methodFilters.length == 0) {
                     println("CompileTheWorld : Compiling all classes in " + entry);
                 } else {
-                    println("CompileTheWorld : Compiling all methods in " + entry + " matching one of the following filters: " +
-                                    Arrays.asList(methodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", ")));
+                    String include = Arrays.asList(methodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", "));
+                    println("CompileTheWorld : Compiling all methods in " + entry + " matching one of the following filters: " + include);
+                }
+                if (excludeMethodFilters != null && excludeMethodFilters.length > 0) {
+                    String exclude = Arrays.asList(excludeMethodFilters).stream().map(MethodFilter::toString).collect(Collectors.joining(", "));
+                    println("CompileTheWorld : Excluding all methods matching one of the follwing filters: " + exclude);
                 }
                 println();
 
@@ -321,6 +333,9 @@
                     if (methodFilters != null && !MethodFilter.matchesClassName(methodFilters, dottedClassName)) {
                         continue;
                     }
+                    if (excludeMethodFilters != null && MethodFilter.matchesClassName(excludeMethodFilters, dottedClassName)) {
+                        continue;
+                    }
 
                     if (dottedClassName.startsWith("jdk.management.") || dottedClassName.startsWith("jdk.internal.cmm.*")) {
                         continue;
@@ -427,6 +442,9 @@
         if (methodFilters != null && !MethodFilter.matches(methodFilters, method)) {
             return;
         }
+        if (excludeMethodFilters != null && MethodFilter.matches(excludeMethodFilters, method)) {
+            return;
+        }
         Future<?> task = threadPool.submit(new Runnable() {
             public void run() {
                 waitToRun();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java	Wed Apr 15 11:03:04 2015 -0700
@@ -552,7 +552,7 @@
             getCompilerToVM().resetCompilationStatistics();
             TTY.println("CompileTheWorld : iteration " + i);
             CompileTheWorld ctw = new CompileTheWorld(CompileTheWorldClasspath.getValue(), new Config(CompileTheWorldConfig.getValue()), CompileTheWorldStartAt.getValue(),
-                            CompileTheWorldStopAt.getValue(), CompileTheWorldMethodFilter.getValue(), CompileTheWorldVerbose.getValue());
+                            CompileTheWorldStopAt.getValue(), CompileTheWorldMethodFilter.getValue(), CompileTheWorldExcludeMethodFilter.getValue(), CompileTheWorldVerbose.getValue());
             ctw.compile();
         }
         System.exit(0);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Wed Apr 15 11:03:04 2015 -0700
@@ -88,7 +88,7 @@
                 }
                 if (BootstrapReplacements.getValue()) {
                     for (ResolvedJavaMethod method : replacements.getAllReplacements()) {
-                        replacements.getSubstitution(method);
+                        replacements.getSubstitution(method, -1);
                     }
                 }
             } catch (Throwable e) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Wed Apr 15 11:03:04 2015 -0700
@@ -99,6 +99,10 @@
                 b.addPush(Kind.Object, new ObjectCloneNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), object));
                 return true;
             }
+
+            public boolean inlineOnly() {
+                return true;
+            }
         });
         r.registerMethodSubstitution(ObjectSubstitutions.class, "hashCode", Receiver.class);
     }
@@ -118,6 +122,10 @@
                     }
                     return true;
                 }
+
+                public boolean inlineOnly() {
+                    return true;
+                }
             });
         }
         r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() {
@@ -131,6 +139,10 @@
                 }
                 return true;
             }
+
+            public boolean inlineOnly() {
+                return true;
+            }
         });
     }
 
@@ -146,6 +158,10 @@
                 }
                 return true;
             }
+
+            public boolean inlineOnly() {
+                return true;
+            }
         };
         plugins.register(plugin, ConstantCallSite.class, "getTarget", Receiver.class);
         plugins.register(plugin, MutableCallSite.class, "getTarget", Receiver.class);
@@ -159,6 +175,10 @@
                 b.addPush(new ReflectionGetCallerClassNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType()));
                 return true;
             }
+
+            public boolean inlineOnly() {
+                return true;
+            }
         });
     }
 
@@ -171,12 +191,20 @@
                 b.addPush(new IdentityHashCodeNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), object));
                 return true;
             }
+
+            public boolean inlineOnly() {
+                return true;
+            }
         });
         r.register5("arraycopy", Object.class, int.class, Object.class, int.class, int.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode src, ValueNode srcPos, ValueNode dst, ValueNode dstPos, ValueNode length) {
                 b.add(new ArrayCopyNode(b.getInvokeKind(), targetMethod, b.bci(), b.getInvokeReturnType(), src, srcPos, dst, dstPos, length));
                 return true;
             }
+
+            public boolean inlineOnly() {
+                return true;
+            }
         });
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Wed Apr 15 11:03:04 2015 -0700
@@ -40,6 +40,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.replacements.StandardGraphBuilderPlugins.BoxPlugin;
+import com.oracle.graal.replacements.nodes.*;
 
 /**
  * Extension of {@link InvocationPlugins} that disables plugins based on runtime configuration.
@@ -136,6 +137,14 @@
 
     @Override
     public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable<Node> newNodes) {
+        for (Node node : newNodes) {
+            if (node instanceof MacroNode) {
+                // MacroNode based plugins can only be used for inlining since they
+                // require a valid bci should they need to replace themselves with
+                // an InvokeNode during lowering.
+                assert plugin.inlineOnly() : String.format("plugin that creates a %s (%s) must return true for inlineOnly(): %s", MacroNode.class.getSimpleName(), node, plugin);
+            }
+        }
         if (GraalOptions.ImmutableCode.getValue()) {
             for (Node node : newNodes) {
                 if (node.hasUsages() && node instanceof ConstantNode) {
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Wed Apr 15 11:03:04 2015 -0700
@@ -225,8 +225,12 @@
                     SPARCMove.move(crb, masm, scratchValue, actualY, SPARCDelayedControlTransfer.DUMMY);
                     actualY = scratchValue;
                 }
+                // Test if the previous instruction was cbcond, if so, put a nop inbetween (See
+                // SPARC Architecture 2011 manual)
+                if (masm.isCbcond(masm.getInt(masm.position() - 1))) {
+                    masm.nop();
+                }
                 emitCBCond(masm, actualX, actualY, actualTrueTarget, actualConditionFlag);
-                masm.nop();
             }
             if (needJump) {
                 masm.jmp(actualFalseTarget);
--- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeProcessor.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeProcessor.java	Wed Apr 15 11:03:04 2015 -0700
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodeinfo.processor;
 
-import static com.oracle.truffle.dsl.processor.java.ElementUtils.*;
 import static java.util.Collections.*;
 
 import java.io.*;
@@ -71,6 +70,21 @@
         }
     }
 
+    private static List<Element> getElementHierarchy(Element e) {
+        List<Element> elements = new ArrayList<>();
+        elements.add(e);
+
+        Element enclosing = e.getEnclosingElement();
+        while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) {
+            elements.add(enclosing);
+            enclosing = enclosing.getEnclosingElement();
+        }
+        if (enclosing != null) {
+            elements.add(enclosing);
+        }
+        return elements;
+    }
+
     /**
      * Bugs in an annotation processor can cause silent failure so try to report any exception
      * throws as errors.
--- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java	Wed Apr 15 11:03:04 2015 -0700
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodeinfo.processor;
 
-import static com.oracle.truffle.dsl.processor.java.ElementUtils.*;
 import static javax.lang.model.element.Modifier.*;
 
 import java.util.*;
@@ -32,10 +31,6 @@
 import javax.lang.model.type.*;
 import javax.lang.model.util.*;
 
-import com.oracle.truffle.dsl.processor.java.*;
-import com.oracle.truffle.dsl.processor.java.compiler.*;
-import com.oracle.truffle.dsl.processor.java.compiler.Compiler;
-
 /**
  * Verifies static constraints on nodes.
  */
@@ -54,6 +49,8 @@
     private final TypeElement NodeInputList;
     private final TypeElement NodeSuccessorList;
 
+    private final TypeElement object;
+
     // Checkstyle: resume
 
     public GraphNodeVerifier(GraphNodeProcessor processor) {
@@ -68,6 +65,7 @@
         this.Node = getTypeElement("com.oracle.graal.graph.Node");
         this.NodeInputList = getTypeElement("com.oracle.graal.graph.NodeInputList");
         this.NodeSuccessorList = getTypeElement("com.oracle.graal.graph.NodeSuccessorList");
+        this.object = getTypeElement("java.lang.Object");
     }
 
     /**
@@ -91,10 +89,6 @@
         return getTypeElement(name).asType();
     }
 
-    public TypeMirror getType(Class<?> cls) {
-        return ElementUtils.getType(getProcessingEnv(), cls);
-    }
-
     public ProcessingEnvironment getProcessingEnv() {
         return env.getProcessingEnv();
     }
@@ -106,10 +100,9 @@
     }
 
     private void scanFields(TypeElement node) {
-        Compiler compiler = CompilerFactory.getCompiler(node);
         TypeElement currentClazz = node;
         do {
-            for (VariableElement field : ElementFilter.fieldsIn(compiler.getEnclosedElementsInDeclarationOrder(currentClazz))) {
+            for (VariableElement field : ElementFilter.fieldsIn(currentClazz.getEnclosedElements())) {
                 Set<Modifier> modifiers = field.getModifiers();
                 if (modifiers.contains(STATIC) || modifiers.contains(TRANSIENT)) {
                     continue;
@@ -117,7 +110,7 @@
 
                 List<? extends AnnotationMirror> annotations = field.getAnnotationMirrors();
 
-                boolean isNonOptionalInput = findAnnotationMirror(annotations, Input.asType()) != null;
+                boolean isNonOptionalInput = findAnnotationMirror(annotations, Input) != null;
                 boolean isOptionalInput = findAnnotationMirror(annotations, OptionalInput) != null;
                 boolean isSuccessor = findAnnotationMirror(annotations, Successor) != null;
 
@@ -187,6 +180,30 @@
         } while (!isObject(getSuperType(currentClazz).asType()));
     }
 
+    private AnnotationMirror findAnnotationMirror(List<? extends AnnotationMirror> mirrors, TypeElement expectedAnnotationType) {
+        for (AnnotationMirror mirror : mirrors) {
+            if (sameType(mirror.getAnnotationType(), expectedAnnotationType.asType())) {
+                return mirror;
+            }
+        }
+        return null;
+    }
+
+    private boolean isObject(TypeMirror type) {
+        return sameType(object.asType(), type);
+    }
+
+    private boolean sameType(TypeMirror type1, TypeMirror type2) {
+        return env.getProcessingEnv().getTypeUtils().isSameType(type1, type2);
+    }
+
+    private TypeElement getSuperType(TypeElement element) {
+        if (element.getSuperclass() != null) {
+            return (TypeElement) env.getProcessingEnv().getTypeUtils().asElement(element.getSuperclass());
+        }
+        return null;
+    }
+
     void verify(TypeElement node) {
         scanFields(node);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Wed Apr 15 11:03:04 2015 -0700
@@ -70,39 +70,47 @@
     /**
      * Gets a graph that is a substitution for a given method.
      *
+     * @param invokeBci the call site BCI if this request is made for inlining a substitute
+     *            otherwise {@code -1}
      * @return the graph, if any, that is a substitution for {@code method}
      */
-    default StructuredGraph getSubstitution(ResolvedJavaMethod method) {
-        return getSubstitution(method, false);
+    default StructuredGraph getSubstitution(ResolvedJavaMethod method, int invokeBci) {
+        return getSubstitution(method, false, invokeBci);
     }
 
     /**
      * Gets a graph that is a substitution for a given method.
      *
      * @param fromBytecodeOnly only return a graph created by parsing the bytecode of another method
+     * @param invokeBci the call site BCI if this request is made for inlining a substitute
+     *            otherwise {@code -1}
      * @return the graph, if any, that is a substitution for {@code method}
      */
-    StructuredGraph getSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly);
+    StructuredGraph getSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly, int invokeBci);
 
     /**
-     * Determines if there is a {@linkplain #getSubstitution(ResolvedJavaMethod) substitution graph}
-     * for a given method.
+     * Determines if there is a {@linkplain #getSubstitution(ResolvedJavaMethod, int) substitution
+     * graph} for a given method.
      *
+     * @param invokeBci the call site BCI if this request is made for inlining a substitute
+     *            otherwise {@code -1}
      * @return true iff there is a substitution graph available for {@code method}
      */
-    default boolean hasSubstitution(ResolvedJavaMethod method) {
-        return hasSubstitution(method, false);
+    default boolean hasSubstitution(ResolvedJavaMethod method, int invokeBci) {
+        return hasSubstitution(method, false, invokeBci);
     }
 
     /**
-     * Determines if there is a {@linkplain #getSubstitution(ResolvedJavaMethod) substitution graph}
-     * for a given method.
+     * Determines if there is a {@linkplain #getSubstitution(ResolvedJavaMethod, int) substitution
+     * graph} for a given method.
      *
      * @param fromBytecodeOnly only consider graphs created by parsing the bytecode of another
      *            method
+     * @param invokeBci the call site BCI if this request is made for inlining a substitute
+     *            otherwise {@code -1}
      * @return true iff there is a substitution graph available for {@code method}
      */
-    boolean hasSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly);
+    boolean hasSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly, int invokeBci);
 
     /**
      * Registers all the {@linkplain MethodSubstitution method} substitutions defined by a given
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Wed Apr 15 11:03:04 2015 -0700
@@ -646,12 +646,12 @@
         return firstParam;
     }
 
-    public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target) {
-        return replacements.hasSubstitution(target, false);
+    public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target, int invokeBci) {
+        return replacements.hasSubstitution(target, false, invokeBci);
     }
 
-    public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target) {
-        return replacements.getSubstitution(target);
+    public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target, int invokeBci) {
+        return replacements.getSubstitution(target, invokeBci);
     }
 
     public static FixedWithNextNode inlineMacroNode(Invoke invoke, ResolvedJavaMethod concrete, Class<? extends FixedWithNextNode> macroNodeClass) throws GraalInternalError {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Wed Apr 15 11:03:04 2015 -0700
@@ -59,7 +59,7 @@
     private FixedNodeProbabilityCache probabilites = new FixedNodeProbabilityCache();
 
     public InlineableGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer) {
-        StructuredGraph original = getOriginalGraph(method, context, canonicalizer, invoke.asNode().graph());
+        StructuredGraph original = getOriginalGraph(method, context, canonicalizer, invoke.asNode().graph(), invoke.bci());
         // TODO copying the graph is only necessary if it is modified or if it contains any invokes
         this.graph = original.copy();
         specializeGraphToArguments(invoke, context, canonicalizer);
@@ -70,8 +70,8 @@
      * The graph thus obtained is returned, ie the caller is responsible for cloning before
      * modification.
      */
-    private static StructuredGraph getOriginalGraph(final ResolvedJavaMethod method, final HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller) {
-        StructuredGraph result = InliningUtil.getIntrinsicGraph(context.getReplacements(), method);
+    private static StructuredGraph getOriginalGraph(final ResolvedJavaMethod method, final HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller, int callerBci) {
+        StructuredGraph result = InliningUtil.getIntrinsicGraph(context.getReplacements(), method, callerBci);
         if (result != null) {
             return result;
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/AbstractInliningPolicy.java	Wed Apr 15 11:03:04 2015 -0700
@@ -66,7 +66,7 @@
 
     private static boolean onlyIntrinsics(Replacements replacements, InlineInfo info) {
         for (int i = 0; i < info.numberOfMethods(); i++) {
-            if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) {
+            if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i), info.invoke().bci())) {
                 return false;
             }
         }
@@ -75,7 +75,7 @@
 
     private static boolean onlyForcedIntrinsics(Replacements replacements, InlineInfo info) {
         for (int i = 0; i < info.numberOfMethods(); i++) {
-            if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) {
+            if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i), info.invoke().bci())) {
                 return false;
             }
             if (!replacements.isForcedSubstitution(info.methodAt(i))) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/policy/InlineMethodSubstitutionsPolicy.java	Wed Apr 15 11:03:04 2015 -0700
@@ -38,7 +38,7 @@
         CallTargetNode callTarget = invocation.callee().invoke().callTarget();
         if (callTarget instanceof MethodCallTargetNode) {
             ResolvedJavaMethod calleeMethod = ((MethodCallTargetNode) callTarget).targetMethod();
-            if (replacements.getSubstitution(calleeMethod) != null) {
+            if (replacements.getSubstitution(calleeMethod, invocation.callee().invoke().bci()) != null) {
                 return true;
             }
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Wed Apr 15 11:03:04 2015 -0700
@@ -108,10 +108,10 @@
         return (arg instanceof AbstractNewObjectNode) || (arg instanceof AllocatedObjectNode) || (arg instanceof VirtualObjectNode);
     }
 
-    private String checkTargetConditionsHelper(ResolvedJavaMethod method) {
+    private String checkTargetConditionsHelper(ResolvedJavaMethod method, int invokeBci) {
         if (method == null) {
             return "the method is not resolved";
-        } else if (method.isNative() && (!Intrinsify.getValue() || !InliningUtil.canIntrinsify(context.getReplacements(), method))) {
+        } else if (method.isNative() && (!Intrinsify.getValue() || !InliningUtil.canIntrinsify(context.getReplacements(), method, invokeBci))) {
             return "it is a non-intrinsic native method";
         } else if (method.isAbstract()) {
             return "it is an abstract method";
@@ -129,7 +129,7 @@
     }
 
     private boolean checkTargetConditions(Invoke invoke, ResolvedJavaMethod method) {
-        final String failureMessage = checkTargetConditionsHelper(method);
+        final String failureMessage = checkTargetConditionsHelper(method, invoke.bci());
         if (failureMessage == null) {
             return true;
         } else {
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java	Wed Apr 15 11:03:04 2015 -0700
@@ -76,7 +76,7 @@
         StructuredGraph graph = testGraph(testMethodName);
 
         // Check to see if the resulting graph contains the expected node
-        StructuredGraph replacement = getReplacements().getSubstitution(realMethod);
+        StructuredGraph replacement = getReplacements().getSubstitution(realMethod, -1);
         if (replacement == null && !optional) {
             assertInGraph(graph, intrinsicClass);
         }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java	Wed Apr 15 11:03:04 2015 -0700
@@ -131,7 +131,7 @@
         StructuredGraph graph = testGraph(testMethodName);
 
         // Check to see if the resulting graph contains the expected node
-        StructuredGraph replacement = getReplacements().getSubstitution(realJavaMethod);
+        StructuredGraph replacement = getReplacements().getSubstitution(realJavaMethod, -1);
         if (replacement == null && !optional) {
             assertInGraph(graph, intrinsicClass);
         }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StringSubstitutionsTest.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StringSubstitutionsTest.java	Wed Apr 15 11:03:04 2015 -0700
@@ -41,7 +41,7 @@
         StructuredGraph graph = testGraph(testMethodName);
 
         // Check to see if the resulting graph contains the expected node
-        StructuredGraph replacement = getReplacements().getSubstitution(realMethod);
+        StructuredGraph replacement = getReplacements().getSubstitution(realMethod, -1);
         if (replacement == null && !optional) {
             assertInGraph(graph, intrinsicClass);
         }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/IntrinsicGraphBuilder.java	Wed Apr 15 11:03:04 2015 -0700
@@ -45,16 +45,18 @@
     private final StampProvider stampProvider;
     private final StructuredGraph graph;
     private final ResolvedJavaMethod method;
+    private final int invokeBci;
     private FixedWithNextNode lastInstr;
     private ValueNode[] arguments;
     private ValueNode returnValue;
 
-    public IntrinsicGraphBuilder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider, ResolvedJavaMethod method) {
+    public IntrinsicGraphBuilder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, StampProvider stampProvider, ResolvedJavaMethod method, int invokeBci) {
         this.metaAccess = metaAccess;
         this.constantReflection = constantReflection;
         this.stampProvider = stampProvider;
         this.graph = new StructuredGraph(method, AllowAssumptions.YES);
         this.method = method;
+        this.invokeBci = invokeBci;
         this.lastInstr = graph.start();
 
         Signature sig = method.getSignature();
@@ -163,7 +165,7 @@
     }
 
     public int bci() {
-        return -1;
+        return invokeBci;
     }
 
     public InvokeKind getInvokeKind() {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Wed Apr 15 11:03:04 2015 -0700
@@ -334,17 +334,21 @@
     }
 
     @Override
-    public StructuredGraph getSubstitution(ResolvedJavaMethod original, boolean fromBytecodeOnly) {
+    public StructuredGraph getSubstitution(ResolvedJavaMethod original, boolean fromBytecodeOnly, int invokeBci) {
         ResolvedJavaMethod substitute = null;
         if (!fromBytecodeOnly) {
             InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(original);
-            if (plugin instanceof MethodSubstitutionPlugin) {
-                MethodSubstitutionPlugin msplugin = (MethodSubstitutionPlugin) plugin;
-                substitute = msplugin.getSubstitute(providers.getMetaAccess());
-            } else if (plugin != null) {
-                StructuredGraph graph = new IntrinsicGraphBuilder(providers.getMetaAccess(), providers.getConstantReflection(), providers.getStampProvider(), original).buildGraph(plugin);
-                if (graph != null) {
-                    return graph;
+            if (plugin != null) {
+                if (!plugin.inlineOnly() || invokeBci >= 0) {
+                    if (plugin instanceof MethodSubstitutionPlugin) {
+                        MethodSubstitutionPlugin msplugin = (MethodSubstitutionPlugin) plugin;
+                        substitute = msplugin.getSubstitute(providers.getMetaAccess());
+                    } else {
+                        StructuredGraph graph = new IntrinsicGraphBuilder(providers.getMetaAccess(), providers.getConstantReflection(), providers.getStampProvider(), original, invokeBci).buildGraph(plugin);
+                        if (graph != null) {
+                            return graph;
+                        }
+                    }
                 }
             }
         }
@@ -806,10 +810,13 @@
         return cr != null && cr.forcedSubstitutions.contains(method);
     }
 
-    public boolean hasSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly) {
+    public boolean hasSubstitution(ResolvedJavaMethod method, boolean fromBytecodeOnly, int callerBci) {
         if (!fromBytecodeOnly) {
-            if (graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method) != null) {
-                return true;
+            InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method);
+            if (plugin != null) {
+                if (!plugin.inlineOnly() || callerBci >= 0) {
+                    return true;
+                }
             }
         }
         return getSubstitutionMethod(method) != null;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -74,6 +74,7 @@
         this.targetMethod = targetMethod;
         this.returnType = returnType;
         this.invokeKind = invokeKind;
+        assert bci >= 0;
     }
 
     public int getBci() {
@@ -108,7 +109,7 @@
      * lowered}.
      */
     protected StructuredGraph getLoweredSubstitutionGraph(LoweringTool tool) {
-        StructuredGraph methodSubstitution = tool.getReplacements().getSubstitution(getTargetMethod(), true);
+        StructuredGraph methodSubstitution = tool.getReplacements().getSubstitution(getTargetMethod(), true, bci);
         if (methodSubstitution != null) {
             methodSubstitution = methodSubstitution.copy();
             if (stateAfter() == null || stateAfter().bci == BytecodeFrame.AFTER_BCI) {
--- a/graal/com.oracle.graal.truffle.test/sl/TestInliningMaxCallerSize.sl	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.truffle.test/sl/TestInliningMaxCallerSize.sl	Wed Apr 15 11:03:04 2015 -0700
@@ -2,11 +2,11 @@
  * This test verifies that CallTargets cannot exceed the TruffleInliningMaxCallerSize limit when inlining.
  */
 function inlinableFunction() { 
-    generateDummyNodes(getOption("TruffleInliningMaxCallerSize") - 8);
+    generateDummyNodes(getOption("TruffleInliningMaxCallerSize") - 7);
 }
 
 function notInlinableFunction() { 
-    generateDummyNodes(getOption("TruffleInliningMaxCallerSize") - 7);
+    generateDummyNodes(getOption("TruffleInliningMaxCallerSize") - 6);
 }
 
 function test1() {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Wed Apr 15 11:03:04 2015 -0700
@@ -184,7 +184,7 @@
             if (original.getAnnotation(TruffleBoundary.class) != null) {
                 return null;
             }
-            assert !replacements.hasSubstitution(original) : "Replacements must have been processed by now";
+            assert !replacements.hasSubstitution(original, builder.bci()) : "Replacements must have been processed by now";
             assert !builder.parsingReplacement();
 
             if (TruffleCompilerOptions.TruffleFunctionInlining.getValue()) {
@@ -260,7 +260,7 @@
             if (original.getAnnotation(TruffleBoundary.class) != null) {
                 return null;
             }
-            assert !replacements.hasSubstitution(original) : "Replacements must have been processed by now";
+            assert !replacements.hasSubstitution(original, builder.bci()) : "Replacements must have been processed by now";
 
             if (original.equals(callSiteProxyMethod) || original.equals(callDirectMethod)) {
                 return null;
@@ -366,7 +366,7 @@
         new ConvertDeoptimizeToGuardPhase().apply(graph, tierContext);
 
         for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.TYPE)) {
-            StructuredGraph inlineGraph = providers.getReplacements().getSubstitution(methodCallTargetNode.targetMethod());
+            StructuredGraph inlineGraph = providers.getReplacements().getSubstitution(methodCallTargetNode.targetMethod(), methodCallTargetNode.invoke().bci());
             if (inlineGraph != null) {
                 InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, true, null);
             }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ArrayTest.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ArrayTest.java	Wed Apr 15 11:03:04 2015 -0700
@@ -26,7 +26,6 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
-import com.oracle.truffle.api.dsl.internal.*;
 import com.oracle.truffle.api.dsl.test.ArrayTestFactory.TestNode1NodeGen;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
@@ -97,7 +96,6 @@
     }
 
     @TypeSystem({int.class, int[].class, double[].class, String[].class, Object[].class})
-    @DSLOptions(useNewLayout = true)
     public static class ArrayTypeSystem {
 
         @ImplicitCast
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteGroupingTest.java	Wed Apr 15 11:03:04 2015 -0700
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2015, 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.dsl.test;
+
+import org.junit.*;
+import org.junit.experimental.theories.*;
+import org.junit.runner.*;
+import org.junit.runners.Parameterized.Parameters;
+
+import static org.junit.Assert.*;
+
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.dsl.test.ExecuteGroupingTestFactory.ExecuteGrouping1NodeGen;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/*
+ * This test aims to test the reuse of execute methods with evaluated parameters as much as possible.
+ */
+@SuppressWarnings("unused")
+@RunWith(Theories.class)
+public class ExecuteGroupingTest {
+
+    @DataPoints public static final Object[] parameters = new Object[]{1, 2};
+
+    static final class ExecuteGroupingChild extends Node {
+
+        int invocationCount = 0;
+
+        private final Object returnValue;
+
+        public ExecuteGroupingChild(Object returnValue) {
+            this.returnValue = returnValue;
+        }
+
+        Object execute() {
+            invocationCount++;
+            return returnValue;
+        }
+
+    }
+
+    @Theory
+    public void testExecuteGrouping1Node(Object a, Object b, Object c) throws UnexpectedResultException {
+        ExecuteGroupingChild child0 = new ExecuteGroupingChild(a);
+        ExecuteGroupingChild child1 = new ExecuteGroupingChild(b);
+        ExecuteGroupingChild child2 = new ExecuteGroupingChild(c);
+
+        int result = ((int) a) + ((int) b) + ((int) c);
+
+        assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(child0, child1, child2)).execute());
+        assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(child0, child1, child2)).execute((VirtualFrame) null));
+        assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, child1, child2)).execute(a));
+        assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, child1, child2)).executeInt(a));
+
+        assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, null, child2)).execute(a, b));
+        assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, null, child2)).execute((int) a, b));
+        assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, null, child2)).execute(a, (int) b));
+        assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, null, child2)).execute((int) a, (int) b));
+        assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, null, child2)).executeInt((int) a, (int) b));
+
+        assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, null, null)).execute(a, b, c));
+        assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, null, null)).execute((int) a, (int) b, c));
+        assertEquals(result, TestHelper.createRoot(ExecuteGrouping1NodeGen.create(null, null, null)).execute((int) a, (int) b, (int) c));
+
+    }
+
+    @NodeChildren({@NodeChild(type = ExecuteGroupingChild.class), @NodeChild(type = ExecuteGroupingChild.class), @NodeChild(type = ExecuteGroupingChild.class)})
+    abstract static class ExecuteGrouping1Node extends Node {
+
+        abstract Object execute();
+
+        int executeInt() throws UnexpectedResultException {
+            Object value = execute();
+            if (value instanceof Integer) {
+                return (int) value;
+            }
+            throw new UnexpectedResultException(value);
+        }
+
+        abstract double executeDouble() throws UnexpectedResultException;
+
+        abstract Object execute(VirtualFrame frame);
+
+        abstract Object execute(Object o1);
+
+        abstract int executeInt(Object o1) throws UnexpectedResultException;
+
+        abstract Object execute(Object o1, Object o2);
+
+        abstract Object execute(int o1, int o2);
+
+        abstract Object execute(int o1, int o2, Object o3);
+
+        abstract int executeInt(int o1, int o2) throws UnexpectedResultException;
+
+        abstract Object execute(Object o1, int o2);
+
+        abstract Object execute(int o1, Object o2);
+
+        abstract Object execute(Object o1, Object o2, Object o3);
+
+        abstract Object execute(int o1, int o2, int o3);
+
+        @Specialization
+        int s1(int a, int b, int c) {
+            return a + b + c;
+        }
+
+        @Specialization
+        int s2(Object a, Object b, Object c) {
+            return ((int) a) + ((int) b) + ((int) c);
+        }
+
+    }
+
+    abstract static class StrangeReturnCase extends Node {
+
+        // we don't know how to implement executeDouble
+        public abstract double executeDouble();
+
+        public int executeInt() {
+            return 42;
+        }
+
+        @Specialization(rewriteOn = RuntimeException.class)
+        int s1() {
+            return 42;
+        }
+
+        @Specialization
+        int s2() {
+            return 42;
+        }
+
+    }
+
+    @ExpectError("Incompatible abstract execute methods found [executeDouble(), executeInt()].%")
+    abstract static class IncompatibleAbstract1 extends Node {
+
+        // we don't know how to implement executeDouble
+        abstract double executeDouble();
+
+        abstract int executeInt();
+
+        @Specialization
+        int s1() {
+            return 42;
+        }
+
+    }
+
+    abstract static class IncompatibleAbstract2 extends Node {
+
+        abstract double executeDouble();
+
+        // we can resolve duplicate path errors by making an execute method final
+        @SuppressWarnings("static-method")
+        public final int executeInt() {
+            return 42;
+        }
+
+        @ExpectError("The provided return type \"int\" does not match expected return type \"double\".%")
+        @Specialization(rewriteOn = RuntimeException.class)
+        int s1() {
+            return 42;
+        }
+
+        @Specialization
+        double s2() {
+            return 42;
+        }
+
+    }
+
+}
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java	Wed Apr 15 11:03:04 2015 -0700
@@ -137,7 +137,6 @@
 
     @TypeSystemReference(ExecuteMethodTypes.class)
     @NodeChild(value = "a", type = ChildNoFrame.class)
-    @ExpectError("Multiple accessible and overridable generic execute methods found [executeInt(), executeObject()]. Remove all but one or mark all but one as final.")
     abstract static class ExecuteThis8 extends Node {
 
         abstract int executeInt();
@@ -175,8 +174,7 @@
         abstract void executeVoid();
 
         @Specialization
-        int doInt(int a) {
-            return a;
+        void doInt(@SuppressWarnings("unused") int a) {
         }
     }
 
@@ -197,7 +195,6 @@
 
     @TypeSystemReference(ExecuteMethodTypes.class)
     @NodeChild(value = "a", type = ChildNoFrame.class)
-    @ExpectError("Multiple accessible and overridable generic execute methods found [executeVoid1(), executeVoid2()]. Remove all but one or mark all but one as final.")
     abstract static class ExecuteThisVoid3 extends Node {
 
         // allow only one execute void
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/FallbackTest.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/FallbackTest.java	Wed Apr 15 11:03:04 2015 -0700
@@ -32,6 +32,7 @@
 import com.oracle.truffle.api.dsl.test.FallbackTestFactory.Fallback3Factory;
 import com.oracle.truffle.api.dsl.test.FallbackTestFactory.Fallback4Factory;
 import com.oracle.truffle.api.dsl.test.TypeSystemTest.*;
+import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 
 public class FallbackTest {
@@ -53,6 +54,9 @@
     @NodeChild("a")
     abstract static class Fallback1 extends ValueNode {
 
+        @Override
+        public abstract String executeString(VirtualFrame frame);
+
         @Specialization
         String f1(int a) {
             return "(int)";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NoTypeSystemTest.java	Wed Apr 15 11:03:04 2015 -0700
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2015, 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.dsl.test;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.dsl.test.NoTypeSystemTestFactory.JustFrameTestNodeGen;
+import com.oracle.truffle.api.dsl.test.NoTypeSystemTestFactory.NoParameterTestNodeGen;
+import com.oracle.truffle.api.dsl.test.NoTypeSystemTestFactory.ObjectInterfaceNodeGen;
+import com.oracle.truffle.api.dsl.test.NoTypeSystemTestFactory.ObjectPrimitiveTestNodeGen;
+import com.oracle.truffle.api.dsl.test.NoTypeSystemTestFactory.ObjectStringTestNodeGen;
+import com.oracle.truffle.api.dsl.test.NoTypeSystemTestFactory.PrimitiveTestNodeGen;
+import com.oracle.truffle.api.dsl.test.NoTypeSystemTestFactory.TypesNotInTypeSystemTestNodeGen;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+public class NoTypeSystemTest {
+
+    abstract static class DummyChild extends Node {
+        abstract Object execute();
+    }
+
+    abstract static class NoParameterTestNode extends Node {
+        abstract void execute();
+
+        @Specialization
+        void s1() {
+        }
+    }
+
+    @Test
+    public void testNoParameter() {
+        NoParameterTestNodeGen.create().execute();
+    }
+
+    abstract static class JustFrameTestNode extends Node {
+
+        abstract void execute(VirtualFrame frames);
+
+        @Specialization
+        void s1(@SuppressWarnings("unused") VirtualFrame frame) {
+        }
+    }
+
+    @Test
+    public void testJustFrame() {
+        JustFrameTestNodeGen.create().execute(null);
+    }
+
+    abstract static class PrimitiveTestNode extends Node {
+
+        abstract int execute(int primitive);
+
+        @Specialization
+        int test(int primitive) {
+            return primitive;
+        }
+
+    }
+
+    @Test
+    public void testPrimitive() {
+        Assert.assertEquals(42, PrimitiveTestNodeGen.create().execute(42));
+    }
+
+    abstract static class ObjectInterfaceNode extends Node {
+
+        abstract CharSequence execute(Object operand);
+
+        @Specialization
+        CharSequence s1(CharSequence operandSpecial) {
+            return operandSpecial;
+        }
+    }
+
+    @Test
+    public void testObjectInterface() {
+        Assert.assertEquals("42", ObjectInterfaceNodeGen.create().execute("42"));
+    }
+
+    abstract static class ObjectPrimitiveTestNode extends Node {
+
+        abstract int execute(Object primitive);
+
+        @Specialization
+        int s1(int primitive) {
+            return primitive;
+        }
+
+    }
+
+    @Test
+    public void testObjectPrimitiveTest() {
+        Assert.assertEquals(42, ObjectPrimitiveTestNodeGen.create().execute(42));
+    }
+
+    abstract static class ObjectStringTestNode extends Node {
+
+        abstract String execute(Object operand);
+
+        @Specialization
+        String s1(String operand) {
+            return operand;
+        }
+    }
+
+    @Test
+    public void testObjectStringTest() {
+        Assert.assertEquals("42", ObjectStringTestNodeGen.create().execute("42"));
+    }
+
+    abstract static class TypesNotInTypeSystemTest extends Node {
+
+        abstract Object execute(Object primitive);
+
+        abstract int executeInt(Object primitive) throws UnexpectedResultException;
+
+        abstract double executeDouble(Object primitive) throws UnexpectedResultException;
+
+        abstract String executeString(Object primitive) throws UnexpectedResultException;
+
+        abstract int[] executeIntArray(Object primitive) throws UnexpectedResultException;
+
+        abstract void executeVoid(Object primitive);
+
+        abstract void executeChar(Object primitive);
+
+        abstract int executeInt(int primitive) throws UnexpectedResultException;
+
+        abstract double executeDouble(double primitive) throws UnexpectedResultException;
+
+        abstract String executeString(String primitive) throws UnexpectedResultException;
+
+        abstract int[] executeIntArray(int[] primitive) throws UnexpectedResultException;
+
+        abstract void executeChar(char primitive);
+
+        @Specialization
+        int s1(int primitive) {
+            return primitive;
+        }
+
+        @Specialization
+        double s2(double primitive) {
+            return (int) primitive;
+        }
+
+        @Specialization
+        String s3(String object) {
+            return object;
+        }
+
+        @Specialization
+        int[] s4(int[] object) {
+            return object;
+        }
+
+        @Specialization
+        void s5(@SuppressWarnings("unused") char object) {
+        }
+
+    }
+
+    @Test
+    public void testTypesNotInTypeSystem() throws UnexpectedResultException {
+        int[] someArray = {1, 2, 3};
+        Assert.assertEquals(42, createTypesNotInTypeSystem().execute(42));
+        Assert.assertEquals(42d, createTypesNotInTypeSystem().execute(42d));
+        Assert.assertEquals(someArray, createTypesNotInTypeSystem().execute(someArray));
+        Assert.assertNull(createTypesNotInTypeSystem().execute((char) 42));
+
+        Assert.assertEquals(42, createTypesNotInTypeSystem().executeInt((Object) 42));
+        Assert.assertEquals(42d, createTypesNotInTypeSystem().executeDouble((Object) 42d), 0d);
+        Assert.assertEquals(someArray, createTypesNotInTypeSystem().executeIntArray((Object) someArray));
+        createTypesNotInTypeSystem().executeChar((Object) (char) 42);
+
+        Assert.assertEquals(42, createTypesNotInTypeSystem().executeInt(42));
+        Assert.assertEquals(42d, createTypesNotInTypeSystem().executeDouble(42d), 0d);
+        Assert.assertEquals(someArray, createTypesNotInTypeSystem().executeIntArray(someArray));
+        createTypesNotInTypeSystem().executeChar((char) 42);
+
+        try {
+            createTypesNotInTypeSystem().executeInt("a");
+            Assert.fail();
+        } catch (UnexpectedResultException e) {
+        }
+
+        try {
+            createTypesNotInTypeSystem().executeDouble("a");
+            Assert.fail();
+        } catch (UnexpectedResultException e) {
+        }
+
+        try {
+            createTypesNotInTypeSystem().executeIntArray("a");
+            Assert.fail();
+        } catch (UnexpectedResultException e) {
+        }
+
+        createTypesNotInTypeSystem().executeChar("a");
+
+    }
+
+    private static TypesNotInTypeSystemTest createTypesNotInTypeSystem() {
+        return TestHelper.createRoot(TypesNotInTypeSystemTestNodeGen.create());
+    }
+
+    abstract static class ErrorImpossibleTypes1 extends Node {
+
+        abstract int execute(int primitive);
+
+        @Specialization
+        int test(int primitive) {
+            return primitive;
+        }
+
+        @ExpectError("The provided return type \"Object\" does not match expected return type \"int\".%")
+        @Specialization
+        Object s2(int arg0) {
+            return arg0;
+        }
+    }
+
+    abstract static class ErrorImpossibleTypes2 extends Node {
+
+        abstract int execute(int primitive);
+
+        @Specialization
+        int test(int primitive) {
+            return primitive;
+        }
+
+        @ExpectError("Method signature (Object) does not match to the expected signature: %")
+        @Specialization
+        int s2(Object arg0) {
+            return (int) arg0;
+        }
+    }
+
+    @ExpectError("Not enough child node declarations found. Please annotate the node class with addtional @NodeChild annotations or remove all execute methods that do not provide all evaluated values. "
+                    + "The following execute methods do not provide all evaluated values for the expected signature size 1: [execute()].")
+    abstract static class ErrorMissingNodeChild1 extends Node {
+
+        abstract int execute();
+
+        @Specialization
+        int s1(int arg0) {
+            return arg0;
+        }
+    }
+
+    @ExpectError("Not enough child node declarations found. Please annotate the node class with addtional @NodeChild annotations or remove all execute methods that do not provide all evaluated values. "
+                    + "The following execute methods do not provide all evaluated values for the expected signature size 2: [execute(int)].")
+    @NodeChild(type = DummyChild.class)
+    abstract static class ErrorMissingNodeChild2 extends Node {
+
+        abstract int execute(int arg0);
+
+        @Specialization
+        int s1(int arg0, int arg1) {
+            return arg0 + arg1;
+        }
+    }
+
+    @ExpectError("Not enough child node declarations found. Please annotate the node class with addtional @NodeChild annotations or remove all execute methods that do not provide all evaluated values. "
+                    + "The following execute methods do not provide all evaluated values for the expected signature size 1: [execute()].")
+    abstract static class ErrorMissingNodeChild3 extends Node {
+
+        abstract int execute();
+
+        abstract int execute(int arg0);
+
+        @Specialization
+        int s1(int arg0) {
+            return arg0;
+        }
+
+    }
+
+    @ExpectError("Unnecessary @NodeChild declaration. All evaluated child values are provided as parameters in execute methods.")
+    @NodeChild(type = DummyChild.class)
+    abstract static class ErrorAdditionalNodeChild1 extends Node {
+
+        abstract int execute(int arg0);
+
+        @Specialization
+        int s1(int arg0) {
+            return arg0;
+        }
+    }
+
+    @NodeChild(type = DummyChild.class)
+    @ExpectError("Not enough child node declarations found. Please annotate the node class with addtional @NodeChild annotations or remove all execute methods that do not provide all evaluated values. "
+                    + "The following execute methods do not provide all evaluated values for the expected signature size 2: [execute(int)].")
+    abstract static class ErrorAdditionalNodeChild2 extends Node {
+
+        abstract int execute(int arg0);
+
+        @Specialization
+        int s1(int arg0, int arg1) {
+            return arg0 + arg1;
+        }
+    }
+
+}
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NodeChildTest.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NodeChildTest.java	Wed Apr 15 11:03:04 2015 -0700
@@ -71,10 +71,11 @@
 
     }
 
+    @ExpectError("Not enough child node declarations found. Please annotate the node class with addtional @NodeChild annotations or remove all execute methods that do not provide all evaluated values. "
+                    + "The following execute methods do not provide all evaluated values for the expected signature size 3:%")
     @NodeChildren({@NodeChild(value = "child2", type = ValueNode.class)})
     abstract static class Child2Node extends Base1Node {
 
-        // TODO this is an error to fix
         @ExpectError("Method signature (int, int, int) does not match to the expected signature:%")
         @Specialization
         int intField(int child0, int child1, int child2) {
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NodeFieldTest.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NodeFieldTest.java	Wed Apr 15 11:03:04 2015 -0700
@@ -123,7 +123,7 @@
         }
 
         @Specialization(contains = "alwaysRewrite")
-        String returnField() {
+        Object returnField() {
             return getField();
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NullLiteralGuardsTest.java	Wed Apr 15 11:03:04 2015 -0700
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2015, 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.dsl.test;
+
+import static com.oracle.truffle.api.dsl.test.TestHelper.*;
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.dsl.test.NullLiteralGuardsTestFactory.CompareNotNullNodeFactory;
+import com.oracle.truffle.api.dsl.test.NullLiteralGuardsTestFactory.CompareObjectsNullNodeFactory;
+import com.oracle.truffle.api.dsl.test.NullLiteralGuardsTestFactory.CompareStringNullNodeFactory;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.ChildrenNode;
+
+@SuppressWarnings("unused")
+public class NullLiteralGuardsTest {
+
+    @Test
+    public void testCompareObjectsNull() {
+        CallTarget root = createCallTarget(CompareObjectsNullNodeFactory.getInstance());
+        assertEquals("do1", root.call((Object) null));
+        assertEquals("do2", root.call("42"));
+    }
+
+    abstract static class CompareObjectsNullNode extends ChildrenNode {
+        @Specialization(guards = "value == null")
+        String do1(Object value) {
+            return "do1";
+        }
+
+        @Specialization
+        String do2(Object value) {
+            return "do2";
+        }
+    }
+
+    @Test
+    public void testCompareStringNull() {
+        CallTarget root = createCallTarget(CompareStringNullNodeFactory.getInstance());
+        assertEquals("do1", root.call("42"));
+        assertEquals("do2", root.call((Object) null));
+    }
+
+    abstract static class CompareStringNullNode extends ChildrenNode {
+        @Specialization(guards = "value != null")
+        String do1(String value) {
+            return "do1";
+        }
+
+        @Specialization
+        String do2(Object value) {
+            return "do2";
+        }
+    }
+
+    @Test
+    public void testCompareNotNull() {
+        CallTarget root = createCallTarget(CompareNotNullNodeFactory.getInstance());
+        assertEquals("do1", root.call("42"));
+        assertEquals("do2", root.call((Object) null));
+    }
+
+    abstract static class CompareNotNullNode extends ChildrenNode {
+        @Specialization(guards = "value != null")
+        String do1(Object value) {
+            return "do1";
+        }
+
+        @Specialization
+        String do2(Object value) {
+            return "do2";
+        }
+    }
+
+    abstract static class ErrorNullIntComparison1 extends ChildrenNode {
+        @ExpectError("Error parsing expression 'value == null': Incompatible operand types int and null.")
+        @Specialization(guards = "value == null")
+        String do1(int value) {
+            return "do1";
+        }
+    }
+
+    abstract static class ErrorNullIntComparison2 extends ChildrenNode {
+        @ExpectError("Error parsing expression '1 == null': Incompatible operand types int and null.")
+        @Specialization(guards = "1 == null")
+        String do1(int value) {
+            return "do1";
+        }
+    }
+
+    abstract static class ErrorNullNullComparison extends ChildrenNode {
+        @ExpectError("Error parsing expression 'null == null': The operator == is undefined for the argument type(s) null null.")
+        @Specialization(guards = "null == null")
+        String do1(int value) {
+            return "do1";
+        }
+    }
+
+    abstract static class ErrorObjectVoidComparison extends ChildrenNode {
+        protected static void returnVoid() {
+        }
+
+        @ExpectError("Error parsing expression 'value == returnVoid()': Incompatible operand types Object and void.")
+        @Specialization(guards = "value == returnVoid()")
+        String do1(Object value) {
+            return "do1";
+        }
+    }
+
+}
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java	Wed Apr 15 11:03:04 2015 -0700
@@ -32,12 +32,27 @@
 import com.oracle.truffle.api.dsl.test.TypeSystemTest.ChildrenNode;
 import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode;
 import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
 
 /**
  * Utility class to provide some test helper functions.
  */
 class TestHelper {
 
+    // make nodes replacable
+    public static <T extends Node> T createRoot(final T node) {
+        new RootNode() {
+            @Child T child = node;
+
+            @Override
+            public Object execute(VirtualFrame frame) {
+                return null;
+            }
+        }.adoptChildren();
+        return node;
+    }
+
     private static ArgumentNode[] arguments(int count) {
         ArgumentNode[] nodes = new ArgumentNode[count];
         for (int i = 0; i < nodes.length; i++) {
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemErrorsTest.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemErrorsTest.java	Wed Apr 15 11:03:04 2015 -0700
@@ -102,15 +102,6 @@
         }
     }
 
-    @TypeSystem({boolean.class})
-    public static class CastError3 {
-        @ExpectError("The type 'int' is not declared in the @TypeSystem.")
-        @TypeCast(int.class)
-        public static int asInt(Object value) {
-            return (int) value;
-        }
-    }
-
     @TypeSystem({int.class})
     public static class CastError4 {
         @ExpectError("@TypeCast annotated method asInt must be public and static.")
@@ -129,15 +120,6 @@
         }
     }
 
-    @TypeSystem({boolean.class})
-    public static class CheckError1 {
-        @ExpectError("The type 'int' is not declared in the @TypeSystem.")
-        @TypeCheck(int.class)
-        public static boolean isInt(Object value) {
-            return value instanceof Integer;
-        }
-    }
-
     @TypeSystem({int.class})
     public static class CheckError2 {
         @ExpectError("@TypeCheck annotated method isInt must be public and static.")
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/RubyCall.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/examples/RubyCall.java	Wed Apr 15 11:03:04 2015 -0700
@@ -96,12 +96,12 @@
 
     public static class RubyHeadNode extends ExampleNode {
 
-        @Child private RubyLookupNode lookup = RubyLookupNodeGen.create(null);
-        @Child private RubyDispatchNode dispatch = RubyDispatchNodeGen.create(null);
+        @Child private RubyLookupNode lookup = RubyLookupNodeGen.create();
+        @Child private RubyDispatchNode dispatch = RubyDispatchNodeGen.create();
 
         @Specialization
-        public Object doCall(VirtualFrame frame, Object receiverObject, Object methodName, Object blockObject, Object... argumentsObjects) {
-            InternalMethod method = lookup.executeLookup(frame, receiverObject, methodName);
+        public Object doCall(VirtualFrame frame, RubyObject receiverObject, Object methodName, Object blockObject, Object... argumentsObjects) {
+            InternalMethod method = lookup.executeLookup(receiverObject, methodName);
 
             Object[] packedArguments = new Object[argumentsObjects.length + 3];
             packedArguments[0] = method;
@@ -113,9 +113,9 @@
         }
     }
 
-    public abstract static class RubyLookupNode extends ExampleNode {
+    public abstract static class RubyLookupNode extends Node {
 
-        public abstract InternalMethod executeLookup(VirtualFrame frame, Object receiverObject, Object methodName);
+        public abstract InternalMethod executeLookup(RubyObject receiver, Object method);
 
         @Specialization(guards = "receiver.getRubyClass() == cachedClass", assumptions = "cachedClass.getDependentAssumptions()")
         protected static InternalMethod cachedLookup(RubyObject receiver, Object name, //
@@ -132,7 +132,7 @@
     }
 
     @ImportStatic(InternalMethod.class)
-    public abstract static class RubyDispatchNode extends ExampleNode {
+    public abstract static class RubyDispatchNode extends Node {
 
         public abstract Object executeDispatch(VirtualFrame frame, InternalMethod function, Object[] packedArguments);
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Wed Apr 15 11:03:04 2015 -0700
@@ -62,24 +62,25 @@
  * </li>
  *
  * <li>The effect of the binding is to intercept {@linkplain TruffleEvents execution events}
- * arriving at the "probed" AST node and notify each attached {@link Instrument} before execution is
+ * arriving at the "probed" AST Node and notify each attached {@link Instrument} before execution is
  * allowed to proceed to the child and again after execution completes.</li>
  *
- * <li>A Probe is "inserted" into a GL node via a call to {@link Node#probe()}. No more than one
- * Probe can be inserted at a node; a redundant call returns the existing Probe<./li>
+ * <li>The method {@link Node#probe()} creates a Probe on an AST Node; redundant calls return the
+ * same Probe.</li>
  *
  * <li>The "probing" of a Truffle AST must be done after the AST is complete (i.e. parent pointers
  * correctly assigned), but before any cloning or executions. This is done by creating an instance
- * of {@link ASTProber} and registering it via {@link #registerASTProber(ASTProber)}, after which it
- * will be applied automatically to every newly created AST.</li>
+ * of {@link ASTProber} and registering it via {@link #registerASTProber(ASTProber)}. Once
+ * registered, it will be applied automatically to every newly created AST.</li>
  *
- * <li>An AST node becomes <em>probed</em> by insertion of a {@link ProbeNode.WrapperNode} into the
- * AST, together with an associated {@link ProbeNode} that routes events to all the
- * {@linkplain Instrument Instruments} attached to its <em>instrument chain</em>.</li>
+ * <li>The "probing" of an AST Node is implemented by insertion of a {@link ProbeNode.WrapperNode}
+ * into the AST (as new parent of the Node being probed), together with an associated
+ * {@link ProbeNode} that routes execution events at the probed Node to all the
+ * {@linkplain Instrument Instruments} attached to the Probe's <em>instrument chain</em>.</li>
  *
  * <li>When Truffle clones an AST, any attached WrapperNodes and ProbeNodes are cloned as well,
- * together with their attached instrument chains. The {@link Probe} instance intercepts cloning
- * events and keeps track of all copies.</li>
+ * together with their attached instrument chains. Each Probe instance intercepts cloning events and
+ * keeps track of all AST copies.</li>
  *
  * <li>All attached {@link InstrumentationNode}s effectively become part of the running program:
  * <ul>
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -42,8 +42,9 @@
  * <p>
  * When Truffle clones an AST, the chain, including all attached {@linkplain Instrument instruments}
  * will be cloned along with the {@link WrapperNode} to which it is attached. An instance of
- * {@link Probe} represents abstractly the instrumentation at a particular location in a GL AST,
- * tracks the clones of the chain, and keeps the instrumentation attached to the clones consistent.
+ * {@link Probe} represents abstractly the instrumentation at a particular location in a Guest
+ * Language AST, tracks the clones of the chain, and keeps the instrumentation attached to the
+ * clones consistent.
  */
 @NodeInfo(cost = NodeCost.NONE)
 public final class ProbeNode extends Node implements TruffleEvents, InstrumentationNode {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ProcessorContext.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ProcessorContext.java	Wed Apr 15 11:03:04 2015 -0700
@@ -88,6 +88,10 @@
         return (DeclaredType) ElementUtils.getType(environment, element);
     }
 
+    public boolean isType(TypeMirror type, Class<?> clazz) {
+        return ElementUtils.typeEquals(type, getType(clazz));
+    }
+
     public TypeMirror getType(Class<?> element) {
         return ElementUtils.getType(environment, element);
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpressionResolver.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpressionResolver.java	Wed Apr 15 11:03:04 2015 -0700
@@ -197,27 +197,32 @@
     public void visitVariable(Variable variable) {
         List<VariableElement> lookupVariables;
         DSLExpression receiver = variable.getReceiver();
-        if (receiver == null) {
-            lookupVariables = this.variables;
+        if (variable.getName().equals("null")) {
+            variable.setResolvedVariable(new CodeVariableElement(new CodeTypeMirror(TypeKind.NULL), "null"));
         } else {
-            TypeMirror type = receiver.getResolvedType();
-            if (type.getKind() == TypeKind.DECLARED) {
-                type = context.reloadType(type); // ensure ECJ has the type loaded
-                lookupVariables = new ArrayList<>();
-                variablesIn(lookupVariables, context.getEnvironment().getElementUtils().getAllMembers((TypeElement) ((DeclaredType) type).asElement()), true);
-            } else if (type.getKind() == TypeKind.ARRAY) {
-                lookupVariables = Arrays.<VariableElement> asList(new CodeVariableElement(context.getType(int.class), "length"));
+            if (receiver == null) {
+                lookupVariables = this.variables;
             } else {
-                lookupVariables = Collections.emptyList();
+                TypeMirror type = receiver.getResolvedType();
+                if (type.getKind() == TypeKind.DECLARED) {
+                    type = context.reloadType(type); // ensure ECJ has the type loaded
+                    lookupVariables = new ArrayList<>();
+                    variablesIn(lookupVariables, context.getEnvironment().getElementUtils().getAllMembers((TypeElement) ((DeclaredType) type).asElement()), true);
+                } else if (type.getKind() == TypeKind.ARRAY) {
+                    lookupVariables = Arrays.<VariableElement> asList(new CodeVariableElement(context.getType(int.class), "length"));
+                } else {
+                    lookupVariables = Collections.emptyList();
+                }
+            }
+
+            for (VariableElement variableElement : lookupVariables) {
+                if (variableElement.getSimpleName().toString().equals(variable.getName())) {
+                    variable.setResolvedVariable(variableElement);
+                    break;
+                }
             }
         }
 
-        for (VariableElement variableElement : lookupVariables) {
-            if (variableElement.getSimpleName().toString().equals(variable.getName())) {
-                variable.setResolvedVariable(variableElement);
-                break;
-            }
-        }
         if (variable.getResolvedVariable() == null) {
             throw new InvalidExpressionException(String.format("%s cannot be resolved.", variable.getName()));
         }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/DSLExpressionGenerator.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/DSLExpressionGenerator.java	Wed Apr 15 11:03:04 2015 -0700
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import javax.lang.model.element.*;
+import javax.lang.model.type.*;
 
 import com.oracle.truffle.dsl.processor.expression.*;
 import com.oracle.truffle.dsl.processor.expression.DSLExpression.Binary;
@@ -97,7 +98,9 @@
     public void visitVariable(Variable variable) {
         VariableElement resolvedVariable = variable.getResolvedVariable();
         CodeTree tree;
-        if (variable.getReceiver() == null) {
+        if (variable.getResolvedType().getKind() == TypeKind.NULL) {
+            tree = CodeTreeBuilder.singleString("null");
+        } else if (variable.getReceiver() == null) {
 
             if (isStatic(resolvedVariable)) {
                 tree = staticReference(resolvedVariable);
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/GeneratorUtils.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/GeneratorUtils.java	Wed Apr 15 11:03:04 2015 -0700
@@ -85,14 +85,14 @@
         return method;
     }
 
-    public static boolean isTypeBoxingOptimized(TypeBoxingOptimization boxing, TypeData type) {
+    public static boolean isTypeBoxingOptimized(TypeBoxingOptimization boxing, TypeMirror type) {
         switch (boxing) {
             case NONE:
                 return false;
             case ALWAYS:
-                return !type.isGeneric() && !type.isVoid();
+                return !ElementUtils.isObject(type) && !ElementUtils.isVoid(type);
             case PRIMITIVE:
-                return type.isPrimitive();
+                return ElementUtils.isPrimitive(type);
             default:
                 throw new AssertionError();
         }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/ImplicitCastNodeFactory.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/ImplicitCastNodeFactory.java	Wed Apr 15 11:03:04 2015 -0700
@@ -44,31 +44,30 @@
 public class ImplicitCastNodeFactory {
 
     private final ProcessorContext context;
-    private final TypeData forType;
+    private final TypeMirror forType;
     private final TypeSystemData typeSystem;
     private final DSLOptions options;
-    private final List<TypeData> sourceTypes;
+    private final List<TypeMirror> sourceTypes;
 
-    public ImplicitCastNodeFactory(ProcessorContext context, TypeData forType) {
+    public ImplicitCastNodeFactory(ProcessorContext context, TypeSystemData typeSystem, TypeMirror forType) {
         this.context = context;
         this.forType = forType;
-        this.typeSystem = forType.getTypeSystem();
+        this.typeSystem = typeSystem;
         this.options = typeSystem.getOptions();
         this.sourceTypes = typeSystem.lookupSourceTypes(forType);
     }
 
-    public static String typeName(TypeData type) {
-        return "Implicit" + getTypeId(type.getBoxedType()) + "Cast";
+    public static String typeName(TypeMirror type) {
+        return "Implicit" + getTypeId(type) + "Cast";
     }
 
-    public static TypeMirror type(TypeData type) {
-        TypeSystemData typeSystem = type.getTypeSystem();
+    public static TypeMirror type(TypeSystemData typeSystem, TypeMirror type) {
         String typeSystemName = TypeSystemCodeGenerator.typeName(typeSystem);
         return new GeneratedTypeMirror(ElementUtils.getPackageName(typeSystem.getTemplateType()) + "." + typeSystemName, typeName(type));
     }
 
-    public static CodeTree create(TypeData type, CodeTree value) {
-        return CodeTreeBuilder.createBuilder().startStaticCall(type(type), "create").tree(value).end().build();
+    public static CodeTree create(TypeSystemData typeSystem, TypeMirror type, CodeTree value) {
+        return CodeTreeBuilder.createBuilder().startStaticCall(type(typeSystem, type), "create").tree(value).end().build();
     }
 
     public static CodeTree cast(String nodeName, CodeTree value) {
@@ -79,8 +78,8 @@
         return CodeTreeBuilder.createBuilder().startCall(nodeName, "check").tree(value).end().build();
     }
 
-    private static String seenFieldName(TypeData type) {
-        return "seen" + getTypeId(type.getBoxedType());
+    private static String seenFieldName(TypeMirror type) {
+        return "seen" + getTypeId(type);
     }
 
     public CodeTypeElement create() {
@@ -88,7 +87,7 @@
         TypeMirror baseType = context.getType(Object.class);
         CodeTypeElement clazz = GeneratorUtils.createClass(typeSystem, null, modifiers(PUBLIC, FINAL, STATIC), typeName, baseType);
 
-        for (TypeData sourceType : sourceTypes) {
+        for (TypeMirror sourceType : sourceTypes) {
             CodeVariableElement hasSeen = new CodeVariableElement(modifiers(PUBLIC), context.getType(boolean.class), seenFieldName(sourceType));
             hasSeen.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(CompilationFinal.class)));
             clazz.add(hasSeen);
@@ -113,7 +112,7 @@
         CodeTreeBuilder builder = method.createBuilder();
         builder.startReturn();
         String operator = "";
-        for (TypeData sourceType : sourceTypes) {
+        for (TypeMirror sourceType : sourceTypes) {
             builder.string(operator);
             builder.string(seenFieldName(sourceType));
             operator = " ^ ";
@@ -129,15 +128,15 @@
     private Element createCreate(CodeTypeElement clazz) {
         String methodName = "create";
         CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), clazz.asType(), methodName);
-        method.addParameter(new CodeVariableElement(typeSystem.getGenericType(), "value"));
+        method.addParameter(new CodeVariableElement(context.getType(Object.class), "value"));
         CodeTreeBuilder builder = method.createBuilder();
 
         builder.declaration(clazz.asType(), "newCast", builder.create().startNew(clazz.asType()).end());
 
-        for (TypeData sourceType : sourceTypes) {
+        for (TypeMirror sourceType : sourceTypes) {
             String seenField = seenFieldName(sourceType);
             builder.startStatement();
-            builder.string("newCast.").string(seenField).string(" = ").tree(TypeSystemCodeGenerator.check(sourceType, "value"));
+            builder.string("newCast.").string(seenField).string(" = ").tree(TypeSystemCodeGenerator.check(typeSystem, sourceType, "value"));
             builder.end();
         }
         builder.startReturn().string("newCast").end();
@@ -150,7 +149,7 @@
         method.addParameter(new CodeVariableElement(clazz.asType(), "otherCast"));
         CodeTreeBuilder builder = method.createBuilder();
 
-        for (TypeData sourceType : sourceTypes) {
+        for (TypeMirror sourceType : sourceTypes) {
             String seenField = seenFieldName(sourceType);
             builder.startStatement();
             builder.string("this.").string(seenField).string(" |= ").string("otherCast.").string(seenField);
@@ -162,13 +161,13 @@
     private Element createCheck() {
         String methodName = "check";
         CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getType(boolean.class), methodName);
-        method.addParameter(new CodeVariableElement(typeSystem.getGenericType(), "value"));
+        method.addParameter(new CodeVariableElement(context.getType(Object.class), "value"));
         CodeTreeBuilder builder = method.createBuilder();
 
         boolean elseIf = false;
-        for (TypeData sourceType : sourceTypes) {
+        for (TypeMirror sourceType : sourceTypes) {
             elseIf = builder.startIf(elseIf);
-            builder.string(seenFieldName(sourceType)).string(" && ").tree(TypeSystemCodeGenerator.check(sourceType, "value"));
+            builder.string(seenFieldName(sourceType)).string(" && ").tree(TypeSystemCodeGenerator.check(typeSystem, sourceType, "value"));
             builder.end();
             builder.startBlock().returnTrue().end();
         }
@@ -178,8 +177,8 @@
 
     private Element createCast(boolean expect) {
         String methodName = expect ? "expect" : "cast";
-        CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), forType.getPrimitiveType(), methodName);
-        method.addParameter(new CodeVariableElement(typeSystem.getGenericType(), "value"));
+        CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), forType, methodName);
+        method.addParameter(new CodeVariableElement(context.getType(Object.class), "value"));
         if (expect) {
             method.getThrownTypes().add(context.getType(UnexpectedResultException.class));
         }
@@ -187,16 +186,16 @@
         CodeTreeBuilder builder = method.createBuilder();
 
         boolean elseIf = false;
-        for (TypeData sourceType : sourceTypes) {
+        for (TypeMirror sourceType : sourceTypes) {
             elseIf = builder.startIf(elseIf);
-            builder.string(seenFieldName(sourceType)).string(" && ").tree(TypeSystemCodeGenerator.check(sourceType, "value"));
+            builder.string(seenFieldName(sourceType)).string(" && ").tree(TypeSystemCodeGenerator.check(typeSystem, sourceType, "value"));
             builder.end();
             builder.startBlock();
             builder.startReturn();
-            CodeTree castTree = TypeSystemCodeGenerator.cast(sourceType, "value");
+            CodeTree castTree = TypeSystemCodeGenerator.cast(typeSystem, sourceType, "value");
             ImplicitCastData cast = typeSystem.lookupCast(sourceType, forType);
             if (cast != null) {
-                builder.tree(TypeSystemCodeGenerator.invokeImplicitCast(cast, castTree));
+                builder.tree(TypeSystemCodeGenerator.invokeImplicitCast(typeSystem, cast, castTree));
             } else {
                 builder.tree(castTree);
             }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java	Wed Apr 15 11:03:04 2015 -0700
@@ -152,7 +152,7 @@
             }
             prev = child.getNodeType();
         }
-        TypeMirror commonNodeSuperType = ElementUtils.getCommonSuperType(context, nodeTypesList.toArray(new TypeMirror[nodeTypesList.size()]));
+        TypeMirror commonNodeSuperType = ElementUtils.getCommonSuperType(context, nodeTypesList);
 
         Types types = context.getEnvironment().getTypeUtils();
         TypeMirror factoryType = context.getType(NodeFactory.class);
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Wed Apr 15 11:03:04 2015 -0700
@@ -61,19 +61,25 @@
     private final ProcessorContext context;
     private final NodeData node;
     private final TypeSystemData typeSystem;
-    private final TypeData genericType;
+    private final TypeMirror genericType;
     private final DSLOptions options;
     private final boolean singleSpecializable;
     private final int varArgsThreshold;
+    private final Set<TypeMirror> expectedTypes = new HashSet<>();
+    private boolean nextUsed;
+    private List<ExecutableTypeData> usedTypes;
+    private List<SpecializationData> reachableSpecializations;
 
     public NodeGenFactory(ProcessorContext context, NodeData node) {
         this.context = context;
         this.node = node;
         this.typeSystem = node.getTypeSystem();
-        this.genericType = typeSystem.getGenericTypeData();
+        this.genericType = context.getType(Object.class);
         this.options = typeSystem.getOptions();
+        this.varArgsThreshold = calculateVarArgsThreshold();
+        this.reachableSpecializations = calculateReachableSpecializations();
         this.singleSpecializable = isSingleSpecializableImpl();
-        this.varArgsThreshold = calculateVarArgsThreshold();
+        this.usedTypes = filterBaseExecutableTypes(node.getExecutableTypes(), reachableSpecializations);
     }
 
     private int calculateVarArgsThreshold() {
@@ -139,8 +145,8 @@
         return "exclude" + specialization.getId() + NAME_SUFFIX;
     }
 
-    private static String executeChildMethodName(NodeExecutionData execution, TypeData type) {
-        return "execute" + ElementUtils.firstLetterUpperCase(execution.getName()) + (type.isGeneric() ? "" : getTypeId(type.getBoxedType())) + NAME_SUFFIX;
+    private static String executeChildMethodName(NodeExecutionData execution, TypeMirror type) {
+        return "execute" + ElementUtils.firstLetterUpperCase(execution.getName()) + (ElementUtils.isObject(type) ? "" : getTypeId(type)) + NAME_SUFFIX;
     }
 
     private CodeTree accessParent(String name) {
@@ -186,7 +192,9 @@
         }
 
         for (NodeExecutionData execution : node.getChildExecutions()) {
-            clazz.add(createNodeField(PRIVATE, execution.getNodeType(), nodeFieldName(execution), Child.class));
+            if (execution.getChild() != null) {
+                clazz.add(createNodeField(PRIVATE, execution.getNodeType(), nodeFieldName(execution), Child.class));
+            }
         }
 
         for (NodeExecutionData execution : node.getChildExecutions()) {
@@ -201,16 +209,13 @@
             }
         }
 
-        Collection<TypeData> specializedTypes = node.findSpecializedReturnTypes();
-        List<ExecutableTypeData> implementedExecutables = new ArrayList<>();
-        for (ExecutableTypeData execType : node.getExecutableTypes()) {
-            if (shouldImplementExecutableType(specializedTypes, execType)) {
-                implementedExecutables.add(execType);
+        for (ExecutableTypeData execType : usedTypes) {
+            if (execType.getMethod() == null) {
+                continue;
             }
+            clazz.add(createExecutableTypeOverride(usedTypes, execType));
         }
-        for (ExecutableTypeData execType : implementedExecutables) {
-            clazz.add(createExecutableTypeOverride(implementedExecutables, execType));
-        }
+
         clazz.add(createGetCostMethod());
 
         avoidFindbugsProblems(clazz);
@@ -235,6 +240,12 @@
             }
         }
 
+        for (TypeMirror type : ElementUtils.uniqueSortedTypes(expectedTypes)) {
+            if (!typeSystem.hasType(type)) {
+                clazz.addOptional(TypeSystemCodeGenerator.createExpectMethod(PRIVATE, typeSystem, context.getType(Object.class), type));
+            }
+        }
+
         return clazz;
     }
 
@@ -295,7 +306,7 @@
                     CodeTree nameTree = CodeTreeBuilder.singleString(name);
                     CodeTreeBuilder callBuilder = builder.create();
                     callBuilder.string(name).string(" != null ? ");
-                    callBuilder.tree(callTemplateMethod(null, createCast, nameTree));
+                    callBuilder.tree(callMethod(null, createCast.getMethod(), nameTree));
                     callBuilder.string(" : null");
                     name += "_";
                     builder.declaration(child.getNodeType(), name, callBuilder.build());
@@ -305,6 +316,9 @@
         }
 
         for (NodeExecutionData execution : node.getChildExecutions()) {
+            if (execution.getChild() == null) {
+                continue;
+            }
             CreateCastData createCast = node.findCast(execution.getChild().getName());
 
             builder.startStatement();
@@ -315,18 +329,18 @@
             accessorBuilder.string(name);
 
             if (execution.isIndexed()) {
-                accessorBuilder.string("[").string(String.valueOf(execution.getIndex())).string("]");
+                accessorBuilder.string("[").string(String.valueOf(execution.getChildIndex())).string("]");
             }
 
             CodeTree accessor = accessorBuilder.build();
 
             if (createCast != null && execution.getChild().getCardinality().isOne()) {
-                accessor = callTemplateMethod(null, createCast, accessor);
+                accessor = callMethod(null, createCast.getMethod(), accessor);
             }
 
             if (execution.isIndexed()) {
                 CodeTreeBuilder nullCheck = builder.create();
-                nullCheck.string(name).string(" != null && ").string(String.valueOf(execution.getIndex())).string(" < ").string(name).string(".length").string(" ? ");
+                nullCheck.string(name).string(" != null && ").string(String.valueOf(execution.getChildIndex())).string(" < ").string(name).string(".length").string(" ? ");
                 nullCheck.tree(accessor);
                 nullCheck.string(" : null");
                 accessor = nullCheck.build();
@@ -345,8 +359,6 @@
     }
 
     private SpecializationData createSpecializations(CodeTypeElement clazz) {
-        List<SpecializationData> reachableSpecializations = getReachableSpecializations();
-
         CodeTypeElement baseSpecialization = clazz.add(createBaseSpecialization());
         TypeMirror baseSpecializationType = baseSpecialization.asType();
 
@@ -366,20 +378,20 @@
         baseSpecialization.addOptional(createCreateNext(generated));
         baseSpecialization.addOptional(createCreateFallback(generated));
         baseSpecialization.addOptional(createCreatePolymorphic(generated));
+        baseSpecialization.addOptional(createGetNext(baseSpecialization));
 
         return node.getUninitializedSpecialization();
     }
 
     private boolean needsPolymorphic() {
-        List<SpecializationData> reachableSpecializations = getReachableSpecializations();
         if (reachableSpecializations.size() != 1) {
             return true;
         }
 
         SpecializationData specialization = reachableSpecializations.get(0);
         for (Parameter parameter : specialization.getSignatureParameters()) {
-            TypeData type = parameter.getTypeSystemType();
-            if (type != null && type.hasImplicitSourceTypes()) {
+            TypeMirror type = parameter.getType();
+            if (type != null && typeSystem.hasImplicitSourceTypes(type)) {
                 return true;
             }
         }
@@ -393,26 +405,23 @@
     // create specialization
 
     private CodeTypeElement createBaseSpecialization() {
-        CodeTypeElement clazz = createClass(node, null, modifiers(PRIVATE, ABSTRACT, STATIC), specializationTypeName(null), TypeSystemNodeFactory.nodeType(typeSystem));
+        CodeTypeElement clazz = createClass(node, null, modifiers(PRIVATE, ABSTRACT, STATIC), specializationTypeName(null), typeSystem.getContext().getType(SpecializationNode.class));
 
         clazz.addOptional(createSpecializationConstructor(clazz, null, null));
         clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), nodeType(node), "root"));
 
         clazz.addOptional(createUnsupported());
         clazz.add(createGetSuppliedChildrenMethod());
-
-        int signatureSize = node.getSignatureSize();
-        Set<Integer> evaluatedCount = getEvaluatedCounts();
-        for (int evaluated : evaluatedCount) {
-            if (signatureSize != evaluated || signatureSize == 0) {
-                clazz.add(createFastPathExecuteMethod(null, evaluated > 0 ? null : genericType, evaluated));
-            }
+        clazz.add(createAcceptAndExecute());
+
+        for (ExecutableTypeData type : usedTypes) {
+            clazz.add(createFastPathExecuteMethod(null, type, usedTypes));
         }
 
         for (NodeExecutionData execution : node.getChildExecutions()) {
-            Collection<TypeData> specializedTypes = node.findSpecializedTypes(execution);
+            Collection<TypeMirror> specializedTypes = node.findSpecializedTypes(execution);
             specializedTypes.add(genericType);
-            for (TypeData specializedType : specializedTypes) {
+            for (TypeMirror specializedType : specializedTypes) {
                 if (isExecuteChildShared(execution, specializedType)) {
                     clazz.add(createExecuteChildMethod(execution, specializedType));
                 }
@@ -422,16 +431,162 @@
         return clazz;
     }
 
+    private Element createAcceptAndExecute() {
+
+        TypeMirror[] parameters = new TypeMirror[node.getSignatureSize()];
+        Arrays.fill(parameters, genericType);
+
+        ExecutableTypeData executableElement = new ExecutableTypeData(genericType, "acceptAndExecute", context.getType(Frame.class), Arrays.asList(parameters));
+
+        LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold);
+        CodeExecutableElement executable = createExecuteMethod(null, executableElement, currentLocals, false);
+
+        executable.getModifiers().add(FINAL);
+        CodeTreeBuilder builder = executable.createBuilder();
+
+        CodeTree receiver = CodeTreeBuilder.singleString("this");
+
+        builder.tree(createCallDelegateExecute(builder, receiver, currentLocals, executableElement, node.getGenericExecutableType(null)));
+
+        return executable;
+    }
+
+    private boolean shouldImplementExecutableType(SpecializationData specialization, ExecutableTypeData executableType) {
+        // always implement the root execute method. they are declared abstract in the base node.
+        if (executableType.getDelegatedTo() == null) {
+            return true;
+        }
+
+        // specializations with more parameters are just ignored
+        if (executableType.getEvaluatedCount() > node.getSignatureSize()) {
+            return false;
+        }
+
+        if (!isSubtypeBoxed(context, specialization.getReturnType().getType(), executableType.getReturnType())) {
+            return false;
+        }
+
+        // the evaluated signature might be compatible to the specialization
+        boolean specializationCompatible = true;
+        for (int i = 0; i < executableType.getEvaluatedCount(); i++) {
+            TypeMirror evaluatedType = executableType.getEvaluatedParameters().get(i);
+            TypeMirror specializedType = specialization.findParameterOrDie(node.getChildExecutions().get(i)).getType();
+
+            if (!isSubtypeBoxed(context, evaluatedType, specializedType) && !isSubtypeBoxed(context, specializedType, evaluatedType)) {
+                specializationCompatible = false;
+                break;
+            }
+        }
+        if (!specializationCompatible) {
+            return false;
+        }
+
+        // possibly trigger void optimization for a specialization if it is enabled
+        if (isVoid(executableType.getReturnType())) {
+            if (isTypeBoxingOptimized(options.voidBoxingOptimization(), specialization.getReturnType().getType())) {
+                return true;
+            }
+        }
+
+        // trigger type boxing elimination for unevaluated arguments
+        for (int i = executableType.getEvaluatedCount(); i < node.getSignatureSize(); i++) {
+            NodeExecutionData execution = node.getChildExecutions().get(i);
+            TypeMirror specializedType = specialization.findParameterOrDie(execution).getType();
+            if (isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), specializedType)) {
+                // it does not make sense to do type boxing elimination for children with
+                // no type specialized execute method
+                if (execution.getChild() != null) {
+                    ExecutableTypeData executedType = execution.getChild().findExecutableType(specializedType);
+                    if (executedType != null) {
+                        return true;
+                    }
+                }
+            }
+        }
+
+        // trigger type boxing elimination for return types
+        if (typeEquals(executableType.getReturnType(), specialization.getReturnType().getType())) {
+            if (isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), executableType.getReturnType())) {
+                return true;
+            }
+        }
+
+        // trigger generation for evaluated assignable type matches other than generic
+        for (int i = 0; i < executableType.getEvaluatedCount(); i++) {
+            TypeMirror evaluatedType = executableType.getEvaluatedParameters().get(i);
+            NodeExecutionData execution = node.getChildExecutions().get(i);
+            TypeMirror specializedType = specialization.findParameterOrDie(execution).getType();
+
+            if (isSubtypeBoxed(context, evaluatedType, specializedType) && !isObject(specializedType)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private List<ExecutableTypeData> filterBaseExecutableTypes(List<ExecutableTypeData> executableTypes, List<SpecializationData> specializations) {
+        Set<TypeMirror> returnTypes = new HashSet<>();
+        for (SpecializationData specialization : node.getSpecializations()) {
+            returnTypes.add(specialization.getReturnType().getType());
+        }
+
+        List<ExecutableTypeData> prefilteredTypes = new ArrayList<>();
+        for (ExecutableTypeData type : executableTypes) {
+            if (type.getDelegatedTo() == null || shouldAlwaysImplementExecutableType(type)) {
+                prefilteredTypes.add(type);
+            } else {
+                boolean foundSubtype = false;
+                for (TypeMirror returnType : returnTypes) {
+                    if (isSubtypeBoxed(context, returnType, type.getReturnType())) {
+                        foundSubtype = true;
+                    }
+                }
+                if (foundSubtype) {
+                    prefilteredTypes.add(type);
+                }
+            }
+        }
+
+        Set<ExecutableTypeData> types = new HashSet<>();
+        type: for (ExecutableTypeData type : prefilteredTypes) {
+            for (SpecializationData specialization : specializations) {
+                if (shouldImplementExecutableType(specialization, type) || shouldAlwaysImplementExecutableType(type)) {
+                    types.add(type);
+                    continue type;
+                }
+            }
+        }
+        Set<ExecutableTypeData> delegatesToAdd = new HashSet<>();
+        do {
+            delegatesToAdd.clear();
+            for (ExecutableTypeData type : types) {
+                ExecutableTypeData delegate = type.getDelegatedTo();
+                if (delegate != null && !types.contains(delegate)) {
+                    delegatesToAdd.add(delegate);
+                }
+            }
+            types.addAll(delegatesToAdd);
+        } while (!delegatesToAdd.isEmpty());
+        List<ExecutableTypeData> newUsedTypes = new ArrayList<>(types);
+        Collections.sort(newUsedTypes);
+        return newUsedTypes;
+    }
+
+    private boolean shouldAlwaysImplementExecutableType(ExecutableTypeData type) {
+        return type.isAbstract() || !(type.hasUnexpectedValue(context) && type.getMethod() != null);
+    }
+
     private CodeTypeElement createSpecialization(SpecializationData specialization, TypeMirror baseType) {
         CodeTypeElement clazz = createClass(node, specialization, modifiers(PRIVATE, STATIC, FINAL), specializationTypeName(specialization), baseType);
 
         CodeExecutableElement constructor = clazz.addOptional(createSpecializationConstructor(clazz, specialization, null));
 
         for (Parameter p : specialization.getSignatureParameters()) {
-            TypeData targetType = p.getTypeSystemType();
-            if (targetType.hasImplicitSourceTypes()) {
+            TypeMirror targetType = p.getType();
+            if (typeSystem.hasImplicitSourceTypes(targetType)) {
                 NodeExecutionData execution = p.getSpecification().getExecution();
-                CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getTypeSystemType());
+                CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getType());
                 if (implicitProfile != null) {
                     implicitProfile.getModifiers().add(PRIVATE);
                     implicitProfile.getModifiers().add(FINAL);
@@ -449,27 +604,35 @@
         clazz.addOptional(createIsSameMethod(specialization));
         clazz.addOptional(createIsIdenticalMethod(specialization));
 
-        TypeData returnType = specialization.getReturnType().getTypeSystemType();
-        int signatureSize = specialization.getSignatureSize();
-
-        clazz.add(createFastPathExecuteMethod(specialization, null, signatureSize));
-
-        if (isTypeBoxingEliminated(specialization)) {
-            clazz.add(createFastPathExecuteMethod(specialization, returnType, 0));
-
-            if (signatureSize > 0 && !returnType.isGeneric()) {
-                clazz.add(createFastPathWrapExecuteMethod(genericType, returnType));
+        // get types that should get implemented
+        List<ExecutableTypeData> types = new ArrayList<>();
+        for (ExecutableTypeData type : node.getExecutableTypes()) {
+            if (shouldImplementExecutableType(specialization, type)) {
+                types.add(type);
             }
-
-            ExecutableTypeData voidExecutableType = node.findExecutableType(typeSystem.getVoidType(), 0);
-            if (voidExecutableType != null && isTypeBoxingOptimized(options.voidBoxingOptimization(), returnType)) {
-                clazz.add(createFastPathWrapVoidMethod(returnType));
-            }
+        }
+        for (ExecutableTypeData type : types) {
+            clazz.add(createFastPathExecuteMethod(specialization, type, types));
         }
 
         return clazz;
     }
 
+    public static List<Parameter> getDynamicParameters(TemplateMethod method) {
+        List<Parameter> parameters = new ArrayList<>();
+        for (Parameter param : method.getReturnTypeAndParameters()) {
+            if (param.getSpecification().isLocal()) {
+                // ignore parameters passed by locals
+                continue;
+            } else if (param.getVariableElement() != null && param.getVariableElement().getAnnotation(Cached.class) != null) {
+                // ignore cached parameters
+                continue;
+            }
+            parameters.add(param);
+        }
+        return parameters;
+    }
+
     private Element createDeepCopyMethod() {
         if (singleSpecializable) {
             return null;
@@ -492,6 +655,7 @@
             builder.startReturn().startCall(specializationStartFieldName(), "getNodeCost").end().end();
         }
         return executable;
+
     }
 
     private Element createIsIdenticalMethod(SpecializationData specialization) {
@@ -517,7 +681,7 @@
             }
         };
 
-        builder.tree(createGuardAndCast(group, typeSystem.getGenericTypeData(), currentLocals, executionFactory));
+        builder.tree(createGuardAndCast(group, genericType, currentLocals, executionFactory));
         builder.returnFalse();
         return method;
     }
@@ -533,7 +697,7 @@
             if (execution == null) {
                 continue;
             }
-            CodeVariableElement var = createImplicitProfileParameter(execution, parameter.getTypeSystemType());
+            CodeVariableElement var = createImplicitProfileParameter(execution, parameter.getType());
             if (var != null) {
                 profiles.add(var);
             }
@@ -605,42 +769,6 @@
         return executable;
     }
 
-    private Element createFastPathWrapVoidMethod(TypeData wrap) {
-        CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), typeSystem.getVoidType().getPrimitiveType(), TypeSystemNodeFactory.executeName(typeSystem.getVoidType()));
-        executable.addParameter(new CodeVariableElement(getType(Frame.class), FRAME_VALUE));
-        executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
-        CodeTreeBuilder builder = executable.createBuilder();
-        builder.startStatement();
-        builder.startCall(TypeSystemNodeFactory.voidBoxingExecuteName(wrap));
-        builder.string(FRAME_VALUE);
-        builder.end();
-        builder.end();
-
-        return executable;
-    }
-
-    private Element createFastPathWrapExecuteMethod(TypeData override, TypeData wrap) {
-        CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), override.getPrimitiveType(), TypeSystemNodeFactory.executeName(override));
-        executable.addParameter(new CodeVariableElement(getType(Frame.class), FRAME_VALUE));
-        executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
-        CodeTreeBuilder builder = executable.createBuilder();
-        if (wrap != null) {
-            builder.startTryBlock();
-        }
-        builder.startReturn();
-        builder.startCall(TypeSystemNodeFactory.executeName(wrap));
-        builder.string(FRAME_VALUE);
-        builder.end();
-        builder.end();
-        if (wrap != null) {
-            builder.end().startCatchBlock(getType(UnexpectedResultException.class), "ex");
-            builder.statement("return ex.getResult()");
-            builder.end();
-        }
-
-        return executable;
-    }
-
     private Element createCreateFallback(Map<SpecializationData, CodeTypeElement> generatedSpecializationClasses) {
         SpecializationData fallback = node.getGenericSpecialization();
         if (fallback == null) {
@@ -752,35 +880,6 @@
         return null;
     }
 
-    private boolean isTypeBoxingEliminated(SpecializationData specialization) {
-        if (specialization.getMethod() == null) {
-            return false;
-        }
-
-        TypeBoxingOptimization optimization = options.monomorphicTypeBoxingOptimization();
-        if (isTypeBoxingOptimized(optimization, specialization.getReturnType().getTypeSystemType())) {
-            return true;
-        }
-        for (Parameter p : specialization.getSignatureParameters()) {
-            if (isTypeBoxingOptimized(optimization, p.getTypeSystemType())) {
-                return true;
-            }
-        }
-        return false;
-
-    }
-
-    private Set<Integer> getEvaluatedCounts() {
-        Set<Integer> evaluatedCount = new TreeSet<>();
-        Collection<TypeData> returnSpecializedTypes = node.findSpecializedReturnTypes();
-        for (ExecutableTypeData execType : node.getExecutableTypes()) {
-            if (shouldImplementExecutableType(returnSpecializedTypes, execType)) {
-                evaluatedCount.add(execType.getEvaluatedCount());
-            }
-        }
-        return evaluatedCount;
-    }
-
     private Element createUnsupported() {
         SpecializationData fallback = node.getGenericSpecialization();
         if (fallback == null || optimizeFallback(fallback) || fallback.getMethod() == null) {
@@ -788,7 +887,7 @@
         }
         LocalContext locals = LocalContext.load(this);
 
-        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType.getPrimitiveType(), "unsupported", FRAME_VALUE);
+        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType, "unsupported", FRAME_VALUE);
         method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
 
         CodeTreeBuilder builder = method.createBuilder();
@@ -800,7 +899,6 @@
     }
 
     private boolean isSingleSpecializableImpl() {
-        List<SpecializationData> reachableSpecializations = getReachableSpecializations();
         if (reachableSpecializations.size() != 1) {
             return false;
         }
@@ -808,8 +906,8 @@
         SpecializationData specialization = reachableSpecializations.get(0);
 
         for (Parameter parameter : specialization.getSignatureParameters()) {
-            TypeData type = parameter.getTypeSystemType();
-            if (type != null && type.hasImplicitSourceTypes()) {
+            TypeMirror type = parameter.getType();
+            if (type != null && typeSystem.hasImplicitSourceTypes(type)) {
                 return false;
             }
         }
@@ -826,7 +924,7 @@
         return true;
     }
 
-    private List<SpecializationData> getReachableSpecializations() {
+    private List<SpecializationData> calculateReachableSpecializations() {
         List<SpecializationData> specializations = new ArrayList<>();
         for (SpecializationData specialization : node.getSpecializations()) {
             if (specialization.isReachable() && //
@@ -851,158 +949,23 @@
         }
     }
 
-    private CodeExecutableElement createExecutableTypeOverride(List<ExecutableTypeData> implementedExecutables, ExecutableTypeData execType) {
-        final String varArgsName = "args";
-        final TypeData returnType = execType.getType();
-        final TypeData executedType = execType.getEvaluatedCount() > 0 ? null : returnType;
-
-        CodeExecutableElement method = cloneExecutableTypeOverride(execType, varArgsName);
-        LocalContext locals = LocalContext.load(this, execType.getSignatureSize(), Integer.MAX_VALUE);
-
-        // rename varargs parameter
-        int signatureIndex = 0;
-        for (Parameter parameter : execType.getSignatureParameters()) {
-            LocalVariable var = locals.get(parameter, signatureIndex);
-            if (var != null) {
-                if (parameter.isTypeVarArgs()) {
-                    var = var.accessWith(CodeTreeBuilder.singleString(varArgsName + "[" + parameter.getTypeVarArgsIndex() + "]"));
-                }
-                if (!parameter.getTypeSystemType().isGeneric()) {
-                    var = var.newType(parameter.getTypeSystemType());
-                }
-                locals.setValue(node.getChildExecutions().get(signatureIndex), var);
-            }
-
-            signatureIndex++;
-        }
-
-        Parameter frame = execType.getFrame();
+    private CodeExecutableElement createExecutableTypeOverride(List<ExecutableTypeData> usedExecutables, ExecutableTypeData execType) {
+        LocalContext locals = LocalContext.load(this, execType.getEvaluatedCount(), Integer.MAX_VALUE);
+        CodeExecutableElement method = createExecuteMethod(null, execType, locals, true);
+
         CodeTreeBuilder builder = method.createBuilder();
         if (singleSpecializable) {
-            LocalVariable frameVar = null;
-            if (frame != null) {
-                frameVar = locals.get(FRAME_VALUE).newType(frame.getType());
-            }
-            method.getThrownTypes().clear();
-            locals.set(FRAME_VALUE, frameVar);
-
-            SpecializationData specialization = getReachableSpecializations().iterator().next();
-            ExecutableTypeData wrappedExecutableType = findWrappedExecutable(specialization, implementedExecutables, execType);
-            if (wrappedExecutableType != null) {
-                builder.startReturn().tree(callTemplateMethod(null, wrappedExecutableType, locals)).end();
-            } else {
-                builder.tree(createFastPath(builder, specialization, execType.getType(), locals));
-            }
+            SpecializationData specialization = reachableSpecializations.iterator().next();
+            builder.tree(createFastPath(builder, specialization, execType, usedExecutables, locals));
         } else {
             // create acceptAndExecute
-            CodeTreeBuilder executeBuilder = builder.create();
-            executeBuilder.startCall(specializationStartFieldName(), TypeSystemNodeFactory.executeName(executedType));
-            if (frame == null) {
-                executeBuilder.nullLiteral();
-            } else {
-                executeBuilder.string(frame.getLocalName());
-            }
-            locals.addReferencesTo(executeBuilder);
-            executeBuilder.end();
-
-            boolean hasExecutedUnexpected = executedType != null && !executedType.isGeneric() && !executedType.isVoid();
-
-            CodeTreeBuilder contentBuilder = builder.create();
-            contentBuilder.startReturn();
-            if (!hasExecutedUnexpected && !execType.hasUnexpectedValue(context)) {
-                if (executedType == null || executedType.needsCastTo(returnType)) {
-                    contentBuilder.cast(returnType.getPrimitiveType(), executeBuilder.build());
-                } else {
-                    contentBuilder.tree(executeBuilder.build());
-                }
-            } else {
-                contentBuilder.tree(TypeSystemCodeGenerator.expect(executedType, returnType, executeBuilder.build()));
-            }
-            contentBuilder.end();
-            // try catch assert if unexpected value is not expected
-            CodeTree content = contentBuilder.build();
-            if (!execType.hasUnexpectedValue(context) && hasExecutedUnexpected) {
-                content = wrapTryCatchUnexpected(content);
-            }
-            builder.tree(content);
+            ExecutableTypeData delegate = execType;
+            CodeTree receiver = CodeTreeBuilder.singleString(specializationStartFieldName());
+            builder.tree(createCallDelegateExecute(builder, receiver, locals, execType, delegate));
         }
         return method;
     }
 
-    private CodeTree wrapTryCatchUnexpected(CodeTree content) {
-        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        builder.startTryBlock();
-        builder.tree(content);
-        builder.end().startCatchBlock(getType(UnexpectedResultException.class), "ex");
-        builder.startThrow().startNew(getType(AssertionError.class)).end().end();
-        builder.end();
-        return builder.build();
-    }
-
-    private static ExecutableTypeData findWrappedExecutable(SpecializationData specialization, List<ExecutableTypeData> implementedExecutables, ExecutableTypeData executedType) {
-        if (specialization.getReturnType().getTypeSystemType() == executedType.getType()) {
-            return null;
-        }
-        for (ExecutableTypeData otherType : implementedExecutables) {
-            if (otherType != executedType && //
-                            otherType.getType() == specialization.getReturnType().getTypeSystemType() && //
-                            otherType.getEvaluatedCount() == executedType.getEvaluatedCount()) {
-                return otherType;
-            }
-        }
-        return null;
-    }
-
-    private CodeExecutableElement cloneExecutableTypeOverride(ExecutableTypeData execType, final String varArgsName) throws AssertionError {
-        CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), execType.getMethod());
-
-        method.getAnnotationMirrors().clear();
-        method.getModifiers().remove(Modifier.ABSTRACT);
-
-        if (!execType.getMethod().isVarArgs() && execType.getParameters().size() != method.getParameters().size()) {
-            throw new AssertionError("Should be verified in the parser");
-        }
-
-        // align argument names
-        int index = 0;
-        for (Parameter parameter : execType.getParameters()) {
-            CodeVariableElement var = (CodeVariableElement) method.getParameters().get(index);
-            if (parameter.isTypeVarArgs()) {
-                var.getAnnotationMirrors().clear();
-                var.setName(varArgsName);
-                break;
-            }
-            var.setName(LocalVariable.fromParameter(parameter).createParameter().getName());
-            var.getAnnotationMirrors().clear();
-            index++;
-        }
-        return method;
-    }
-
-    private boolean shouldImplementExecutableType(Collection<TypeData> specializedTypes, ExecutableTypeData execType) {
-        TypeData type = execType.getType();
-        Set<Modifier> modifiers = execType.getMethod().getModifiers();
-        if (modifiers.contains(FINAL) || modifiers.contains(STATIC) || modifiers.contains(PRIVATE)) {
-            return false;
-        } else if (execType.isAbstract()) {
-            return true;
-        } else if (type.isGeneric()) {
-            return true;
-        } else if (type.isVoid()) {
-            for (TypeData specializedType : specializedTypes) {
-                if (isTypeBoxingOptimized(options.voidBoxingOptimization(), specializedType)) {
-                    return true;
-                }
-            }
-            return false;
-        } else if (!specializedTypes.contains(type)) {
-            return false;
-        } else if (!isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), type)) {
-            return false;
-        }
-        return true;
-    }
-
     private Element createMethodGetSpecializationNode() {
         TypeMirror returntype = getType(SpecializationNode.class);
         CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returntype, "getSpecializationNode");
@@ -1021,7 +984,7 @@
         return childField;
     }
 
-    private static List<ExecutableTypeData> resolveSpecializedExecutables(NodeExecutionData execution, Collection<TypeData> types, TypeBoxingOptimization optimization) {
+    private static List<ExecutableTypeData> resolveSpecializedExecutables(NodeExecutionData execution, Collection<TypeMirror> types, TypeBoxingOptimization optimization) {
         if (optimization == TypeBoxingOptimization.NONE) {
             return Collections.emptyList();
         } else if (types.isEmpty()) {
@@ -1029,10 +992,13 @@
         }
 
         List<ExecutableTypeData> executables = new ArrayList<>();
-        for (TypeData type : types) {
+        for (TypeMirror type : types) {
             if (!isTypeBoxingOptimized(optimization, type)) {
                 continue;
             }
+            if (execution.getChild() == null) {
+                continue;
+            }
             ExecutableTypeData foundType = execution.getChild().getNodeData().findExecutableType(type, execution.getChild().getExecuteWith().size());
             if (foundType != null) {
                 executables.add(foundType);
@@ -1041,15 +1007,15 @@
         return executables;
     }
 
-    private static CodeTree callTemplateMethod(CodeTree receiver, TemplateMethod method, CodeTree... boundValues) {
+    private static CodeTree callMethod(CodeTree receiver, ExecutableElement method, CodeTree... boundValues) {
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        if (method.getMethod().getModifiers().contains(STATIC)) {
-            builder.startStaticCall(method.getMethod().getEnclosingElement().asType(), method.getMethodName());
+        if (method.getModifiers().contains(STATIC)) {
+            builder.startStaticCall(method.getEnclosingElement().asType(), method.getSimpleName().toString());
         } else {
-            builder.startCall(receiver, method.getMethodName());
+            builder.startCall(receiver, method.getSimpleName().toString());
         }
         int index = -1;
-        for (Parameter parameter : method.getParameters()) {
+        for (VariableElement parameter : method.getParameters()) {
             index++;
             if (index < boundValues.length) {
                 CodeTree tree = boundValues[index];
@@ -1059,13 +1025,44 @@
                 }
             }
 
-            builder.defaultValue(parameter.getType());
+            builder.defaultValue(parameter.asType());
         }
         builder.end();
         return builder.build();
     }
 
-    private static CodeTree callTemplateMethod(CodeTree receiver, TemplateMethod method, LocalContext currentValues) {
+    private CodeTree[] bindExecuteMethodParameters(NodeExecutionData execution, ExecutableTypeData method, LocalContext currentValues) {
+        List<NodeExecutionData> executeWith = execution != null ? execution.getChild().getExecuteWith() : null;
+
+        List<CodeTree> values = new ArrayList<>();
+        if (method.getFrameParameter() != null) {
+            LocalVariable frameLocal = currentValues.get(FRAME_VALUE);
+            if (frameLocal == null) {
+                values.add(CodeTreeBuilder.singleString("null"));
+            } else {
+                values.add(createTypeSafeReference(frameLocal, method.getFrameParameter()));
+            }
+        }
+        for (int parameterIndex = 0; parameterIndex < method.getEvaluatedCount(); parameterIndex++) {
+            TypeMirror targetParameter = method.getEvaluatedParameters().get(parameterIndex);
+            LocalVariable variable;
+            if (executeWith != null && parameterIndex < executeWith.size()) {
+                variable = currentValues.getValue(executeWith.get(parameterIndex));
+            } else {
+                variable = currentValues.getValue(parameterIndex);
+            }
+            values.add(createTypeSafeReference(variable, targetParameter));
+        }
+
+        return values.toArray(new CodeTree[values.size()]);
+    }
+
+    private CodeTree callExecuteMethod(NodeExecutionData execution, ExecutableTypeData method, LocalContext currentValues) {
+        CodeTree receiver = execution != null ? accessParent(nodeFieldName(execution)) : null;
+        return callMethod(receiver, method.getMethod(), bindExecuteMethodParameters(execution, method, currentValues));
+    }
+
+    private CodeTree callTemplateMethod(CodeTree receiver, TemplateMethod method, LocalContext currentValues) {
         CodeTree[] bindings = new CodeTree[method.getParameters().size()];
 
         int signatureIndex = 0;
@@ -1078,24 +1075,30 @@
             }
 
             if (var != null) {
-                CodeTree valueReference = var.createReference();
-                if (parameter.getTypeSystemType() != null && var.getType() != null && var.getType().needsCastTo(parameter.getTypeSystemType())) {
-                    valueReference = TypeSystemCodeGenerator.cast(parameter.getTypeSystemType(), valueReference);
-                } else if (ElementUtils.needsCastTo(var.getTypeMirror(), parameter.getType())) {
-                    valueReference = CodeTreeBuilder.createBuilder().cast(parameter.getType(), valueReference).build();
-                }
-                bindings[i] = valueReference;
+                bindings[i] = createTypeSafeReference(var, parameter.getType());
             }
 
             if (parameter.getSpecification().isSignature()) {
                 signatureIndex++;
             }
         }
-        return callTemplateMethod(receiver, method, bindings);
+        return callMethod(receiver, method.getMethod(), bindings);
+    }
+
+    private CodeTree createTypeSafeReference(LocalVariable var, TypeMirror targetType) {
+        CodeTree valueReference = var.createReference();
+        TypeMirror sourceType = var.getTypeMirror();
+        if (targetType == null || sourceType == null) {
+            return valueReference;
+        }
+        if (needsCastTo(sourceType, targetType)) {
+            valueReference = TypeSystemCodeGenerator.cast(typeSystem, targetType, valueReference);
+        }
+        return valueReference;
     }
 
     private SpecializationGroup createSpecializationGroups() {
-        return SpecializationGroup.create(getReachableSpecializations());
+        return SpecializationGroup.create(reachableSpecializations);
     }
 
     private CodeTree createSlowPathExecute(SpecializationData specialization, LocalContext currentValues) {
@@ -1125,7 +1128,7 @@
                 String varName = name + specialization.getIndex();
                 TypeMirror type = assumption.getExpression().getResolvedType();
                 builder.declaration(type, varName, assumptions);
-                currentValues.set(name, new LocalVariable(null, type, varName, null, null));
+                currentValues.set(name, new LocalVariable(type, varName, null, null));
             }
 
             builder.startIf();
@@ -1189,14 +1192,14 @@
         return builder.build();
     }
 
-    private boolean hasFallthrough(SpecializationGroup group, TypeData forType, LocalContext currentValues, boolean fastPath, List<GuardExpression> ignoreGuards) {
+    private boolean hasFallthrough(SpecializationGroup group, TypeMirror forType, LocalContext currentValues, boolean fastPath, List<GuardExpression> ignoreGuards) {
         for (TypeGuard guard : group.getTypeGuards()) {
             if (currentValues.getValue(guard.getSignatureIndex()) == null) {
                 // not evaluated
                 return true;
             }
             LocalVariable value = currentValues.getValue(guard.getSignatureIndex());
-            if (value.getType().needsCastTo(guard.getType())) {
+            if (needsCastTo(value.getTypeMirror(), guard.getType())) {
                 return true;
             }
         }
@@ -1244,6 +1247,16 @@
         return false;
     }
 
+    private Element createGetNext(CodeTypeElement type) {
+        if (!nextUsed) {
+            return null;
+        }
+        CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), type.asType(), "getNext");
+        CodeTreeBuilder builder = method.createBuilder();
+        builder.startReturn().cast(type.asType(), CodeTreeBuilder.singleString("this.next")).end();
+        return method;
+    }
+
     private Element createGetSuppliedChildrenMethod() {
         ArrayType nodeArray = context.getEnvironment().getTypeUtils().getArrayType(getType(Node.class));
 
@@ -1265,7 +1278,11 @@
             if (execution.isShortCircuit()) {
                 builder.nullLiteral();
             }
-            builder.tree(accessParent(nodeFieldName(execution)));
+            if (execution.getChild() == null) {
+                builder.nullLiteral();
+            } else {
+                builder.tree(accessParent(nodeFieldName(execution)));
+            }
         }
         builder.end();
         return builder.build();
@@ -1289,7 +1306,7 @@
         }
         if (currentValues != null) {
             for (Parameter p : specialization.getSignatureParameters()) {
-                CodeVariableElement var = createImplicitProfileParameter(p.getSpecification().getExecution(), p.getTypeSystemType());
+                CodeVariableElement var = createImplicitProfileParameter(p.getSpecification().getExecution(), p.getType());
                 if (var != null) {
                     LocalVariable variable = currentValues.get(p.getLocalName());
                     if (variable == null) {
@@ -1370,19 +1387,19 @@
             for (Parameter p : specialization.getSignatureParameters()) {
                 NodeExecutionData execution = p.getSpecification().getExecution();
 
-                CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getTypeSystemType());
+                CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getType());
                 if (implicitProfile != null) {
-                    LocalVariable var = LocalVariable.fromParameter(p).makeGeneric();
+                    LocalVariable var = LocalVariable.fromParameter(p).makeGeneric(context);
 
                     String implicitFieldName = implicitProfile.getName();
                     if (options.implicitCastOptimization().isDuplicateTail()) {
                         constructor.addParameter(var.createParameter());
-                        CodeTree implicitType = TypeSystemCodeGenerator.implicitType(p.getTypeSystemType(), var.createReference());
+                        CodeTree implicitType = TypeSystemCodeGenerator.implicitType(typeSystem, p.getType(), var.createReference());
                         builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(implicitType).end();
                     } else if (options.implicitCastOptimization().isMergeCasts()) {
                         // use node that supports polymorphism
                         constructor.addParameter(var.createParameter());
-                        builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(ImplicitCastNodeFactory.create(p.getTypeSystemType(), var.createReference())).end();
+                        builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(ImplicitCastNodeFactory.create(typeSystem, p.getType(), var.createReference())).end();
                     } else {
                         throw new AssertionError();
                     }
@@ -1443,18 +1460,17 @@
         return builder.build();
     }
 
-    private CodeTree createCallNext(TypeData forType, LocalContext currentValues) {
+    private CodeTree createCallNext(CodeTreeBuilder parent, ExecutableTypeData currentType, ExecutableTypeData callType, LocalContext currentValues) {
         if (singleSpecializable) {
             return createThrowUnsupported(currentValues);
         }
-        CodeTreeBuilder callBuilder = CodeTreeBuilder.createBuilder();
-        callBuilder.startCall("next", TypeSystemNodeFactory.executeName(null));
-        currentValues.addReferencesTo(callBuilder, FRAME_VALUE);
-        callBuilder.end();
-        return CodeTreeBuilder.createBuilder().startReturn().tree(TypeSystemCodeGenerator.expect(genericType, forType, callBuilder.build())).end().build();
+        CodeTreeBuilder callBuilder = parent.create();
+        callBuilder.tree(createCallDelegateExecute(callBuilder, CodeTreeBuilder.singleString("getNext()"), currentValues, currentType, callType));
+        nextUsed = true;
+        return callBuilder.build();
     }
 
-    private CodeTree createCallRemove(String reason, TypeData forType, LocalContext currentValues) {
+    private CodeTree createCallRemove(String reason, ExecutableTypeData forType, LocalContext currentValues) {
         if (singleSpecializable) {
             return createThrowUnsupported(currentValues);
         }
@@ -1467,12 +1483,12 @@
 
         builder = builder.create();
         builder.startReturn();
-        builder.tree(TypeSystemCodeGenerator.expect(genericType, forType, call));
+        builder.tree(expectOrCast(genericType, forType, call));
         builder.end();
         return builder.build();
     }
 
-    private static CodeTree createCallDelegate(String methodName, String reason, TypeData forType, LocalContext currentValues) {
+    private CodeTree createCallDelegate(String methodName, String reason, ExecutableTypeData forType, LocalContext currentValues) {
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
         builder.startCall(methodName);
         if (reason != null) {
@@ -1481,21 +1497,45 @@
         currentValues.addReferencesTo(builder, FRAME_VALUE);
         builder.end();
 
-        TypeData executedType = forType.getTypeSystem().getGenericTypeData();
-        return TypeSystemCodeGenerator.expect(executedType, forType, builder.build());
+        CodeTree expectOrCast = expectOrCast(genericType, forType, builder.build());
+        return expectOrCast;
+    }
+
+    private CodeTree expectOrCast(TypeMirror sourceType, ExecutableTypeData targetType, CodeTree content) {
+        if (needsUnexpectedResultException(targetType)) {
+            return expect(sourceType, targetType.getReturnType(), content);
+        } else {
+            return cast(sourceType, targetType.getReturnType(), content);
+        }
     }
 
-    private Set<ExecutableTypeData> findSpecializedExecutableTypes(NodeExecutionData execution, TypeData type) {
+    private CodeTree cast(TypeMirror sourceType, TypeMirror targetType, CodeTree content) {
+        if (ElementUtils.needsCastTo(sourceType, targetType) && !isVoid(sourceType)) {
+            return TypeSystemCodeGenerator.cast(typeSystem, targetType, content);
+        } else {
+            return content;
+        }
+    }
+
+    private CodeTree expect(TypeMirror sourceType, TypeMirror forType, CodeTree tree) {
+        expectedTypes.add(forType);
+        return TypeSystemCodeGenerator.expect(typeSystem, sourceType, forType, tree);
+    }
+
+    private Set<ExecutableTypeData> findSpecializedExecutableTypes(NodeExecutionData execution, TypeMirror type) {
+        if (execution.getChild() == null) {
+            return Collections.emptySet();
+        }
         ExecutableTypeData executableType = resolveExecutableType(execution.getChild(), type);
         Set<ExecutableTypeData> executedTypes = new HashSet<>();
         executedTypes.add(executableType);
-        if (type.hasImplicitSourceTypes()) {
-            executedTypes.addAll(resolveSpecializedExecutables(execution, type.getImplicitSourceTypes(), options.implicitTypeBoxingOptimization()));
+        if (typeSystem.hasImplicitSourceTypes(type)) {
+            executedTypes.addAll(resolveSpecializedExecutables(execution, typeSystem.lookupSourceTypes(type), options.implicitTypeBoxingOptimization()));
         }
         return executedTypes;
     }
 
-    private ExecutableTypeData resolveExecutableType(NodeChildData child, TypeData type) {
+    private ExecutableTypeData resolveExecutableType(NodeChildData child, TypeMirror type) {
         int executeWithCount = child.getExecuteWith().size();
         ExecutableTypeData executableType = child.getNodeData().findExecutableType(type, executeWithCount);
         if (executableType == null) {
@@ -1504,79 +1544,254 @@
         return executableType;
     }
 
-    private boolean hasUnexpectedResult(NodeExecutionData execution, TypeData type) {
+    private boolean hasChildUnexpectedResult(NodeExecutionData execution, TypeMirror type) {
         for (ExecutableTypeData executableType : findSpecializedExecutableTypes(execution, type)) {
-            if (executableType != null && (executableType.hasUnexpectedValue(context) || executableType.getType().needsCastTo(type))) {
+            if (executableType != null && (executableType.hasUnexpectedValue(context) || needsCastTo(executableType.getReturnType(), type))) {
                 return true;
             }
         }
         return false;
     }
 
-    private Element createFastPathExecuteMethod(SpecializationData specialization, final TypeData forType, int evaluatedArguments) {
-        TypeData type = forType == null ? genericType : forType;
-        LocalContext currentLocals = LocalContext.load(this, evaluatedArguments, varArgsThreshold);
+    private Element createFastPathExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, List<ExecutableTypeData> allTypes) {
+        LocalContext currentLocals = LocalContext.load(this, executedType.getEvaluatedCount(), varArgsThreshold);
+        CodeExecutableElement executable = createExecuteMethod(specialization, executedType, currentLocals, false);
+        CodeTreeBuilder builder = executable.createBuilder();
+        if (specialization == null) {
+            if (executedType.getDelegatedTo() == null) {
+                executable.getModifiers().add(ABSTRACT);
+            }
+        } else {
+            executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
+        }
+        builder.tree(createFastPath(builder, specialization, executedType, allTypes, currentLocals));
+
+        return executable;
+    }
+
+    private CodeExecutableElement createExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, LocalContext currentLocals, boolean originalOverride) {
+        TypeMirror returnType = executedType.getReturnType();
+        TypeMirror frame = executedType.getFrameParameter();
+        List<TypeMirror> evaluatedParameters = executedType.getEvaluatedParameters();
 
         if (specialization != null) {
             currentLocals.loadFastPathState(specialization);
         }
 
-        CodeExecutableElement executable = currentLocals.createMethod(modifiers(PUBLIC), type.getPrimitiveType(), TypeSystemNodeFactory.executeName(forType), FRAME_VALUE);
-        executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
-
-        if (!type.isGeneric()) {
-            executable.getThrownTypes().add(getType(UnexpectedResultException.class));
+        if (frame == null) {
+            currentLocals.removeValue(FRAME_VALUE);
+        } else {
+            currentLocals.set(FRAME_VALUE, currentLocals.get(FRAME_VALUE).newType(frame));
+        }
+
+        for (int i = 0; i < Math.min(node.getChildExecutions().size(), evaluatedParameters.size()); i++) {
+            NodeExecutionData execution = node.getChildExecutions().get(i);
+            currentLocals.setValue(execution, currentLocals.getValue(execution).newType(evaluatedParameters.get(i)));
+        }
+
+        String methodName;
+        if (originalOverride) {
+            methodName = executedType.getMethod().getSimpleName().toString();
+        } else {
+            methodName = executedType.getUniqueName();
         }
 
-        CodeTreeBuilder builder = executable.createBuilder();
-        builder.tree(createFastPath(builder, specialization, type, currentLocals));
+        CodeExecutableElement executable;
+        if (originalOverride && executedType.getMethod() != null) {
+            executable = CodeExecutableElement.clone(context.getEnvironment(), executedType.getMethod());
+            executable.getAnnotationMirrors().clear();
+            executable.getModifiers().remove(ABSTRACT);
+            for (VariableElement var : executable.getParameters()) {
+                ((CodeVariableElement) var).getAnnotationMirrors().clear();
+            }
+            if (executedType.getFrameParameter() != null) {
+                ((CodeVariableElement) executable.getParameters().get(0)).setName(FRAME_VALUE);
+            }
+
+            final String varArgsName = "args";
+            if (executable.isVarArgs()) {
+                ((CodeVariableElement) executable.getParameters().get(executable.getParameters().size() - 1)).setName(varArgsName);
+            }
+
+            // rename varargs parameter
+            int signatureIndex = 0;
+            for (TypeMirror parameter : executedType.getEvaluatedParameters()) {
+                LocalVariable var = currentLocals.getValue(signatureIndex);
+                if (var != null) {
+                    int varArgsIndex = executedType.getVarArgsIndex(executedType.getParameterIndex(signatureIndex));
+                    if (varArgsIndex >= 0) {
+                        var = var.accessWith(CodeTreeBuilder.singleString(varArgsName + "[" + varArgsIndex + "]"));
+                    } else {
+                        ((CodeVariableElement) executable.getParameters().get(executedType.getParameterIndex(signatureIndex))).setName(var.getName());
+                    }
+                    if (!isObject(parameter)) {
+                        var = var.newType(parameter);
+                    }
+                    currentLocals.setValue(node.getChildExecutions().get(signatureIndex), var);
+                }
+
+                signatureIndex++;
+            }
+        } else {
+            executable = currentLocals.createMethod(modifiers(PUBLIC), returnType, methodName, FRAME_VALUE);
+        }
+        executable.getThrownTypes().clear();
+
+        if (needsUnexpectedResultException(executedType)) {
+            executable.getThrownTypes().add(context.getDeclaredType(UnexpectedResultException.class));
+        }
 
         return executable;
     }
 
-    private CodeTree createFastPath(CodeTreeBuilder parent, SpecializationData specialization, TypeData type, LocalContext currentLocals) {
+    private boolean needsUnexpectedResultException(ExecutableTypeData executedType) {
+        if (!executedType.hasUnexpectedValue(context)) {
+            return false;
+        }
+
+        SpecializationData polymorphicSpecialization = node.getPolymorphicSpecialization();
+        if (polymorphicSpecialization != null && isSubtypeBoxed(context, polymorphicSpecialization.getReturnType().getType(), executedType.getReturnType())) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    private CodeTree createFastPath(CodeTreeBuilder parent, SpecializationData specialization, final ExecutableTypeData executableType, List<ExecutableTypeData> allTypes, LocalContext currentLocals) {
         final CodeTreeBuilder builder = parent.create();
+        TypeMirror returnType = executableType.getReturnType();
+
+        ExecutableTypeData delegate = null;
+        if (specialization == null) {
+            delegate = executableType.getDelegatedTo();
+        }
+
+        if (delegate == null) {
+            delegate = findFastPathDelegate((specialization != null ? specialization.getReturnType().getType() : genericType), executableType, allTypes);
+        }
 
         for (NodeExecutionData execution : node.getChildExecutions()) {
+            if (specialization == null && delegate != null && execution.getIndex() >= delegate.getEvaluatedCount()) {
+                // we just evaluate children for the next delegate
+                continue;
+            } else if (specialization != null && delegate != null) {
+                // skip if already delegated
+                break;
+            }
+
             LocalVariable var = currentLocals.getValue(execution);
             if (var == null) {
-                TypeData targetType;
+                TypeMirror targetType;
                 if (specialization == null) {
-                    targetType = genericType;
+                    targetType = node.getGenericType(execution);
                 } else {
-                    targetType = specialization.findParameterOrDie(execution).getTypeSystemType();
+                    targetType = specialization.findParameterOrDie(execution).getType();
                 }
                 LocalVariable shortCircuit = resolveShortCircuit(specialization, execution, currentLocals);
-                LocalVariable value = currentLocals.createValue(execution, targetType).nextName();
-                builder.tree(createAssignExecuteChild(execution, type, value, shortCircuit, currentLocals));
-                currentLocals.setValue(execution, value);
+                var = currentLocals.createValue(execution, targetType).nextName();
+                builder.tree(createAssignExecuteChild(builder, execution, executableType, var, shortCircuit, currentLocals));
+                currentLocals.setValue(execution, var);
             }
         }
 
         LocalContext originalValues = currentLocals.copy();
-        if (specialization == null) {
-            builder.startReturn().tree(createCallDelegate("acceptAndExecute", null, type, currentLocals)).end();
+        if (delegate != null) {
+            builder.tree(createCallDelegateExecute(builder, null, currentLocals, executableType, delegate));
+        } else if (specialization == null) {
+            // nothing to do. abstract anyway
         } else if (specialization.isPolymorphic()) {
-            builder.tree(createCallNext(type, currentLocals));
+            builder.tree(createCallNext(builder, executableType, node.getGenericExecutableType(executableType), currentLocals));
         } else if (specialization.isUninitialized()) {
-            builder.startReturn().tree(createCallDelegate("uninitialized", null, type, currentLocals)).end();
+            builder.startReturn().tree(createCallDelegate("uninitialized", null, executableType, currentLocals)).end();
         } else {
-            final TypeData finalType = type;
             SpecializationGroup group = SpecializationGroup.create(specialization);
             SpecializationBody executionFactory = new SpecializationBody(true, true) {
                 @Override
                 public CodeTree createBody(SpecializationData s, LocalContext values) {
-                    return createFastPathExecute(builder, finalType, s, values);
+                    return createFastPathExecute(builder, executableType, s, values);
                 }
             };
-            builder.tree(createGuardAndCast(group, type, currentLocals, executionFactory));
-            if (hasFallthrough(group, type, originalValues, true, null) || group.getSpecialization().isFallback()) {
-                builder.tree(createCallNext(type, originalValues));
+            builder.tree(createGuardAndCast(group, returnType, currentLocals, executionFactory));
+            if (hasFallthrough(group, returnType, originalValues, true, null) || group.getSpecialization().isFallback()) {
+                builder.tree(createCallNext(builder, executableType, node.getGenericExecutableType(executableType), originalValues));
             }
         }
         return builder.build();
     }
 
+    private CodeTree createCallDelegateExecute(final CodeTreeBuilder parent, CodeTree receiver, LocalContext currentLocals, ExecutableTypeData source, ExecutableTypeData delegate) {
+        CodeTreeBuilder callBuilder = parent.create();
+
+        if (singleSpecializable && delegate.getMethod() != null) {
+            callBuilder.startCall(receiver, delegate.getMethod().getSimpleName().toString());
+        } else {
+            callBuilder.startCall(receiver, delegate.getUniqueName());
+        }
+        callBuilder.trees(bindExecuteMethodParameters(null, delegate, currentLocals));
+        callBuilder.end();
+        CodeTree call = expectOrCast(delegate.getReturnType(), source, callBuilder.build());
+
+        CodeTreeBuilder returnBuilder = parent.create();
+        if (isVoid(source.getReturnType())) {
+            returnBuilder.statement(call);
+            returnBuilder.returnStatement();
+        } else if (isVoid(delegate.getReturnType())) {
+            returnBuilder.statement(call);
+            returnBuilder.returnDefault();
+        } else {
+            returnBuilder.startReturn().tree(call).end();
+        }
+
+        CodeTreeBuilder builder = parent.create();
+
+        if (!needsUnexpectedResultException(source) && needsUnexpectedResultException(delegate)) {
+            builder.startTryBlock();
+            builder.tree(returnBuilder.build());
+            builder.end().startCatchBlock(context.getType(UnexpectedResultException.class), "ex");
+            if (!isVoid(source.getReturnType())) {
+                builder.startReturn().tree(cast(context.getType(Object.class), source.getReturnType(), CodeTreeBuilder.singleString("ex.getResult()"))).end();
+            }
+            builder.end();
+        } else {
+            builder.tree(returnBuilder.build());
+        }
+        return builder.build();
+    }
+
+    private ExecutableTypeData findFastPathDelegate(TypeMirror targetType, ExecutableTypeData executableType, List<ExecutableTypeData> allTypes) {
+        if (typeEquals(executableType.getReturnType(), targetType)) {
+            // type matches look for even better delegates
+            for (ExecutableTypeData type : allTypes) {
+                if (typeEquals(type.getReturnType(), targetType) && executableType.sameParameters(type)) {
+                    if (type != executableType) {
+                        return type;
+                    }
+                }
+            }
+            return null;
+        } else {
+            for (ExecutableTypeData type : allTypes) {
+                if (typeEquals(type.getReturnType(), targetType) && executableType.sameParameters(type)) {
+                    return type;
+                }
+            }
+            int executableIndex = allTypes.indexOf(executableType);
+            int compareIndex = 0;
+            for (ExecutableTypeData type : allTypes) {
+                if (executableIndex != compareIndex && executableType.sameParameters(type)) {
+                    int result = ExecutableTypeData.compareType(context, type.getReturnType(), executableType.getReturnType());
+                    if (result < 0) {
+                        return type;
+                    } else if (result == 0 && executableIndex < compareIndex) {
+                        return type;
+                    }
+                }
+                compareIndex++;
+            }
+            return null;
+        }
+    }
+
     private LocalVariable resolveShortCircuit(SpecializationData specialization, NodeExecutionData execution, LocalContext currentLocals) {
         LocalVariable shortCircuit = null;
         SpecializationData resolvedSpecialization = specialization;
@@ -1605,13 +1820,17 @@
         return shortCircuitIndex;
     }
 
-    private CodeTree createFastPathExecute(CodeTreeBuilder parent, final TypeData forType, SpecializationData specialization, LocalContext currentValues) {
+    private CodeTree createFastPathExecute(CodeTreeBuilder parent, final ExecutableTypeData forType, SpecializationData specialization, LocalContext currentValues) {
         CodeTreeBuilder builder = parent.create();
         int ifCount = 0;
         if (specialization.isFallback()) {
             builder.startIf().startCall("guardFallback");
             if (node.isFrameUsedByAnyGuard()) {
-                builder.string(FRAME_VALUE);
+                if (currentValues.get(FRAME_VALUE) != null) {
+                    builder.string(FRAME_VALUE);
+                } else {
+                    builder.nullLiteral();
+                }
             }
             currentValues.addReferencesTo(builder);
 
@@ -1642,21 +1861,37 @@
             builder.end();
         }
 
-        execute.startReturn();
         if (specialization.getMethod() == null) {
+            execute.startReturn();
             execute.startCall("unsupported");
             currentValues.addReferencesTo(execute, FRAME_VALUE);
             execute.end();
+            execute.end();
         } else {
+            boolean doReturn = !isVoid(specialization.getMethod().getReturnType());
+            if (doReturn) {
+                execute.startReturn();
+            } else {
+                execute.startStatement();
+            }
             execute.tree(callTemplateMethod(accessParent(null), specialization, currentValues));
+            execute.end();
+            if (!doReturn) {
+                if (isVoid(forType.getReturnType())) {
+                    execute.returnStatement();
+                } else {
+                    execute.startReturn();
+                    execute.defaultValue(forType.getReturnType());
+                    execute.end();
+                }
+            }
         }
-        execute.end();
         builder.tree(createFastPathTryCatchRewriteException(specialization, forType, currentValues, execute.build()));
         builder.end(ifCount);
         return builder.build();
     }
 
-    private CodeTree createGuardAndCast(SpecializationGroup group, TypeData forType, LocalContext currentValues, SpecializationBody execution) {
+    private CodeTree createGuardAndCast(SpecializationGroup group, TypeMirror forType, LocalContext currentValues, SpecializationBody execution) {
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
 
         Set<TypeGuard> castGuards;
@@ -1780,11 +2015,11 @@
         return false;
     }
 
-    private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeData targetType) {
+    private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeMirror targetType) {
         LocalContext locals = LocalContext.load(this, 0, varArgsThreshold);
 
-        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType.getPrimitiveType(), executeChildMethodName(execution, targetType), FRAME_VALUE);
-        if (hasUnexpectedResult(execution, targetType)) {
+        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType, executeChildMethodName(execution, targetType), FRAME_VALUE);
+        if (hasChildUnexpectedResult(execution, targetType)) {
             method.getThrownTypes().add(getType(UnexpectedResultException.class));
         }
 
@@ -1810,30 +2045,30 @@
         return method;
     }
 
-    private CodeVariableElement createImplicitProfileParameter(NodeExecutionData execution, TypeData targetType) {
-        if (targetType.hasImplicitSourceTypes()) {
+    private CodeVariableElement createImplicitProfileParameter(NodeExecutionData execution, TypeMirror targetType) {
+        if (typeSystem.hasImplicitSourceTypes(targetType)) {
             switch (options.implicitCastOptimization()) {
                 case NONE:
                     return null;
                 case DUPLICATE_TAIL:
                     return new CodeVariableElement(getType(Class.class), implicitClassFieldName(execution));
                 case MERGE_CASTS:
-                    return new CodeVariableElement(ImplicitCastNodeFactory.type(targetType), implicitNodeFieldName(execution));
+                    return new CodeVariableElement(ImplicitCastNodeFactory.type(typeSystem, targetType), implicitNodeFieldName(execution));
             }
         }
         return null;
     }
 
-    private boolean isExecuteChildShared(NodeExecutionData execution, TypeData targetType) {
-        if (targetType.isVoid()) {
+    private boolean isExecuteChildShared(NodeExecutionData execution, TypeMirror targetType) {
+        if (isVoid(targetType)) {
             return false;
-        } else if (targetType.isGeneric()) {
+        } else if (isObject(targetType)) {
             return resolvePolymorphicExecutables(execution).size() >= 1;
         } else {
             if (!isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), targetType)) {
                 return false;
             }
-            if (!targetType.hasImplicitSourceTypes()) {
+            if (!typeSystem.hasImplicitSourceTypes(targetType)) {
                 return false;
             }
 
@@ -1841,25 +2076,26 @@
             for (SpecializationData specialization : node.getSpecializations()) {
                 List<Parameter> parameters = specialization.findByExecutionData(execution);
                 for (Parameter parameter : parameters) {
-                    if (targetType.equals(parameter.getTypeSystemType())) {
+                    if (targetType.equals(parameter.getType())) {
                         uses++;
                     }
                 }
             }
             if (uses > 1) {
-                return resolveSpecializedExecutables(execution, targetType.getImplicitSourceTypes(), options.implicitTypeBoxingOptimization()).size() > 1;
+                return resolveSpecializedExecutables(execution, typeSystem.lookupSourceTypes(targetType), options.implicitTypeBoxingOptimization()).size() > 1;
             } else {
                 return false;
             }
         }
     }
 
-    private CodeTree createAssignExecuteChild(NodeExecutionData execution, TypeData returnType, LocalVariable targetValue, LocalVariable shortCircuit, LocalContext currentValues) {
-        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        boolean hasUnexpected = hasUnexpectedResult(execution, targetValue.getType());
+    private CodeTree createAssignExecuteChild(CodeTreeBuilder parent, NodeExecutionData execution, ExecutableTypeData type, LocalVariable targetValue, LocalVariable shortCircuit,
+                    LocalContext currentValues) {
+        CodeTreeBuilder builder = parent.create();
+        boolean hasUnexpected = hasChildUnexpectedResult(execution, targetValue.getTypeMirror());
 
         CodeTree executeChild;
-        if (isExecuteChildShared(execution, targetValue.getType())) {
+        if (isExecuteChildShared(execution, targetValue.getTypeMirror())) {
             executeChild = createCallSharedExecuteChild(execution, targetValue, currentValues);
         } else {
             executeChild = createExecuteChild(execution, targetValue, currentValues, false);
@@ -1875,21 +2111,22 @@
         if (hasUnexpected) {
             builder.startCatchBlock(getType(UnexpectedResultException.class), "ex");
             LocalContext slowPathValues = currentValues.copy();
-
-            slowPathValues.setValue(execution, targetValue.makeGeneric().accessWith(CodeTreeBuilder.singleString("ex.getResult()")));
+            slowPathValues.setValue(execution, targetValue.makeGeneric(context).accessWith(CodeTreeBuilder.singleString("ex.getResult()")));
+
+            ExecutableTypeData delegateType = node.getGenericExecutableType(type);
             boolean found = false;
             for (NodeExecutionData otherExecution : node.getChildExecutions()) {
                 if (found) {
                     LocalVariable childEvaluatedValue = slowPathValues.createValue(otherExecution, genericType);
                     LocalVariable genericShortCircuit = resolveShortCircuit(null, otherExecution, slowPathValues);
-                    builder.tree(createAssignExecuteChild(otherExecution, genericType, childEvaluatedValue, genericShortCircuit, slowPathValues));
+                    builder.tree(createAssignExecuteChild(builder, otherExecution, delegateType, childEvaluatedValue, genericShortCircuit, slowPathValues));
                     slowPathValues.setValue(otherExecution, childEvaluatedValue);
                 } else {
                     // skip forward already evaluated
                     found = execution == otherExecution;
                 }
             }
-            builder.tree(createCallNext(returnType, slowPathValues));
+            builder.tree(createCallNext(builder, type, delegateType, slowPathValues));
             builder.end();
         }
 
@@ -1945,16 +2182,20 @@
     }
 
     private CodeTree createCallSharedExecuteChild(NodeExecutionData execution, LocalVariable targetValue, LocalContext currentValues) {
-        if (!isExecuteChildShared(execution, targetValue.getType())) {
+        if (!isExecuteChildShared(execution, targetValue.getTypeMirror())) {
             throw new AssertionError("Execute child not shared with method but called.");
         }
 
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
         builder.tree(targetValue.createReference()).string(" = ");
-        builder.startCall(executeChildMethodName(execution, targetValue.getType()));
-        builder.string(FRAME_VALUE);
-
-        CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetValue.getType());
+        builder.startCall(executeChildMethodName(execution, targetValue.getTypeMirror()));
+        if (currentValues.get(FRAME_VALUE) == null) {
+            builder.nullLiteral();
+        } else {
+            builder.string(FRAME_VALUE);
+        }
+
+        CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetValue.getTypeMirror());
         if (implicitProfile != null) {
             builder.string(implicitProfile.getName());
         }
@@ -1970,12 +2211,12 @@
 
         CodeTree assignment = createAssignmentStart(target, shared);
 
-        final Set<ExecutableTypeData> executableTypes = findSpecializedExecutableTypes(execution, target.getType());
+        final Set<ExecutableTypeData> executableTypes = findSpecializedExecutableTypes(execution, target.getTypeMirror());
         if (executableTypes.isEmpty()) {
             throw new AssertionError(); // cannot execute child
-        } else if (executableTypes.size() == 1 && !target.getType().hasImplicitSourceTypes()) {
+        } else if (executableTypes.size() == 1 && !typeSystem.hasImplicitSourceTypes(target.getTypeMirror())) {
             ExecutableTypeData executableType = executableTypes.iterator().next();
-            if (target.getType().isGeneric() && executableType.getEvaluatedCount() == 0) {
+            if (isObject(target.getTypeMirror()) && executableType.getEvaluatedCount() == 0) {
                 return createPolymorphicExecuteChild(execution, target, currentValues, shared);
             } else {
                 builder.tree(assignment);
@@ -1997,9 +2238,8 @@
     }
 
     private CodeTree createSingleExecute(NodeExecutionData execution, LocalVariable target, LocalContext currentValues, ExecutableTypeData executableType) {
-        CodeTree accessChild = accessParent(nodeFieldName(execution));
-        CodeTree execute = callTemplateMethod(accessChild, executableType, currentValues);
-        return TypeSystemCodeGenerator.expect(executableType.getType(), target.getType(), execute);
+        CodeTree execute = callExecuteMethod(execution, executableType, currentValues);
+        return expect(executableType.getReturnType(), target.getTypeMirror(), execute);
     }
 
     private CodeTree createPolymorphicExecuteChild(NodeExecutionData execution, LocalVariable target, LocalContext currentValues, boolean shared) throws AssertionError {
@@ -2011,7 +2251,7 @@
         List<ExecutableTypeData> specializedExecutables = resolvePolymorphicExecutables(execution);
         Collections.sort(specializedExecutables, new Comparator<ExecutableTypeData>() {
             public int compare(ExecutableTypeData o1, ExecutableTypeData o2) {
-                return o1.getType().compareTo(o2.getType());
+                return compareType(o1.getReturnType(), o2.getReturnType());
             }
         });
 
@@ -2034,7 +2274,7 @@
             for (ExecutableTypeData executableType : specializedExecutables) {
                 hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes);
                 polyChainBuilder.string(profileField);
-                polyChainBuilder.string(" == ").typeLiteral(executableType.getType().getPrimitiveType());
+                polyChainBuilder.string(" == ").typeLiteral(executableType.getReturnType());
                 polyChainBuilder.end();
                 polyChainBuilder.startBlock();
                 polyChainBuilder.startStatement();
@@ -2048,20 +2288,20 @@
             polyChainBuilder.startElseIf().string(profileField).string(" == null").end();
             polyChainBuilder.startBlock();
             polyChainBuilder.tree(createTransferToInterpreterAndInvalidate());
-            polyChainBuilder.declaration(genericExecutableType.getType().getPrimitiveType(), valueFieldName, executeGeneric);
+            polyChainBuilder.declaration(genericExecutableType.getReturnType(), valueFieldName, executeGeneric);
 
             hasSpecializedTypes = false;
             for (ExecutableTypeData executableType : specializedExecutables) {
                 hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes);
-                polyChainBuilder.tree(TypeSystemCodeGenerator.check(executableType.getType(), CodeTreeBuilder.singleString(valueFieldName)));
+                polyChainBuilder.tree(TypeSystemCodeGenerator.check(typeSystem, executableType.getReturnType(), CodeTreeBuilder.singleString(valueFieldName)));
                 polyChainBuilder.end();
                 polyChainBuilder.startBlock();
-                polyChainBuilder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(executableType.getType().getPrimitiveType()).end();
+                polyChainBuilder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(executableType.getReturnType()).end();
                 polyChainBuilder.end();
             }
 
             polyChainBuilder.startElseBlock();
-            polyChainBuilder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(genericType.getPrimitiveType()).end();
+            polyChainBuilder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(genericType).end();
             polyChainBuilder.end();
             polyChainBuilder.startReturn().string(valueFieldName).end();
             polyChainBuilder.end();
@@ -2077,7 +2317,7 @@
                 builder.tree(executePolymorphic);
                 builder.end();
                 builder.startCatchBlock(getType(UnexpectedResultException.class), "ex");
-                builder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(genericType.getPrimitiveType()).end();
+                builder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(genericType).end();
                 builder.startReturn().string("ex.getResult()").end();
                 builder.end();
             } else {
@@ -2091,9 +2331,9 @@
         if (singleSpecializable) {
             return Collections.emptyList();
         }
-        Set<TypeData> specializedTypes = new HashSet<>();
-        for (TypeData type : node.findSpecializedTypes(execution)) {
-            specializedTypes.addAll(type.getImplicitSourceTypes());
+        Set<TypeMirror> specializedTypes = new HashSet<>();
+        for (TypeMirror type : node.findSpecializedTypes(execution)) {
+            specializedTypes.addAll(typeSystem.lookupSourceTypes(type));
         }
         return resolveSpecializedExecutables(execution, specializedTypes, options.polymorphicTypeBoxingElimination());
     }
@@ -2110,23 +2350,22 @@
 
     private CodeTree createExecuteChildDuplicateTail(CodeTreeBuilder parent, NodeExecutionData execution, CodeTree assignment, LocalVariable target, LocalContext currentValues) {
         CodeTreeBuilder builder = parent.create();
-        List<TypeData> sourceTypes = target.getType().getImplicitSourceTypes();
+        List<TypeMirror> sourceTypes = typeSystem.lookupSourceTypes(target.getTypeMirror());
         String implicitClassFieldName = implicitClassFieldName(execution);
-        String nodeFieldName = nodeFieldName(execution);
         List<ExecutableTypeData> executableTypes = resolveSpecializedExecutables(execution, sourceTypes, options.implicitTypeBoxingOptimization());
 
         boolean elseIf = false;
         for (ExecutableTypeData executableType : executableTypes) {
             elseIf = builder.startIf(elseIf);
-            builder.string(implicitClassFieldName).string(" == ").typeLiteral(executableType.getType().getPrimitiveType());
+            builder.string(implicitClassFieldName).string(" == ").typeLiteral(executableType.getReturnType());
             builder.end();
             builder.startBlock();
             builder.startStatement().tree(assignment);
 
-            CodeTree execute = callTemplateMethod(accessParent(nodeFieldName), executableType, currentValues);
-            ImplicitCastData cast = typeSystem.lookupCast(executableType.getType(), target.getType());
+            CodeTree execute = callExecuteMethod(execution, executableType, currentValues);
+            ImplicitCastData cast = typeSystem.lookupCast(executableType.getReturnType(), target.getTypeMirror());
             if (cast != null) {
-                execute = callTemplateMethod(null, cast, execute);
+                execute = callMethod(null, cast.getMethod(), execute);
             }
             builder.tree(execute);
             builder.end();
@@ -2137,13 +2376,13 @@
             builder.startElseBlock();
         }
 
-        LocalVariable genericValue = target.makeGeneric().nextName();
-        builder.tree(createAssignExecuteChild(execution, genericValue.getType(), genericValue, null, currentValues));
+        LocalVariable genericValue = target.makeGeneric(context).nextName();
+        builder.tree(createAssignExecuteChild(builder, execution, node.getGenericExecutableType(null), genericValue, null, currentValues));
         if (executableTypes.size() == sourceTypes.size()) {
             builder.startThrow().startNew(getType(UnexpectedResultException.class)).tree(genericValue.createReference()).end().end();
         } else {
             builder.startStatement().tree(assignment);
-            builder.tree(TypeSystemCodeGenerator.implicitExpect(target.getType(), genericValue.createReference(), implicitClassFieldName));
+            builder.tree(TypeSystemCodeGenerator.implicitExpect(typeSystem, target.getTypeMirror(), genericValue.createReference(), implicitClassFieldName));
             builder.end();
         }
 
@@ -2153,7 +2392,7 @@
         return builder.build();
     }
 
-    private CodeTree createFastPathTryCatchRewriteException(SpecializationData specialization, TypeData forType, LocalContext currentValues, CodeTree execution) {
+    private CodeTree createFastPathTryCatchRewriteException(SpecializationData specialization, ExecutableTypeData forType, LocalContext currentValues, CodeTree execution) {
         if (specialization.getExceptions().isEmpty()) {
             return execution;
         }
@@ -2248,8 +2487,8 @@
         for (TypeGuard typeGuard : typeGuards) {
             int signatureIndex = typeGuard.getSignatureIndex();
             LocalVariable value = currentValues.getValue(signatureIndex);
-            TypeData targetType = typeGuard.getType();
-            if (!value.getType().needsCastTo(targetType)) {
+            TypeMirror targetType = typeGuard.getType();
+            if (!ElementUtils.needsCastTo(value.getTypeMirror(), targetType)) {
                 continue;
             }
             NodeExecutionData execution = node.getChildExecutions().get(signatureIndex);
@@ -2264,7 +2503,7 @@
             if (shortCircuit != null) {
                 checkBuilder.string("(");
                 CodeTreeBuilder referenceBuilder = checkBuilder.create();
-                if (!shortCircuit.getType().isPrimitive()) {
+                if (!ElementUtils.isPrimitive(shortCircuit.getTypeMirror())) {
                     referenceBuilder.string("(boolean) ");
                 }
                 referenceBuilder.tree(shortCircuit.createReference());
@@ -2276,15 +2515,15 @@
             List<ImplicitCastData> sourceTypes = typeSystem.lookupByTargetType(targetType);
             CodeTree valueReference = value.createReference();
             if (sourceTypes.isEmpty()) {
-                checkBuilder.tree(TypeSystemCodeGenerator.check(targetType, value.createReference()));
-                castBuilder.tree(TypeSystemCodeGenerator.cast(targetType, valueReference));
+                checkBuilder.tree(TypeSystemCodeGenerator.check(typeSystem, targetType, value.createReference()));
+                castBuilder.tree(TypeSystemCodeGenerator.cast(typeSystem, targetType, valueReference));
             } else {
                 ImplicitCastOptimization opt = options.implicitCastOptimization();
                 if (specializationExecution.isFastPath() && !opt.isNone()) {
                     if (opt.isDuplicateTail()) {
                         String typeHintField = implicitClassFieldName(execution);
-                        checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(targetType, valueReference, typeHintField));
-                        castBuilder.tree(TypeSystemCodeGenerator.implicitCast(targetType, valueReference, typeHintField));
+                        checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(typeSystem, targetType, valueReference, typeHintField));
+                        castBuilder.tree(TypeSystemCodeGenerator.implicitCast(typeSystem, targetType, valueReference, typeHintField));
                     } else if (opt.isMergeCasts()) {
                         checkBuilder.tree(ImplicitCastNodeFactory.check(implicitNodeFieldName(execution), valueReference));
                         castBuilder.tree(ImplicitCastNodeFactory.cast(implicitNodeFieldName(execution), valueReference));
@@ -2292,14 +2531,14 @@
                         throw new AssertionError("implicit cast opt");
                     }
                 } else {
-                    checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(targetType, valueReference, null));
-                    castBuilder.tree(TypeSystemCodeGenerator.implicitCast(targetType, valueReference, null));
+                    checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(typeSystem, targetType, valueReference, null));
+                    castBuilder.tree(TypeSystemCodeGenerator.implicitCast(typeSystem, targetType, valueReference, null));
                 }
             }
 
             if (shortCircuit != null) {
                 checkBuilder.string(")");
-                castBuilder.string(" : ").defaultValue(targetType.getPrimitiveType());
+                castBuilder.string(" : ").defaultValue(targetType);
             }
 
             if (castGuards == null || castGuards.contains(typeGuard)) {
@@ -2329,7 +2568,7 @@
         String varName = name + specialization.getIndex();
         TypeMirror type = cache.getParameter().getType();
         builder.declaration(type, varName, initializer);
-        currentValues.set(name, new LocalVariable(null, type, varName, null, null));
+        currentValues.set(name, new LocalVariable(type, varName, null, null));
     }
 
     public static final class LocalContext {
@@ -2345,13 +2584,13 @@
             for (CacheExpression cache : specialization.getCaches()) {
                 Parameter cacheParameter = cache.getParameter();
                 String name = cacheParameter.getVariableElement().getSimpleName().toString();
-                set(cacheParameter.getLocalName(), new LocalVariable(cacheParameter.getTypeSystemType(), cacheParameter.getType(), name, CodeTreeBuilder.singleString("this." + name), null));
+                set(cacheParameter.getLocalName(), new LocalVariable(cacheParameter.getType(), name, CodeTreeBuilder.singleString("this." + name), null));
             }
 
             for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) {
                 String name = assumptionName(assumption);
                 TypeMirror type = assumption.getExpression().getResolvedType();
-                set(name, new LocalVariable(null, type, name, CodeTreeBuilder.singleString("this." + name), null));
+                set(name, new LocalVariable(type, name, CodeTreeBuilder.singleString("this." + name), null));
             }
         }
 
@@ -2382,12 +2621,12 @@
         }
 
         @SuppressWarnings("static-method")
-        public LocalVariable createValue(NodeExecutionData execution, TypeData type) {
-            return new LocalVariable(type, type.getPrimitiveType(), valueName(execution), null, null);
+        public LocalVariable createValue(NodeExecutionData execution, TypeMirror type) {
+            return new LocalVariable(type, valueName(execution), null, null);
         }
 
         public LocalVariable createShortCircuitValue(NodeExecutionData execution) {
-            return new LocalVariable(factory.typeSystem.getBooleanType(), factory.getType(boolean.class), shortCircuitName(execution), null, null);
+            return new LocalVariable(factory.getType(boolean.class), shortCircuitName(execution), null, null);
         }
 
         private static String valueName(NodeExecutionData execution) {
@@ -2424,7 +2663,12 @@
         }
 
         public LocalVariable getValue(int signatureIndex) {
-            return getValue(factory.node.getChildExecutions().get(signatureIndex));
+            List<NodeExecutionData> childExecutions = factory.node.getChildExecutions();
+            if (signatureIndex < childExecutions.size()) {
+                return getValue(childExecutions.get(signatureIndex));
+            } else {
+                return null;
+            }
         }
 
         public void removeValue(String id) {
@@ -2458,11 +2702,11 @@
         }
 
         private void loadValues(int evaluatedArguments, int varargsThreshold) {
-            values.put(FRAME_VALUE, new LocalVariable(null, factory.getType(Frame.class), FRAME_VALUE, null, null));
+            values.put(FRAME_VALUE, new LocalVariable(factory.getType(Frame.class), FRAME_VALUE, null, null));
 
             for (NodeFieldData field : factory.node.getFields()) {
                 String fieldName = fieldValueName(field);
-                values.put(fieldName, new LocalVariable(null, field.getType(), fieldName, factory.accessParent(field.getName()), null));
+                values.put(fieldName, new LocalVariable(field.getType(), fieldName, factory.accessParent(field.getName()), null));
             }
 
             boolean varargs = needsVarargs(false, varargsThreshold);
@@ -2473,7 +2717,7 @@
                 }
                 NodeExecutionData execution = childExecutions.get(i);
                 if (execution.isShortCircuit()) {
-                    LocalVariable shortCircuit = createShortCircuitValue(execution).makeGeneric();
+                    LocalVariable shortCircuit = createShortCircuitValue(execution).makeGeneric(factory.context);
                     if (varargs) {
                         shortCircuit = shortCircuit.accessWith(createReadVarargs(i));
                     }
@@ -2562,7 +2806,6 @@
 
     public static final class LocalVariable {
 
-        private final TypeData type;
         private final TypeMirror typeMirror;
         private final CodeTree accessorTree;
         private final String name;
@@ -2576,22 +2819,17 @@
             } else {
                 name = createName(execution);
             }
-            return new LocalVariable(parameter.getTypeSystemType(), parameter.getType(), name, null, null);
+            return new LocalVariable(parameter.getType(), name, null, null);
         }
 
-        private LocalVariable(TypeData type, TypeMirror typeMirror, String name, CodeTree accessorTree, LocalVariable previous) {
+        private LocalVariable(TypeMirror typeMirror, String name, CodeTree accessorTree, LocalVariable previous) {
             Objects.requireNonNull(typeMirror);
             this.typeMirror = typeMirror;
             this.accessorTree = accessorTree;
-            this.type = type;
             this.name = name;
             this.previous = previous;
         }
 
-        public TypeData getType() {
-            return type;
-        }
-
         public String getShortCircuitName() {
             return "has" + ElementUtils.firstLetterUpperCase(getName());
         }
@@ -2631,24 +2869,20 @@
             }
         }
 
-        public LocalVariable newType(TypeData newType) {
-            return new LocalVariable(newType, newType.getPrimitiveType(), name, accessorTree, this);
-        }
-
         public LocalVariable newType(TypeMirror newType) {
-            return new LocalVariable(type, newType, name, accessorTree, this);
+            return new LocalVariable(newType, name, accessorTree, this);
         }
 
         public LocalVariable accessWith(CodeTree tree) {
-            return new LocalVariable(type, typeMirror, name, tree, this);
+            return new LocalVariable(typeMirror, name, tree, this);
         }
 
         public LocalVariable nextName() {
-            return new LocalVariable(type, typeMirror, createNextName(name), accessorTree, this);
+            return new LocalVariable(typeMirror, createNextName(name), accessorTree, this);
         }
 
         public LocalVariable makeOriginal() {
-            return new LocalVariable(type, typeMirror, name, accessorTree, null);
+            return new LocalVariable(typeMirror, name, accessorTree, null);
         }
 
         public LocalVariable original() {
@@ -2659,8 +2893,8 @@
             return variable;
         }
 
-        public LocalVariable makeGeneric() {
-            return newType(type.getTypeSystem().getGenericTypeData());
+        public LocalVariable makeGeneric(ProcessorContext context) {
+            return newType(context.getType(Object.class));
         }
 
         @Override
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java	Wed Apr 15 11:03:04 2015 -0700
@@ -22,12 +22,13 @@
  */
 package com.oracle.truffle.dsl.processor.generator;
 
+import static com.oracle.truffle.dsl.processor.generator.GeneratorUtils.*;
 import static com.oracle.truffle.dsl.processor.java.ElementUtils.*;
-import static com.oracle.truffle.dsl.processor.generator.GeneratorUtils.*;
 import static javax.lang.model.element.Modifier.*;
 
 import java.util.*;
 
+import javax.lang.model.element.*;
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.api.nodes.*;
@@ -38,64 +39,47 @@
 
 public class TypeSystemCodeGenerator extends CodeTypeElementFactory<TypeSystemData> {
 
-    public static CodeTree cast(TypeData type, String content) {
-        return cast(type, CodeTreeBuilder.singleString(content));
+    private static final String LOCAL_VALUE = "value";
+
+    public static CodeTree cast(TypeSystemData typeSystem, TypeMirror type, String content) {
+        return cast(typeSystem, type, CodeTreeBuilder.singleString(content));
     }
 
-    public static CodeTree implicitType(TypeData type, CodeTree value) {
-        if (type.isGeneric()) {
+    public static CodeTree implicitType(TypeSystemData typeSystem, TypeMirror type, CodeTree value) {
+        if (ElementUtils.isObject(type)) {
             return value;
         }
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        TypeSystemData typeSystem = type.getTypeSystem();
-        builder.startStaticCall(createTypeSystemGen(typeSystem), getImplicitClass(type)).tree(value);
+        builder.startStaticCall(createTypeSystemGen(typeSystem), getImplicitClass(typeSystem, type)).tree(value);
         builder.end();
         return builder.build();
     }
 
-    public static CodeTree invokeImplicitCast(ImplicitCastData cast, CodeTree expression) {
+    public static CodeTree invokeImplicitCast(TypeSystemData typeSystem, ImplicitCastData cast, CodeTree expression) {
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        TypeSystemData typeSystem = cast.getTargetType().getTypeSystem();
         builder.startStaticCall(createTypeSystemGen(typeSystem), cast.getMethodName()).tree(expression);
         builder.end();
         return builder.build();
     }
 
-    public static CodeTree implicitCheck(TypeData type, CodeTree value, String typeHint) {
-        if (type.isGeneric()) {
+    public static CodeTree implicitCheck(TypeSystemData typeSystem, TypeMirror type, CodeTree value, String typeHint) {
+        return callImplictMethod(typeSystem, type, isImplicitTypeMethodName(typeSystem, type), value, typeHint);
+    }
+
+    public static CodeTree implicitExpect(TypeSystemData typeSystem, TypeMirror type, CodeTree value, String typeHint) {
+        return callImplictMethod(typeSystem, type, expectImplicitTypeMethodName(typeSystem, type), value, typeHint);
+    }
+
+    public static CodeTree implicitCast(TypeSystemData typeSystem, TypeMirror type, CodeTree value, String typeHint) {
+        return callImplictMethod(typeSystem, type, asImplicitTypeMethodName(typeSystem, type), value, typeHint);
+    }
+
+    private static CodeTree callImplictMethod(TypeSystemData typeSystem, TypeMirror type, String methodName, CodeTree value, String typeHint) {
+        if (ElementUtils.isObject(type)) {
             return value;
         }
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        TypeSystemData typeSystem = type.getTypeSystem();
-        builder.startStaticCall(createTypeSystemGen(typeSystem), isImplicitTypeMethodName(type)).tree(value);
-        if (typeHint != null) {
-            builder.string(typeHint);
-        }
-        builder.end();
-        return builder.build();
-    }
-
-    public static CodeTree implicitExpect(TypeData type, CodeTree value, String typeHint) {
-        if (type.isGeneric()) {
-            return value;
-        }
-        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        TypeSystemData typeSystem = type.getTypeSystem();
-        builder.startStaticCall(createTypeSystemGen(typeSystem), expectImplicitTypeMethodName(type)).tree(value);
-        if (typeHint != null) {
-            builder.string(typeHint);
-        }
-        builder.end();
-        return builder.build();
-    }
-
-    public static CodeTree implicitCast(TypeData type, CodeTree value, String typeHint) {
-        if (type.isGeneric()) {
-            return value;
-        }
-        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        TypeSystemData typeSystem = type.getTypeSystem();
-        builder.startStaticCall(createTypeSystemGen(typeSystem), asImplicitTypeMethodName(type)).tree(value);
+        builder.startStaticCall(createTypeSystemGen(typeSystem), methodName).tree(value);
         if (typeHint != null) {
             builder.string(typeHint);
         }
@@ -103,36 +87,60 @@
         return builder.build();
     }
 
-    public static CodeTree cast(TypeData type, CodeTree content) {
-        if (type.isGeneric()) {
+    public static CodeTree cast(TypeSystemData typeSystem, TypeMirror type, CodeTree content) {
+        if (ElementUtils.isObject(type)) {
             return content;
         }
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        TypeSystemData typeSystem = type.getTypeSystem();
 
-        if (type.isDefaultCast()) {
-            builder.cast(type.getPrimitiveType(), content);
+        TypeCastData cast = typeSystem.getCast(type);
+        if (cast == null) {
+            builder.cast(ElementUtils.fillInGenericWildcards(type), content);
         } else {
-            builder.startStaticCall(typeSystem.getTemplateType().asType(), type.getTypeCasts().get(0).getMethodName()).tree(content).end();
+            builder.startStaticCall(typeSystem.getTemplateType().asType(), cast.getMethodName()).tree(content).end();
         }
         return builder.build();
     }
 
-    public static CodeTree expect(TypeData type, CodeTree content) {
-        if (type.isGeneric() || type.isVoid()) {
+    public static CodeTree expect(TypeSystemData typeSystem, TypeMirror type, CodeTree content) {
+        if (ElementUtils.isObject(type) || ElementUtils.isVoid(type)) {
             return content;
         }
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        TypeSystemData typeSystem = type.getTypeSystem();
-        builder.startStaticCall(createTypeSystemGen(typeSystem), expectTypeMethodName(type)).tree(content).end();
+        if (typeSystem.hasType(type)) {
+            builder.startStaticCall(createTypeSystemGen(typeSystem), expectTypeMethodName(typeSystem, type)).tree(content).end();
+        } else {
+            builder.startCall(expectTypeMethodName(typeSystem, type)).tree(content).end();
+        }
+
         return builder.build();
     }
 
-    public static CodeTree expect(TypeData sourceType, TypeData targetType, CodeTree content) {
-        if (sourceType != null && !sourceType.needsCastTo(targetType)) {
+    public static CodeExecutableElement createExpectMethod(Modifier visibility, TypeSystemData typeSystem, TypeMirror sourceTypeOriginal, TypeMirror expectedTypeOriginal) {
+        TypeMirror expectedType = ElementUtils.fillInGenericWildcards(expectedTypeOriginal);
+        TypeMirror sourceType = ElementUtils.fillInGenericWildcards(sourceTypeOriginal);
+        if (ElementUtils.isObject(expectedType) || ElementUtils.isVoid(expectedType)) {
+            return null;
+        }
+
+        CodeExecutableElement method = new CodeExecutableElement(modifiers(STATIC), expectedType, TypeSystemCodeGenerator.expectTypeMethodName(typeSystem, expectedType));
+        method.setVisibility(visibility);
+        method.addParameter(new CodeVariableElement(sourceType, LOCAL_VALUE));
+        method.addThrownType(typeSystem.getContext().getTruffleTypes().getUnexpectedValueException());
+
+        CodeTreeBuilder body = method.createBuilder();
+        body.startIf().tree(check(typeSystem, expectedType, LOCAL_VALUE)).end().startBlock();
+        body.startReturn().tree(cast(typeSystem, expectedType, LOCAL_VALUE)).end();
+        body.end();
+        body.startThrow().startNew(typeSystem.getContext().getTruffleTypes().getUnexpectedValueException()).string(LOCAL_VALUE).end().end();
+        return method;
+    }
+
+    public static CodeTree expect(TypeSystemData typeSystem, TypeMirror sourceType, TypeMirror targetType, CodeTree content) {
+        if (sourceType != null && !ElementUtils.needsCastTo(sourceType, targetType)) {
             return content;
         } else {
-            return expect(targetType, content);
+            return expect(typeSystem, targetType, content);
         }
     }
 
@@ -140,51 +148,55 @@
         return new GeneratedTypeMirror(ElementUtils.getPackageName(typeSystem.getTemplateType()), typeName(typeSystem));
     }
 
-    public static CodeTree check(TypeData type, String content) {
-        return check(type, CodeTreeBuilder.singleString(content));
+    public static CodeTree check(TypeSystemData typeSystem, TypeMirror type, String content) {
+        return check(typeSystem, type, CodeTreeBuilder.singleString(content));
     }
 
-    public static CodeTree check(TypeData type, CodeTree content) {
-        if (type.isGeneric()) {
+    public static CodeTree check(TypeSystemData typeSystem, TypeMirror type, CodeTree content) {
+        if (ElementUtils.isObject(type)) {
             return content;
         }
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        TypeSystemData typeSystem = type.getTypeSystem();
 
-        if (type.isDefaultCheck()) {
-            builder.instanceOf(content, type.getBoxedType());
+        TypeCheckData check = typeSystem.getCheck(type);
+        if (check == null) {
+            builder.instanceOf(content, ElementUtils.boxType(typeSystem.getContext(), type));
         } else {
-            builder.startStaticCall(typeSystem.getTemplateType().asType(), type.getTypeChecks().get(0).getMethodName()).tree(content).end();
+            builder.startStaticCall(typeSystem.getTemplateType().asType(), check.getMethodName()).tree(content).end();
         }
         return builder.build();
     }
 
-    public static String isTypeMethodName(TypeData type) {
-        return "is" + ElementUtils.getTypeId(type.getBoxedType());
+    public static String isTypeMethodName(TypeSystemData typeSystem, TypeMirror type) {
+        return "is" + getTypeId(typeSystem, type);
     }
 
-    static String isImplicitTypeMethodName(TypeData type) {
-        return "isImplicit" + ElementUtils.getTypeId(type.getBoxedType());
+    private static String getTypeId(TypeSystemData typeSystem, TypeMirror type) {
+        return ElementUtils.getTypeId(typeSystem.boxType(type));
     }
 
-    public static String asTypeMethodName(TypeData type) {
-        return "as" + ElementUtils.getTypeId(type.getBoxedType());
+    static String isImplicitTypeMethodName(TypeSystemData typeSystem, TypeMirror type) {
+        return "isImplicit" + getTypeId(typeSystem, type);
     }
 
-    static String asImplicitTypeMethodName(TypeData type) {
-        return "asImplicit" + ElementUtils.getTypeId(type.getBoxedType());
+    public static String asTypeMethodName(TypeSystemData typeSystem, TypeMirror type) {
+        return "as" + getTypeId(typeSystem, type);
+    }
+
+    static String asImplicitTypeMethodName(TypeSystemData typeSystem, TypeMirror type) {
+        return "asImplicit" + getTypeId(typeSystem, type);
     }
 
-    static String expectImplicitTypeMethodName(TypeData type) {
-        return "expectImplicit" + ElementUtils.getTypeId(type.getBoxedType());
+    static String expectImplicitTypeMethodName(TypeSystemData typeSystem, TypeMirror type) {
+        return "expectImplicit" + getTypeId(typeSystem, type);
     }
 
-    static String getImplicitClass(TypeData type) {
-        return "getImplicit" + ElementUtils.getTypeId(type.getBoxedType()) + "Class";
+    static String getImplicitClass(TypeSystemData typeSystem, TypeMirror type) {
+        return "getImplicit" + getTypeId(typeSystem, type) + "Class";
     }
 
-    public static String expectTypeMethodName(TypeData type) {
-        return "expect" + ElementUtils.getTypeId(type.getBoxedType());
+    public static String expectTypeMethodName(TypeSystemData typeSystem, TypeMirror type) {
+        return "expect" + getTypeId(typeSystem, type);
     }
 
     static String typeName(TypeSystemData typeSystem) {
@@ -200,14 +212,9 @@
     public CodeTypeElement create(ProcessorContext context, TypeSystemData typeSystem) {
         CodeTypeElement clazz = new TypeClassFactory(context, typeSystem).create();
 
-        clazz.add(new TypeSystemNodeFactory(context, typeSystem).create());
-
         if (typeSystem.getOptions().implicitCastOptimization().isMergeCasts()) {
-            for (TypeData type : typeSystem.getTypes()) {
-                List<TypeData> sourceTypes = typeSystem.lookupSourceTypes(type);
-                if (sourceTypes.size() > 1) {
-                    clazz.add(new ImplicitCastNodeFactory(context, type).create());
-                }
+            for (TypeMirror type : typeSystem.lookupTargetTypes()) {
+                clazz.add(new ImplicitCastNodeFactory(context, typeSystem, type).create());
             }
         }
         return clazz;
@@ -215,8 +222,6 @@
 
     private static class TypeClassFactory {
 
-        private static final String LOCAL_VALUE = "value";
-
         private final ProcessorContext context;
         private final TypeSystemData typeSystem;
 
@@ -233,50 +238,35 @@
             CodeVariableElement singleton = createSingleton(clazz);
             clazz.add(singleton);
 
-            for (TypeData type : typeSystem.getTypes()) {
-                if (type.isVoid() || type.isGeneric()) {
+            for (TypeMirror type : typeSystem.getLegacyTypes()) {
+                if (ElementUtils.isVoid(type) || ElementUtils.isObject(type)) {
                     continue;
                 }
 
                 clazz.addOptional(createIsTypeMethod(type));
                 clazz.addOptional(createAsTypeMethod(type));
+                clazz.addOptional(createExpectTypeMethod(type, context.getType(Object.class)));
 
-                for (TypeData sourceType : collectExpectSourceTypes(type)) {
-                    clazz.addOptional(createExpectTypeMethod(type, sourceType));
-                }
+            }
 
-                if (type.hasImplicitSourceTypes()) {
-                    clazz.add(createAsImplicitTypeMethod(type, false));
-                    if (typeSystem.getOptions().implicitCastOptimization().isNone()) {
-                        clazz.add(createExpectImplicitTypeMethod(type, false));
-                    }
-                    clazz.add(createIsImplicitTypeMethod(type, false));
+            List<TypeMirror> lookupTargetTypes = typeSystem.lookupTargetTypes();
+            for (TypeMirror type : lookupTargetTypes) {
+                clazz.add(createAsImplicitTypeMethod(type, false));
+                if (typeSystem.getOptions().implicitCastOptimization().isNone()) {
+                    clazz.add(createExpectImplicitTypeMethod(type, false));
+                }
+                clazz.add(createIsImplicitTypeMethod(type, false));
 
-                    if (typeSystem.getOptions().implicitCastOptimization().isDuplicateTail()) {
-                        clazz.add(createAsImplicitTypeMethod(type, true));
-                        clazz.add(createExpectImplicitTypeMethod(type, true));
-                        clazz.add(createIsImplicitTypeMethod(type, true));
-                        clazz.add(createGetImplicitClass(type));
-                    }
+                if (typeSystem.getOptions().implicitCastOptimization().isDuplicateTail()) {
+                    clazz.add(createAsImplicitTypeMethod(type, true));
+                    clazz.add(createExpectImplicitTypeMethod(type, true));
+                    clazz.add(createIsImplicitTypeMethod(type, true));
+                    clazz.add(createGetImplicitClass(type));
                 }
             }
-
             return clazz;
         }
 
-        private static List<TypeData> collectExpectSourceTypes(TypeData type) {
-            Set<TypeData> sourceTypes = new HashSet<>();
-            sourceTypes.add(type.getTypeSystem().getGenericTypeData());
-            for (TypeCastData cast : type.getTypeCasts()) {
-                sourceTypes.add(cast.getSourceType());
-            }
-            for (TypeCheckData cast : type.getTypeChecks()) {
-                sourceTypes.add(cast.getCheckedType());
-            }
-            sourceTypes.remove(type);
-            return new ArrayList<>(sourceTypes);
-        }
-
         private CodeVariableElement createSingleton(CodeTypeElement clazz) {
             CodeVariableElement field = new CodeVariableElement(modifiers(PUBLIC, STATIC, FINAL), clazz.asType(), singletonName(typeSystem));
             field.createInitBuilder().startNew(clazz.asType()).end();
@@ -287,24 +277,24 @@
             return field;
         }
 
-        private CodeExecutableElement createIsImplicitTypeMethod(TypeData type, boolean typed) {
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), context.getType(boolean.class), TypeSystemCodeGenerator.isImplicitTypeMethodName(type));
+        private CodeExecutableElement createIsImplicitTypeMethod(TypeMirror type, boolean typed) {
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), context.getType(boolean.class), TypeSystemCodeGenerator.isImplicitTypeMethodName(typeSystem, type));
             method.addParameter(new CodeVariableElement(context.getType(Object.class), LOCAL_VALUE));
             if (typed) {
                 method.addParameter(new CodeVariableElement(context.getType(Class.class), "typeHint"));
             }
             CodeTreeBuilder builder = method.createBuilder();
 
-            List<TypeData> sourceTypes = typeSystem.lookupSourceTypes(type);
+            List<TypeMirror> sourceTypes = typeSystem.lookupSourceTypes(type);
 
             builder.startReturn();
             String sep = "";
-            for (TypeData sourceType : sourceTypes) {
+            for (TypeMirror sourceType : sourceTypes) {
                 builder.string(sep);
                 if (typed) {
-                    builder.string("(typeHint == ").typeLiteral(sourceType.getPrimitiveType()).string(" && ");
+                    builder.string("(typeHint == ").typeLiteral(sourceType).string(" && ");
                 }
-                builder.tree(check(sourceType, LOCAL_VALUE));
+                builder.tree(check(typeSystem, sourceType, LOCAL_VALUE));
                 if (typed) {
                     builder.string(")");
                 }
@@ -321,24 +311,24 @@
             return method;
         }
 
-        private CodeExecutableElement createAsImplicitTypeMethod(TypeData type, boolean useTypeHint) {
-            String name = asImplicitTypeMethodName(type);
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), type.getPrimitiveType(), name);
+        private CodeExecutableElement createAsImplicitTypeMethod(TypeMirror type, boolean useTypeHint) {
+            String name = asImplicitTypeMethodName(typeSystem, type);
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), type, name);
             method.addParameter(new CodeVariableElement(context.getType(Object.class), LOCAL_VALUE));
             if (useTypeHint) {
                 method.addParameter(new CodeVariableElement(context.getType(Class.class), "typeHint"));
             }
 
-            List<TypeData> sourceTypes = typeSystem.lookupSourceTypes(type);
+            List<TypeMirror> sourceTypes = typeSystem.lookupSourceTypes(type);
 
             CodeTreeBuilder builder = method.createBuilder();
             boolean elseIf = false;
-            for (TypeData sourceType : sourceTypes) {
+            for (TypeMirror sourceType : sourceTypes) {
                 elseIf = builder.startIf(elseIf);
                 if (useTypeHint) {
-                    builder.string("typeHint == ").typeLiteral(sourceType.getPrimitiveType());
+                    builder.string("typeHint == ").typeLiteral(sourceType);
                 } else {
-                    builder.tree(check(sourceType, LOCAL_VALUE));
+                    builder.tree(check(typeSystem, sourceType, LOCAL_VALUE));
                 }
 
                 builder.end().startBlock();
@@ -348,7 +338,7 @@
                 if (cast != null) {
                     builder.startCall(cast.getMethodName());
                 }
-                builder.tree(cast(sourceType, LOCAL_VALUE)).end();
+                builder.tree(cast(typeSystem, sourceType, LOCAL_VALUE)).end();
                 if (cast != null) {
                     builder.end();
                 }
@@ -363,26 +353,26 @@
             return method;
         }
 
-        private CodeExecutableElement createExpectImplicitTypeMethod(TypeData type, boolean useTypeHint) {
-            String name = expectImplicitTypeMethodName(type);
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), type.getPrimitiveType(), name);
+        private CodeExecutableElement createExpectImplicitTypeMethod(TypeMirror type, boolean useTypeHint) {
+            String name = expectImplicitTypeMethodName(typeSystem, type);
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), type, name);
             method.addParameter(new CodeVariableElement(context.getType(Object.class), LOCAL_VALUE));
             if (useTypeHint) {
                 method.addParameter(new CodeVariableElement(context.getType(Class.class), "typeHint"));
             }
             method.getThrownTypes().add(context.getType(UnexpectedResultException.class));
 
-            List<TypeData> sourceTypes = typeSystem.lookupSourceTypes(type);
+            List<TypeMirror> sourceTypes = typeSystem.lookupSourceTypes(type);
 
             CodeTreeBuilder builder = method.createBuilder();
             boolean elseIf = false;
-            for (TypeData sourceType : sourceTypes) {
+            for (TypeMirror sourceType : sourceTypes) {
                 elseIf = builder.startIf(elseIf);
                 if (useTypeHint) {
-                    builder.string("typeHint == ").typeLiteral(sourceType.getPrimitiveType());
+                    builder.string("typeHint == ").typeLiteral(sourceType);
                     builder.string(" && ");
                 }
-                builder.tree(check(sourceType, LOCAL_VALUE));
+                builder.tree(check(typeSystem, sourceType, LOCAL_VALUE));
 
                 builder.end().startBlock();
 
@@ -391,7 +381,7 @@
                 if (cast != null) {
                     builder.startCall(cast.getMethodName());
                 }
-                builder.tree(cast(sourceType, LOCAL_VALUE)).end();
+                builder.tree(cast(typeSystem, sourceType, LOCAL_VALUE)).end();
                 if (cast != null) {
                     builder.end();
                 }
@@ -405,18 +395,18 @@
             return method;
         }
 
-        private CodeExecutableElement createGetImplicitClass(TypeData type) {
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), context.getType(Class.class), TypeSystemCodeGenerator.getImplicitClass(type));
+        private CodeExecutableElement createGetImplicitClass(TypeMirror type) {
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), context.getType(Class.class), TypeSystemCodeGenerator.getImplicitClass(typeSystem, type));
             method.addParameter(new CodeVariableElement(context.getType(Object.class), LOCAL_VALUE));
 
-            List<TypeData> sourceTypes = typeSystem.lookupSourceTypes(type);
+            List<TypeMirror> sourceTypes = typeSystem.lookupSourceTypes(type);
             CodeTreeBuilder builder = method.createBuilder();
             boolean elseIf = false;
-            for (TypeData sourceType : sourceTypes) {
+            for (TypeMirror sourceType : sourceTypes) {
                 elseIf = builder.startIf(elseIf);
-                builder.tree(check(sourceType, LOCAL_VALUE)).end();
+                builder.tree(check(typeSystem, sourceType, LOCAL_VALUE)).end();
                 builder.end().startBlock();
-                builder.startReturn().typeLiteral(sourceType.getPrimitiveType()).end();
+                builder.startReturn().typeLiteral(sourceType).end();
                 builder.end();
             }
 
@@ -428,50 +418,39 @@
             return method;
         }
 
-        private CodeExecutableElement createIsTypeMethod(TypeData type) {
-            if (!type.getTypeChecks().isEmpty()) {
+        private CodeExecutableElement createIsTypeMethod(TypeMirror type) {
+            if (typeSystem.getCheck(type) != null) {
                 return null;
             }
 
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), context.getType(boolean.class), TypeSystemCodeGenerator.isTypeMethodName(type));
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), context.getType(boolean.class), TypeSystemCodeGenerator.isTypeMethodName(typeSystem, type));
             method.addParameter(new CodeVariableElement(context.getType(Object.class), LOCAL_VALUE));
 
             CodeTreeBuilder body = method.createBuilder();
-            body.startReturn().tree(check(type, LOCAL_VALUE)).end();
+            body.startReturn().tree(check(typeSystem, type, LOCAL_VALUE)).end();
 
             return method;
         }
 
-        private CodeExecutableElement createAsTypeMethod(TypeData type) {
-            if (!type.getTypeCasts().isEmpty()) {
+        private CodeExecutableElement createAsTypeMethod(TypeMirror type) {
+            if (typeSystem.getCast(type) != null) {
                 return null;
             }
 
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), type.getPrimitiveType(), TypeSystemCodeGenerator.asTypeMethodName(type));
+            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), type, TypeSystemCodeGenerator.asTypeMethodName(typeSystem, type));
             method.addParameter(new CodeVariableElement(context.getType(Object.class), LOCAL_VALUE));
 
             CodeTreeBuilder body = method.createBuilder();
-            String assertMessage = typeName(typeSystem) + "." + asTypeMethodName(type) + ": " + ElementUtils.getSimpleName(type.getBoxedType()) + " expected";
-            body.startAssert().tree(check(type, LOCAL_VALUE)).string(" : ").doubleQuote(assertMessage).end();
-            body.startReturn().tree(cast(type, LOCAL_VALUE)).end();
+            String assertMessage = typeName(typeSystem) + "." + asTypeMethodName(typeSystem, type) + ": " + ElementUtils.getSimpleName(type) + " expected";
+            body.startAssert().tree(check(typeSystem, type, LOCAL_VALUE)).string(" : ").doubleQuote(assertMessage).end();
+            body.startReturn().tree(cast(typeSystem, type, LOCAL_VALUE)).end();
 
             return method;
         }
 
-        private CodeExecutableElement createExpectTypeMethod(TypeData expectedType, TypeData sourceType) {
-            CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), expectedType.getPrimitiveType(), TypeSystemCodeGenerator.expectTypeMethodName(expectedType));
-            method.addParameter(new CodeVariableElement(sourceType.getPrimitiveType(), LOCAL_VALUE));
-            method.addThrownType(context.getTruffleTypes().getUnexpectedValueException());
-
-            CodeTreeBuilder body = method.createBuilder();
-            body.startIf().tree(check(expectedType, LOCAL_VALUE)).end().startBlock();
-            body.startReturn().tree(cast(expectedType, LOCAL_VALUE)).end().end();
-            body.end(); // if-block
-            body.startThrow().startNew(context.getTruffleTypes().getUnexpectedValueException()).string(LOCAL_VALUE).end().end();
-
-            return method;
+        private CodeExecutableElement createExpectTypeMethod(TypeMirror expectedType, TypeMirror sourceType) {
+            return createExpectMethod(Modifier.PUBLIC, typeSystem, sourceType, expectedType);
         }
-
     }
 
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemNodeFactory.java	Wed Apr 15 10:09:13 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,132 +0,0 @@
-/*
- * Copyright (c) 2014, 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.dsl.processor.generator;
-
-import static com.oracle.truffle.dsl.processor.java.ElementUtils.*;
-import static javax.lang.model.element.Modifier.*;
-
-import javax.lang.model.element.*;
-import javax.lang.model.type.*;
-import javax.lang.model.util.*;
-
-import com.oracle.truffle.api.dsl.internal.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.dsl.processor.*;
-import com.oracle.truffle.dsl.processor.java.*;
-import com.oracle.truffle.dsl.processor.java.model.*;
-import com.oracle.truffle.dsl.processor.model.*;
-
-public class TypeSystemNodeFactory {
-
-    private final ProcessorContext context;
-    private final TypeSystemData typeSystem;
-    private final DSLOptions options;
-
-    public TypeSystemNodeFactory(ProcessorContext context, TypeSystemData typeSystem) {
-        this.context = context;
-        this.typeSystem = typeSystem;
-        this.options = typeSystem.getOptions();
-    }
-
-    public static TypeMirror nodeType(TypeSystemData typeSystem) {
-        TypeMirror parentType = TypeSystemCodeGenerator.createTypeSystemGen(typeSystem);
-        return new GeneratedTypeMirror(getQualifiedName(parentType), typeName(typeSystem));
-    }
-
-    public static String typeName(TypeSystemData typeSystem) {
-        return getTypeId(typeSystem.getTemplateType().asType()) + "Node";
-    }
-
-    public static String acceptAndExecuteName() {
-        return "acceptAndExecute";
-    }
-
-    public static String executeName(TypeData type) {
-        if (type == null) {
-            return acceptAndExecuteName();
-        } else if (type.isGeneric()) {
-            return "executeGeneric";
-        } else {
-            return "execute" + getTypeId(type.getBoxedType());
-        }
-    }
-
-    public static String voidBoxingExecuteName(TypeData type) {
-        return executeName(type) + "Void";
-    }
-
-    public CodeTypeElement create() {
-        String typeName = typeName(typeSystem);
-        TypeMirror baseType = context.getType(SpecializationNode.class);
-        CodeTypeElement clazz = GeneratorUtils.createClass(typeSystem, null, modifiers(PUBLIC, ABSTRACT, STATIC), typeName, baseType);
-
-        for (ExecutableElement constructor : ElementFilter.constructorsIn(ElementUtils.fromTypeMirror(baseType).getEnclosedElements())) {
-            clazz.add(GeneratorUtils.createSuperConstructor(context, clazz, constructor));
-        }
-
-        for (TypeData type : typeSystem.getTypes()) {
-            clazz.add(createExecuteMethod(type));
-            if (GeneratorUtils.isTypeBoxingOptimized(options.voidBoxingOptimization(), type)) {
-                clazz.add(createVoidBoxingExecuteMethod(type));
-            }
-        }
-        return clazz;
-    }
-
-    private Element createVoidBoxingExecuteMethod(TypeData type) {
-        TypeData voidType = typeSystem.getVoidType();
-        String methodName = voidBoxingExecuteName(type);
-        CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), voidType.getPrimitiveType(), methodName);
-        method.addParameter(new CodeVariableElement(context.getType(Frame.class), "frame"));
-
-        CodeTreeBuilder builder = method.createBuilder();
-        builder.startTryBlock();
-        builder.startStatement().startCall(executeName(type)).string("frame").end().end();
-        builder.end();
-        builder.startCatchBlock(context.getType(UnexpectedResultException.class), "e");
-        builder.end();
-
-        return method;
-    }
-
-    private Element createExecuteMethod(TypeData type) {
-        TypeData genericType = typeSystem.getGenericTypeData();
-        String methodName = executeName(type);
-        CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), type.getPrimitiveType(), methodName);
-        method.addParameter(new CodeVariableElement(context.getType(Frame.class), "frame"));
-
-        if (type.isGeneric()) {
-            method.getModifiers().add(ABSTRACT);
-        } else {
-            CodeTreeBuilder builder = method.createBuilder();
-            CodeTree executeGeneric = builder.create().startCall(executeName(genericType)).string("frame").end().build();
-            if (!type.isVoid()) {
-                method.getThrownTypes().add(context.getType(UnexpectedResultException.class));
-            }
-            builder.startReturn().tree(TypeSystemCodeGenerator.expect(type, executeGeneric)).end();
-        }
-
-        return method;
-    }
-}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java	Wed Apr 15 11:03:04 2015 -0700
@@ -120,6 +120,9 @@
     }
 
     public static TypeMirror boxType(ProcessorContext context, TypeMirror primitiveType) {
+        if (primitiveType == null) {
+            return null;
+        }
         TypeMirror boxedType = primitiveType;
         if (boxedType.getKind().isPrimitive()) {
             boxedType = context.getEnvironment().getTypeUtils().boxedClass((PrimitiveType) boxedType).asType();
@@ -144,13 +147,14 @@
         return result;
     }
 
-    public static TypeMirror getCommonSuperType(ProcessorContext context, TypeMirror[] types) {
-        if (types.length == 0) {
+    public static TypeMirror getCommonSuperType(ProcessorContext context, Collection<TypeMirror> types) {
+        if (types.isEmpty()) {
             return context.getType(Object.class);
         }
-        TypeMirror prev = types[0];
-        for (int i = 1; i < types.length; i++) {
-            prev = getCommonSuperType(context, prev, types[i]);
+        Iterator<TypeMirror> typesIterator = types.iterator();
+        TypeMirror prev = typesIterator.next();
+        while (typesIterator.hasNext()) {
+            prev = getCommonSuperType(context, prev, typesIterator.next());
         }
         return prev;
     }
@@ -162,6 +166,11 @@
         TypeElement element1 = fromTypeMirror(type1);
         TypeElement element2 = fromTypeMirror(type2);
         if (element1 == null || element2 == null) {
+            if (element1 != null) {
+                return type1;
+            } else if (element2 != null) {
+                return type2;
+            }
             return context.getType(Object.class);
         }
 
@@ -217,6 +226,10 @@
         }
     }
 
+    public static boolean isSubtypeBoxed(ProcessorContext context, TypeMirror from, TypeMirror to) {
+        return isSubtype(boxType(context, from), boxType(context, to));
+    }
+
     public static boolean isSubtype(TypeMirror type1, TypeMirror type2) {
         if (type1 instanceof CodeTypeMirror || type2 instanceof CodeTypeMirror) {
             throw new UnsupportedOperationException();
@@ -225,8 +238,14 @@
     }
 
     public static boolean isAssignable(TypeMirror from, TypeMirror to) {
+        if (typeEquals(from, to)) {
+            return true;
+        } else if (isVoid(to)) {
+            return true;
+        } else if (isObject(to)) {
+            return true;
+        }
         ProcessorContext context = ProcessorContext.getInstance();
-
         if (!(from instanceof CodeTypeMirror) && !(to instanceof CodeTypeMirror)) {
             return context.getEnvironment().getTypeUtils().isAssignable(context.reloadType(from), context.reloadType(to));
         } else {
@@ -359,6 +378,8 @@
                 return getTypeId(((ArrayType) mirror).getComponentType()) + "Array";
             case VOID:
                 return "Void";
+            case NULL:
+                return "Null";
             case WILDCARD:
                 StringBuilder b = new StringBuilder();
                 WildcardType type = (WildcardType) mirror;
@@ -405,6 +426,8 @@
                 return getSimpleName(((ArrayType) mirror).getComponentType()) + "[]";
             case VOID:
                 return "void";
+            case NULL:
+                return "null";
             case WILDCARD:
                 return getWildcardName((WildcardType) mirror);
             case TYPEVAR:
@@ -495,6 +518,8 @@
                 return getQualifiedName(((ArrayType) mirror).getComponentType());
             case VOID:
                 return "void";
+            case NULL:
+                return "null";
             case TYPEVAR:
                 return getSimpleName(mirror);
             case ERROR:
@@ -656,6 +681,7 @@
             case INT:
             case LONG:
             case VOID:
+            case NULL:
             case TYPEVAR:
                 return null;
             case DECLARED:
@@ -939,6 +965,13 @@
             return true;
         } else if (kindIsIntegral(type1.getKind())) {
             return kindIsIntegral(type2.getKind());
+        } else if (type1.getKind() == TypeKind.NULL) {
+            if (type2.getKind() == TypeKind.NULL) {
+                return false;
+            }
+            return true;
+        } else if (type2.getKind() == TypeKind.NULL) {
+            return true;
         } else {
             return false;
         }
@@ -1122,4 +1155,82 @@
             throw new AssertionError("unsupported element type");
         }
     }
+
+    public static List<TypeMirror> sortTypes(List<TypeMirror> list) {
+        Collections.sort(list, new Comparator<TypeMirror>() {
+            public int compare(TypeMirror o1, TypeMirror o2) {
+                return compareType(o1, o2);
+            }
+        });
+        return list;
+    }
+
+    public static int compareType(TypeMirror signature1, TypeMirror signature2) {
+        if (signature1 == null) {
+            return 1;
+        } else if (signature2 == null) {
+            return -1;
+        }
+
+        if (ElementUtils.typeEquals(signature1, signature2)) {
+            return 0;
+        }
+
+        if (signature1.getKind() == TypeKind.DECLARED && signature2.getKind() == TypeKind.DECLARED) {
+            TypeElement element1 = ElementUtils.fromTypeMirror(signature1);
+            TypeElement element2 = ElementUtils.fromTypeMirror(signature2);
+
+            if (ElementUtils.getDirectSuperTypes(element1).contains(element2)) {
+                return -1;
+            } else if (ElementUtils.getDirectSuperTypes(element2).contains(element1)) {
+                return 1;
+            }
+        }
+        return ElementUtils.getSimpleName(signature1).compareTo(ElementUtils.getSimpleName(signature2));
+    }
+
+    public static List<TypeMirror> uniqueSortedTypes(Collection<TypeMirror> types) {
+        if (types.isEmpty()) {
+            return new ArrayList<>(0);
+        } else if (types.size() <= 1) {
+            if (types instanceof List) {
+                return (List<TypeMirror>) types;
+            } else {
+                return new ArrayList<>(types);
+            }
+        }
+        Map<String, TypeMirror> sourceTypes = new HashMap<>();
+        for (TypeMirror type : types) {
+            sourceTypes.put(ElementUtils.getTypeId(type), type);
+        }
+        return sortTypes(new ArrayList<>(sourceTypes.values()));
+    }
+
+    public static int compareMethod(ExecutableElement method1, ExecutableElement method2) {
+        List<? extends VariableElement> parameters1 = method1.getParameters();
+        List<? extends VariableElement> parameters2 = method2.getParameters();
+        if (parameters1.size() != parameters2.size()) {
+            return Integer.compare(parameters1.size(), parameters2.size());
+        }
+
+        int result = 0;
+        for (int i = 0; i < parameters1.size(); i++) {
+            VariableElement var1 = parameters1.get(i);
+            VariableElement var2 = parameters2.get(i);
+            result = compareType(var1.asType(), var2.asType());
+            if (result != 0) {
+                return result;
+            }
+        }
+
+        result = method1.getSimpleName().toString().compareTo(method2.getSimpleName().toString());
+        if (result == 0) {
+            // if still no difference sort by enclosing type name
+            TypeElement enclosingType1 = ElementUtils.findNearestEnclosingType(method1);
+            TypeElement enclosingType2 = ElementUtils.findNearestEnclosingType(method2);
+            result = enclosingType1.getQualifiedName().toString().compareTo(enclosingType2.getQualifiedName().toString());
+        }
+        return result;
+    }
+
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeExecutableElement.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeExecutableElement.java	Wed Apr 15 11:03:04 2015 -0700
@@ -58,6 +58,14 @@
         }
     }
 
+    public void setVisibility(Modifier visibility) {
+        ElementUtils.setVisibility(getModifiers(), visibility);
+    }
+
+    public Modifier getVisibility() {
+        return ElementUtils.getVisibility(getModifiers());
+    }
+
     /* Support JDK8 langtools. */
     public boolean isDefault() {
         return false;
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java	Wed Apr 15 11:03:04 2015 -0700
@@ -316,6 +316,13 @@
         }
     }
 
+    public CodeTreeBuilder trees(CodeTree... trees) {
+        for (CodeTree tree : trees) {
+            tree(tree);
+        }
+        return this;
+    }
+
     public CodeTreeBuilder string(String chunk1, String chunk2, String chunk3, String chunk4, String... chunks) {
         push(GROUP).string(chunk1).string(chunk2).string(chunk3).string(chunk4);
         for (int i = 0; i < chunks.length; i++) {
@@ -861,4 +868,15 @@
         }
     }
 
+    public CodeTreeBuilder returnDefault() {
+        ExecutableElement method = findMethod();
+        if (ElementUtils.isVoid(method.getReturnType())) {
+            returnStatement();
+        } else {
+            startReturn().defaultValue(method.getReturnType()).end();
+        }
+        return this;
+
+    }
+
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/AbstractCodeWriter.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/AbstractCodeWriter.java	Wed Apr 15 11:03:04 2015 -0700
@@ -258,7 +258,7 @@
             init = ((CodeVariableElement) f).getInit();
         }
 
-        if (parent.getKind() == ElementKind.ENUM && f.getModifiers().contains(Modifier.STATIC)) {
+        if (parent != null && parent.getKind() == ElementKind.ENUM && f.getModifiers().contains(Modifier.STATIC)) {
             write(f.getSimpleName());
             if (init != null) {
                 write("(");
@@ -266,12 +266,11 @@
                 write(")");
             }
         } else {
-            Element enclosing = f.getEnclosingElement();
             writeModifiers(f.getModifiers(), true);
 
             boolean varArgs = false;
-            if (enclosing.getKind() == ElementKind.METHOD) {
-                ExecutableElement method = (ExecutableElement) enclosing;
+            if (parent != null && parent.getKind() == ElementKind.METHOD) {
+                ExecutableElement method = (ExecutableElement) parent;
                 if (method.isVarArgs() && method.getParameters().indexOf(f) == method.getParameters().size() - 1) {
                     varArgs = true;
                 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java	Wed Apr 15 11:03:04 2015 -0700
@@ -22,67 +22,309 @@
  */
 package com.oracle.truffle.dsl.processor.model;
 
+import java.util.*;
+
+import static com.oracle.truffle.dsl.processor.java.ElementUtils.*;
+
 import javax.lang.model.element.*;
+import javax.lang.model.type.*;
 
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.dsl.processor.*;
 import com.oracle.truffle.dsl.processor.java.*;
 
-public class ExecutableTypeData extends TemplateMethod {
+public class ExecutableTypeData extends MessageContainer implements Comparable<ExecutableTypeData> {
 
-    private final TypeSystemData typeSystem;
-    private final TypeData type;
+    private final ExecutableElement method;
+    private final TypeMirror returnType;
+    private final TypeMirror frameParameter;
+    private final List<TypeMirror> evaluatedParameters;
+    private ExecutableTypeData delegatedTo;
+    private final List<ExecutableTypeData> delegatedFrom = new ArrayList<>();
 
-    public ExecutableTypeData(TemplateMethod method, ExecutableElement executable, TypeSystemData typeSystem, TypeData type) {
-        super(method, executable);
-        this.typeSystem = typeSystem;
-        this.type = type;
-        if (executable.getParameters().size() < method.getMethod().getParameters().size()) {
-            throw new IllegalArgumentException(String.format("Method parameter count mismatch %s != %s.", executable.getParameters(), method.getMethod().getParameters()));
-        }
+    private String uniqueName;
+
+    public ExecutableTypeData(TypeMirror returnType, String uniqueName, TypeMirror frameParameter, List<TypeMirror> evaluatedParameters) {
+        this.returnType = returnType;
+        this.frameParameter = frameParameter;
+        this.evaluatedParameters = evaluatedParameters;
+        this.uniqueName = uniqueName;
+        this.method = null;
     }
 
-    public TypeData getType() {
-        return type;
+    public ExecutableTypeData(ExecutableElement method, int signatureSize, List<TypeMirror> frameTypes) {
+        this.method = method;
+        this.returnType = method.getReturnType();
+        TypeMirror foundFrameParameter = null;
+        List<? extends VariableElement> parameters = method.getParameters();
+
+        int parameterIndex = 0;
+        evaluatedParameters = new ArrayList<>();
+        if (!parameters.isEmpty()) {
+            TypeMirror firstParameter = parameters.get(0).asType();
+            for (TypeMirror frameType : frameTypes) {
+                if (ElementUtils.typeEquals(firstParameter, frameType)) {
+                    foundFrameParameter = firstParameter;
+                    parameterIndex++;
+                    break;
+                }
+            }
+        }
+
+        int numberParameters = Math.max(parameters.size() - parameterIndex, signatureSize);
+        for (int i = 0; i < numberParameters; i++) {
+            TypeMirror parameter;
+            if (method.isVarArgs() && parameterIndex >= parameters.size() - 1) {
+                ArrayType varArgsArray = (ArrayType) parameters.get(parameters.size() - 1).asType();
+                parameter = varArgsArray.getComponentType();
+            } else if (parameterIndex < parameters.size()) {
+                parameter = parameters.get(parameterIndex).asType();
+            } else {
+                break;
+            }
+            parameterIndex++;
+            evaluatedParameters.add(parameter);
+        }
+        this.frameParameter = foundFrameParameter;
+        this.uniqueName = "execute" + (ElementUtils.isObject(getReturnType()) ? "" : ElementUtils.getTypeId(getReturnType()));
+    }
+
+    public void addDelegatedFrom(ExecutableTypeData child) {
+        this.delegatedFrom.add(child);
+        child.delegatedTo = this;
     }
 
-    public TypeSystemData getTypeSystem() {
-        return typeSystem;
+    public List<ExecutableTypeData> getDelegatedFrom() {
+        return delegatedFrom;
+    }
+
+    public ExecutableTypeData getDelegatedTo() {
+        return delegatedTo;
+    }
+
+    public ExecutableElement getMethod() {
+        return method;
+    }
+
+    public String getUniqueName() {
+        return uniqueName;
+    }
+
+    public void setUniqueName(String name) {
+        this.uniqueName = name;
+    }
+
+    @Override
+    public Element getMessageElement() {
+        return method;
+    }
+
+    public List<TypeMirror> getEvaluatedParameters() {
+        return evaluatedParameters;
+    }
+
+    public int getVarArgsIndex(int parameterIndex) {
+        if (method.isVarArgs()) {
+            int index = parameterIndex - (method.getParameters().size() - 1);
+            return index;
+        }
+        return -1;
+    }
+
+    public int getParameterIndex(int signatureIndex) {
+        return frameParameter != null ? signatureIndex + 1 : signatureIndex;
+    }
+
+    public TypeMirror getFrameParameter() {
+        return frameParameter;
+    }
+
+    public TypeMirror getReturnType() {
+        return returnType;
     }
 
     public boolean hasUnexpectedValue(ProcessorContext context) {
-        return ElementUtils.canThrowType(getMethod().getThrownTypes(), context.getType(UnexpectedResultException.class));
+        return method == null ? false : ElementUtils.canThrowType(method.getThrownTypes(), context.getType(UnexpectedResultException.class));
     }
 
     public boolean isFinal() {
-        return getMethod().getModifiers().contains(Modifier.FINAL);
+        return method == null ? false : method.getModifiers().contains(Modifier.FINAL);
     }
 
     public boolean isAbstract() {
-        return getMethod().getModifiers().contains(Modifier.ABSTRACT);
+        return method == null ? false : method.getModifiers().contains(Modifier.ABSTRACT);
     }
 
     public int getEvaluatedCount() {
-        int count = 0;
-        for (Parameter parameter : getParameters()) {
-            if (parameter.getSpecification().isSignature()) {
-                count++;
+        return evaluatedParameters.size();
+    }
+
+    public boolean canDelegateTo(NodeData node, ExecutableTypeData to) {
+        ExecutableTypeData from = this;
+        if (to.getEvaluatedCount() < from.getEvaluatedCount()) {
+            return false;
+        }
+
+        ProcessorContext context = node.getContext();
+
+        // we cannot delegate from generic to unexpected
+        if (!from.hasUnexpectedValue(context) && to.hasUnexpectedValue(context)) {
+            return false;
+        }
+
+        // we can skip the return type check for void. everything is assignable to void.
+        if (!isVoid(from.getReturnType())) {
+            if (!isSubtypeBoxed(context, from.getReturnType(), to.getReturnType()) && !isSubtypeBoxed(context, to.getReturnType(), from.getReturnType())) {
+                return false;
+            }
+        }
+        if (from.getFrameParameter() != to.getFrameParameter() && from.getFrameParameter() != null && to.getFrameParameter() != null &&
+                        !isSubtypeBoxed(context, from.getFrameParameter(), to.getFrameParameter())) {
+            return false;
+        }
+
+        for (int i = 0; i < from.getEvaluatedCount(); i++) {
+            if (!isSubtypeBoxed(context, from.getEvaluatedParameters().get(i), to.getEvaluatedParameters().get(i))) {
+                return false;
+            }
+        }
+
+        for (int i = from.getEvaluatedCount(); i < to.getEvaluatedCount(); i++) {
+            TypeMirror delegateToParameter = to.getEvaluatedParameters().get(i);
+            if (i < node.getChildExecutions().size()) {
+                TypeMirror genericType = node.getGenericType(node.getChildExecutions().get(i));
+                if (!isSubtypeBoxed(context, genericType, delegateToParameter)) {
+                    return false;
+                }
             }
         }
-        return count;
+
+        return true;
+    }
+
+    public int compareTo(ExecutableTypeData o2) {
+        ExecutableTypeData o1 = this;
+        ProcessorContext context = ProcessorContext.getInstance();
+
+        int result = Integer.compare(o2.getEvaluatedCount(), o1.getEvaluatedCount());
+        if (result != 0) {
+            return result;
+        }
+
+        result = Boolean.compare(o1.hasUnexpectedValue(context), o2.hasUnexpectedValue(context));
+        if (result != 0) {
+            return result;
+        }
+
+        result = compareType(context, o1.getReturnType(), o2.getReturnType());
+        if (result != 0) {
+            return result;
+        }
+        result = compareType(context, o1.getFrameParameter(), o2.getFrameParameter());
+        if (result != 0) {
+            return result;
+        }
+
+        for (int i = 0; i < o1.getEvaluatedCount(); i++) {
+            result = compareType(context, o1.getEvaluatedParameters().get(i), o2.getEvaluatedParameters().get(i));
+            if (result != 0) {
+                return result;
+            }
+        }
+
+        result = o1.getUniqueName().compareTo(o2.getUniqueName());
+        if (result != 0) {
+            return result;
+        }
+
+        if (o1.getMethod() != null && o2.getMethod() != null) {
+            result = ElementUtils.compareMethod(o1.getMethod(), o2.getMethod());
+            if (result != 0) {
+                return result;
+            }
+        }
+        return 0;
+    }
+
+    public static int compareType(ProcessorContext context, TypeMirror signature1, TypeMirror signature2) {
+        if (signature1 == null) {
+            if (signature2 == null) {
+                return 0;
+            }
+            return -1;
+        } else if (signature2 == null) {
+            return 1;
+        }
+        if (ElementUtils.typeEquals(signature1, signature2)) {
+            return 0;
+        }
+        if (isVoid(signature1)) {
+            if (isVoid(signature2)) {
+                return 0;
+            }
+            return 1;
+        } else if (isVoid(signature2)) {
+            return -1;
+        }
+
+        TypeMirror boxedType1 = ElementUtils.boxType(context, signature1);
+        TypeMirror boxedType2 = ElementUtils.boxType(context, signature2);
+
+        if (ElementUtils.isSubtype(boxedType1, boxedType2)) {
+            if (ElementUtils.isSubtype(boxedType2, boxedType1)) {
+                return 0;
+            }
+            return 1;
+        } else if (ElementUtils.isSubtype(boxedType2, boxedType1)) {
+            return -1;
+        } else {
+            return ElementUtils.getSimpleName(signature1).compareTo(ElementUtils.getSimpleName(signature2));
+        }
     }
 
     @Override
-    public int hashCode() {
-        return type.hashCode();
+    public String toString() {
+        return method != null ? ElementUtils.createReferenceName(method) : getUniqueName() + evaluatedParameters.toString();
+    }
+
+    public boolean sameParameters(ExecutableTypeData other) {
+        if (!typeEquals(other.getFrameParameter(), getFrameParameter())) {
+            return false;
+        }
+
+        if (getEvaluatedCount() != other.getEvaluatedCount()) {
+            return false;
+        }
+
+        for (int i = 0; i < getEvaluatedCount(); i++) {
+            if (!typeEquals(getEvaluatedParameters().get(i), other.getEvaluatedParameters().get(i))) {
+                return false;
+            }
+        }
+        return true;
     }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (obj instanceof ExecutableTypeData) {
-            return type.equals(((ExecutableTypeData) obj).type);
+    public boolean sameSignature(ExecutableTypeData other) {
+        if (!typeEquals(other.getReturnType(), getReturnType())) {
+            return false;
+        }
+
+        if (other.getFrameParameter() != null) {
+            if (!typeEquals(getFrameParameter(), other.getFrameParameter())) {
+                return false;
+            }
         }
-        return super.equals(obj);
+
+        if (getEvaluatedCount() != other.getEvaluatedCount()) {
+            return false;
+        }
+
+        for (int i = 0; i < getEvaluatedCount(); i++) {
+            if (!typeEquals(getEvaluatedParameters().get(i), other.getEvaluatedParameters().get(i))) {
+                return false;
+            }
+        }
+
+        return true;
     }
-
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ImplicitCastData.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ImplicitCastData.java	Wed Apr 15 11:03:04 2015 -0700
@@ -22,35 +22,29 @@
  */
 package com.oracle.truffle.dsl.processor.model;
 
+import javax.lang.model.type.*;
+
 public class ImplicitCastData extends TemplateMethod {
 
-    private final TypeData sourceType;
-    private final TypeData targetType;
+    private final TypeMirror sourceType;
+    private final TypeMirror targetType;
 
-    public ImplicitCastData(TemplateMethod method, TypeData sourceType, TypeData targetType) {
+    public ImplicitCastData(TemplateMethod method, TypeMirror sourceType, TypeMirror targetType) {
         super(method);
         this.sourceType = sourceType;
         this.targetType = targetType;
     }
 
-    public TypeData getSourceType() {
+    public TypeMirror getSourceType() {
         return sourceType;
     }
 
-    public TypeData getTargetType() {
+    public TypeMirror getTargetType() {
         return targetType;
     }
 
     @Override
     public int compareTo(TemplateMethod o) {
-        if (o instanceof ImplicitCastData && sourceType != null) {
-            // implicit casts are ordered by source type since
-            // its also the order in which they are checked.
-            TypeData otherSourceType = ((ImplicitCastData) o).getSourceType();
-            if (otherSourceType != null) {
-                return this.sourceType.compareTo(otherSourceType);
-            }
-        }
         return super.compareTo(o);
     }
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java	Wed Apr 15 11:03:04 2015 -0700
@@ -106,7 +106,7 @@
         visitedSinks.add(this);
 
         List<Message> foundMessages = new ArrayList<>();
-        if (ElementUtils.typeEquals(getMessageElement().asType(), e.asType())) {
+        if (getMessageElement() != null && ElementUtils.typeEquals(getMessageElement().asType(), e.asType())) {
             foundMessages.addAll(getMessages());
         }
         for (MessageContainer sink : findChildContainers()) {
@@ -119,14 +119,16 @@
         TypeElement expectError = context.getTruffleTypes().getExpectError();
         if (expectError != null) {
             Element element = getMessageElement();
-            AnnotationMirror mirror = ElementUtils.findAnnotationMirror(element.getAnnotationMirrors(), expectError.asType());
-            if (mirror != null) {
-                List<String> values = ElementUtils.getAnnotationValueList(String.class, mirror, "value");
-                if (values == null) {
-                    values = Collections.emptyList();
-                }
-                if (values.size() != msgs.size()) {
-                    log.message(Kind.ERROR, element, mirror, ElementUtils.getAnnotationValue(mirror, "value"), String.format("Error count expected %s but was %s.", values.size(), msgs.size()));
+            if (element != null) {
+                AnnotationMirror mirror = ElementUtils.findAnnotationMirror(element.getAnnotationMirrors(), expectError.asType());
+                if (mirror != null) {
+                    List<String> values = ElementUtils.getAnnotationValueList(String.class, mirror, "value");
+                    if (values == null) {
+                        values = Collections.emptyList();
+                    }
+                    if (values.size() != msgs.size()) {
+                        log.message(Kind.ERROR, element, mirror, ElementUtils.getAnnotationValue(mirror, "value"), String.format("Error count expected %s but was %s.", values.size(), msgs.size()));
+                    }
                 }
             }
         }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MethodSpec.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MethodSpec.java	Wed Apr 15 11:03:04 2015 -0700
@@ -103,8 +103,8 @@
 
         int defIndex = 0;
         for (ParameterSpec spec : getAll()) {
-            List<TypeMirror> allowedTypes = spec.getAllowedTypes();
-            List<TypeMirror> types = spec.getAllowedTypes();
+            Collection<TypeMirror> allowedTypes = spec.getAllowedTypes();
+            Collection<TypeMirror> types = spec.getAllowedTypes();
             if (types != null && allowedTypes.size() > 1) {
                 TypeDef foundDef = null;
                 for (TypeDef def : typeDefs) {
@@ -189,7 +189,7 @@
         if (foundTypeDef != null) {
             builder.append("<" + foundTypeDef.getName() + ">");
         } else if (spec.getAllowedTypes().size() >= 1) {
-            builder.append(ElementUtils.getSimpleName(spec.getAllowedTypes().get(0)));
+            builder.append(ElementUtils.getSimpleName(spec.getAllowedTypes().iterator().next()));
         } else {
             builder.append("void");
         }
@@ -207,15 +207,15 @@
 
     static final class TypeDef {
 
-        private final List<TypeMirror> types;
+        private final Collection<TypeMirror> types;
         private final String name;
 
-        private TypeDef(List<TypeMirror> types, String name) {
+        private TypeDef(Collection<TypeMirror> types, String name) {
             this.types = types;
             this.name = name;
         }
 
-        public List<TypeMirror> getTypes() {
+        public Collection<TypeMirror> getTypes() {
             return types;
         }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeChildData.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeChildData.java	Wed Apr 15 11:03:04 2015 -0700
@@ -74,7 +74,7 @@
         this.executeWith = executeWith;
     }
 
-    public ExecutableTypeData findExecutableType(TypeData targetType) {
+    public ExecutableTypeData findExecutableType(TypeMirror targetType) {
         return childNode.findExecutableType(targetType, getExecuteWith().size());
     }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java	Wed Apr 15 11:03:04 2015 -0700
@@ -48,7 +48,7 @@
     private final List<SpecializationData> specializations = new ArrayList<>();
     private final List<ShortCircuitData> shortCircuits = new ArrayList<>();
     private final List<CreateCastData> casts = new ArrayList<>();
-    private Map<Integer, List<ExecutableTypeData>> executableTypes;
+    private final List<ExecutableTypeData> executableTypes = new ArrayList<>();
 
     private final NodeExecutionData thisExecution;
     private final boolean generateFactory;
@@ -63,7 +63,7 @@
         this.fields = new ArrayList<>();
         this.children = new ArrayList<>();
         this.childExecutions = new ArrayList<>();
-        this.thisExecution = new NodeExecutionData(new NodeChildData(null, null, "this", getNodeType(), getNodeType(), null, Cardinality.ONE), -1, false);
+        this.thisExecution = new NodeExecutionData(new NodeChildData(null, null, "this", getNodeType(), getNodeType(), null, Cardinality.ONE), -1, -1, false);
         this.thisExecution.getChild().setNode(this);
         this.generateFactory = generateFactory;
     }
@@ -105,15 +105,15 @@
         return childExecutions;
     }
 
-    public Set<TypeData> findSpecializedTypes(NodeExecutionData execution) {
-        Set<TypeData> types = new HashSet<>();
+    public Set<TypeMirror> findSpecializedTypes(NodeExecutionData execution) {
+        Set<TypeMirror> types = new HashSet<>();
         for (SpecializationData specialization : getSpecializations()) {
             if (!specialization.isSpecialized()) {
                 continue;
             }
             List<Parameter> parameters = specialization.findByExecutionData(execution);
             for (Parameter parameter : parameters) {
-                TypeData type = parameter.getTypeSystemType();
+                TypeMirror type = parameter.getType();
                 if (type == null) {
                     throw new AssertionError();
                 }
@@ -123,22 +123,19 @@
         return types;
     }
 
-    public Collection<TypeData> findSpecializedReturnTypes() {
-        Set<TypeData> types = new HashSet<>();
+    public Collection<TypeMirror> findSpecializedReturnTypes() {
+        Set<TypeMirror> types = new HashSet<>();
         for (SpecializationData specialization : getSpecializations()) {
             if (!specialization.isSpecialized()) {
                 continue;
             }
-            types.add(specialization.getReturnType().getTypeSystemType());
+            types.add(specialization.getReturnType().getType());
         }
         return types;
     }
 
     public int getSignatureSize() {
-        if (getSpecializations() != null && !getSpecializations().isEmpty()) {
-            return getSpecializations().get(0).getSignatureSize();
-        }
-        return 0;
+        return getChildExecutions().size();
     }
 
     public boolean isFrameUsedByAnyGuard() {
@@ -146,8 +143,18 @@
             if (!specialization.isReachable()) {
                 continue;
             }
-            if (specialization.isFrameUsed()) {
-                return true;
+            Parameter frame = specialization.getFrame();
+            if (frame != null) {
+                for (GuardExpression guard : specialization.getGuards()) {
+                    if (guard.getExpression().findBoundVariableElements().contains(frame.getVariableElement())) {
+                        return true;
+                    }
+                }
+                for (CacheExpression cache : specialization.getCaches()) {
+                    if (cache.getExpression().findBoundVariableElements().contains(frame.getVariableElement())) {
+                        return true;
+                    }
+                }
             }
         }
         return false;
@@ -233,7 +240,7 @@
     public boolean supportsFrame() {
         if (executableTypes != null) {
             for (ExecutableTypeData execType : getExecutableTypes(-1)) {
-                if (execType.findParameter(TemplateMethod.FRAME_NAME) == null) {
+                if (execType.getFrameParameter() == null) {
                     return false;
                 }
             }
@@ -258,7 +265,7 @@
         }
 
         for (NodeExecutionData execution : childExecutions) {
-            if (execution.getName().equals(childName) && (execution.getIndex() == -1 || execution.getIndex() == index)) {
+            if (execution.getName().equals(childName) && (execution.getChildIndex() == -1 || execution.getChildIndex() == index)) {
                 return execution;
             }
         }
@@ -284,17 +291,26 @@
         return enclosingNodes;
     }
 
-    public List<TemplateMethod> getAllTemplateMethods() {
-        List<TemplateMethod> methods = new ArrayList<>();
+    public List<ExecutableElement> getAllTemplateMethods() {
+        List<ExecutableElement> methods = new ArrayList<>();
 
         for (SpecializationData specialization : getSpecializations()) {
-            methods.add(specialization);
+            methods.add(specialization.getMethod());
         }
 
-        methods.addAll(getExecutableTypes());
-        methods.addAll(getShortCircuits());
+        for (ExecutableTypeData execType : getExecutableTypes()) {
+            if (execType.getMethod() != null) {
+                methods.add(execType.getMethod());
+            }
+        }
+        for (ShortCircuitData shortcircuit : getShortCircuits()) {
+            methods.add(shortcircuit.getMethod());
+        }
+
         if (getCasts() != null) {
-            methods.addAll(getCasts());
+            for (CreateCastData castData : getCasts()) {
+                methods.add(castData.getMethod());
+            }
         }
 
         return methods;
@@ -303,13 +319,13 @@
     public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context, int evaluatedCount) {
         List<ExecutableTypeData> types = findGenericExecutableTypes(context, evaluatedCount);
         for (ExecutableTypeData type : types) {
-            if (type.getType().isGeneric()) {
+            if (context.isType(type.getReturnType(), Object.class)) {
                 return type;
             }
         }
 
         for (ExecutableTypeData type : types) {
-            if (!type.getType().isVoid()) {
+            if (!context.isType(type.getReturnType(), void.class)) {
                 return type;
             }
         }
@@ -321,21 +337,16 @@
     }
 
     public List<ExecutableTypeData> getExecutableTypes(int evaluatedCount) {
-        if (executableTypes == null) {
-            return Collections.emptyList();
-        }
         if (evaluatedCount == -1) {
-            List<ExecutableTypeData> typeData = new ArrayList<>();
-            for (int currentEvaluationCount : executableTypes.keySet()) {
-                typeData.addAll(executableTypes.get(currentEvaluationCount));
+            return executableTypes;
+        } else {
+            List<ExecutableTypeData> filteredTypes = new ArrayList<>();
+            for (ExecutableTypeData type : executableTypes) {
+                if (type.getEvaluatedCount() == evaluatedCount) {
+                    filteredTypes.add(type);
+                }
             }
-            return typeData;
-        } else {
-            List<ExecutableTypeData> types = executableTypes.get(evaluatedCount);
-            if (types == null) {
-                return Collections.emptyList();
-            }
-            return types;
+            return filteredTypes;
         }
     }
 
@@ -349,9 +360,9 @@
         return types;
     }
 
-    public ExecutableTypeData findExecutableType(TypeData prmitiveType, int evaluatedCount) {
+    public ExecutableTypeData findExecutableType(TypeMirror primitiveType, int evaluatedCount) {
         for (ExecutableTypeData type : getExecutableTypes(evaluatedCount)) {
-            if (ElementUtils.typeEquals(type.getType().getPrimitiveType(), prmitiveType.getPrimitiveType())) {
+            if (ElementUtils.typeEquals(type.getReturnType(), primitiveType)) {
                 return type;
             }
         }
@@ -488,6 +499,25 @@
         return specializations;
     }
 
+    public ExecutableTypeData getGenericExecutableType(ExecutableTypeData typeHint) {
+        ExecutableTypeData polymorphicDelegate = null;
+        if (typeHint != null) {
+            polymorphicDelegate = typeHint;
+            while (polymorphicDelegate.getDelegatedTo() != null && polymorphicDelegate.getEvaluatedCount() != getSignatureSize()) {
+                polymorphicDelegate = polymorphicDelegate.getDelegatedTo();
+            }
+        }
+        if (polymorphicDelegate == null) {
+            for (ExecutableTypeData type : getExecutableTypes()) {
+                if (type.getDelegatedTo() == null && type.getEvaluatedCount() == getSignatureSize()) {
+                    polymorphicDelegate = type;
+                    break;
+                }
+            }
+        }
+        return polymorphicDelegate;
+    }
+
     public List<ExecutableTypeData> getExecutableTypes() {
         return getExecutableTypes(-1);
     }
@@ -496,8 +526,12 @@
         return shortCircuits;
     }
 
-    public void setExecutableTypes(Map<Integer, List<ExecutableTypeData>> executableTypes) {
-        this.executableTypes = executableTypes;
+    public int getMinimalEvaluatedParameters() {
+        int minimalEvaluatedParameters = Integer.MAX_VALUE;
+        for (ExecutableTypeData type : getExecutableTypes()) {
+            minimalEvaluatedParameters = Math.min(minimalEvaluatedParameters, type.getEvaluatedCount());
+        }
+        return minimalEvaluatedParameters;
     }
 
     @Override
@@ -520,4 +554,38 @@
         return getNodeId().compareTo(o.getNodeId());
     }
 
+    public TypeMirror getGenericType(NodeExecutionData execution) {
+        return ElementUtils.getCommonSuperType(getContext(), getGenericTypes(execution));
+    }
+
+    public List<TypeMirror> getGenericTypes(NodeExecutionData execution) {
+        List<TypeMirror> types = new ArrayList<>();
+
+        // add types possible through return types and evaluated parameters in execute methods
+        if (execution.getChild() != null) {
+            for (ExecutableTypeData executable : execution.getChild().getNodeData().getExecutableTypes()) {
+                if (executable.hasUnexpectedValue(getContext())) {
+                    continue;
+                }
+                if (!typeSystem.hasImplicitSourceTypes(executable.getReturnType())) {
+                    types.add(executable.getReturnType());
+                }
+            }
+        }
+
+        int executionIndex = execution.getIndex();
+        if (executionIndex >= 0) {
+            for (ExecutableTypeData typeData : getExecutableTypes()) {
+                if (executionIndex < typeData.getEvaluatedCount()) {
+                    TypeMirror genericType = typeData.getEvaluatedParameters().get(executionIndex);
+                    if (!typeSystem.hasImplicitSourceTypes(genericType)) {
+                        types.add(genericType);
+                    }
+                }
+            }
+        }
+
+        return ElementUtils.uniqueSortedTypes(types);
+    }
+
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeExecutionData.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeExecutionData.java	Wed Apr 15 11:03:04 2015 -0700
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.dsl.processor.model;
 
+import java.util.*;
+
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality;
@@ -31,17 +33,28 @@
     private final NodeChildData child;
     private final String name;
     private final int index;
+    private final int childIndex;
     private final boolean shortCircuit;
+    private final List<TypeMirror> typeRestrictions = new ArrayList<>();
 
-    public NodeExecutionData(NodeChildData child, int index, boolean shortCircuit) {
+    public NodeExecutionData(NodeChildData child, int index, int childIndex, boolean shortCircuit) {
         this.child = child;
         this.index = index;
+        this.childIndex = childIndex;
         this.shortCircuit = shortCircuit;
         this.name = createName();
     }
 
     private String createName() {
-        return createName(child.getName(), index);
+        return child != null ? createName(child.getName(), childIndex) : ("arg" + index);
+    }
+
+    public int getIndex() {
+        return index;
+    }
+
+    public List<TypeMirror> getTypeRestrictions() {
+        return typeRestrictions;
     }
 
     public TypeMirror getNodeType() {
@@ -62,12 +75,12 @@
         return child;
     }
 
-    public int getIndex() {
-        return index;
+    public int getChildIndex() {
+        return childIndex;
     }
 
     public boolean isIndexed() {
-        return index > -1;
+        return childIndex > -1;
     }
 
     public boolean isShortCircuit() {
@@ -75,7 +88,7 @@
     }
 
     public String getIndexedName() {
-        return createIndexedName(child, index);
+        return createIndexedName(child, childIndex);
     }
 
     public static String createIndexedName(NodeChildData child, int varArgsIndex) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Parameter.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Parameter.java	Wed Apr 15 11:03:04 2015 -0700
@@ -28,19 +28,17 @@
 public final class Parameter {
 
     private final ParameterSpec specification;
-    private TypeData typeSystemType;
     private TemplateMethod method;
     private String localName;
     private final int specificationVarArgsIndex;
     private final int typeVarArgsIndex;
-
     private final VariableElement variableElement;
+    private final TypeMirror type;
 
     public Parameter(ParameterSpec specification, VariableElement variableElement, int specificationVarArgsIndex, int typeVarArgsIndex) {
         this.specification = specification;
         this.variableElement = variableElement;
-        this.typeSystemType = null;
-
+        this.type = variableElement.asType();
         this.specificationVarArgsIndex = specificationVarArgsIndex;
 
         String valueName = specification.getName() + "Value";
@@ -51,22 +49,22 @@
         this.localName = valueName;
     }
 
-    public Parameter(ParameterSpec specification, TypeData actualType, VariableElement variableElement, int specificationIndex, int varArgsIndex) {
-        this(specification, variableElement, specificationIndex, varArgsIndex);
-        this.typeSystemType = actualType;
-    }
-
-    public Parameter(Parameter parameter, TypeData otherType) {
-        this(parameter.specification, otherType, parameter.variableElement, parameter.specificationVarArgsIndex, parameter.typeVarArgsIndex);
-    }
-
     public Parameter(Parameter parameter) {
         this.specification = parameter.specification;
-        this.typeSystemType = parameter.typeSystemType;
         this.specificationVarArgsIndex = parameter.specificationVarArgsIndex;
         this.localName = parameter.localName;
         this.typeVarArgsIndex = parameter.typeVarArgsIndex;
         this.variableElement = parameter.variableElement;
+        this.type = parameter.type;
+    }
+
+    public Parameter(Parameter parameter, TypeMirror newType) {
+        this.specification = parameter.specification;
+        this.specificationVarArgsIndex = parameter.specificationVarArgsIndex;
+        this.localName = parameter.localName;
+        this.typeVarArgsIndex = parameter.typeVarArgsIndex;
+        this.variableElement = parameter.variableElement;
+        this.type = newType;
     }
 
     public void setLocalName(String localName) {
@@ -102,11 +100,7 @@
     }
 
     public TypeMirror getType() {
-        return variableElement.asType();
-    }
-
-    public TypeData getTypeSystemType() {
-        return typeSystemType;
+        return type;
     }
 
     public boolean isTypeVarArgs() {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java	Wed Apr 15 11:03:04 2015 -0700
@@ -27,51 +27,53 @@
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
 
+import com.oracle.truffle.dsl.processor.*;
 import com.oracle.truffle.dsl.processor.java.*;
 import com.oracle.truffle.dsl.processor.model.MethodSpec.TypeDef;
 
 public class ParameterSpec {
 
     private final String name;
-    private final List<TypeMirror> allowedTypes;
-    private final Set<String> allowedTypesIdentifier;
+    private final Collection<TypeMirror> allowedTypes;
+    private final boolean anyType;
 
     /** Type is bound to local final variable. */
     private boolean local;
     private boolean signature;
+    private boolean allowSubclasses = true;
 
     /** Optional bound execution of node. */
     private NodeExecutionData execution;
     private TypeDef typeDefinition;
 
-    public ParameterSpec(String name, List<TypeMirror> allowedTypes, Set<String> typeIdentifiers) {
+    public ParameterSpec(String name, Collection<TypeMirror> allowedTypes) {
         this.name = name;
         this.allowedTypes = allowedTypes;
-        this.allowedTypesIdentifier = typeIdentifiers;
+        boolean anyTypeTemp = false;
+        for (TypeMirror type : allowedTypes) {
+            if (ElementUtils.isObject(type)) {
+                anyTypeTemp = true;
+                break;
+            }
+        }
+        this.anyType = anyTypeTemp;
     }
 
-    public ParameterSpec(String name, List<TypeMirror> allowedTypes) {
-        this.name = name;
-        this.allowedTypes = allowedTypes;
-        Set<String> typeIdentifiers = new HashSet<>();
-        for (TypeMirror type : allowedTypes) {
-            typeIdentifiers.add(ElementUtils.getUniqueIdentifier(type));
-        }
-        this.allowedTypesIdentifier = typeIdentifiers;
+    public ParameterSpec(ParameterSpec original, TypeMirror newType) {
+        this(original.name, newType);
+        this.local = original.local;
+        this.signature = original.signature;
+        this.execution = original.execution;
+        this.typeDefinition = original.typeDefinition;
+        this.allowSubclasses = original.allowSubclasses;
     }
 
     public ParameterSpec(String name, TypeMirror type) {
-        this(name, Arrays.asList(type), new HashSet<>(Arrays.asList(ElementUtils.getUniqueIdentifier(type))));
+        this(name, Arrays.asList(type));
     }
 
-    public ParameterSpec(ParameterSpec o, List<TypeMirror> allowedTypes, Set<String> typeIdentifiers) {
-        this.name = o.name;
-        this.local = o.local;
-        this.typeDefinition = o.typeDefinition;
-        this.execution = o.execution;
-        this.signature = o.signature;
-        this.allowedTypes = allowedTypes;
-        this.allowedTypesIdentifier = typeIdentifiers;
+    public void setAllowSubclasses(boolean allowSubclasses) {
+        this.allowSubclasses = allowSubclasses;
     }
 
     public NodeExecutionData getExecution() {
@@ -111,15 +113,28 @@
         return name;
     }
 
-    public List<TypeMirror> getAllowedTypes() {
+    public Collection<TypeMirror> getAllowedTypes() {
         return allowedTypes;
     }
 
     public boolean matches(VariableElement variable) {
-        if (allowedTypesIdentifier != null) {
-            return allowedTypesIdentifier.contains(ElementUtils.getUniqueIdentifier(variable.asType()));
+        if (anyType) {
+            return true;
+        } else {
+            for (TypeMirror type : allowedTypes) {
+                if (ElementUtils.typeEquals(variable.asType(), type)) {
+                    return true;
+                }
+            }
+            if (allowSubclasses) {
+                for (TypeMirror type : allowedTypes) {
+                    if (ElementUtils.isSubtypeBoxed(ProcessorContext.getInstance(), variable.asType(), type)) {
+                        return true;
+                    }
+                }
+            }
         }
-        return true;
+        return false;
     }
 
     @Override
@@ -132,7 +147,7 @@
         if (typeDefinition != null) {
             builder.append("<" + typeDefinition.getName() + ">");
         } else if (getAllowedTypes().size() >= 1) {
-            builder.append(ElementUtils.getSimpleName(getAllowedTypes().get(0)));
+            builder.append(ElementUtils.getSimpleName(getAllowedTypes().iterator().next()));
         } else {
             builder.append("void");
         }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java	Wed Apr 15 11:03:04 2015 -0700
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import javax.lang.model.element.*;
+import javax.lang.model.type.*;
 
 import com.oracle.truffle.dsl.processor.*;
 import com.oracle.truffle.dsl.processor.expression.*;
@@ -40,7 +41,7 @@
     }
 
     private final NodeData node;
-    private final SpecializationKind kind;
+    private SpecializationKind kind;
     private final List<SpecializationThrowsData> exceptions;
     private List<GuardExpression> guards = Collections.emptyList();
     private List<CacheExpression> caches = Collections.emptyList();
@@ -91,6 +92,10 @@
         return false;
     }
 
+    public void setKind(SpecializationKind kind) {
+        this.kind = kind;
+    }
+
     public boolean isDynamicParameterBound(DSLExpression expression) {
         Set<VariableElement> boundVariables = expression.findBoundVariableElements();
         for (Parameter parameter : getDynamicParameters()) {
@@ -201,17 +206,18 @@
 
         for (Parameter parameter : getSignatureParameters()) {
             NodeChildData child = parameter.getSpecification().getExecution().getChild();
-            ExecutableTypeData type = child.findExecutableType(parameter.getTypeSystemType());
-            if (type == null) {
-                type = child.findAnyGenericExecutableType(context);
+            if (child != null) {
+                ExecutableTypeData type = child.findExecutableType(parameter.getType());
+                if (type == null) {
+                    type = child.findAnyGenericExecutableType(context);
+                }
+                if (type.hasUnexpectedValue(context)) {
+                    return true;
+                }
+                if (ElementUtils.needsCastTo(type.getReturnType(), parameter.getType())) {
+                    return true;
+                }
             }
-            if (type.hasUnexpectedValue(context)) {
-                return true;
-            }
-            if (type.getReturnType().getTypeSystemType().needsCastTo(parameter.getTypeSystemType())) {
-                return true;
-            }
-
         }
         return false;
     }
@@ -356,11 +362,12 @@
         Iterator<Parameter> currentSignature = getSignatureParameters().iterator();
         Iterator<Parameter> prevSignature = prev.getSignatureParameters().iterator();
 
+        TypeSystemData typeSystem = prev.getNode().getTypeSystem();
         while (currentSignature.hasNext() && prevSignature.hasNext()) {
-            TypeData currentType = currentSignature.next().getTypeSystemType();
-            TypeData prevType = prevSignature.next().getTypeSystemType();
+            TypeMirror currentType = currentSignature.next().getType();
+            TypeMirror prevType = prevSignature.next().getType();
 
-            if (!currentType.isImplicitSubtypeOf(prevType)) {
+            if (!typeSystem.isImplicitSubtypeOf(currentType, prevType)) {
                 return true;
             }
         }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java	Wed Apr 15 11:03:04 2015 -0700
@@ -73,6 +73,18 @@
         return findParameter(FRAME_NAME);
     }
 
+    public void removeParameter(Parameter p) {
+        this.parameters.remove(p);
+        this.parameterCache.remove(p.getLocalName());
+        p.setMethod(this);
+    }
+
+    public void addParameter(int index, Parameter p) {
+        this.parameters.add(index, p);
+        this.parameterCache.put(p.getLocalName(), p);
+        p.setMethod(this);
+    }
+
     public String createReferenceName() {
         if (getMethod() == null) {
             return "-";
@@ -132,12 +144,13 @@
     public void replaceParameter(String localName, Parameter newParameter) {
         if (returnType.getLocalName().equals(localName)) {
             returnType = newParameter;
-            returnType.setMethod(this);
         } else {
             Parameter local = findParameter(localName);
             int index = parameters.indexOf(local);
             parameters.set(index, newParameter);
         }
+        parameterCache.put(newParameter.getLocalName(), newParameter);
+        newParameter.setMethod(this);
     }
 
     public Iterable<Parameter> getSignatureParameters() {
@@ -228,9 +241,9 @@
 
     public TypeSignature getTypeSignature() {
         TypeSignature signature = new TypeSignature();
-        signature.types.add(getReturnType().getTypeSystemType());
+        signature.types.add(getReturnType().getType());
         for (Parameter parameter : getSignatureParameters()) {
-            TypeData typeData = parameter.getTypeSystemType();
+            TypeMirror typeData = parameter.getType();
             if (typeData != null) {
                 signature.types.add(typeData);
             }
@@ -250,8 +263,8 @@
             if (signatureIndex >= signature.size()) {
                 break;
             }
-            TypeData newType = signature.get(signatureIndex++);
-            if (!parameter.getTypeSystemType().equals(newType)) {
+            TypeMirror newType = signature.get(signatureIndex++);
+            if (!ElementUtils.typeEquals(newType, parameter.getType())) {
                 replaceParameter(parameter.getLocalName(), new Parameter(parameter, newType));
             }
         }
@@ -278,11 +291,6 @@
     }
 
     public int compareBySignature(TemplateMethod compareMethod) {
-        final TypeSystemData typeSystem = getTemplate().getTypeSystem();
-        if (typeSystem != compareMethod.getTemplate().getTypeSystem()) {
-            throw new IllegalStateException("Cannot compare two methods with different type systems.");
-        }
-
         List<TypeMirror> signature1 = getSignatureTypes(this);
         List<TypeMirror> signature2 = getSignatureTypes(compareMethod);
 
@@ -290,7 +298,7 @@
         for (int i = 0; i < Math.max(signature1.size(), signature2.size()); i++) {
             TypeMirror t1 = i < signature1.size() ? signature1.get(i) : null;
             TypeMirror t2 = i < signature2.size() ? signature2.get(i) : null;
-            result = compareParameter(typeSystem, t1, t2);
+            result = ElementUtils.compareType(t1, t2);
             if (result != 0) {
                 break;
             }
@@ -299,37 +307,6 @@
         return result;
     }
 
-    protected static int compareParameter(TypeSystemData data, TypeMirror signature1, TypeMirror signature2) {
-        if (signature1 == null) {
-            return 1;
-        } else if (signature2 == null) {
-            return -1;
-        }
-
-        if (ElementUtils.typeEquals(signature1, signature2)) {
-            return 0;
-        }
-
-        int index1 = data.findType(signature1);
-        int index2 = data.findType(signature2);
-        if (index1 != -1 && index2 != -1) {
-            return index1 - index2;
-        }
-
-        // TODO this version if subclass of should be improved.
-        if (signature1.getKind() == TypeKind.DECLARED && signature2.getKind() == TypeKind.DECLARED) {
-            TypeElement element1 = ElementUtils.fromTypeMirror(signature1);
-            TypeElement element2 = ElementUtils.fromTypeMirror(signature2);
-
-            if (ElementUtils.getDirectSuperTypes(element1).contains(element2)) {
-                return -1;
-            } else if (ElementUtils.getDirectSuperTypes(element2).contains(element1)) {
-                return 1;
-            }
-        }
-        return ElementUtils.getSimpleName(signature1).compareTo(ElementUtils.getSimpleName(signature2));
-    }
-
     public static List<TypeMirror> getSignatureTypes(TemplateMethod method) {
         List<TypeMirror> types = new ArrayList<>();
         for (Parameter param : method.getSignatureParameters()) {
@@ -338,15 +315,15 @@
         return types;
     }
 
-    public static class TypeSignature implements Iterable<TypeData>, Comparable<TypeSignature> {
+    public static class TypeSignature implements Iterable<TypeMirror> {
 
-        private final List<TypeData> types;
+        private final List<TypeMirror> types;
 
         public TypeSignature() {
             this.types = new ArrayList<>();
         }
 
-        public TypeSignature(List<TypeData> signature) {
+        public TypeSignature(List<TypeMirror> signature) {
             this.types = signature;
         }
 
@@ -359,32 +336,10 @@
             return types.size();
         }
 
-        public TypeData get(int index) {
+        public TypeMirror get(int index) {
             return types.get(index);
         }
 
-        public int compareTo(TypeSignature other) {
-            if (this == other) {
-                return 0;
-            } else if (types.size() != other.types.size()) {
-                return types.size() - other.types.size();
-            } else if (types.isEmpty()) {
-                return 0;
-            }
-
-            for (int i = 0; i < types.size(); i++) {
-                TypeData type1 = types.get(i);
-                TypeData type2 = other.types.get(i);
-
-                int comparison = type1.compareTo(type2);
-                if (comparison != 0) {
-                    return comparison;
-                }
-            }
-
-            return 0;
-        }
-
         @Override
         public boolean equals(Object obj) {
             if (obj instanceof TypeSignature) {
@@ -393,7 +348,7 @@
             return super.equals(obj);
         }
 
-        public Iterator<TypeData> iterator() {
+        public Iterator<TypeMirror> iterator() {
             return types.iterator();
         }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeCastData.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeCastData.java	Wed Apr 15 11:03:04 2015 -0700
@@ -22,26 +22,24 @@
  */
 package com.oracle.truffle.dsl.processor.model;
 
+import javax.lang.model.type.*;
+
 public class TypeCastData extends TemplateMethod {
 
-    private final TypeData targetType;
-    private final TypeData sourceType;
+    private final TypeMirror targetType;
+    private final TypeMirror sourceType;
 
-    public TypeCastData(TemplateMethod method, TypeData sourceType, TypeData targetType) {
+    public TypeCastData(TemplateMethod method, TypeMirror sourceType, TypeMirror targetType) {
         super(method);
         this.sourceType = sourceType;
         this.targetType = targetType;
     }
 
-    public boolean isGeneric() {
-        return sourceType.isGeneric();
-    }
-
-    public TypeData getSourceType() {
+    public TypeMirror getSourceType() {
         return sourceType;
     }
 
-    public TypeData getTargetType() {
+    public TypeMirror getTargetType() {
         return targetType;
     }
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeCheckData.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeCheckData.java	Wed Apr 15 11:03:04 2015 -0700
@@ -22,26 +22,24 @@
  */
 package com.oracle.truffle.dsl.processor.model;
 
+import javax.lang.model.type.*;
+
 public class TypeCheckData extends TemplateMethod {
 
-    private final TypeData checkedType;
-    private final TypeData valueType;
+    private final TypeMirror checkedType;
+    private final TypeMirror valueType;
 
-    public TypeCheckData(TemplateMethod method, TypeData checkedType, TypeData valueType) {
+    public TypeCheckData(TemplateMethod method, TypeMirror checkedType, TypeMirror valueType) {
         super(method);
         this.checkedType = checkedType;
         this.valueType = valueType;
     }
 
-    public boolean isGeneric() {
-        return valueType.isGeneric();
-    }
-
-    public TypeData getCheckedType() {
+    public TypeMirror getCheckedType() {
         return checkedType;
     }
 
-    public TypeData getValueType() {
+    public TypeMirror getValueType() {
         return valueType;
     }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeData.java	Wed Apr 15 10:09:13 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,181 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.dsl.processor.model;
-
-import java.util.*;
-
-import javax.lang.model.element.*;
-import javax.lang.model.type.*;
-
-import com.oracle.truffle.dsl.processor.java.*;
-
-public class TypeData extends MessageContainer implements Comparable<TypeData> {
-
-    private final TypeSystemData typeSystem;
-    private final AnnotationValue annotationValue;
-    private final TypeMirror primitiveType;
-    private final TypeMirror boxedType;
-
-    private final int index;
-    private final List<TypeCastData> typeCasts = new ArrayList<>();
-    private final List<TypeCheckData> typeChecks = new ArrayList<>();
-
-    public TypeData(TypeSystemData typeSystem, int index, AnnotationValue value, TypeMirror primitiveType, TypeMirror boxedType) {
-        this.index = index;
-        this.typeSystem = typeSystem;
-        this.annotationValue = value;
-        this.primitiveType = primitiveType;
-        this.boxedType = boxedType;
-    }
-
-    public int getIndex() {
-        return index;
-    }
-
-    public boolean isDefaultCast() {
-        return getTypeCasts().isEmpty();
-    }
-
-    public boolean isDefaultCheck() {
-        return getTypeChecks().isEmpty();
-    }
-
-    @Override
-    public Element getMessageElement() {
-        return typeSystem.getMessageElement();
-    }
-
-    @Override
-    public AnnotationMirror getMessageAnnotation() {
-        return typeSystem.getMessageAnnotation();
-    }
-
-    @Override
-    public AnnotationValue getMessageAnnotationValue() {
-        return annotationValue;
-    }
-
-    public void addTypeCast(TypeCastData typeCast) {
-        this.typeCasts.add(typeCast);
-    }
-
-    public void addTypeCheck(TypeCheckData typeCheck) {
-        this.typeChecks.add(typeCheck);
-    }
-
-    public List<TypeCastData> getTypeCasts() {
-        return typeCasts;
-    }
-
-    public List<TypeCheckData> getTypeChecks() {
-        return typeChecks;
-    }
-
-    public TypeSystemData getTypeSystem() {
-        return typeSystem;
-    }
-
-    public TypeMirror getPrimitiveType() {
-        return primitiveType;
-    }
-
-    public TypeMirror getBoxedType() {
-        return boxedType;
-    }
-
-    public boolean isGeneric() {
-        return ElementUtils.typeEquals(boxedType, getTypeSystem().getGenericType());
-    }
-
-    public boolean isVoid() {
-        if (getTypeSystem().getVoidType() == null) {
-            return false;
-        }
-        return ElementUtils.typeEquals(boxedType, getTypeSystem().getVoidType().getBoxedType());
-    }
-
-    public int compareTo(TypeData o) {
-        if (this.equals(o)) {
-            return 0;
-        }
-        return index - o.index;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(index, primitiveType);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof TypeData)) {
-            return false;
-        }
-        TypeData otherType = (TypeData) obj;
-        return index == otherType.index && ElementUtils.typeEquals(primitiveType, otherType.primitiveType);
-    }
-
-    @Override
-    public String toString() {
-        return getClass().getSimpleName() + "[" + ElementUtils.getSimpleName(primitiveType) + "]";
-    }
-
-    public boolean equalsType(TypeData actualTypeData) {
-        return ElementUtils.typeEquals(boxedType, actualTypeData.boxedType);
-    }
-
-    public boolean needsCastTo(TypeData targetType) {
-        return ElementUtils.needsCastTo(getPrimitiveType(), targetType.getPrimitiveType());
-    }
-
-    public boolean needsCastTo(TypeMirror targetType) {
-        return ElementUtils.needsCastTo(getPrimitiveType(), targetType);
-    }
-
-    public boolean isPrimitive() {
-        return ElementUtils.isPrimitive(getPrimitiveType());
-    }
-
-    public List<TypeData> getImplicitSourceTypes() {
-        return getTypeSystem().lookupSourceTypes(this);
-    }
-
-    public boolean hasImplicitSourceTypes() {
-        return getTypeSystem().hasImplicitSourceTypes(this);
-    }
-
-    public boolean isImplicitSubtypeOf(TypeData other) {
-        List<ImplicitCastData> casts = other.getTypeSystem().lookupByTargetType(other);
-        for (ImplicitCastData cast : casts) {
-            if (isSubtypeOf(cast.getSourceType())) {
-                return true;
-            }
-        }
-        return isSubtypeOf(other);
-    }
-
-    public boolean isSubtypeOf(TypeData other) {
-        return ElementUtils.isSubtype(boxedType, other.boxedType);
-    }
-
-}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java	Wed Apr 15 11:03:04 2015 -0700
@@ -33,24 +33,24 @@
 
 public class TypeSystemData extends Template {
 
-    private List<TypeData> types;
-    private List<TypeMirror> primitiveTypeMirrors = new ArrayList<>();
-    private List<TypeMirror> boxedTypeMirrors = new ArrayList<>();
-    private Map<String, TypeData> cachedTypes = new HashMap<>();
+    private final List<ImplicitCastData> implicitCasts = new ArrayList<>();
+    private final List<TypeCastData> casts = new ArrayList<>();
+    private final List<TypeCheckData> checks = new ArrayList<>();
+    private final List<TypeMirror> legacyTypes = new ArrayList<>();
 
-    private List<ImplicitCastData> implicitCasts;
-    private List<TypeCastData> casts;
-    private List<TypeCheckData> checks;
+    private Set<String> legacyTypeIds;
 
-    private TypeMirror genericType;
-    private TypeData booleanType;
-    private TypeData voidType;
+    private final boolean isDefault;
+    private final DSLOptions options;
 
-    private DSLOptions options;
-
-    public TypeSystemData(ProcessorContext context, TypeElement templateType, AnnotationMirror annotation, DSLOptions options) {
+    public TypeSystemData(ProcessorContext context, TypeElement templateType, AnnotationMirror annotation, DSLOptions options, boolean isDefault) {
         super(context, templateType, annotation);
         this.options = options;
+        this.isDefault = isDefault;
+    }
+
+    public boolean isDefault() {
+        return isDefault;
     }
 
     public DSLOptions getOptions() {
@@ -62,48 +62,43 @@
         return this;
     }
 
-    public void setTypes(List<TypeData> types) {
-        this.types = types;
-        if (types != null) {
-            for (TypeData typeData : types) {
-                primitiveTypeMirrors.add(typeData.getPrimitiveType());
-                boxedTypeMirrors.add(typeData.getBoxedType());
-                cachedTypes.put(ElementUtils.getUniqueIdentifier(typeData.getPrimitiveType()), typeData);
-                cachedTypes.put(ElementUtils.getUniqueIdentifier(typeData.getBoxedType()), typeData);
+    public List<TypeMirror> getLegacyTypes() {
+        return legacyTypes;
+    }
+
+    public TypeCastData getCast(TypeMirror targetType) {
+        for (TypeCastData cast : casts) {
+            if (ElementUtils.typeEquals(cast.getTargetType(), targetType)) {
+                return cast;
             }
         }
+        return null;
     }
 
-    public void setImplicitCasts(List<ImplicitCastData> implicitCasts) {
-        this.implicitCasts = implicitCasts;
+    public TypeCheckData getCheck(TypeMirror type) {
+        for (TypeCheckData check : checks) {
+            if (ElementUtils.typeEquals(check.getCheckedType(), type)) {
+                return check;
+            }
+        }
+        return null;
     }
 
     public List<ImplicitCastData> getImplicitCasts() {
         return implicitCasts;
     }
 
-    public void setCasts(List<TypeCastData> casts) {
-        this.casts = casts;
+    public List<TypeCastData> getCasts() {
+        return casts;
     }
 
-    public void setChecks(List<TypeCheckData> checks) {
-        this.checks = checks;
-    }
-
-    public void setGenericType(TypeMirror genericType) {
-        this.genericType = genericType;
-    }
-
-    public void setVoidType(TypeData voidType) {
-        this.voidType = voidType;
+    public List<TypeCheckData> getChecks() {
+        return checks;
     }
 
     @Override
     protected List<MessageContainer> findChildContainers() {
         List<MessageContainer> sinks = new ArrayList<>();
-        if (types != null) {
-            sinks.addAll(types);
-        }
         if (checks != null) {
             sinks.addAll(checks);
         }
@@ -116,75 +111,25 @@
         return sinks;
     }
 
-    public TypeData getVoidType() {
-        return voidType;
-    }
-
-    public List<TypeMirror> getBoxedTypeMirrors() {
-        return boxedTypeMirrors;
-    }
-
-    public List<TypeMirror> getPrimitiveTypeMirrors() {
-        return primitiveTypeMirrors;
-    }
-
-    public Set<String> getTypeIdentifiers() {
-        return cachedTypes.keySet();
-    }
-
-    public List<TypeData> getTypes() {
-        return types;
-    }
-
-    public TypeMirror getGenericType() {
-        return genericType;
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "[template = " + ElementUtils.getSimpleName(getTemplateType()) + "]";
     }
 
-    public TypeData getGenericTypeData() {
-        TypeData result = types.get(types.size() - 2);
-        assert result.getBoxedType() == genericType;
-        return result;
-    }
-
-    public TypeData findTypeData(TypeMirror type) {
-        if (ElementUtils.typeEquals(voidType.getPrimitiveType(), type)) {
-            return voidType;
-        }
-
-        int index = findType(type);
-        if (index == -1) {
-            return null;
-        }
-        return types.get(index);
-    }
-
-    public int findType(TypeMirror type) {
-        TypeData data = cachedTypes.get(ElementUtils.getUniqueIdentifier(type));
-        if (data != null) {
-            return data.getIndex();
-        }
-        return -1;
-    }
-
-    @Override
-    public String toString() {
-        return getClass().getSimpleName() + "[template = " + ElementUtils.getSimpleName(getTemplateType()) + ", types = " + types + "]";
-    }
-
-    public List<ImplicitCastData> lookupByTargetType(TypeData targetType) {
+    public List<ImplicitCastData> lookupByTargetType(TypeMirror targetType) {
         if (getImplicitCasts() == null) {
             return Collections.emptyList();
         }
         List<ImplicitCastData> foundCasts = new ArrayList<>();
         for (ImplicitCastData cast : getImplicitCasts()) {
-            if (cast.getTargetType().equals(targetType)) {
+            if (ElementUtils.typeEquals(cast.getTargetType(), targetType)) {
                 foundCasts.add(cast);
             }
         }
         return foundCasts;
     }
 
-    public ImplicitCastData lookupCast(TypeData sourceType, TypeData targetType) {
+    public ImplicitCastData lookupCast(TypeMirror sourceType, TypeMirror targetType) {
         if (getImplicitCasts() == null) {
             return null;
         }
@@ -196,38 +141,59 @@
         return null;
     }
 
-    public boolean hasImplicitSourceTypes(TypeData targetType) {
+    public boolean hasImplicitSourceTypes(TypeMirror targetType) {
         if (getImplicitCasts() == null) {
             return false;
         }
         for (ImplicitCastData cast : getImplicitCasts()) {
-            if (cast.getTargetType() == targetType) {
+            if (ElementUtils.typeEquals(cast.getTargetType(), targetType)) {
                 return true;
             }
         }
         return false;
     }
 
-    public List<TypeData> lookupSourceTypes(TypeData type) {
-        List<TypeData> sourceTypes = new ArrayList<>();
-        sourceTypes.add(type);
-        if (getImplicitCasts() != null) {
-            for (ImplicitCastData cast : getImplicitCasts()) {
-                if (cast.getTargetType() == type) {
-                    sourceTypes.add(cast.getSourceType());
-                }
+    public List<TypeMirror> lookupTargetTypes() {
+        List<TypeMirror> sourceTypes = new ArrayList<>();
+        for (ImplicitCastData cast : getImplicitCasts()) {
+            sourceTypes.add(cast.getTargetType());
+        }
+        return ElementUtils.uniqueSortedTypes(sourceTypes);
+    }
+
+    public List<TypeMirror> lookupSourceTypes(TypeMirror targetType) {
+        List<TypeMirror> sourceTypes = new ArrayList<>();
+        sourceTypes.add(targetType);
+        for (ImplicitCastData cast : getImplicitCasts()) {
+            if (ElementUtils.typeEquals(cast.getTargetType(), targetType)) {
+                sourceTypes.add(cast.getSourceType());
             }
         }
-        Collections.sort(sourceTypes);
         return sourceTypes;
     }
 
-    public TypeData getBooleanType() {
-        return booleanType;
+    public boolean isImplicitSubtypeOf(TypeMirror source, TypeMirror target) {
+        List<ImplicitCastData> targetCasts = lookupByTargetType(target);
+        for (ImplicitCastData cast : targetCasts) {
+            if (ElementUtils.isSubtype(boxType(source), boxType(cast.getSourceType()))) {
+                return true;
+            }
+        }
+        return ElementUtils.isSubtype(boxType(source), boxType(target));
     }
 
-    public void setBooleanType(TypeData booleanType) {
-        this.booleanType = booleanType;
+    public TypeMirror boxType(TypeMirror type) {
+        return ElementUtils.boxType(getContext(), type);
+    }
+
+    public boolean hasType(TypeMirror type) {
+        if (legacyTypeIds == null) {
+            legacyTypeIds = new HashSet<>();
+            for (TypeMirror legacyType : legacyTypes) {
+                legacyTypeIds.add(ElementUtils.getTypeId(legacyType));
+            }
+        }
+        return legacyTypeIds.contains(ElementUtils.getTypeId(type));
     }
 
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/CreateCastParser.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/CreateCastParser.java	Wed Apr 15 11:03:04 2015 -0700
@@ -59,7 +59,7 @@
             baseType = foundChild.getOriginalType();
         }
 
-        MethodSpec spec = new MethodSpec(new InheritsParameterSpec("child", baseType));
+        MethodSpec spec = new MethodSpec(new ParameterSpec("child", baseType));
         addDefaultFieldMethodSpec(spec);
         ParameterSpec childSpec = new ParameterSpec("castedChild", baseType);
         childSpec.setSignature(true);
@@ -96,22 +96,4 @@
         return cast;
     }
 
-    private static class InheritsParameterSpec extends ParameterSpec {
-
-        public InheritsParameterSpec(String name, TypeMirror... allowedTypes) {
-            super(name, Arrays.asList(allowedTypes), null);
-        }
-
-        @Override
-        public boolean matches(VariableElement variable) {
-            boolean found = false;
-            for (TypeMirror specType : getAllowedTypes()) {
-                if (ElementUtils.isAssignable(variable.asType(), specType)) {
-                    found = true;
-                    break;
-                }
-            }
-            return found;
-        }
-    }
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java	Wed Apr 15 10:09:13 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.dsl.processor.parser;
-
-import java.lang.annotation.*;
-import java.util.*;
-
-import javax.lang.model.element.*;
-import javax.lang.model.type.*;
-
-import com.oracle.truffle.api.dsl.*;
-import com.oracle.truffle.dsl.processor.*;
-import com.oracle.truffle.dsl.processor.java.*;
-import com.oracle.truffle.dsl.processor.model.*;
-
-public class ExecutableTypeMethodParser extends NodeMethodParser<ExecutableTypeData> {
-
-    private final List<TypeMirror> frameTypes;
-    private final NodeChildData child;
-
-    public ExecutableTypeMethodParser(ProcessorContext context, NodeData node, NodeChildData child, List<TypeMirror> frameTypes) {
-        super(context, node);
-        this.child = child;
-        this.frameTypes = frameTypes;
-        setParseNullOnError(false);
-        getParser().setEmitErrors(false);
-        getParser().setUseVarArgs(true);
-    }
-
-    @Override
-    public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        MethodSpec spec = createDefaultMethodSpec(method, mirror, false, null);
-        List<ParameterSpec> requiredSpecs = new ArrayList<>(spec.getRequired());
-        spec.getRequired().clear();
-
-        TypeSystemData typeSystem = getNode().getTypeSystem();
-        List<TypeMirror> allowedTypes = typeSystem.getPrimitiveTypeMirrors();
-        Set<String> allowedIdentifiers = typeSystem.getTypeIdentifiers();
-
-        if (child != null) {
-            for (NodeExecutionData executeWith : child.getExecuteWith()) {
-                ParameterSpec parameter = spec.addRequired(new ParameterSpec(executeWith.getName(), allowedTypes, allowedIdentifiers));
-                parameter.setExecution(executeWith);
-                parameter.setSignature(true);
-            }
-        } else {
-            for (ParameterSpec originalSpec : requiredSpecs) {
-                spec.addRequired(new ParameterSpec(originalSpec, allowedTypes, allowedIdentifiers));
-            }
-        }
-
-        spec.setIgnoreAdditionalSpecifications(true);
-        spec.setIgnoreAdditionalParameters(true);
-        spec.setVariableRequiredParameters(true);
-        // varargs
-        ParameterSpec otherParameters = new ParameterSpec("other", allowedTypes, allowedIdentifiers);
-        otherParameters.setSignature(true);
-        spec.addRequired(otherParameters);
-        return spec;
-    }
-
-    @Override
-    protected void addDefaultFrame(MethodSpec methodSpec) {
-        methodSpec.addOptional(new ParameterSpec("frame", frameTypes));
-    }
-
-    @Override
-    protected List<TypeMirror> nodeTypeMirrors(NodeData nodeData) {
-        return getNode().getTypeSystem().getPrimitiveTypeMirrors();
-    }
-
-    @Override
-    protected Set<String> nodeTypeIdentifiers(NodeData nodeData) {
-        return getNode().getTypeSystem().getTypeIdentifiers();
-    }
-
-    @Override
-    public final boolean isParsable(ExecutableElement method) {
-        if (method.getModifiers().contains(Modifier.STATIC)) {
-            return false;
-        } else if (method.getModifiers().contains(Modifier.NATIVE)) {
-            return false;
-        } else if (ElementUtils.findAnnotationMirror(getContext().getEnvironment(), method, Specialization.class) != null) {
-            return false;
-        } else if (method.getModifiers().contains(Modifier.PRIVATE)) {
-            return false;
-        }
-        return method.getSimpleName().toString().startsWith("execute");
-    }
-
-    @Override
-    public ExecutableTypeData create(TemplateMethod method, boolean invalid) {
-        TypeData resolvedType = method.getReturnType().getTypeSystemType();
-        return new ExecutableTypeData(method, method.getMethod(), getNode().getTypeSystem(), resolvedType);
-    }
-
-    @Override
-    public Class<? extends Annotation> getAnnotationType() {
-        return null;
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/FallbackParser.java	Wed Apr 15 11:03:04 2015 -0700
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2012, 2015, 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.dsl.processor.parser;
+
+import java.lang.annotation.*;
+
+import javax.lang.model.element.*;
+
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.dsl.processor.*;
+import com.oracle.truffle.dsl.processor.model.*;
+import com.oracle.truffle.dsl.processor.model.SpecializationData.SpecializationKind;
+
+public class FallbackParser extends NodeMethodParser<SpecializationData> {
+
+    public FallbackParser(ProcessorContext context, NodeData node) {
+        super(context, node);
+    }
+
+    @Override
+    public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
+        return createDefaultMethodSpec(method, mirror, true, null);
+    }
+
+    @Override
+    protected ParameterSpec createValueParameterSpec(NodeExecutionData execution) {
+        ParameterSpec parameterSpec = super.createValueParameterSpec(execution);
+        parameterSpec.setAllowSubclasses(false);
+        return parameterSpec;
+    }
+
+    @Override
+    public SpecializationData create(TemplateMethod method, boolean invalid) {
+        return new SpecializationData(getNode(), method, SpecializationKind.FALLBACK);
+    }
+
+    @Override
+    public Class<? extends Annotation> getAnnotationType() {
+        return Fallback.class;
+    }
+
+}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GenericParser.java	Wed Apr 15 10:09:13 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.dsl.processor.parser;
-
-import java.lang.annotation.*;
-import java.util.*;
-
-import javax.lang.model.element.*;
-import javax.lang.model.type.*;
-
-import com.oracle.truffle.api.dsl.*;
-import com.oracle.truffle.dsl.processor.*;
-import com.oracle.truffle.dsl.processor.java.*;
-import com.oracle.truffle.dsl.processor.model.*;
-import com.oracle.truffle.dsl.processor.model.SpecializationData.SpecializationKind;
-
-public class GenericParser extends NodeMethodParser<SpecializationData> {
-
-    public GenericParser(ProcessorContext context, NodeData node) {
-        super(context, node);
-    }
-
-    @Override
-    public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        return createDefaultMethodSpec(method, mirror, true, null);
-    }
-
-    @Override
-    protected ParameterSpec createValueParameterSpec(NodeExecutionData execution) {
-        List<ExecutableTypeData> execTypes = execution.getChild().findGenericExecutableTypes(getContext());
-        List<TypeMirror> types = new ArrayList<>();
-        Set<String> typeIds = new HashSet<>();
-        for (ExecutableTypeData type : execTypes) {
-            TypeMirror typeMirror = type.getType().getPrimitiveType();
-            types.add(typeMirror);
-            typeIds.add(ElementUtils.getUniqueIdentifier(typeMirror));
-        }
-        ParameterSpec spec = new ParameterSpec(execution.getName(), types, typeIds);
-        spec.setExecution(execution);
-        return spec;
-    }
-
-    @Override
-    public SpecializationData create(TemplateMethod method, boolean invalid) {
-        return new SpecializationData(getNode(), method, SpecializationKind.FALLBACK);
-    }
-
-    @Override
-    public Class<? extends Annotation> getAnnotationType() {
-        return Fallback.class;
-    }
-
-}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ImplicitCastParser.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ImplicitCastParser.java	Wed Apr 15 11:03:04 2015 -0700
@@ -23,13 +23,13 @@
 package com.oracle.truffle.dsl.processor.parser;
 
 import java.lang.annotation.*;
-import java.util.*;
 
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.dsl.processor.*;
+import com.oracle.truffle.dsl.processor.java.*;
 import com.oracle.truffle.dsl.processor.model.*;
 
 public class ImplicitCastParser extends TypeSystemMethodParser<ImplicitCastData> {
@@ -45,10 +45,8 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        List<TypeMirror> types = getTypeSystem().getPrimitiveTypeMirrors();
-        Set<String> identifiers = getTypeSystem().getTypeIdentifiers();
-        MethodSpec spec = new MethodSpec(new ParameterSpec("target", types, identifiers));
-        spec.addRequired(new ParameterSpec("source", types, identifiers)).setSignature(true);
+        MethodSpec spec = new MethodSpec(new ParameterSpec("target", getContext().getType(Object.class)));
+        spec.addRequired(new ParameterSpec("source", getContext().getType(Object.class))).setSignature(true);
         return spec;
     }
 
@@ -61,10 +59,10 @@
         Parameter target = method.findParameter("targetValue");
         Parameter source = method.findParameter("sourceValue");
 
-        TypeData targetType = target.getTypeSystemType();
-        TypeData sourceType = source.getTypeSystemType();
+        TypeMirror targetType = target.getType();
+        TypeMirror sourceType = source.getType();
 
-        if (targetType.equals(sourceType)) {
+        if (ElementUtils.typeEquals(targetType, sourceType)) {
             method.addError("Target type and source type of an @%s must not be the same type.", ImplicitCast.class.getSimpleName());
         }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java	Wed Apr 15 11:03:04 2015 -0700
@@ -48,10 +48,6 @@
         return template;
     }
 
-    public TypeSystemData getTypeSystem() {
-        return template.getTypeSystem();
-    }
-
     public boolean isEmitErrors() {
         return emitErrors;
     }
@@ -85,7 +81,7 @@
         ParameterSpec returnTypeSpec = methodSpecification.getReturnType();
         Parameter returnTypeMirror = matchParameter(returnTypeSpec, new CodeVariableElement(returnType, "returnType"), -1, -1);
         if (returnTypeMirror == null) {
-            if (emitErrors) {
+            if (isEmitErrors() && method != null) {
                 TemplateMethod invalidMethod = new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections.<Parameter> emptyList());
                 String expectedReturnType = returnTypeSpec.toSignatureString(true);
                 String actualReturnType = ElementUtils.getSimpleName(returnType);
@@ -135,7 +131,7 @@
      * end matching the required arguments, parsing fails. Parameters prior to the parsed required
      * ones are cut and used to parse the optional parameters.
      */
-    private List<Parameter> parseParameters(MethodSpec spec, List<? extends VariableElement> parameterTypes, boolean varArgs) {
+    private static List<Parameter> parseParameters(MethodSpec spec, List<? extends VariableElement> parameterTypes, boolean varArgs) {
         List<Parameter> parsedRequired = null;
         int offset = 0;
         for (; offset <= parameterTypes.size(); offset++) {
@@ -166,7 +162,7 @@
         return finalParameters;
     }
 
-    private List<Parameter> parseParametersOptional(MethodSpec spec, List<? extends VariableElement> types) {
+    private static List<Parameter> parseParametersOptional(MethodSpec spec, List<? extends VariableElement> types) {
         List<Parameter> parsedParams = new ArrayList<>();
 
         int typeStartIndex = 0;
@@ -191,7 +187,7 @@
         return parsedParams;
     }
 
-    private List<Parameter> parseParametersRequired(MethodSpec spec, List<VariableElement> types, boolean typeVarArgs) {
+    private static List<Parameter> parseParametersRequired(MethodSpec spec, List<VariableElement> types, boolean typeVarArgs) {
         List<Parameter> parsedParams = new ArrayList<>();
         List<ParameterSpec> specifications = spec.getRequired();
         boolean specVarArgs = spec.isVariableRequiredParameters();
@@ -248,7 +244,7 @@
         return parsedParams;
     }
 
-    private Parameter matchAnnotatedParameter(MethodSpec spec, VariableElement variable) {
+    private static Parameter matchAnnotatedParameter(MethodSpec spec, VariableElement variable) {
         for (ParameterSpec parameterSpec : spec.getAnnotations()) {
             if (parameterSpec.matches(variable)) {
                 Parameter matchedParameter = matchParameter(parameterSpec, variable, -1, -1);
@@ -286,7 +282,7 @@
         }
     }
 
-    private Parameter matchParameter(ParameterSpec specification, VariableElement variable, int specificationIndex, int varArgsIndex) {
+    private static Parameter matchParameter(ParameterSpec specification, VariableElement variable, int specificationIndex, int varArgsIndex) {
         TypeMirror resolvedType = variable.asType();
         if (hasError(resolvedType)) {
             return null;
@@ -296,12 +292,6 @@
             return null;
         }
 
-        TypeData resolvedTypeData = getTypeSystem().findTypeData(resolvedType);
-        if (resolvedTypeData != null) {
-            return new Parameter(specification, resolvedTypeData, variable, specificationIndex, varArgsIndex);
-        } else {
-            return new Parameter(specification, variable, specificationIndex, varArgsIndex);
-        }
+        return new Parameter(specification, variable, specificationIndex, varArgsIndex);
     }
-
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeMethodParser.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeMethodParser.java	Wed Apr 15 11:03:04 2015 -0700
@@ -42,26 +42,25 @@
     }
 
     protected ParameterSpec createValueParameterSpec(NodeExecutionData execution) {
-        NodeData childNode = execution.getChild().getNodeData();
-        ParameterSpec spec = new ParameterSpec(execution.getName(), nodeTypeMirrors(childNode), nodeTypeIdentifiers(childNode));
+        ParameterSpec spec = new ParameterSpec(execution.getName(), getPossibleParameterTypes(execution));
         spec.setExecution(execution);
         return spec;
     }
 
-    protected List<TypeMirror> nodeTypeMirrors(NodeData nodeData) {
-        return nodeData.getTypeSystem().getPrimitiveTypeMirrors();
-    }
-
-    protected Set<String> nodeTypeIdentifiers(NodeData nodeData) {
-        return nodeData.getTypeSystem().getTypeIdentifiers();
+    protected Collection<TypeMirror> getPossibleParameterTypes(NodeExecutionData execution) {
+        return getNode().getGenericTypes(execution);
     }
 
     protected ParameterSpec createReturnParameterSpec() {
-        ParameterSpec returnValue = new ParameterSpec("returnValue", nodeTypeMirrors(getNode()), nodeTypeIdentifiers(getNode()));
+        ParameterSpec returnValue = new ParameterSpec("returnValue", getPossibleReturnTypes());
         returnValue.setExecution(getNode().getThisExecution());
         return returnValue;
     }
 
+    protected Collection<TypeMirror> getPossibleReturnTypes() {
+        return Arrays.asList(getNode().getGenericType(getNode().getThisExecution()));
+    }
+
     @Override
     public boolean isParsable(ExecutableElement method) {
         if (getAnnotationType() != null) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java	Wed Apr 15 11:03:04 2015 -0700
@@ -32,7 +32,8 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
-import com.oracle.truffle.api.dsl.NodeField;
+import com.oracle.truffle.api.dsl.internal.*;
+import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.dsl.processor.*;
 import com.oracle.truffle.dsl.processor.expression.*;
@@ -43,8 +44,8 @@
 import com.oracle.truffle.dsl.processor.model.*;
 import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality;
 import com.oracle.truffle.dsl.processor.model.SpecializationData.SpecializationKind;
-import com.oracle.truffle.dsl.processor.model.TemplateMethod.TypeSignature;
 
+@DSLOptions
 public class NodeParser extends AbstractParser<NodeData> {
 
     public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Fallback.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, NodeChild.class,
@@ -103,8 +104,9 @@
         } catch (CompileErrorException e) {
             throw e;
         } catch (Throwable e) {
-            e.addSuppressed(new RuntimeException(String.format("Parsing of Node %s failed.", ElementUtils.getQualifiedName(rootType)), e));
-            throw e;
+            RuntimeException e2 = new RuntimeException(String.format("Parsing of Node %s failed.", ElementUtils.getQualifiedName(rootType)));
+            e2.addSuppressed(e);
+            throw e2;
         }
         if (node == null && !enclosedNodes.isEmpty()) {
             node = new NodeData(context, rootType);
@@ -145,33 +147,33 @@
 
         node.getFields().addAll(parseFields(lookupTypes, members));
         node.getChildren().addAll(parseChildren(lookupTypes, members));
-        node.getChildExecutions().addAll(parseExecutions(node.getChildren(), members));
-        node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node, null, context.getFrameTypes()).parse(members)));
+        node.getChildExecutions().addAll(parseExecutions(node.getFields(), node.getChildren(), members));
+        node.getExecutableTypes().addAll(parseExecutableTypeData(members, node.getChildExecutions().size(), context.getFrameTypes(), false));
 
         initializeExecutableTypes(node);
         initializeImportGuards(node, lookupTypes, members);
-
-        if (node.hasErrors()) {
-            return node; // error sync point
-        }
-
         initializeChildren(node);
 
         if (node.hasErrors()) {
             return node; // error sync point
         }
 
+        if (node.hasErrors()) {
+            return node; // error sync point
+        }
+
         node.getSpecializations().addAll(new SpecializationMethodParser(context, node).parse(members));
-        node.getSpecializations().addAll(new GenericParser(context, node).parse(members));
+        node.getSpecializations().addAll(new FallbackParser(context, node).parse(members));
         node.getCasts().addAll(new CreateCastParser(context, node).parse(members));
         node.getShortCircuits().addAll(new ShortCircuitParser(context, node).parse(members));
 
         if (node.hasErrors()) {
             return node;  // error sync point
         }
+        initializeSpecializations(members, node);
+        initializeExecutableTypeHierarchy(node);
 
         verifySpecializationSameLength(node);
-        initializeSpecializations(members, node);
         initializeShortCircuits(node); // requires specializations and polymorphic specializations
 
         verifyVisibilities(node);
@@ -182,6 +184,67 @@
         return node;
     }
 
+    private static void initializeExecutableTypeHierarchy(NodeData node) {
+        SpecializationData polymorphic = node.getPolymorphicSpecialization();
+        if (polymorphic != null) {
+            boolean polymorphicSignatureFound = false;
+            TypeMirror frame = polymorphic.getFrame() != null ? polymorphic.getFrame().getType() : null;
+            ExecutableTypeData polymorphicType = new ExecutableTypeData(polymorphic.getReturnType().getType(), "execute", frame, TemplateMethod.getSignatureTypes(polymorphic));
+            for (ExecutableTypeData type : node.getExecutableTypes()) {
+                if (polymorphicType.sameSignature(type)) {
+                    polymorphicSignatureFound = true;
+                    break;
+                }
+            }
+
+            if (!polymorphicSignatureFound) {
+                node.getExecutableTypes().add(polymorphicType);
+            }
+        }
+
+        List<ExecutableTypeData> rootTypes = buildExecutableHierarchy(node);
+        List<ExecutableTypeData> additionalAbstractRootTypes = new ArrayList<>();
+        for (int i = 1; i < rootTypes.size(); i++) {
+            ExecutableTypeData rootType = rootTypes.get(i);
+            if (rootType.isAbstract()) {
+                // cannot implemement root
+                additionalAbstractRootTypes.add(rootType);
+            } else {
+                node.getExecutableTypes().remove(rootType);
+            }
+        }
+        if (!additionalAbstractRootTypes.isEmpty()) {
+            node.addError("Incompatible abstract execute methods found %s.", rootTypes);
+        }
+
+    }
+
+    private static List<ExecutableTypeData> buildExecutableHierarchy(NodeData node) {
+        List<ExecutableTypeData> executes = node.getExecutableTypes();
+        if (executes.isEmpty()) {
+            return Collections.emptyList();
+        }
+        List<ExecutableTypeData> hierarchyExecutes = new ArrayList<>(executes);
+        Collections.sort(hierarchyExecutes);
+        ExecutableTypeData parent = hierarchyExecutes.get(0);
+        ListIterator<ExecutableTypeData> executesIterator = hierarchyExecutes.listIterator(1);
+        buildExecutableHierarchy(node, parent, executesIterator);
+        return hierarchyExecutes;
+    }
+
+    private static void buildExecutableHierarchy(NodeData node, ExecutableTypeData parent, ListIterator<ExecutableTypeData> executesIterator) {
+        while (executesIterator.hasNext()) {
+            ExecutableTypeData other = executesIterator.next();
+            if (other.canDelegateTo(node, parent)) {
+                parent.addDelegatedFrom(other);
+                executesIterator.remove();
+            }
+        }
+        for (int i = 1; i < parent.getDelegatedFrom().size(); i++) {
+            buildExecutableHierarchy(node, parent.getDelegatedFrom().get(i - 1), parent.getDelegatedFrom().listIterator(i));
+        }
+    }
+
     private List<Element> loadMembers(TypeElement templateType) {
         List<Element> members = new ArrayList<>(CompilerFactory.getCompiler(templateType).getAllMembersInDeclarationOrder(context.getEnvironment(), templateType));
 
@@ -256,20 +319,19 @@
 
     private NodeData parseNodeData(TypeElement templateType, List<TypeElement> typeHierarchy) {
         AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class);
-        if (typeSystemMirror == null) {
-            NodeData nodeData = new NodeData(context, templateType);
-            nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), ElementUtils.getQualifiedName(templateType));
-            return nodeData;
+        TypeSystemData typeSystem = null;
+        if (typeSystemMirror != null) {
+            TypeMirror typeSystemType = ElementUtils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value");
+            typeSystem = (TypeSystemData) context.getTemplate(typeSystemType, true);
+            if (typeSystem == null) {
+                NodeData nodeData = new NodeData(context, templateType);
+                nodeData.addError("The used type system '%s' is invalid. Fix errors in the type system first.", ElementUtils.getQualifiedName(typeSystemType));
+                return nodeData;
+            }
+        } else {
+            // default dummy type system
+            typeSystem = new TypeSystemData(context, templateType, null, NodeParser.class.getAnnotation(DSLOptions.class), true);
         }
-
-        TypeMirror typeSystemType = ElementUtils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value");
-        final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSystemType, true);
-        if (typeSystem == null) {
-            NodeData nodeData = new NodeData(context, templateType);
-            nodeData.addError("The used type system '%s' is invalid. Fix errors in the type system first.", ElementUtils.getQualifiedName(typeSystemType));
-            return nodeData;
-        }
-
         AnnotationMirror nodeInfoMirror = findFirstAnnotation(typeHierarchy, NodeInfo.class);
         String shortName = null;
         if (nodeInfoMirror != null) {
@@ -406,11 +468,7 @@
         return filteredChildren;
     }
 
-    private List<NodeExecutionData> parseExecutions(List<NodeChildData> children, List<? extends Element> elements) {
-        if (children == null) {
-            return null;
-        }
-
+    private List<NodeExecutionData> parseExecutions(List<NodeFieldData> fields, List<NodeChildData> children, List<? extends Element> elements) {
         // pre-parse short circuits
         Set<String> shortCircuits = new HashSet<>();
         List<ExecutableElement> methods = ElementFilter.methodsIn(elements);
@@ -433,6 +491,13 @@
             }
         }
 
+        List<NodeFieldData> nonGetterFields = new ArrayList<>();
+        for (NodeFieldData field : fields) {
+            if (field.getGetter() == null && field.isGenerated()) {
+                nonGetterFields.add(field);
+            }
+        }
+
         TypeMirror cacheAnnotation = context.getType(Cached.class);
         List<TypeMirror> frameTypes = context.getFrameTypes();
         // pre-parse specializations to find signature size
@@ -443,34 +508,40 @@
             }
             int currentArgumentIndex = 0;
             boolean skipShortCircuit = false;
-            outer: for (VariableElement var : method.getParameters()) {
+            parameter: for (VariableElement var : method.getParameters()) {
+                if (skipShortCircuit) {
+                    skipShortCircuit = false;
+                    continue parameter;
+                }
 
                 TypeMirror type = var.asType();
                 if (currentArgumentIndex == 0) {
                     // skip optionals
                     for (TypeMirror frameType : frameTypes) {
                         if (ElementUtils.typeEquals(type, frameType)) {
-                            continue outer;
+                            continue parameter;
+                        }
+                    }
+                }
+
+                if (currentArgumentIndex < nonGetterFields.size()) {
+                    for (NodeFieldData field : nonGetterFields) {
+                        if (ElementUtils.typeEquals(var.asType(), field.getType())) {
+                            continue parameter;
                         }
                     }
                 }
 
                 if (ElementUtils.findAnnotationMirror(var.getAnnotationMirrors(), cacheAnnotation) != null) {
-                    continue outer;
+                    continue parameter;
                 }
 
                 int childIndex = currentArgumentIndex < children.size() ? currentArgumentIndex : children.size() - 1;
-                if (childIndex == -1) {
-                    continue;
-                }
-                if (!skipShortCircuit) {
+                if (childIndex != -1) {
                     NodeChildData child = children.get(childIndex);
                     if (shortCircuits.contains(NodeExecutionData.createIndexedName(child, currentArgumentIndex - childIndex))) {
                         skipShortCircuit = true;
-                        continue;
                     }
-                } else {
-                    skipShortCircuit = false;
                 }
 
                 currentArgumentIndex++;
@@ -480,24 +551,82 @@
 
         List<NodeExecutionData> executions = new ArrayList<>();
         for (int i = 0; i < maxSignatureSize; i++) {
+            boolean varArgParameter = false;
             int childIndex = i;
-            boolean varArg = false;
-            if (childIndex >= children.size() - 1) {
+            if (i >= children.size() - 1) {
                 if (hasVarArgs) {
-                    childIndex = children.size() - 1;
-                    varArg = hasVarArgs;
-                } else if (childIndex >= children.size()) {
-                    break;
+                    varArgParameter = hasVarArgs;
+                    childIndex = Math.min(i, children.size() - 1);
+                } else if (i >= children.size()) {
+                    childIndex = -1;
                 }
             }
-            int varArgsIndex = varArg ? Math.abs(childIndex - i) : -1;
-            NodeChildData child = children.get(childIndex);
-            boolean shortCircuit = shortCircuits.contains(NodeExecutionData.createIndexedName(child, varArgsIndex));
-            executions.add(new NodeExecutionData(child, varArgsIndex, shortCircuit));
+            int varArgsIndex = -1;
+            boolean shortCircuit = false;
+            NodeChildData child = null;
+            if (childIndex != -1) {
+                varArgsIndex = varArgParameter ? Math.abs(childIndex - i) : -1;
+                child = children.get(childIndex);
+                shortCircuit = shortCircuits.contains(NodeExecutionData.createIndexedName(child, varArgsIndex));
+            }
+            executions.add(new NodeExecutionData(child, i, varArgsIndex, shortCircuit));
         }
         return executions;
     }
 
+    private List<ExecutableTypeData> parseExecutableTypeData(List<? extends Element> elements, int signatureSize, List<TypeMirror> frameTypes, boolean includeFinals) {
+        List<ExecutableTypeData> typeData = new ArrayList<>();
+        for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
+            Set<Modifier> modifiers = method.getModifiers();
+            if (modifiers.contains(Modifier.PRIVATE) || modifiers.contains(Modifier.STATIC)) {
+                continue;
+            }
+            if (!includeFinals && modifiers.contains(Modifier.FINAL)) {
+                continue;
+            }
+
+            if (!method.getSimpleName().toString().startsWith("execute")) {
+                continue;
+            }
+            if (ElementUtils.findAnnotationMirror(context.getEnvironment(), method, Specialization.class) != null) {
+                continue;
+            }
+
+            ExecutableTypeData executableType = new ExecutableTypeData(method, signatureSize, context.getFrameTypes());
+
+            if (executableType.getFrameParameter() != null) {
+                boolean supportedType = false;
+                for (TypeMirror type : frameTypes) {
+                    if (ElementUtils.isAssignable(type, executableType.getFrameParameter())) {
+                        supportedType = true;
+                        break;
+                    }
+                }
+                if (!supportedType) {
+                    continue;
+                }
+            }
+
+            typeData.add(executableType);
+        }
+
+        Collections.sort(typeData);
+
+        List<String> names = new ArrayList<>();
+        for (ExecutableTypeData type : typeData) {
+            names.add(type.getUniqueName());
+        }
+        while (renameDuplicateIds(names)) {
+            // fix point
+        }
+
+        for (int i = 0; i < typeData.size(); i++) {
+            typeData.get(i).setUniqueName(names.get(i));
+        }
+
+        return typeData;
+    }
+
     private void initializeExecutableTypes(NodeData node) {
         List<ExecutableTypeData> allExecutes = node.getExecutableTypes();
 
@@ -507,10 +636,10 @@
         for (ExecutableTypeData execute : allExecutes) {
             evaluatedCounts.add(execute.getEvaluatedCount());
 
-            Parameter frame = execute.getFrame();
+            TypeMirror frame = execute.getFrameParameter();
             TypeMirror resolvedFrameType;
             if (frame != null) {
-                resolvedFrameType = frame.getType();
+                resolvedFrameType = frame;
                 if (frameType == null) {
                     frameType = resolvedFrameType;
                 } else if (!ElementUtils.typeEquals(frameType, resolvedFrameType)) {
@@ -532,70 +661,49 @@
 
         node.setFrameType(frameType);
 
-        int totalGenericCount = 0;
-        int totalVoidCount = 0;
-        for (Integer evaluatedCount : evaluatedCounts) {
-            List<ExecutableTypeData> genericExecutes = node.findGenericExecutableTypes(context, evaluatedCount);
-            int genericCount = 0;
-            int voidCount = 0;
-            for (ExecutableTypeData executableTypeData : genericExecutes) {
-                if (!executableTypeData.getMethod().getModifiers().contains(Modifier.FINAL)) {
-                    if (ElementUtils.isVoid(executableTypeData.getReturnType().getType())) {
-                        voidCount++;
-                    } else {
-                        genericCount++;
-                    }
-                }
+        boolean genericFound = false;
+        for (ExecutableTypeData type : node.getExecutableTypes()) {
+            if (!type.hasUnexpectedValue(context)) {
+                genericFound = true;
+                break;
             }
-            // multiple generic execute
-            if (evaluatedCount == 0) {
-                if (voidCount > 1) {
-                    List<String> methodSignatures = new ArrayList<>();
-                    for (ExecutableTypeData type : genericExecutes) {
-                        if (type.getType().isVoid()) {
-                            methodSignatures.add(type.createReferenceName());
-                        }
-                    }
-                    node.addWarning("Multiple accessible and overridable generic execute methods found %s. Remove all but one or mark all but one as final.", methodSignatures);
-                } else if (genericCount > 1) {
-                    List<String> methodSignatures = new ArrayList<>();
-                    for (ExecutableTypeData type : genericExecutes) {
-                        if (!type.getType().isVoid()) {
-                            methodSignatures.add(type.createReferenceName());
-                        }
-                    }
-                    node.addWarning("Multiple accessible and overridable generic execute methods found %s. Remove all but one or mark all but one as final.", methodSignatures);
-                }
-            }
-            totalGenericCount += genericCount;
-            totalVoidCount += voidCount;
         }
 
         // no generic executes
-        if (totalGenericCount + totalVoidCount == 0) {
+        if (!genericFound) {
             node.addError("No accessible and overridable generic execute method found. Generic execute methods usually have the "
                             + "signature 'public abstract {Type} execute(VirtualFrame)' and must not throw any checked exceptions.");
         }
 
-    }
-
-    private static Map<Integer, List<ExecutableTypeData>> groupExecutableTypes(List<ExecutableTypeData> executableTypes) {
-        Map<Integer, List<ExecutableTypeData>> groupedTypes = new TreeMap<>();
-        for (ExecutableTypeData type : executableTypes) {
-            int evaluatedCount = type.getEvaluatedCount();
-
-            List<ExecutableTypeData> types = groupedTypes.get(evaluatedCount);
-            if (types == null) {
-                types = new ArrayList<>();
-                groupedTypes.put(evaluatedCount, types);
+        int nodeChildDeclarations = 0;
+        int nodeChildDeclarationsRequired = 0;
+        List<NodeExecutionData> executions = node.getChildExecutions();
+        for (NodeExecutionData execution : executions) {
+            if (execution.getChild() == null) {
+                nodeChildDeclarationsRequired = execution.getIndex() + 1;
+            } else {
+                nodeChildDeclarations++;
             }
-            types.add(type);
         }
 
-        for (List<ExecutableTypeData> types : groupedTypes.values()) {
-            Collections.sort(types);
+        List<String> requireNodeChildDeclarations = new ArrayList<>();
+        for (ExecutableTypeData type : allExecutes) {
+            if (type.getEvaluatedCount() < nodeChildDeclarationsRequired) {
+                requireNodeChildDeclarations.add(ElementUtils.createReferenceName(type.getMethod()));
+            }
         }
-        return groupedTypes;
+
+        if (!requireNodeChildDeclarations.isEmpty()) {
+            node.addError("Not enough child node declarations found. Please annotate the node class with addtional @NodeChild annotations or remove all execute methods that do not provide all evaluated values. "
+                            + "The following execute methods do not provide all evaluated values for the expected signature size %s: %s.", executions.size(), requireNodeChildDeclarations);
+        }
+
+        if (nodeChildDeclarations > 0 && executions.size() == node.getMinimalEvaluatedParameters()) {
+            for (NodeChildData child : node.getChildren()) {
+                child.addError("Unnecessary @NodeChild declaration. All evaluated child values are provided as parameters in execute methods.");
+            }
+        }
+
     }
 
     private void initializeChildren(NodeData node) {
@@ -608,10 +716,6 @@
             child.setNode(fieldNodeData);
             if (fieldNodeData == null || fieldNodeData.hasErrors()) {
                 child.addError("Node type '%s' is invalid or not a subclass of Node.", ElementUtils.getQualifiedName(nodeType));
-            } else if (!ElementUtils.typeEquals(fieldNodeData.getTypeSystem().getTemplateType().asType(), (node.getTypeSystem().getTemplateType().asType()))) {
-                child.addError("The @%s of the node and the @%s of the @%s does not match. %s != %s. ", TypeSystem.class.getSimpleName(), TypeSystem.class.getSimpleName(),
-                                NodeChild.class.getSimpleName(), ElementUtils.getSimpleName(node.getTypeSystem().getTemplateType()),
-                                ElementUtils.getSimpleName(fieldNodeData.getTypeSystem().getTemplateType()));
             } else {
                 List<ExecutableTypeData> types = child.findGenericExecutableTypes(context);
                 if (types.isEmpty()) {
@@ -680,7 +784,11 @@
         if (node.hasErrors()) {
             return node;
         }
-        node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node, child, createAllowedChildFrameTypes(parentNode)).parse(members)));
+        List<TypeMirror> frameTypes = Collections.emptyList();
+        if (parentNode.getFrameType() != null) {
+            frameTypes = Arrays.asList(parentNode.getFrameType());
+        }
+        node.getExecutableTypes().addAll(parseExecutableTypeData(members, child.getExecuteWith().size(), frameTypes, true));
         node.setFrameType(parentNode.getFrameType());
         return node;
     }
@@ -1153,19 +1261,19 @@
     }
 
     private SpecializationData createGenericSpecialization(final NodeData node) {
-        GenericParser parser = new GenericParser(context, node);
+        FallbackParser parser = new FallbackParser(context, node);
         MethodSpec specification = parser.createDefaultMethodSpec(node.getSpecializations().iterator().next().getMethod(), null, true, null);
 
         List<VariableElement> parameterTypes = new ArrayList<>();
         int signatureIndex = 1;
         for (ParameterSpec spec : specification.getRequired()) {
-            parameterTypes.add(new CodeVariableElement(createGenericType(spec, node.getSpecializations(), signatureIndex), "arg" + signatureIndex));
+            parameterTypes.add(new CodeVariableElement(createGenericType(node, spec), "arg" + signatureIndex));
             if (spec.isSignature()) {
                 signatureIndex++;
             }
         }
 
-        TypeMirror returnType = createGenericType(specification.getReturnType(), node.getSpecializations(), 0);
+        TypeMirror returnType = createGenericType(node, specification.getReturnType());
         SpecializationData generic = parser.create("Generic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, parameterTypes);
         if (generic == null) {
             throw new RuntimeException("Unable to create generic signature for node " + node.getNodeId() + " with " + parameterTypes + ". Specification " + specification + ".");
@@ -1174,41 +1282,22 @@
         return generic;
     }
 
-    private TypeMirror createGenericType(ParameterSpec spec, List<SpecializationData> specializations, int signatureIndex) {
+    private TypeMirror createGenericType(NodeData node, ParameterSpec spec) {
         NodeExecutionData execution = spec.getExecution();
+        Collection<TypeMirror> allowedTypes;
         if (execution == null) {
-            if (spec.getAllowedTypes().size() == 1) {
-                return spec.getAllowedTypes().get(0);
-            } else {
-                return ElementUtils.getCommonSuperType(context, spec.getAllowedTypes().toArray(new TypeMirror[0]));
-            }
+            allowedTypes = spec.getAllowedTypes();
         } else {
-            Set<TypeData> types = new HashSet<>();
-            for (SpecializationData specialization : specializations) {
-                types.add(specialization.getTypeSignature().get(signatureIndex));
-            }
-
-            NodeChildData child = execution.getChild();
-            TypeData genericType = null;
-            if (types.size() == 1) {
-                TypeData singleType = types.iterator().next();
-                ExecutableTypeData executable = child.findExecutableType(singleType);
-                if (executable != null && (signatureIndex == 0 || !executable.hasUnexpectedValue(context))) {
-                    genericType = singleType;
-                }
-            }
-            if (genericType == null) {
-                ExecutableTypeData type = child.findAnyGenericExecutableType(context);
-                if (type == null) {
-                    throw new AssertionError("No generic type not yet catched by parser.");
-                }
-                genericType = type.getType();
-            }
-            return genericType.getPrimitiveType();
+            allowedTypes = Arrays.asList(node.getGenericType(execution));
+        }
+        if (allowedTypes.size() == 1) {
+            return allowedTypes.iterator().next();
+        } else {
+            return ElementUtils.getCommonSuperType(context, allowedTypes);
         }
     }
 
-    private static void initializeUninitialized(final NodeData node) {
+    private void initializeUninitialized(final NodeData node) {
         SpecializationData generic = node.getGenericSpecialization();
         if (generic == null) {
             return;
@@ -1225,7 +1314,7 @@
                 }
             }
             if (types.size() > 1) {
-                generic.replaceParameter(parameter.getLocalName(), new Parameter(parameter, node.getTypeSystem().getGenericTypeData()));
+                generic.replaceParameter(parameter.getLocalName(), new Parameter(parameter, context.getType(Object.class)));
             }
         }
         TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", -1, node, generic.getSpecification(), null, null, generic.getReturnType(), generic.getParameters());
@@ -1241,36 +1330,74 @@
 
         SpecializationData generic = node.getGenericSpecialization();
 
-        List<TypeData> polymorphicSignature = new ArrayList<>();
-        List<Parameter> updatePolymorphic = Arrays.asList();
-        for (Parameter genericParameter : updatePolymorphic) {
-            if (!genericParameter.getSpecification().isSignature()) {
+        List<VariableElement> types = new ArrayList<>();
+
+        Collection<TypeMirror> frameTypes = new HashSet<>();
+        for (SpecializationData specialization : node.getSpecializations()) {
+            if (specialization.getFrame() != null) {
+                frameTypes.add(specialization.getFrame().getType());
+            }
+        }
+        if (!frameTypes.isEmpty()) {
+            frameTypes = ElementUtils.uniqueSortedTypes(frameTypes);
+            TypeMirror frameType;
+            if (frameTypes.size() == 1) {
+                frameType = frameTypes.iterator().next();
+            } else {
+                frameType = context.getType(Frame.class);
+            }
+            types.add(new CodeVariableElement(frameType, TemplateMethod.FRAME_NAME));
+        }
+
+        TypeMirror returnType = null;
+        int index = 0;
+        for (Parameter genericParameter : generic.getReturnTypeAndParameters()) {
+            TypeMirror polymorphicType;
+            if (genericParameter.getLocalName().equals(TemplateMethod.FRAME_NAME)) {
                 continue;
             }
-
-            Set<TypeData> usedTypes = new HashSet<>();
-            for (SpecializationData specialization : node.getSpecializations()) {
-                if (!specialization.isSpecialized()) {
-                    continue;
-                }
-                Parameter parameter = specialization.findParameter(genericParameter.getLocalName());
-                if (parameter == null) {
-                    throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName());
+            boolean isReturnParameter = genericParameter == generic.getReturnType();
+            if (!genericParameter.getSpecification().isSignature()) {
+                polymorphicType = genericParameter.getType();
+            } else {
+                Collection<TypeMirror> usedTypes = new HashSet<>();
+                for (SpecializationData specialization : node.getSpecializations()) {
+                    if (specialization.isUninitialized()) {
+                        continue;
+                    }
+                    Parameter parameter = specialization.findParameter(genericParameter.getLocalName());
+                    if (parameter == specialization.getReturnType() && specialization.isFallback() && specialization.getMethod() == null) {
+                        continue;
+                    }
+                    if (parameter == null) {
+                        throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName());
+                    }
+                    usedTypes.add(parameter.getType());
                 }
-                usedTypes.add(parameter.getTypeSystemType());
-            }
+                usedTypes = ElementUtils.uniqueSortedTypes(usedTypes);
+
+                if (usedTypes.size() == 1) {
+                    polymorphicType = usedTypes.iterator().next();
 
-            TypeData polymorphicType;
-            if (usedTypes.size() == 1) {
-                polymorphicType = usedTypes.iterator().next();
+                    if (!isReturnParameter && node.getTypeSystem().hasImplicitSourceTypes(polymorphicType)) {
+                        polymorphicType = context.getType(Object.class);
+                    }
+                } else {
+                    polymorphicType = context.getType(Object.class);
+                }
+            }
+            if (isReturnParameter) {
+                returnType = polymorphicType;
             } else {
-                polymorphicType = node.getTypeSystem().getGenericTypeData();
+                types.add(new CodeVariableElement(polymorphicType, "param" + index));
             }
-            polymorphicSignature.add(polymorphicType);
+            index++;
         }
 
-        SpecializationData polymorphic = new SpecializationData(node, generic, SpecializationKind.POLYMORPHIC);
-        polymorphic.updateSignature(new TypeSignature(polymorphicSignature));
+        SpecializationMethodParser parser = new SpecializationMethodParser(context, node);
+
+        SpecializationData polymorphic = parser.create("Polymorphic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, types);
+        polymorphic.setKind(SpecializationKind.POLYMORPHIC);
         node.getSpecializations().add(polymorphic);
     }
 
@@ -1370,7 +1497,7 @@
             ExecutableTypeData found = null;
             List<ExecutableTypeData> executableElements = execution.getChild().findGenericExecutableTypes(context);
             for (ExecutableTypeData executable : executableElements) {
-                if (executable.getType().equalsType(parameter.getTypeSystemType())) {
+                if (ElementUtils.typeEquals(executable.getReturnType(), parameter.getType())) {
                     found = executable;
                     break;
                 }
@@ -1429,8 +1556,8 @@
 
         List<Element> elements = new ArrayList<>(originalElements);
         Set<Element> unusedElements = new HashSet<>(elements);
-        for (TemplateMethod method : nodeData.getAllTemplateMethods()) {
-            unusedElements.remove(method.getMethod());
+        for (ExecutableElement method : nodeData.getAllTemplateMethods()) {
+            unusedElements.remove(method);
         }
 
         for (NodeFieldData field : nodeData.getFields()) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java	Wed Apr 15 11:03:04 2015 -0700
@@ -24,6 +24,8 @@
 
 import java.util.*;
 
+import javax.lang.model.type.*;
+
 import com.oracle.truffle.dsl.processor.model.*;
 import com.oracle.truffle.dsl.processor.model.TemplateMethod.TypeSignature;
 
@@ -299,9 +301,9 @@
     public static final class TypeGuard {
 
         private final int signatureIndex;
-        private final TypeData type;
+        private final TypeMirror type;
 
-        public TypeGuard(TypeData type, int signatureIndex) {
+        public TypeGuard(TypeMirror type, int signatureIndex) {
             this.type = type;
             this.signatureIndex = signatureIndex;
         }
@@ -338,7 +340,7 @@
             return signatureIndex;
         }
 
-        public TypeData getType() {
+        public TypeMirror getType() {
             return type;
         }
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java	Wed Apr 15 11:03:04 2015 -0700
@@ -58,55 +58,59 @@
     }
 
     private SpecializationData parseSpecialization(TemplateMethod method) {
-        AnnotationValue rewriteValue = ElementUtils.getAnnotationValue(method.getMarkerAnnotation(), "rewriteOn");
-        List<TypeMirror> exceptionTypes = ElementUtils.getAnnotationValueList(TypeMirror.class, method.getMarkerAnnotation(), "rewriteOn");
         List<SpecializationThrowsData> exceptionData = new ArrayList<>();
-        List<TypeMirror> rewriteOnTypes = new ArrayList<>();
-        for (TypeMirror exceptionType : exceptionTypes) {
-            SpecializationThrowsData throwsData = new SpecializationThrowsData(method.getMarkerAnnotation(), rewriteValue, exceptionType);
-            if (!ElementUtils.canThrowType(method.getMethod().getThrownTypes(), exceptionType)) {
-                method.addError("A rewriteOn checked exception was specified but not thrown in the method's throws clause. The @%s method must specify a throws clause with the exception type '%s'.",
-                                Specialization.class.getSimpleName(), ElementUtils.getQualifiedName(exceptionType));
+        if (method.getMethod() != null) {
+            AnnotationValue rewriteValue = ElementUtils.getAnnotationValue(method.getMarkerAnnotation(), "rewriteOn");
+            List<TypeMirror> exceptionTypes = ElementUtils.getAnnotationValueList(TypeMirror.class, method.getMarkerAnnotation(), "rewriteOn");
+            List<TypeMirror> rewriteOnTypes = new ArrayList<>();
+            for (TypeMirror exceptionType : exceptionTypes) {
+                SpecializationThrowsData throwsData = new SpecializationThrowsData(method.getMarkerAnnotation(), rewriteValue, exceptionType);
+                if (!ElementUtils.canThrowType(method.getMethod().getThrownTypes(), exceptionType)) {
+                    method.addError("A rewriteOn checked exception was specified but not thrown in the method's throws clause. The @%s method must specify a throws clause with the exception type '%s'.",
+                                    Specialization.class.getSimpleName(), ElementUtils.getQualifiedName(exceptionType));
+                }
+                rewriteOnTypes.add(throwsData.getJavaClass());
+                exceptionData.add(throwsData);
             }
-            rewriteOnTypes.add(throwsData.getJavaClass());
-            exceptionData.add(throwsData);
-        }
-
-        for (TypeMirror typeMirror : method.getMethod().getThrownTypes()) {
-            if (!ElementUtils.canThrowType(rewriteOnTypes, typeMirror)) {
-                method.addError(rewriteValue,
-                                "A checked exception '%s' is thrown but is not specified using the rewriteOn property. Checked exceptions that are not used for rewriting are not handled by the DSL. Use RuntimeExceptions for this purpose instead.",
-                                ElementUtils.getQualifiedName(typeMirror));
-            }
-        }
 
-        Collections.sort(exceptionData, new Comparator<SpecializationThrowsData>() {
-
-            @Override
-            public int compare(SpecializationThrowsData o1, SpecializationThrowsData o2) {
-                return ElementUtils.compareByTypeHierarchy(o1.getJavaClass(), o2.getJavaClass());
-            }
-        });
-        SpecializationData specialization = new SpecializationData(getNode(), method, SpecializationKind.SPECIALIZED, exceptionData);
-
-        String insertBeforeName = ElementUtils.getAnnotationValue(String.class, method.getMarkerAnnotation(), "insertBefore");
-        if (!insertBeforeName.equals("")) {
-            specialization.setInsertBeforeName(insertBeforeName);
-        }
-
-        List<String> containsDefs = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "contains");
-        Set<String> containsNames = specialization.getContainsNames();
-        containsNames.clear();
-        if (containsDefs != null) {
-            for (String include : containsDefs) {
-                if (!containsNames.contains(include)) {
-                    specialization.getContainsNames().add(include);
-                } else {
-                    AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "contains");
-                    specialization.addError(value, "Duplicate contains declaration '%s'.", include);
+            for (TypeMirror typeMirror : method.getMethod().getThrownTypes()) {
+                if (!ElementUtils.canThrowType(rewriteOnTypes, typeMirror)) {
+                    method.addError(rewriteValue, "A checked exception '%s' is thrown but is not specified using the rewriteOn property. "
+                                    + "Checked exceptions that are not used for rewriting are not handled by the DSL. Use RuntimeExceptions for this purpose instead.",
+                                    ElementUtils.getQualifiedName(typeMirror));
                 }
             }
 
+            Collections.sort(exceptionData, new Comparator<SpecializationThrowsData>() {
+
+                @Override
+                public int compare(SpecializationThrowsData o1, SpecializationThrowsData o2) {
+                    return ElementUtils.compareByTypeHierarchy(o1.getJavaClass(), o2.getJavaClass());
+                }
+            });
+        }
+        SpecializationData specialization = new SpecializationData(getNode(), method, SpecializationKind.SPECIALIZED, exceptionData);
+
+        if (method.getMethod() != null) {
+            String insertBeforeName = ElementUtils.getAnnotationValue(String.class, method.getMarkerAnnotation(), "insertBefore");
+            if (!insertBeforeName.equals("")) {
+                specialization.setInsertBeforeName(insertBeforeName);
+            }
+
+            List<String> containsDefs = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "contains");
+            Set<String> containsNames = specialization.getContainsNames();
+            containsNames.clear();
+            if (containsDefs != null) {
+                for (String include : containsDefs) {
+                    if (!containsNames.contains(include)) {
+                        specialization.getContainsNames().add(include);
+                    } else {
+                        AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "contains");
+                        specialization.addError(value, "Duplicate contains declaration '%s'.", include);
+                    }
+                }
+
+            }
         }
 
         return specialization;
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCastParser.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCastParser.java	Wed Apr 15 11:03:04 2015 -0700
@@ -41,15 +41,17 @@
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
         TypeMirror targetTypeMirror = ElementUtils.getAnnotationValue(TypeMirror.class, mirror, "value");
-        MethodSpec spec = new MethodSpec(new ParameterSpec("returnType", targetTypeMirror));
-        spec.addRequired(new ParameterSpec("value", getTypeSystem().getGenericType()));
+        ParameterSpec returnTypeSpec = new ParameterSpec("returnType", targetTypeMirror);
+        returnTypeSpec.setAllowSubclasses(false);
+        MethodSpec spec = new MethodSpec(returnTypeSpec);
+        spec.addRequired(new ParameterSpec("value", getContext().getType(Object.class)));
         return spec;
     }
 
     @Override
     public TypeCastData create(TemplateMethod method, boolean invalid) {
-        TypeData targetType = resolveCastOrCheck(method);
-        TypeData sourceType = getTypeSystem().getGenericTypeData();
+        TypeMirror targetType = resolveCastOrCheck(method);
+        TypeMirror sourceType = getContext().getType(Object.class);
         return new TypeCastData(method, sourceType, targetType);
     }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCheckParser.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeCheckParser.java	Wed Apr 15 11:03:04 2015 -0700
@@ -25,6 +25,7 @@
 import java.lang.annotation.*;
 
 import javax.lang.model.element.*;
+import javax.lang.model.type.*;
 
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.dsl.processor.*;
@@ -39,13 +40,13 @@
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
         MethodSpec spec = new MethodSpec(new ParameterSpec("returnType", getContext().getType(boolean.class)));
-        spec.addRequired(new ParameterSpec("value", getTypeSystem().getGenericType()));
+        spec.addRequired(new ParameterSpec("value", getContext().getType(Object.class)));
         return spec;
     }
 
     @Override
     public TypeCheckData create(TemplateMethod method, boolean invalid) {
-        TypeData targetType = resolveCastOrCheck(method);
+        TypeMirror targetType = resolveCastOrCheck(method);
         return new TypeCheckData(method, targetType, targetType);
     }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemMethodParser.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemMethodParser.java	Wed Apr 15 11:03:04 2015 -0700
@@ -25,7 +25,6 @@
 import javax.lang.model.element.*;
 import javax.lang.model.type.*;
 
-import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.dsl.processor.*;
 import com.oracle.truffle.dsl.processor.java.*;
 import com.oracle.truffle.dsl.processor.model.*;
@@ -41,18 +40,13 @@
         return ElementUtils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null;
     }
 
-    protected final TypeData resolveCastOrCheck(TemplateMethod method) {
+    protected final TypeMirror resolveCastOrCheck(TemplateMethod method) {
         Class<?> annotationType = getAnnotationType();
         TypeMirror targetTypeMirror = ElementUtils.getAnnotationValue(TypeMirror.class, method.getMessageAnnotation(), "value");
-        TypeData targetType = getTypeSystem().findTypeData(targetTypeMirror);
-        if (targetType == null) {
-            method.addError("The type '%s' is not declared in the @%s.", ElementUtils.getSimpleName(targetTypeMirror), TypeSystem.class.getSimpleName());
-            return null;
-        }
         if (!method.getMethod().getModifiers().contains(Modifier.PUBLIC) || !method.getMethod().getModifiers().contains(Modifier.STATIC)) {
             method.addError("@%s annotated method %s must be public and static.", annotationType.getSimpleName(), method.getMethodName());
         }
-        return targetType;
+        return targetTypeMirror;
     }
 
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java	Wed Apr 15 11:03:04 2015 -0700
@@ -22,8 +22,6 @@
  */
 package com.oracle.truffle.dsl.processor.parser;
 
-import static com.oracle.truffle.dsl.processor.java.ElementUtils.*;
-
 import java.lang.annotation.*;
 import java.util.*;
 
@@ -33,7 +31,6 @@
 
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.dsl.internal.*;
-import com.oracle.truffle.dsl.processor.generator.*;
 import com.oracle.truffle.dsl.processor.java.*;
 import com.oracle.truffle.dsl.processor.model.*;
 
@@ -57,7 +54,7 @@
         }
         assert options != null;
 
-        TypeSystemData typeSystem = new TypeSystemData(context, templateType, templateTypeAnnotation, options);
+        TypeSystemData typeSystem = new TypeSystemData(context, templateType, templateTypeAnnotation, options, false);
 
         // annotation type on class path!?
         TypeElement annotationTypeElement = processingEnv.getElementUtils().getTypeElement(getAnnotationType().getCanonicalName());
@@ -75,24 +72,9 @@
             return typeSystem;
         }
 
-        List<TypeData> types = parseTypes(typeSystem);
-
-        TypeMirror genericType = context.getType(Object.class);
-        TypeData voidType = new TypeData(typeSystem, types.size(), null, context.getType(void.class), context.getType(Void.class));
-        types.add(voidType);
-
-        typeSystem.setTypes(types);
         if (typeSystem.hasErrors()) {
             return typeSystem;
         }
-        typeSystem.setGenericType(genericType);
-        typeSystem.setVoidType(voidType);
-
-        TypeData booleanType = typeSystem.findTypeData(context.getType(boolean.class));
-        if (booleanType == null) {
-            booleanType = new TypeData(typeSystem, types.size(), null, context.getType(boolean.class), context.getType(Boolean.class));
-        }
-        typeSystem.setBooleanType(booleanType);
 
         verifyExclusiveMethodAnnotation(typeSystem, TypeCast.class, TypeCheck.class);
 
@@ -105,25 +87,24 @@
             return typeSystem;
         }
 
-        typeSystem.setImplicitCasts(implicitCasts);
-        typeSystem.setCasts(casts);
-        typeSystem.setChecks(checks);
+        List<TypeMirror> legacyTypes = ElementUtils.getAnnotationValueList(TypeMirror.class, typeSystem.getTemplateTypeAnnotation(), "value");
+        for (int i = 0; i < legacyTypes.size(); i++) {
+            legacyTypes.set(i, ElementUtils.fillInGenericWildcards(legacyTypes.get(i)));
+        }
+
+        typeSystem.getLegacyTypes().addAll(legacyTypes);
+        verifyTypes(typeSystem);
+        typeSystem.getLegacyTypes().add(context.getType(Object.class));
+        typeSystem.getLegacyTypes().add(context.getType(void.class));
+        verifyNamesUnique(typeSystem);
+
+        typeSystem.getImplicitCasts().addAll(implicitCasts);
+        typeSystem.getCasts().addAll(casts);
+        typeSystem.getChecks().addAll(checks);
 
         if (typeSystem.hasErrors()) {
             return typeSystem;
         }
-
-        for (TypeCheckData check : checks) {
-            check.getCheckedType().addTypeCheck(check);
-        }
-
-        for (TypeCastData cast : casts) {
-            cast.getTargetType().addTypeCast(cast);
-        }
-
-        verifyMethodSignatures(typeSystem);
-        verifyNamesUnique(typeSystem);
-
         return typeSystem;
     }
 
@@ -149,50 +130,28 @@
         }
     }
 
-    private List<TypeData> parseTypes(TypeSystemData typeSystem) {
-        List<TypeData> types = new ArrayList<>();
-        List<TypeMirror> typeMirrors = ElementUtils.getAnnotationValueList(TypeMirror.class, typeSystem.getTemplateTypeAnnotation(), "value");
-        if (typeMirrors.isEmpty()) {
-            typeSystem.addError("At least one type must be defined.");
-            return types;
-        }
-
-        final AnnotationValue annotationValue = ElementUtils.getAnnotationValue(typeSystem.getTemplateTypeAnnotation(), "value");
-        final TypeMirror objectType = context.getType(Object.class);
-
-        int index = 0;
-        for (TypeMirror primitiveType : typeMirrors) {
-            TypeMirror primitive = ElementUtils.fillInGenericWildcards(primitiveType);
-
-            TypeMirror boxedType = ElementUtils.boxType(context, primitive);
-            TypeData typeData = new TypeData(typeSystem, index, annotationValue, primitive, boxedType);
-
-            if (isPrimitiveWrapper(primitive)) {
-                typeData.addError("Types must not contain primitive wrapper types.");
+    private void verifyTypes(TypeSystemData typeSystem) {
+        for (TypeMirror type : typeSystem.getLegacyTypes()) {
+            if (isPrimitiveWrapper(type)) {
+                typeSystem.addError("Types must not contain primitive wrapper types.");
             }
 
-            if (ElementUtils.typeEquals(boxedType, objectType)) {
-                typeData.addError("Types must not contain the generic type java.lang.Object.");
+            if (ElementUtils.typeEquals(type, context.getType(Object.class))) {
+                typeSystem.addError("Types must not contain the generic type java.lang.Object.");
             }
-
-            types.add(typeData);
-            index++;
         }
 
-        verifyTypeOrder(types);
-
-        types.add(new TypeData(typeSystem, index, annotationValue, objectType, objectType));
-        return types;
+        verifyTypeOrder(typeSystem);
     }
 
-    private static void verifyTypeOrder(List<TypeData> types) {
+    private static void verifyTypeOrder(TypeSystemData typeSystem) {
         Map<String, List<String>> invalidTypes = new HashMap<>();
 
-        for (int i = types.size() - 1; i >= 0; i--) {
-            TypeData typeData = types.get(i);
-            TypeMirror type = typeData.getBoxedType();
+        for (int i = typeSystem.getLegacyTypes().size() - 1; i >= 0; i--) {
+            TypeMirror typeData = typeSystem.getLegacyTypes().get(i);
+            TypeMirror type = typeSystem.boxType(typeData);
             if (invalidTypes.containsKey(ElementUtils.getQualifiedName(type))) {
-                typeData.addError("Invalid type order. The type(s) %s are inherited from a earlier defined type %s.", invalidTypes.get(ElementUtils.getQualifiedName(type)),
+                typeSystem.addError("Invalid type order. The type(s) %s are inherited from a earlier defined type %s.", invalidTypes.get(ElementUtils.getQualifiedName(type)),
                                 ElementUtils.getQualifiedName(type));
             }
             TypeElement element = ElementUtils.fromTypeMirror(type);
@@ -200,7 +159,7 @@
             if (element != null) {
                 nextInvalidTypes.addAll(ElementUtils.getQualifiedSuperTypeNames(element));
             }
-            nextInvalidTypes.add(getQualifiedName(type));
+            nextInvalidTypes.add(ElementUtils.getQualifiedName(type));
 
             for (String qualifiedName : nextInvalidTypes) {
                 List<String> inheritedTypes = invalidTypes.get(qualifiedName);
@@ -208,7 +167,7 @@
                     inheritedTypes = new ArrayList<>();
                     invalidTypes.put(qualifiedName, inheritedTypes);
                 }
-                inheritedTypes.add(ElementUtils.getQualifiedName(typeData.getBoxedType()));
+                inheritedTypes.add(ElementUtils.getQualifiedName(typeSystem.boxType(typeData)));
             }
         }
     }
@@ -226,64 +185,11 @@
         return false;
     }
 
-    private void verifyMethodSignatures(TypeSystemData typeSystem) {
-        Set<String> generatedIsMethodNames = new HashSet<>();
-        Set<String> generatedAsMethodNames = new HashSet<>();
-        Set<String> generatedExpectMethodNames = new HashSet<>();
-
-        for (TypeData typeData : typeSystem.getTypes()) {
-            generatedIsMethodNames.add(TypeSystemCodeGenerator.isTypeMethodName(typeData));
-            generatedAsMethodNames.add(TypeSystemCodeGenerator.asTypeMethodName(typeData));
-            generatedExpectMethodNames.add(TypeSystemCodeGenerator.expectTypeMethodName(typeData));
-        }
-
-        List<ExecutableElement> methods = ElementFilter.methodsIn(typeSystem.getTemplateType().getEnclosedElements());
-        for (ExecutableElement method : methods) {
-            if (method.getModifiers().contains(Modifier.PRIVATE)) {
-                // will not conflict overridden methods
-                continue;
-            } else if (method.getParameters().size() != 1) {
-                continue;
-            }
-            String methodName = method.getSimpleName().toString();
-            if (generatedIsMethodNames.contains(methodName)) {
-                verifyIsMethod(typeSystem, method);
-            } else if (generatedAsMethodNames.contains(methodName)) {
-                verifyAsMethod(typeSystem, method);
-            } else if (generatedExpectMethodNames.contains(methodName)) {
-                verifyExpectMethod(typeSystem);
-            }
-        }
-    }
-
-    private boolean verifyIsMethod(TypeSystemData typeSystem, ExecutableElement method) {
-        AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, TypeCheck.class);
-        if (mirror == null) {
-            typeSystem.addError("Method starting with the pattern is${typeName} must be annotated with @%s.", TypeCheck.class.getSimpleName());
-            return false;
-        }
-        return true;
-    }
-
-    private boolean verifyAsMethod(TypeSystemData typeSystem, ExecutableElement method) {
-        AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, TypeCast.class);
-        if (mirror == null) {
-            typeSystem.addError("Method starting with the pattern as${typeName} must be annotated with @%s.", TypeCast.class.getSimpleName());
-            return false;
-        }
-        return true;
-    }
-
-    private static boolean verifyExpectMethod(TypeSystemData typeSystem) {
-        typeSystem.addError("Method starting with the pattern expect${typeName} must not be declared manually.");
-        return false;
-    }
-
     private static void verifyNamesUnique(TypeSystemData typeSystem) {
         Set<String> usedNames = new HashSet<>();
-        for (TypeData type : typeSystem.getTypes()) {
-            String boxedName = ElementUtils.getSimpleName(type.getBoxedType());
-            String primitiveName = ElementUtils.getSimpleName(type.getPrimitiveType());
+        for (TypeMirror type : typeSystem.getLegacyTypes()) {
+            String boxedName = ElementUtils.getSimpleName(typeSystem.boxType(type));
+            String primitiveName = ElementUtils.getSimpleName(type);
             if (usedNames.contains(boxedName)) {
                 typeSystem.addError("Two types result in the same boxed name: %s.", boxedName);
             } else if (usedNames.contains(primitiveName)) {
@@ -293,4 +199,5 @@
             usedNames.add(primitiveName);
         }
     }
+
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java	Wed Apr 15 11:03:04 2015 -0700
@@ -86,7 +86,7 @@
  * {@link SLWhileNode while} with {@link SLBreakNode break} and {@link SLContinueNode continue},
  * {@link SLReturnNode return}.
  * <li>Function calls: {@link SLInvokeNode invocations} are efficiently implemented with
- * {@link SLAbstractDispatchNode polymorphic inline caches}.
+ * {@link SLDispatchNode polymorphic inline caches}.
  * </ul>
  *
  * <p>
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/SLExpressionNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -22,8 +22,6 @@
  */
 package com.oracle.truffle.sl.nodes;
 
-import java.math.*;
-
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode;
@@ -70,26 +68,14 @@
         return SLTypesGen.expectLong(executeGeneric(frame));
     }
 
-    public BigInteger executeBigInteger(VirtualFrame frame) throws UnexpectedResultException {
-        return SLTypesGen.expectBigInteger(executeGeneric(frame));
+    public SLFunction executeFunction(VirtualFrame frame) throws UnexpectedResultException {
+        return SLTypesGen.expectSLFunction(executeGeneric(frame));
     }
 
     public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException {
         return SLTypesGen.expectBoolean(executeGeneric(frame));
     }
 
-    public String executeString(VirtualFrame frame) throws UnexpectedResultException {
-        return SLTypesGen.expectString(executeGeneric(frame));
-    }
-
-    public SLFunction executeFunction(VirtualFrame frame) throws UnexpectedResultException {
-        return SLTypesGen.expectSLFunction(executeGeneric(frame));
-    }
-
-    public SLNull executeNull(VirtualFrame frame) throws UnexpectedResultException {
-        return SLTypesGen.expectSLNull(executeGeneric(frame));
-    }
-
     @Override
     public boolean isInstrumentable() {
         return true;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyCacheNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyCacheNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -22,170 +22,90 @@
  */
 package com.oracle.truffle.sl.nodes.access;
 
-import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.object.*;
-import com.oracle.truffle.sl.nodes.*;
 import com.oracle.truffle.sl.runtime.*;
 
-/**
- * The node for accessing a property of an object. When executed, this node first evaluates the
- * object expression on the left side of the dot operator and then reads the named property.
- */
 public abstract class SLReadPropertyCacheNode extends Node {
 
+    protected static final int CACHE_LIMIT = 3;
+
+    protected final String propertyName;
+
+    public SLReadPropertyCacheNode(String propertyName) {
+        this.propertyName = propertyName;
+    }
+
     public static SLReadPropertyCacheNode create(String propertyName) {
-        return new SLUninitializedReadObjectPropertyNode(propertyName);
+        return SLReadPropertyCacheNodeGen.create(propertyName);
     }
 
     public abstract Object executeObject(DynamicObject receiver);
 
     public abstract long executeLong(DynamicObject receiver) throws UnexpectedResultException;
 
-    protected abstract static class SLReadPropertyCacheChainNode extends SLReadPropertyCacheNode {
-        protected final Shape shape;
-        @Child protected SLReadPropertyCacheNode next;
-
-        public SLReadPropertyCacheChainNode(Shape shape, SLReadPropertyCacheNode next) {
-            this.shape = shape;
-            this.next = next;
-        }
-
-        @Override
-        public final Object executeObject(DynamicObject receiver) {
-            try {
-                // if this assumption fails, the object needs to be updated to a valid shape
-                shape.getValidAssumption().check();
-            } catch (InvalidAssumptionException e) {
-                return this.replace(next).executeObject(receiver);
-            }
-
-            boolean condition = shape.check(receiver);
+    /*
+     * We use a separate long specialization to avoid boxing for long.
+     */
+    @Specialization(limit = "CACHE_LIMIT", guards = {"longLocation != null", "shape.check(receiver)"}, assumptions = "shape.getValidAssumption()")
+    @SuppressWarnings("unused")
+    protected long doCachedLong(DynamicObject receiver, //
+                    @Cached("receiver.getShape()") Shape shape, //
+                    @Cached("getLongLocation(shape)") LongLocation longLocation) {
+        return longLocation.getLong(receiver, true);
+    }
 
-            if (condition) {
-                return executeObjectUnchecked(receiver, condition);
-            } else {
-                return next.executeObject(receiver);
-            }
+    protected LongLocation getLongLocation(Shape shape) {
+        Property property = shape.getProperty(propertyName);
+        if (property != null && property.getLocation() instanceof LongLocation) {
+            return (LongLocation) property.getLocation();
         }
+        return null;
+    }
 
-        @Override
-        public final long executeLong(DynamicObject receiver) throws UnexpectedResultException {
-            try {
-                // if this assumption fails, the object needs to be updated to a valid shape
-                shape.getValidAssumption().check();
-            } catch (InvalidAssumptionException e) {
-                return this.replace(next).executeLong(receiver);
-            }
-
-            boolean condition = shape.check(receiver);
-
-            if (condition) {
-                return executeLongUnchecked(receiver, condition);
-            } else {
-                return next.executeLong(receiver);
-            }
-        }
-
-        protected abstract Object executeObjectUnchecked(DynamicObject receiver, boolean condition);
-
-        protected long executeLongUnchecked(DynamicObject receiver, boolean condition) throws UnexpectedResultException {
-            return SLTypesGen.expectLong(executeObjectUnchecked(receiver, condition));
+    /*
+     * As soon as we have seen an object read, we cannot avoid boxing long anymore therefore we can
+     * contain all long cache entries.
+     */
+    @Specialization(limit = "CACHE_LIMIT", contains = "doCachedLong", guards = "shape.check(receiver)", assumptions = "shape.getValidAssumption()")
+    protected static Object doCachedObject(DynamicObject receiver, //
+                    @Cached("receiver.getShape()") Shape shape, //
+                    @Cached("shape.getProperty(propertyName)") Property property) {
+        if (property == null) {
+            return SLNull.SINGLETON;
+        } else {
+            return property.get(receiver, shape);
         }
     }
 
-    protected static class SLReadObjectPropertyNode extends SLReadPropertyCacheChainNode {
-        private final Location location;
-
-        protected SLReadObjectPropertyNode(Shape shape, Location location, SLReadPropertyCacheNode next) {
-            super(shape, next);
-            this.location = location;
-        }
-
-        @Override
-        protected Object executeObjectUnchecked(DynamicObject receiver, boolean condition) {
-            return location.get(receiver, condition);
-        }
-    }
-
-    protected static class SLReadBooleanPropertyNode extends SLReadPropertyCacheChainNode {
-        private final BooleanLocation location;
-
-        protected SLReadBooleanPropertyNode(Shape shape, BooleanLocation location, SLReadPropertyCacheNode next) {
-            super(shape, next);
-            this.location = location;
-        }
-
-        @Override
-        protected Object executeObjectUnchecked(DynamicObject receiver, boolean condition) {
-            return location.getBoolean(receiver, condition);
+    /*
+     * The generic case is used if the number of shapes accessed overflows the limit.
+     */
+    @Specialization(contains = "doCachedObject")
+    @TruffleBoundary
+    protected Object doGeneric(DynamicObject receiver, @Cached("new()") LRUPropertyLookup lruCache) {
+        if (!lruCache.shape.check(receiver)) {
+            Shape receiverShape = receiver.getShape();
+            lruCache.shape = receiverShape;
+            lruCache.property = receiverShape.getProperty(propertyName);
         }
-    }
-
-    protected static class SLReadLongPropertyNode extends SLReadPropertyCacheChainNode {
-        private final LongLocation location;
-
-        protected SLReadLongPropertyNode(Shape shape, LongLocation location, SLReadPropertyCacheNode next) {
-            super(shape, next);
-            this.location = location;
-        }
-
-        @Override
-        protected Object executeObjectUnchecked(DynamicObject receiver, boolean condition) {
-            return location.getLong(receiver, condition);
-        }
-
-        @Override
-        protected long executeLongUnchecked(DynamicObject receiver, boolean condition) throws UnexpectedResultException {
-            return location.getLong(receiver, condition);
-        }
-    }
-
-    protected static class SLReadMissingPropertyNode extends SLReadPropertyCacheChainNode {
-        protected SLReadMissingPropertyNode(Shape shape, SLReadPropertyCacheNode next) {
-            super(shape, next);
-        }
-
-        @Override
-        protected Object executeObjectUnchecked(DynamicObject receiver, boolean condition) {
-            // The property was not found in the object, return null
+        if (lruCache.property != null) {
+            return lruCache.property.get(receiver, true);
+        } else {
             return SLNull.SINGLETON;
         }
     }
 
-    protected static class SLUninitializedReadObjectPropertyNode extends SLReadPropertyCacheNode {
-        protected final String propertyName;
+    protected static class LRUPropertyLookup {
 
-        protected SLUninitializedReadObjectPropertyNode(String propertyName) {
-            this.propertyName = propertyName;
+        private Shape shape;
+        private Property property;
+
+        public LRUPropertyLookup() {
         }
 
-        @Override
-        public Object executeObject(DynamicObject receiver) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-
-            receiver.updateShape();
-
-            Shape shape = receiver.getShape();
-            Property property = shape.getProperty(propertyName);
+    }
 
-            final SLReadPropertyCacheNode resolvedNode;
-            if (property == null) {
-                resolvedNode = new SLReadMissingPropertyNode(shape, this);
-            } else if (property.getLocation() instanceof LongLocation) {
-                resolvedNode = new SLReadLongPropertyNode(shape, (LongLocation) property.getLocation(), this);
-            } else if (property.getLocation() instanceof BooleanLocation) {
-                resolvedNode = new SLReadBooleanPropertyNode(shape, (BooleanLocation) property.getLocation(), this);
-            } else {
-                resolvedNode = new SLReadObjectPropertyNode(shape, property.getLocation(), this);
-            }
-
-            return this.replace(resolvedNode, "resolved '" + propertyName + "'").executeObject(receiver);
-        }
-
-        @Override
-        public long executeLong(DynamicObject receiver) throws UnexpectedResultException {
-            return SLTypesGen.expectLong(executeObject(receiver));
-        }
-    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLReadPropertyNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -41,16 +41,14 @@
         return new SLReadPropertyNode(src, receiverNode, propertyName);
     }
 
-    @Child protected SLExpressionNode receiverNode;
-    protected final String propertyName;
-    @Child protected SLReadPropertyCacheNode cacheNode;
+    @Child private SLExpressionNode receiverNode;
+    @Child private SLReadPropertyCacheNode cacheNode;
     private final ConditionProfile receiverTypeCondition = ConditionProfile.createBinaryProfile();
 
     private SLReadPropertyNode(SourceSection src, SLExpressionNode receiverNode, String propertyName) {
         super(src);
         this.receiverNode = receiverNode;
-        this.propertyName = propertyName;
-        this.cacheNode = SLReadPropertyCacheNode.create(propertyName);
+        this.cacheNode = SLReadPropertyCacheNodeGen.create(propertyName);
     }
 
     @Override
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyCacheNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyCacheNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -23,276 +23,120 @@
 package com.oracle.truffle.sl.nodes.access;
 
 import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.*;
+import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.object.*;
 
-/**
- * The node for accessing a property of an object. When executed, this node first evaluates the
- * object expression on the left side of the dot operator and then reads the named property.
- */
 public abstract class SLWritePropertyCacheNode extends Node {
 
-    public static SLWritePropertyCacheNode create(String propertyName) {
-        return new SLUninitializedWritePropertyNode(propertyName);
+    protected final String propertyName;
+
+    public SLWritePropertyCacheNode(String propertyName) {
+        this.propertyName = propertyName;
     }
 
     public abstract void executeObject(DynamicObject receiver, Object value);
 
-    public abstract void executeLong(DynamicObject receiver, long value);
-
-    public abstract void executeBoolean(DynamicObject receiver, boolean value);
-
-    protected abstract static class SLWritePropertyCacheChainNode extends SLWritePropertyCacheNode {
-        protected final Shape oldShape;
-        protected final Shape newShape;
-        @Child protected SLWritePropertyCacheNode next;
-
-        public SLWritePropertyCacheChainNode(Shape oldShape, Shape newShape, SLWritePropertyCacheNode next) {
-            this.oldShape = oldShape;
-            this.newShape = newShape;
-            this.next = next;
+    @Specialization(guards = "location.isValid(receiver, value)", assumptions = "location.getAssumptions()")
+    public void writeCached(DynamicObject receiver, Object value, //
+                    @Cached("createCachedWrite(receiver, value)") CachedWriteLocation location) {
+        if (location.writeUnchecked(receiver, value)) {
+            // write successful
+        } else {
+            executeObject(receiver, value);
         }
-
-        @Override
-        public final void executeObject(DynamicObject receiver, Object value) {
-            try {
-                // if this assumption fails, the object needs to be updated to a valid shape
-                oldShape.getValidAssumption().check();
-                newShape.getValidAssumption().check();
-            } catch (InvalidAssumptionException e) {
-                this.replace(next).executeObject(receiver, value);
-                return;
-            }
-
-            boolean condition = oldShape.check(receiver) && checkValue(receiver, value);
-
-            if (condition) {
-                executeObjectUnchecked(receiver, value);
-            } else {
-                next.executeObject(receiver, value);
-            }
-        }
+    }
 
-        @Override
-        public final void executeLong(DynamicObject receiver, long value) {
-            try {
-                // if this assumption fails, the object needs to be updated to a valid shape
-                oldShape.getValidAssumption().check();
-                newShape.getValidAssumption().check();
-            } catch (InvalidAssumptionException e) {
-                this.replace(next).executeLong(receiver, value);
-                return;
-            }
-
-            boolean condition = oldShape.check(receiver) && checkValue(receiver, value);
-
-            if (condition) {
-                executeLongUnchecked(receiver, value);
-            } else {
-                next.executeLong(receiver, value);
-            }
+    @Specialization(contains = "writeCached")
+    @TruffleBoundary
+    public void writeGeneric(DynamicObject receiver, Object value, //
+                    @Cached("new(createCachedWrite(receiver, value))") LRUCachedWriteLocation lru) {
+        CachedWriteLocation location = lru.location;
+        if (!location.isValid(receiver, value) || !location.areAssumptionsValid()) {
+            location = createCachedWrite(receiver, value);
+            lru.location = location;
         }
-
-        @Override
-        public final void executeBoolean(DynamicObject receiver, boolean value) {
-            try {
-                // if this assumption fails, the object needs to be updated to a valid shape
-                oldShape.getValidAssumption().check();
-                newShape.getValidAssumption().check();
-            } catch (InvalidAssumptionException e) {
-                this.replace(next).executeBoolean(receiver, value);
-                return;
-            }
-
-            boolean condition = oldShape.check(receiver) && checkValue(receiver, value);
-
-            if (condition) {
-                executeBooleanUnchecked(receiver, value);
-            } else {
-                next.executeBoolean(receiver, value);
-            }
-        }
-
-        @SuppressWarnings("unused")
-        protected boolean checkValue(DynamicObject receiver, Object value) {
-            return true;
-        }
-
-        protected abstract void executeObjectUnchecked(DynamicObject receiver, Object value);
-
-        protected void executeLongUnchecked(DynamicObject receiver, long value) {
-            executeObjectUnchecked(receiver, value);
-        }
-
-        protected void executeBooleanUnchecked(DynamicObject receiver, boolean value) {
-            executeObjectUnchecked(receiver, value);
+        if (location.writeUnchecked(receiver, value)) {
+            // write successful
+        } else {
+            executeObject(receiver, value);
         }
     }
 
-    protected static class SLWriteObjectPropertyNode extends SLWritePropertyCacheChainNode {
-        private final Location location;
+    protected CachedWriteLocation createCachedWrite(DynamicObject receiver, Object value) {
+        while (receiver.updateShape()) {
+            // multiple shape updates might be needed.
+        }
+
+        Shape oldShape = receiver.getShape();
+        Shape newShape;
+        Property property = oldShape.getProperty(propertyName);
+
+        if (property != null && property.getLocation().canSet(receiver, value)) {
+            newShape = oldShape;
+        } else {
+            receiver.define(propertyName, value, 0);
+            newShape = receiver.getShape();
+            property = newShape.getProperty(propertyName);
+        }
 
-        protected SLWriteObjectPropertyNode(Shape oldShape, Shape newShape, Location location, SLWritePropertyCacheNode next) {
-            super(oldShape, newShape, next);
+        if (!oldShape.check(receiver)) {
+            return createCachedWrite(receiver, value);
+        }
+
+        return new CachedWriteLocation(oldShape, newShape, property.getLocation());
+
+    }
+
+    protected static final class CachedWriteLocation {
+
+        private final Shape oldShape;
+        private final Shape newShape;
+        private final Location location;
+        private final Assumption validLocation = Truffle.getRuntime().createAssumption();
+
+        public CachedWriteLocation(Shape oldShape, Shape newShape, Location location) {
+            this.oldShape = oldShape;
+            this.newShape = newShape;
             this.location = location;
         }
 
-        @Override
-        protected void executeObjectUnchecked(DynamicObject receiver, Object value) {
+        public boolean areAssumptionsValid() {
+            return validLocation.isValid() && oldShape.getValidAssumption().isValid() && newShape.getValidAssumption().isValid();
+        }
+
+        public Assumption[] getAssumptions() {
+            return new Assumption[]{oldShape.getValidAssumption(), newShape.getValidAssumption(), validLocation};
+        }
+
+        public boolean isValid(DynamicObject receiver, Object value) {
+            return oldShape.check(receiver) && location.canSet(receiver, value);
+        }
+
+        public boolean writeUnchecked(DynamicObject receiver, Object value) {
             try {
                 if (oldShape == newShape) {
                     location.set(receiver, value, oldShape);
                 } else {
                     location.set(receiver, value, oldShape, newShape);
                 }
+                return true;
             } catch (IncompatibleLocationException | FinalLocationException e) {
-                replace(next).executeObject(receiver, value);
+                validLocation.invalidate();
+                return false;
             }
         }
-
-        @Override
-        protected boolean checkValue(DynamicObject receiver, Object value) {
-            return location.canSet(receiver, value);
-        }
     }
 
-    protected static class SLWriteBooleanPropertyNode extends SLWritePropertyCacheChainNode {
-        private final BooleanLocation location;
-
-        protected SLWriteBooleanPropertyNode(Shape oldShape, Shape newShape, BooleanLocation location, SLWritePropertyCacheNode next) {
-            super(oldShape, newShape, next);
-            this.location = location;
-        }
-
-        @Override
-        protected void executeObjectUnchecked(DynamicObject receiver, Object value) {
-            try {
-                if (oldShape == newShape) {
-                    location.set(receiver, value, oldShape);
-                } else {
-                    location.set(receiver, value, oldShape, newShape);
-                }
-            } catch (IncompatibleLocationException | FinalLocationException e) {
-                replace(next).executeObject(receiver, value);
-            }
-        }
+    protected static final class LRUCachedWriteLocation {
 
-        @Override
-        protected void executeBooleanUnchecked(DynamicObject receiver, boolean value) {
-            try {
-                if (oldShape == newShape) {
-                    location.setBoolean(receiver, value, oldShape);
-                } else {
-                    location.setBoolean(receiver, value, oldShape, newShape);
-                }
-            } catch (FinalLocationException e) {
-                replace(next).executeBoolean(receiver, value);
-            }
-        }
+        private CachedWriteLocation location;
 
-        @Override
-        protected boolean checkValue(DynamicObject receiver, Object value) {
-            return value instanceof Boolean;
-        }
-    }
-
-    protected static class SLWriteLongPropertyNode extends SLWritePropertyCacheChainNode {
-        private final LongLocation location;
-
-        protected SLWriteLongPropertyNode(Shape oldShape, Shape newShape, LongLocation location, SLWritePropertyCacheNode next) {
-            super(oldShape, newShape, next);
+        public LRUCachedWriteLocation(CachedWriteLocation location) {
             this.location = location;
         }
 
-        @Override
-        protected void executeObjectUnchecked(DynamicObject receiver, Object value) {
-            try {
-                if (oldShape == newShape) {
-                    location.set(receiver, value, oldShape);
-                } else {
-                    location.set(receiver, value, oldShape, newShape);
-                }
-            } catch (IncompatibleLocationException | FinalLocationException e) {
-                replace(next).executeObject(receiver, value);
-            }
-        }
-
-        @Override
-        protected void executeLongUnchecked(DynamicObject receiver, long value) {
-            try {
-                if (oldShape == newShape) {
-                    location.setLong(receiver, value, oldShape);
-                } else {
-                    location.setLong(receiver, value, oldShape, newShape);
-                }
-            } catch (FinalLocationException e) {
-                replace(next).executeLong(receiver, value);
-            }
-        }
-
-        @Override
-        protected boolean checkValue(DynamicObject receiver, Object value) {
-            return value instanceof Long;
-        }
     }
 
-    protected static class SLUninitializedWritePropertyNode extends SLWritePropertyCacheNode {
-        protected final String propertyName;
-
-        protected SLUninitializedWritePropertyNode(String propertyName) {
-            this.propertyName = propertyName;
-        }
-
-        @Override
-        public void executeObject(DynamicObject receiver, Object value) {
-            CompilerDirectives.transferToInterpreterAndInvalidate();
-
-            if (receiver.updateShape()) {
-                // shape changed, retry cache again
-                getTopNode().executeObject(receiver, value);
-                return;
-            }
-
-            Shape oldShape = receiver.getShape();
-            Shape newShape;
-            Property property = oldShape.getProperty(propertyName);
-
-            final SLWritePropertyCacheNode resolvedNode;
-            if (property != null && property.getLocation().canSet(receiver, value)) {
-                newShape = oldShape;
-            } else {
-                receiver.define(propertyName, value, 0);
-                newShape = receiver.getShape();
-                property = newShape.getProperty(propertyName);
-            }
-
-            if (property.getLocation() instanceof LongLocation) {
-                resolvedNode = new SLWriteLongPropertyNode(oldShape, newShape, (LongLocation) property.getLocation(), this);
-            } else if (property.getLocation() instanceof BooleanLocation) {
-                resolvedNode = new SLWriteBooleanPropertyNode(oldShape, newShape, (BooleanLocation) property.getLocation(), this);
-            } else {
-                resolvedNode = new SLWriteObjectPropertyNode(oldShape, newShape, property.getLocation(), this);
-            }
-
-            this.replace(resolvedNode, "resolved '" + propertyName + "'").executeObject(receiver, value);
-        }
-
-        private SLWritePropertyCacheNode getTopNode() {
-            SLWritePropertyCacheNode top = this;
-            while (top.getParent() instanceof SLWritePropertyCacheNode) {
-                top = (SLWritePropertyCacheNode) top.getParent();
-            }
-            return top;
-        }
-
-        @Override
-        public void executeLong(DynamicObject receiver, long value) {
-            executeObject(receiver, value);
-        }
-
-        @Override
-        public void executeBoolean(DynamicObject receiver, boolean value) {
-            executeObject(receiver, value);
-        }
-    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/access/SLWritePropertyNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -54,7 +54,7 @@
         this.receiverNode = receiverNode;
         this.propertyName = propertyName;
         this.valueNode = valueNode;
-        this.cacheNode = SLWritePropertyCacheNode.create(propertyName);
+        this.cacheNode = SLWritePropertyCacheNodeGen.create(propertyName);
     }
 
     @Override
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLAbstractDispatchNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, 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.sl.nodes.call;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.sl.runtime.*;
-
-/**
- * Before a call is executed the first time, the dispatch node is a
- * {@link SLUninitializedDispatchNode}. During execution, the call is optimized using a polymorphic
- * inline cache, i.e., a chain of {@link SLDirectDispatchNode}s. The chain is terminated by a
- * {@link SLUninitializedDispatchNode}. If the chain gets too long (longer than
- * {@link #INLINE_CACHE_SIZE}), i.e., if the call is too polymorphic, the whole chain is replaced by
- * a single {@link SLGenericDispatchNode}. All this rewriting happens on runtime, based on profiling
- * feedback of the actual execution.
- * <p>
- * Example of the chain of nodes ({@code I}: {@link SLInvokeNode}; {@code U}:
- * {@link SLUninitializedDispatchNode}; {@code D}: {@link SLDirectDispatchNode}; {@code G}:
- * {@link SLGenericDispatchNode}):
- * <ol>
- * <li>After parsing: {@code I->U}
- * <li>After execution of function {@code f1}: {@code I->D(f1)->U}
- * <li>After execution of function {@code f2}: {@code I->D(f1)->D(f2)->U}
- * <li>After execution of function {@code f3}: {@code I->G}
- * </ol>
- */
-public abstract class SLAbstractDispatchNode extends Node {
-
-    protected static final int INLINE_CACHE_SIZE = 2;
-
-    protected abstract Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments);
-}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDirectDispatchNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,112 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, 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.sl.nodes.call;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.sl.runtime.*;
-
-/**
- * An entry in the polymorphic inline cache.
- */
-final class SLDirectDispatchNode extends SLAbstractDispatchNode {
-
-    /** The cached function. */
-    private final SLFunction cachedFunction;
-
-    /**
-     * {@link DirectCallNode} is part of the Truffle API and handles all the steps necessary for
-     * method inlining: if the call is executed frequently and the callee is small, then the call is
-     * inlined, i.e., the call node is replaced with a copy of the callee's AST.
-     */
-    @Child private DirectCallNode callCachedTargetNode;
-
-    /** Assumption that the {@link #callCachedTargetNode} is still valid. */
-    private final Assumption cachedTargetStable;
-
-    /**
-     * The next entry of the polymorphic inline cache, either another {@link SLDirectDispatchNode}
-     * or a {@link SLUninitializedDispatchNode}.
-     */
-    @Child private SLAbstractDispatchNode nextNode;
-
-    protected SLDirectDispatchNode(SLAbstractDispatchNode next, SLFunction cachedFunction) {
-        this.cachedFunction = cachedFunction;
-        this.callCachedTargetNode = Truffle.getRuntime().createDirectCallNode(cachedFunction.getCallTarget());
-        this.cachedTargetStable = cachedFunction.getCallTargetStable();
-        this.nextNode = next;
-    }
-
-    /**
-     * Perform the inline cache check. If it succeeds, execute the cached
-     * {@link #cachedTargetStable call target}; if it fails, defer to the next element in the chain.
-     * <p>
-     * Since SL is a quite simple language, the benefit of the inline cache is quite small: after
-     * checking that the actual function to be executed is the same as the
-     * {@link SLDirectDispatchNode#cachedFunction}, we can safely execute the cached call target.
-     * You can reasonably argue that caching the call target is overkill, since we could just
-     * retrieve it via {@code function.getCallTarget()}. However, in a more complex language the
-     * lookup of the call target is usually much more complicated than in SL. In addition, caching
-     * the call target allows method inlining.
-     */
-    @Override
-    protected Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments) {
-        /*
-         * The inline cache check. Note that cachedFunction must be a final field so that the
-         * compiler can optimize the check.
-         */
-        if (this.cachedFunction == function) {
-            /* Inline cache hit, we are safe to execute the cached call target. */
-            try {
-                /*
-                 * Support for function redefinition: When a function is redefined, the call target
-                 * maintained by the SLFunction object is change. To avoid a check for that, we use
-                 * an Assumption that is invalidated by the SLFunction when the change is performed.
-                 * Since checking an assumption is a no-op in compiled code, the line below does not
-                 * add any overhead during optimized execution.
-                 */
-                cachedTargetStable.check();
-
-                /*
-                 * Now we are really ready to perform the call. We use a Truffle CallNode for that,
-                 * because it does all the work for method inlining.
-                 */
-                return callCachedTargetNode.call(frame, arguments);
-
-            } catch (InvalidAssumptionException ex) {
-                /*
-                 * The function has been redefined. Remove ourself from the polymorphic inline
-                 * cache, so that we fail the check only once. Note that this replacement has subtle
-                 * semantics: we are changing a node in the tree that is currently executed. This is
-                 * only safe because we know that after the call to replace(), there is no more code
-                 * that requires that this node is part of the tree.
-                 */
-                replace(nextNode);
-                /* Execute the next node in the chain by falling out of the if block. */
-            }
-        }
-        /* Inline cache miss, defer to the next element in the chain. */
-        return nextNode.executeDispatch(frame, function, arguments);
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLDispatchNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2013, 2015, 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.sl.nodes.call;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.runtime.*;
+
+public abstract class SLDispatchNode extends Node {
+
+    protected static final int INLINE_CACHE_SIZE = 2;
+
+    public abstract Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments);
+
+    /**
+     * Inline cached specialization of the dispatch.
+     *
+     * <p>
+     * Since SL is a quite simple language, the benefit of the inline cache is quite small: after
+     * checking that the actual function to be executed is the same as the cachedFuntion, we can
+     * safely execute the cached call target. You can reasonably argue that caching the call target
+     * is overkill, since we could just retrieve it via {@code function.getCallTarget()}. However,
+     * in a more complex language the lookup of the call target is usually much more complicated
+     * than in SL. In addition, caching the call target allows method inlining.
+     * </p>
+     *
+     * <p>
+     * {@code limit = "INLINE_CACHE_SIZE"} Specifies the limit number of inline cache specialization
+     * instantiations.
+     * </p>
+     * <p>
+     * {@code guards = "function == cachedFunction"} The inline cache check. Note that
+     * cachedFunction is a final field so that the compiler can optimize the check.
+     * </p>
+     * <p>
+     * {@code assumptions = "cachedFunction.getCallTargetStable()"} Support for function
+     * redefinition: When a function is redefined, the call target maintained by the SLFunction
+     * object is change. To avoid a check for that, we use an Assumption that is invalidated by the
+     * SLFunction when the change is performed. Since checking an assumption is a no-op in compiled
+     * code, the assumption check performed by the DSL does not add any overhead during optimized
+     * execution.
+     * </p>
+     *
+     * @see Cached
+     * @see Specialization
+     *
+     * @param function the dynamically provided function
+     * @param cachedFunction the cached function of the specialization instance
+     * @param callNode the {@link DirectCallNode} specifically created for the {@link CallTarget} in
+     *            cachedFunction.
+     */
+    @Specialization(limit = "INLINE_CACHE_SIZE", guards = "function == cachedFunction", assumptions = "cachedFunction.getCallTargetStable()")
+    protected static Object doDirect(VirtualFrame frame, SLFunction function, Object[] arguments, //
+                    @Cached("function") SLFunction cachedFunction, //
+                    @Cached("create(cachedFunction.getCallTarget())") DirectCallNode callNode) {
+        /* Inline cache hit, we are safe to execute the cached call target. */
+        return callNode.call(frame, arguments);
+    }
+
+    /**
+     * Slow-path code for a call, used when the polymorphic inline cache exceeded its maximum size
+     * specified in <code>INLINE_CACHE_SIZE</code>. Such calls are not optimized any further, e.g.,
+     * no method inlining is performed.
+     */
+    @Specialization(contains = "doDirect")
+    protected static Object doIndirect(VirtualFrame frame, SLFunction function, Object[] arguments, //
+                    @Cached("create()") IndirectCallNode callNode) {
+        /*
+         * SL has a quite simple call lookup: just ask the function for the current call target, and
+         * call it.
+         */
+        return callNode.call(frame, function.getCallTarget(), arguments);
+    }
+
+}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLGenericDispatchNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, 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.sl.nodes.call;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.sl.runtime.*;
-
-/**
- * Slow-path code for a call, used when the polymorphic inline cache exceeded its maximum size. Such
- * calls are not optimized any further, e.g., no method inlining is performed.
- */
-final class SLGenericDispatchNode extends SLAbstractDispatchNode {
-
-    /**
-     * {@link IndirectCallNode} is part of the Truffle API and handles all the steps necessary for
-     * calling a megamorphic call-site. The Graal specific version of this node performs additional
-     * optimizations for the fast access of the SimpleLanguage stack trace.
-     */
-    @Child private IndirectCallNode callNode = Truffle.getRuntime().createIndirectCallNode();
-
-    @Override
-    protected Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments) {
-        /*
-         * SL has a quite simple call lookup: just ask the function for the current call target, and
-         * call it.
-         */
-        return callNode.call(frame, function.getCallTarget(), arguments);
-    }
-
-}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInvokeNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLInvokeNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, 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
@@ -35,24 +35,24 @@
  * {@link SLFunction target function} can be computed by an {@link #functionNode arbitrary
  * expression}. This node is responsible for evaluating this expression, as well as evaluating the
  * {@link #argumentNodes arguments}. The actual dispatch is then delegated to a chain of
- * {@link SLAbstractDispatchNode}s that form a polymorphic inline cache.
+ * {@link SLDispatchNode} that form a polymorphic inline cache.
  */
 @NodeInfo(shortName = "invoke")
 public final class SLInvokeNode extends SLExpressionNode {
 
     public static SLInvokeNode create(SourceSection src, SLExpressionNode function, SLExpressionNode[] arguments) {
-        return new SLInvokeNode(src, function, arguments, new SLUninitializedDispatchNode());
+        return new SLInvokeNode(src, function, arguments);
     }
 
-    @Child protected SLExpressionNode functionNode;
-    @Children protected final SLExpressionNode[] argumentNodes;
-    @Child protected SLAbstractDispatchNode dispatchNode;
+    @Child private SLExpressionNode functionNode;
+    @Children private final SLExpressionNode[] argumentNodes;
+    @Child private SLDispatchNode dispatchNode;
 
-    private SLInvokeNode(SourceSection src, SLExpressionNode functionNode, SLExpressionNode[] argumentNodes, SLAbstractDispatchNode dispatchNode) {
+    private SLInvokeNode(SourceSection src, SLExpressionNode functionNode, SLExpressionNode[] argumentNodes) {
         super(src);
         this.functionNode = functionNode;
         this.argumentNodes = argumentNodes;
-        this.dispatchNode = dispatchNode;
+        this.dispatchNode = SLDispatchNodeGen.create();
     }
 
     @Override
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/call/SLUninitializedDispatchNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, 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.sl.nodes.call;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.sl.*;
-import com.oracle.truffle.sl.runtime.*;
-
-/**
- * The last entry of a polymorphic inline cache.
- */
-final class SLUninitializedDispatchNode extends SLAbstractDispatchNode {
-
-    /**
-     * When we reach this method, all the previous cache entries did not match the function. If the
-     * cache is still small enough, we extend it by adding another {@link SLDirectDispatchNode}. If
-     * the cache reached its maximum size, we replace the whole dispatch chain with a
-     * {@link SLGenericDispatchNode}.
-     */
-    @Override
-    protected Object executeDispatch(VirtualFrame frame, SLFunction function, Object[] arguments) {
-        /* The following code modifies the AST, so compiled code must be invalidated. */
-        CompilerDirectives.transferToInterpreterAndInvalidate();
-
-        /*
-         * Count the number of SLDirectDispatchNodes we already have in the cache. We walk the chain
-         * of parent nodes until we hit the SLCallNode. We know that a SLCallNode is always present.
-         */
-        Node cur = this;
-        int depth = 0;
-        while (cur.getParent() instanceof SLAbstractDispatchNode) {
-            cur = cur.getParent();
-            depth++;
-        }
-        SLInvokeNode invokeNode = (SLInvokeNode) cur.getParent();
-
-        SLAbstractDispatchNode replacement;
-        if (function.getCallTarget() == null) {
-            /* Corner case: the function is not defined, so report an error to the user. */
-            throw new SLException("Call of undefined function: " + function.getName());
-
-        } else if (depth < INLINE_CACHE_SIZE) {
-            /* Extend the inline cache. Allocate the new cache entry, and the new end of the cache. */
-            SLAbstractDispatchNode next = new SLUninitializedDispatchNode();
-            replacement = new SLDirectDispatchNode(next, function);
-            /* Replace ourself with the new cache entry. */
-            replace(replacement);
-
-        } else {
-            /* Cache size exceeded, fall back to a single generic dispatch node. */
-            replacement = new SLGenericDispatchNode();
-            /* Replace the whole chain, not just ourself, with the new generic node. */
-            invokeNode.dispatchNode.replace(replacement);
-        }
-
-        /*
-         * Execute the newly created node perform the actual dispatch. That saves us from
-         * duplicating the actual call logic here.
-         */
-        return replacement.executeDispatch(frame, function, arguments);
-    }
-}
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/controlflow/SLBlockNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -55,8 +55,7 @@
     @ExplodeLoop
     public void executeVoid(VirtualFrame frame) {
         /*
-         * This assertion illustrates that the arryay length is really a constant during
-         * compilation.
+         * This assertion illustrates that the array length is really a constant during compilation.
          */
         CompilerAsserts.compilationConstant(bodyNodes.length);
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLBigIntegerLiteralNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -44,12 +44,7 @@
     }
 
     @Override
-    public BigInteger executeBigInteger(VirtualFrame frame) {
-        return value;
-    }
-
-    @Override
-    public Object executeGeneric(VirtualFrame frame) {
+    public BigInteger executeGeneric(VirtualFrame frame) {
         return value;
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLEqualNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLEqualNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -25,6 +25,7 @@
 import java.math.*;
 
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.nodes.*;
@@ -47,6 +48,9 @@
         super(src);
     }
 
+    @Override
+    public abstract boolean executeBoolean(VirtualFrame frame);
+
     @Specialization
     protected boolean equal(long left, long right) {
         return left == right;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLFunctionLiteralNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -46,12 +46,7 @@
     }
 
     @Override
-    public SLFunction executeFunction(VirtualFrame frame) {
-        return value;
-    }
-
-    @Override
-    public Object executeGeneric(VirtualFrame frame) {
+    public SLFunction executeGeneric(VirtualFrame frame) {
         return value;
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessOrEqualNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessOrEqualNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -25,6 +25,7 @@
 import java.math.*;
 
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.nodes.*;
@@ -39,6 +40,9 @@
         super(src);
     }
 
+    @Override
+    public abstract boolean executeBoolean(VirtualFrame frame);
+
     @Specialization
     protected boolean lessOrEqual(long left, long right) {
         return left <= right;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessThanNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLessThanNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -25,6 +25,7 @@
 import java.math.*;
 
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.nodes.*;
@@ -40,6 +41,9 @@
         super(src);
     }
 
+    @Override
+    public abstract boolean executeBoolean(VirtualFrame frame);
+
     @Specialization
     protected boolean lessThan(long left, long right) {
         return left < right;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalAndNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalAndNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -23,6 +23,7 @@
 package com.oracle.truffle.sl.nodes.expression;
 
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.nodes.*;
@@ -44,6 +45,9 @@
         super(src);
     }
 
+    @Override
+    public abstract boolean executeBoolean(VirtualFrame frame);
+
     /**
      * This method is called after the left child was evaluated, but before the right child is
      * evaluated. The right child is only evaluated when the return value is {code true}.
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalNotNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalNotNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -23,6 +23,7 @@
 package com.oracle.truffle.sl.nodes.expression;
 
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.nodes.*;
@@ -39,6 +40,9 @@
         super(src);
     }
 
+    @Override
+    public abstract boolean executeBoolean(VirtualFrame frame);
+
     @Specialization
     protected boolean doBoolean(boolean value) {
         return !value;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -39,6 +39,9 @@
         super(src);
     }
 
+    @Override
+    public abstract boolean executeBoolean(VirtualFrame frame);
+
     @ShortCircuit("rightNode")
     protected boolean needsRightNode(boolean left) {
         return !left;
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLParenExpressionNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLParenExpressionNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -22,13 +22,10 @@
  */
 package com.oracle.truffle.sl.nodes.expression;
 
-import java.math.*;
-
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.sl.nodes.*;
-import com.oracle.truffle.sl.runtime.*;
 
 /**
  * A {@link SLExpressionNode} that represents a parenthesized expression; it simply returns the
@@ -57,27 +54,8 @@
     }
 
     @Override
-    public BigInteger executeBigInteger(VirtualFrame frame) throws UnexpectedResultException {
-        return expression.executeBigInteger(frame);
-    }
-
-    @Override
     public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException {
         return expression.executeBoolean(frame);
     }
 
-    @Override
-    public String executeString(VirtualFrame frame) throws UnexpectedResultException {
-        return expression.executeString(frame);
-    }
-
-    @Override
-    public SLFunction executeFunction(VirtualFrame frame) throws UnexpectedResultException {
-        return expression.executeFunction(frame);
-    }
-
-    @Override
-    public SLNull executeNull(VirtualFrame frame) throws UnexpectedResultException {
-        return expression.executeNull(frame);
-    }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLStringLiteralNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -41,12 +41,7 @@
     }
 
     @Override
-    public String executeString(VirtualFrame frame) {
-        return value;
-    }
-
-    @Override
-    public Object executeGeneric(VirtualFrame frame) {
+    public String executeGeneric(VirtualFrame frame) {
         return value;
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java	Wed Apr 15 10:09:13 2015 -0700
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java	Wed Apr 15 11:03:04 2015 -0700
@@ -22,8 +22,6 @@
  */
 package com.oracle.truffle.sl.nodes.instrument;
 
-import java.math.*;
-
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode;
@@ -101,21 +99,11 @@
     }
 
     @Override
-    public BigInteger executeBigInteger(VirtualFrame vFrame) throws UnexpectedResultException {
-        return SLTypesGen.expectBigInteger(executeGeneric(vFrame));
-    }
-
-    @Override
     public boolean executeBoolean(VirtualFrame vFrame) throws UnexpectedResultException {
         return SLTypesGen.expectBoolean(executeGeneric(vFrame));
     }
 
     @Override
-    public String executeString(VirtualFrame vFrame) throws UnexpectedResultException {
-        return SLTypesGen.expectString(executeGeneric(vFrame));
-    }
-
-    @Override
     public SLFunction executeFunction(VirtualFrame vFrame) throws UnexpectedResultException {
         probeNode.enter(child, vFrame);
         SLFunction result;
@@ -130,8 +118,4 @@
         return result;
     }
 
-    @Override
-    public SLNull executeNull(VirtualFrame vFrame) throws UnexpectedResultException {
-        return SLTypesGen.expectSLNull(executeGeneric(vFrame));
-    }
 }
--- a/mx/mx_graal.py	Wed Apr 15 10:09:13 2015 -0700
+++ b/mx/mx_graal.py	Wed Apr 15 11:03:04 2015 -0700
@@ -1482,6 +1482,7 @@
         jar = os.path.abspath(args.jar)
     else:
         jar = join(_jdk(installJars=False), 'jre', 'lib', 'rt.jar')
+        vmargs.append('-G:CompileTheWorldExcludeMethodFilter=sun.awt.X11.*.*')
 
     vmargs += ['-XX:+CompileTheWorld']
     vm_ = _get_vm()
@@ -1492,7 +1493,7 @@
     else:
         vmargs += ['-Xbootclasspath/p:' + jar]
 
-    # suppress menubar and dock when running on Mac
+    # suppress menubar and dock when running on Mac; exclude x11 classes as they may cause vm crashes (on Solaris)
     vmargs = ['-Djava.awt.headless=true'] + vmargs
 
     vm(vmargs)
--- a/mx/suite.py	Wed Apr 15 10:09:13 2015 -0700
+++ b/mx/suite.py	Wed Apr 15 11:03:04 2015 -0700
@@ -465,7 +465,6 @@
       "checkstyle" : "com.oracle.graal.graph",
       "dependencies" : [
         "com.oracle.graal.nodeinfo",
-        "com.oracle.truffle.dsl.processor",
       ],
       "javaCompliance" : "1.8",
       "workingSets" : "Graal,Graph",
@@ -1037,6 +1036,7 @@
       "dependencies" : [
         "com.oracle.truffle.api.dsl",
         "com.oracle.truffle.api.object",
+        "FINDBUGS"
       ],
       "checkstyle" : "com.oracle.graal.graph",
       "javaCompliance" : "1.8",
--- a/mxtool/mx.py	Wed Apr 15 10:09:13 2015 -0700
+++ b/mxtool/mx.py	Wed Apr 15 11:03:04 2015 -0700
@@ -2097,7 +2097,9 @@
         return cmp(self.parts, other.parts)
 
 def _filter_non_existant_paths(paths):
-    return os.pathsep.join([path for path in _separatedCygpathW2U(paths).split(os.pathsep) if exists(path)])
+    if paths:
+        return os.pathsep.join([path for path in _separatedCygpathW2U(paths).split(os.pathsep) if exists(path)])
+    return None
 
 """
 A JavaConfig object encapsulates info on how Java commands are run.
@@ -2161,11 +2163,14 @@
         if not exists(outDir):
             os.makedirs(outDir)
         javaSource = join(myDir, 'ClasspathDump.java')
-        if not exists(join(outDir, 'ClasspathDump.class')):
+        javaClass = join(outDir, 'ClasspathDump.class')
+        if not exists(javaClass) or getmtime(javaClass) < getmtime(javaSource):
             subprocess.check_call([self.javac, '-d', _cygpathU2W(outDir), _cygpathU2W(javaSource)], stderr=subprocess.PIPE, stdout=subprocess.PIPE)
         self._bootclasspath, self._extdirs, self._endorseddirs = [x if x != 'null' else None for x in subprocess.check_output([self.java, '-cp', _cygpathU2W(outDir), 'ClasspathDump'], stderr=subprocess.PIPE).split('|')]
-        if not self._bootclasspath or not self._extdirs or not self._endorseddirs:
-            warn("Could not find all classpaths: boot='" + str(self._bootclasspath) + "' extdirs='" + str(self._extdirs) + "' endorseddirs='" + str(self._endorseddirs) + "'")
+        if self.javaCompliance <= JavaCompliance('1.8'):
+            # All 3 system properties accessed by ClasspathDump are expected to exist
+            if not self._bootclasspath or not self._extdirs or not self._endorseddirs:
+                warn("Could not find all classpaths: boot='" + str(self._bootclasspath) + "' extdirs='" + str(self._extdirs) + "' endorseddirs='" + str(self._endorseddirs) + "'")
         self._bootclasspath = _filter_non_existant_paths(self._bootclasspath)
         self._extdirs = _filter_non_existant_paths(self._extdirs)
         self._endorseddirs = _filter_non_existant_paths(self._endorseddirs)
@@ -2214,6 +2219,33 @@
             self._init_classpaths()
         return _separatedCygpathU2W(self._endorseddirs)
 
+    """
+    Add javadoc style options for the library paths of this JDK.
+    """
+    def javadocLibOptions(self, args):
+        if args is None:
+            args = []
+        if self.bootclasspath():
+            args.append('-bootclasspath')
+            args.append(self.bootclasspath())
+        if self.endorseddirs():
+            args.append('-endorseddirs')
+            args.append(self.endorseddirs())
+        if self.extdirs():
+            args.append('-extdirs')
+            args.append(self.extdirs())
+        return args
+
+    """
+    Add javac style options for the library paths of this JDK.
+    """
+    def javacLibOptions(self, args):
+        args = self.javadocLibOptions(args)
+        if self.endorseddirs():
+            args.append('-endorseddirs')
+            args.append(self.endorseddirs())
+        return args
+
     def containsJar(self, jar):
         if self._bootclasspath is None:
             self._init_classpaths()
@@ -2447,7 +2479,8 @@
                 if not args.error_prone:
                     javac = args.alt_javac if args.alt_javac else mainJava.javac
                     self.logCompilation('javac' if not args.alt_javac else args.alt_javac)
-                    javacCmd = [javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
+                    javacCmd = [javac, '-g', '-J-Xmx1g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir]
+                    jdk.javacLibOptions(javacCmd)
                     if jdk.debug_port is not None:
                         javacCmd += ['-J-Xdebug', '-J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(jdk.debug_port)]
                     javacCmd += processorArgs
@@ -2459,7 +2492,8 @@
                 else:
                     self.logCompilation('javac (with error-prone)')
                     javaArgs = ['-Xmx1g']
-                    javacArgs = ['-g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir, '-bootclasspath', jdk.bootclasspath(), '-endorseddirs', jdk.endorseddirs(), '-extdirs', jdk.extdirs()]
+                    javacArgs = ['-g', '-source', compliance, '-target', compliance, '-classpath', cp, '-d', outputDir]
+                    jdk.javacLibOptions(javacCmd)
                     javacArgs += processorArgs
                     javacArgs += ['@' + argfile.name]
                     if not args.warnAPI:
@@ -2472,10 +2506,8 @@
 
                 jdtArgs = ['-' + compliance,
                          '-cp', cp, '-g', '-enableJavadoc',
-                         '-d', outputDir,
-                         '-bootclasspath', jdk.bootclasspath(),
-                         '-endorseddirs', jdk.endorseddirs(),
-                         '-extdirs', jdk.extdirs()]
+                         '-d', outputDir]
+                jdk.javacLibOptions(jdtArgs)
                 jdtArgs += processorArgs
 
                 jdtProperties = join(self.proj.dir, '.settings', 'org.eclipse.jdt.core.prefs')
@@ -4840,9 +4872,8 @@
                      '-d', out,
                      '-overview', overviewFile,
                      '-sourcepath', sp,
-                     '-source', str(projectJava.javaCompliance),
-                     '-bootclasspath', projectJava.bootclasspath(),
-                     '-extdirs', projectJava.extdirs()] +
+                     '-source', str(projectJava.javaCompliance)] +
+                     projectJava.javadocLibOptions() +
                      ([] if projectJava.javaCompliance < JavaCompliance('1.8') else ['-Xdoclint:none']) +
                      links +
                      extraArgs +
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cpu/x86/vm/registerMap_x86.cpp	Wed Apr 15 11:03:04 2015 -0700
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, 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.
+ *
+ */
+
+#include <runtime/registerMap.hpp>
+#include "vmreg_x86.inline.hpp"
+
+address RegisterMap::pd_location(VMReg reg) const {
+  if (reg->is_XMMRegister()) {
+    int regBase = reg->value() - ConcreteRegisterImpl::max_fpr;
+    if (regBase % 4 == 0) {
+      // Reads of the low and high 16 byte parts should be handled by location itself
+      return NULL;
+    }
+    VMReg baseReg = as_XMMRegister(regBase >> 3)->as_VMReg();
+    intptr_t offset = (reg->value() - baseReg->value()) * 4;
+    if (offset >= 16) {
+      // The high part of YMM registers are saved in a their own area in the frame
+      baseReg = baseReg->next()->next()->next()->next();
+      offset -= 16;
+    }
+    address baseLocation = location(baseReg);
+    if (baseLocation != NULL) {
+      return baseLocation + offset;
+    }
+  }
+  return NULL;
+}
--- a/src/cpu/x86/vm/registerMap_x86.hpp	Wed Apr 15 10:09:13 2015 -0700
+++ b/src/cpu/x86/vm/registerMap_x86.hpp	Wed Apr 15 11:03:04 2015 -0700
@@ -31,11 +31,7 @@
  private:
   // This is the hook for finding a register in an "well-known" location,
   // such as a register block of a predetermined format.
-  // Since there is none, we just return NULL.
-  // See registerMap_sparc.hpp for an example of grabbing registers
-  // from register save areas of a standard layout.
-   address pd_location(VMReg reg) const {return NULL;}
-
+  address pd_location(VMReg reg) const;
   // no PD state to clear or copy:
   void pd_clear() {}
   void pd_initialize() {}
--- a/src/cpu/x86/vm/register_x86.cpp	Wed Apr 15 10:09:13 2015 -0700
+++ b/src/cpu/x86/vm/register_x86.cpp	Wed Apr 15 11:03:04 2015 -0700
@@ -64,3 +64,28 @@
   };
   return is_valid() ? names[encoding()] : "xnoreg";
 }
+
+const char* XMMRegisterImpl::sub_word_name(int i) const {
+  const char* names[number_of_registers * 8] = {
+      "xmm0:0", "xmm0:1", "xmm0:2", "xmm0:3", "xmm0:4", "xmm0:5", "xmm0:6", "xmm0:7",
+      "xmm1:0", "xmm1:1", "xmm1:2", "xmm1:3", "xmm1:4", "xmm1:5", "xmm1:6", "xmm1:7",
+      "xmm2:0", "xmm2:1", "xmm2:2", "xmm2:3", "xmm2:4", "xmm2:5", "xmm2:6", "xmm2:7",
+      "xmm3:0", "xmm3:1", "xmm3:2", "xmm3:3", "xmm3:4", "xmm3:5", "xmm3:6", "xmm3:7",
+      "xmm4:0", "xmm4:1", "xmm4:2", "xmm4:3", "xmm4:4", "xmm4:5", "xmm4:6", "xmm4:7",
+      "xmm5:0", "xmm5:1", "xmm5:2", "xmm5:3", "xmm5:4", "xmm5:5", "xmm5:6", "xmm5:7",
+      "xmm6:0", "xmm6:1", "xmm6:2", "xmm6:3", "xmm6:4", "xmm6:5", "xmm6:6", "xmm6:7",
+      "xmm7:0", "xmm7:1", "xmm7:2", "xmm7:3", "xmm7:4", "xmm7:5", "xmm7:6", "xmm7:7",
+#ifdef AMD64
+      "xmm8:0", "xmm8:1", "xmm8:2", "xmm8:3", "xmm8:4", "xmm8:5", "xmm8:6", "xmm8:7",
+      "xmm9:0", "xmm9:1", "xmm9:2", "xmm9:3", "xmm9:4", "xmm9:5", "xmm9:6", "xmm9:7",
+      "xmm10:0", "xmm10:1", "xmm10:2", "xmm10:3", "xmm10:4", "xmm10:5", "xmm10:6", "xmm10:7",
+      "xmm11:0", "xmm11:1", "xmm11:2", "xmm11:3", "xmm11:4", "xmm11:5", "xmm11:6", "xmm11:7",
+      "xmm12:0", "xmm12:1", "xmm12:2", "xmm12:3", "xmm12:4", "xmm12:5", "xmm12:6", "xmm12:7",
+      "xmm13:0", "xmm13:1", "xmm13:2", "xmm13:3", "xmm13:4", "xmm13:5", "xmm13:6", "xmm13:7",
+      "xmm14:0", "xmm14:1", "xmm14:2", "xmm14:3", "xmm14:4", "xmm14:5", "xmm14:6", "xmm14:7",
+      "xmm15:0", "xmm15:1", "xmm15:2", "xmm15:3", "xmm15:4", "xmm15:5", "xmm15:6", "xmm15:7",
+#endif // AMD64
+  };
+  assert(i >= 0 && i < 8, "offset too large");
+  return is_valid() ? names[encoding() * 8 + i] : "xnoreg";
+}
--- a/src/cpu/x86/vm/register_x86.hpp	Wed Apr 15 10:09:13 2015 -0700
+++ b/src/cpu/x86/vm/register_x86.hpp	Wed Apr 15 11:03:04 2015 -0700
@@ -161,6 +161,7 @@
   int   encoding() const                          { assert(is_valid(), err_msg("invalid register (%d)", (int)(intptr_t)this )); return (intptr_t)this; }
   bool  is_valid() const                          { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; }
   const char* name() const;
+  const char* sub_word_name(int offset) const;
 };
 
 
--- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Wed Apr 15 10:09:13 2015 -0700
+++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Wed Apr 15 11:03:04 2015 -0700
@@ -70,9 +70,32 @@
   // Capture info about frame layout.  Layout offsets are in jint
   // units because compiler frame slots are jints.
 #define DEF_XMM_OFFS(regnum) xmm ## regnum ## _off = xmm_off + (regnum)*16/BytesPerInt, xmm ## regnum ## H_off
+#define DEF_YMM_HI_OFFS(regnum) ymm_hi ## regnum ## _off = ymm_off + (regnum)*16/BytesPerInt
   enum layout {
     fpu_state_off = frame::arg_reg_save_area_bytes/BytesPerInt, // fxsave save area
-    xmm_off       = fpu_state_off + 160/BytesPerInt,            // offset in fxsave save area
+#if defined(COMPILER2) || defined(GRAAL)
+    ymm_off       = fpu_state_off,            // offset in fxsave save area
+    DEF_YMM_HI_OFFS(0),
+    DEF_YMM_HI_OFFS(1),
+    DEF_YMM_HI_OFFS(2),
+    DEF_YMM_HI_OFFS(3),
+    DEF_YMM_HI_OFFS(4),
+    DEF_YMM_HI_OFFS(5),
+    DEF_YMM_HI_OFFS(6),
+    DEF_YMM_HI_OFFS(7),
+    DEF_YMM_HI_OFFS(8),
+    DEF_YMM_HI_OFFS(9),
+    DEF_YMM_HI_OFFS(10),
+    DEF_YMM_HI_OFFS(11),
+    DEF_YMM_HI_OFFS(12),
+    DEF_YMM_HI_OFFS(13),
+    DEF_YMM_HI_OFFS(14),
+    DEF_YMM_HI_OFFS(15),
+    ymm_hi_save_size = 16 * 16 / BytesPerInt,
+#else
+    ymm_hi_save_size = 0,
+#endif
+    xmm_off       = fpu_state_off + 160/BytesPerInt + ymm_hi_save_size,            // offset in fxsave save area
     DEF_XMM_OFFS(0),
     DEF_XMM_OFFS(1),
     DEF_XMM_OFFS(2),
@@ -89,7 +112,7 @@
     DEF_XMM_OFFS(13),
     DEF_XMM_OFFS(14),
     DEF_XMM_OFFS(15),
-    fpu_state_end = fpu_state_off + ((FPUStateSizeInWords-1)*wordSize / BytesPerInt),
+    fpu_state_end = fpu_state_off + ((FPUStateSizeInWords-1)*wordSize / BytesPerInt) + ymm_hi_save_size,
     fpu_stateH_end,
     r15_off, r15H_off,
     r14_off, r14H_off,
@@ -139,19 +162,6 @@
 };
 
 OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words, bool save_vectors) {
-  int vect_words = 0;
-#ifdef COMPILER2
-  if (save_vectors) {
-    assert(UseAVX > 0, "256bit vectors are supported only with AVX");
-    assert(MaxVectorSize == 32, "only 256bit vectors are supported now");
-    // Save upper half of YMM registes
-    vect_words = 16 * 16 / wordSize;
-    additional_frame_words += vect_words;
-  }
-#else
-  assert(!save_vectors, "vectors are generated only by C2");
-#endif
-
   // Always make the frame size 16-byte aligned
   int frame_size_in_bytes = round_to(additional_frame_words*wordSize +
                                      reg_save_size*BytesPerInt, 16);
@@ -172,26 +182,34 @@
   __ enter();          // rsp becomes 16-byte aligned here
   __ push_CPU_state(); // Push a multiple of 16 bytes
 
-  if (vect_words > 0) {
-    assert(vect_words*wordSize == 256, "");
-    __ subptr(rsp, 256); // Save upper half of YMM registes
-    __ vextractf128h(Address(rsp,  0),xmm0);
-    __ vextractf128h(Address(rsp, 16),xmm1);
-    __ vextractf128h(Address(rsp, 32),xmm2);
-    __ vextractf128h(Address(rsp, 48),xmm3);
-    __ vextractf128h(Address(rsp, 64),xmm4);
-    __ vextractf128h(Address(rsp, 80),xmm5);
-    __ vextractf128h(Address(rsp, 96),xmm6);
-    __ vextractf128h(Address(rsp,112),xmm7);
-    __ vextractf128h(Address(rsp,128),xmm8);
-    __ vextractf128h(Address(rsp,144),xmm9);
-    __ vextractf128h(Address(rsp,160),xmm10);
-    __ vextractf128h(Address(rsp,176),xmm11);
-    __ vextractf128h(Address(rsp,192),xmm12);
-    __ vextractf128h(Address(rsp,208),xmm13);
-    __ vextractf128h(Address(rsp,224),xmm14);
-    __ vextractf128h(Address(rsp,240),xmm15);
+#if defined(COMPILER2) || defined(GRAAL)
+  __ subptr(rsp, 256); // Save upper half of YMM registers
+  if (save_vectors) {
+    assert(UseAVX > 0, "256bit vectors are supported only with AVX");
+#ifdef COMPILER2
+    assert(MaxVectorSize == 32, "only 256bit vectors are supported now");
+#endif
+    // Save upper half of YMM registers
+    __ vextractf128h(Address(rsp, ymm_hi0_off * BytesPerInt),  xmm0);
+    __ vextractf128h(Address(rsp, ymm_hi1_off * BytesPerInt),  xmm1);
+    __ vextractf128h(Address(rsp, ymm_hi2_off * BytesPerInt),  xmm2);
+    __ vextractf128h(Address(rsp, ymm_hi3_off * BytesPerInt),  xmm3);
+    __ vextractf128h(Address(rsp, ymm_hi4_off * BytesPerInt),  xmm4);
+    __ vextractf128h(Address(rsp, ymm_hi5_off * BytesPerInt),  xmm5);
+    __ vextractf128h(Address(rsp, ymm_hi6_off * BytesPerInt),  xmm6);
+    __ vextractf128h(Address(rsp, ymm_hi7_off * BytesPerInt),  xmm7);
+    __ vextractf128h(Address(rsp, ymm_hi8_off * BytesPerInt),  xmm8);
+    __ vextractf128h(Address(rsp, ymm_hi9_off * BytesPerInt),  xmm9);
+    __ vextractf128h(Address(rsp, ymm_hi10_off * BytesPerInt), xmm10);
+    __ vextractf128h(Address(rsp, ymm_hi11_off * BytesPerInt), xmm11);
+    __ vextractf128h(Address(rsp, ymm_hi12_off * BytesPerInt), xmm12);
+    __ vextractf128h(Address(rsp, ymm_hi13_off * BytesPerInt), xmm13);
+    __ vextractf128h(Address(rsp, ymm_hi14_off * BytesPerInt), xmm14);
+    __ vextractf128h(Address(rsp, ymm_hi15_off * BytesPerInt), xmm15);
   }
+#else
+  assert(!save_vectors, "vectors are generated only by C2 and Graal");
+#endif
   if (frame::arg_reg_save_area_bytes != 0) {
     // Allocate argument register save area
     __ subptr(rsp, frame::arg_reg_save_area_bytes);
@@ -240,6 +258,28 @@
   map->set_callee_saved(STACK_OFFSET(xmm14_off), xmm14->as_VMReg());
   map->set_callee_saved(STACK_OFFSET(xmm15_off), xmm15->as_VMReg());
 
+
+#if defined(COMPILER2) || defined(GRAAL)
+  if (save_vectors) {
+    map->set_callee_saved(STACK_OFFSET(ymm_hi0_off ), xmm0->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi1_off ), xmm1->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi2_off ), xmm2->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi3_off ), xmm3->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi4_off ), xmm4->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi5_off ), xmm5->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi6_off ), xmm6->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi7_off ), xmm7->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi8_off ), xmm8->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi9_off ), xmm9->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi10_off), xmm10->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi11_off), xmm11->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi12_off), xmm12->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi13_off), xmm13->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi14_off), xmm14->as_VMReg()->next()->next()->next()->next());
+    map->set_callee_saved(STACK_OFFSET(ymm_hi15_off), xmm15->as_VMReg()->next()->next()->next()->next());
+  }
+#endif
+
   // %%% These should all be a waste but we'll keep things as they were for now
   if (true) {
     map->set_callee_saved(STACK_OFFSET( raxH_off ), rax->as_VMReg()->next());
@@ -283,31 +323,33 @@
     // Pop arg register save area
     __ addptr(rsp, frame::arg_reg_save_area_bytes);
   }
-#ifdef COMPILER2
+#if defined(COMPILER2) || defined(GRAAL)
   if (restore_vectors) {
     // Restore upper half of YMM registes.
     assert(UseAVX > 0, "256bit vectors are supported only with AVX");
+#if defined(COMPILER2)
     assert(MaxVectorSize == 32, "only 256bit vectors are supported now");
-    __ vinsertf128h(xmm0, Address(rsp,  0));
-    __ vinsertf128h(xmm1, Address(rsp, 16));
-    __ vinsertf128h(xmm2, Address(rsp, 32));
-    __ vinsertf128h(xmm3, Address(rsp, 48));
-    __ vinsertf128h(xmm4, Address(rsp, 64));
-    __ vinsertf128h(xmm5, Address(rsp, 80));
-    __ vinsertf128h(xmm6, Address(rsp, 96));
-    __ vinsertf128h(xmm7, Address(rsp,112));
-    __ vinsertf128h(xmm8, Address(rsp,128));
-    __ vinsertf128h(xmm9, Address(rsp,144));
-    __ vinsertf128h(xmm10, Address(rsp,160));
-    __ vinsertf128h(xmm11, Address(rsp,176));
-    __ vinsertf128h(xmm12, Address(rsp,192));
-    __ vinsertf128h(xmm13, Address(rsp,208));
-    __ vinsertf128h(xmm14, Address(rsp,224));
-    __ vinsertf128h(xmm15, Address(rsp,240));
-    __ addptr(rsp, 256);
+#endif
+    __ vinsertf128h(xmm0,  Address(rsp, ymm_hi0_off * BytesPerInt));
+    __ vinsertf128h(xmm1,  Address(rsp, ymm_hi1_off * BytesPerInt));
+    __ vinsertf128h(xmm2,  Address(rsp, ymm_hi2_off * BytesPerInt));
+    __ vinsertf128h(xmm3,  Address(rsp, ymm_hi3_off * BytesPerInt));
+    __ vinsertf128h(xmm4,  Address(rsp, ymm_hi4_off * BytesPerInt));
+    __ vinsertf128h(xmm5,  Address(rsp, ymm_hi5_off * BytesPerInt));
+    __ vinsertf128h(xmm6,  Address(rsp, ymm_hi6_off * BytesPerInt));
+    __ vinsertf128h(xmm7,  Address(rsp, ymm_hi7_off * BytesPerInt));
+    __ vinsertf128h(xmm8,  Address(rsp, ymm_hi8_off * BytesPerInt));
+    __ vinsertf128h(xmm9,  Address(rsp, ymm_hi9_off * BytesPerInt));
+    __ vinsertf128h(xmm10, Address(rsp, ymm_hi10_off * BytesPerInt));
+    __ vinsertf128h(xmm11, Address(rsp, ymm_hi11_off * BytesPerInt));
+    __ vinsertf128h(xmm12, Address(rsp, ymm_hi12_off * BytesPerInt));
+    __ vinsertf128h(xmm13, Address(rsp, ymm_hi13_off * BytesPerInt));
+    __ vinsertf128h(xmm14, Address(rsp, ymm_hi14_off * BytesPerInt));
+    __ vinsertf128h(xmm15, Address(rsp, ymm_hi15_off * BytesPerInt));
   }
+  __ addptr(rsp, 256);
 #else
-  assert(!restore_vectors, "vectors are generated only by C2");
+  assert(!restore_vectors, "vectors are generated only by C2 and Graal");
 #endif
   // Recover CPU state
   __ pop_CPU_state();
--- a/src/cpu/x86/vm/vmreg_x86.cpp	Wed Apr 15 10:09:13 2015 -0700
+++ b/src/cpu/x86/vm/vmreg_x86.cpp	Wed Apr 15 11:03:04 2015 -0700
@@ -48,8 +48,9 @@
 
   XMMRegister xreg = ::as_XMMRegister(0);
   for ( ; i < ConcreteRegisterImpl::max_xmm ; ) {
-    for (int j = 0 ; j < 8 ; j++) {
-      regName[i++] = xreg->name();
+    regName[i++] = xreg->name();
+    for (int j = 1 ; j < 8 ; j++) {
+      regName[i++] = xreg->sub_word_name(j);
     }
     xreg = xreg->successor();
   }
--- a/src/share/vm/compiler/oopMap.cpp	Wed Apr 15 10:09:13 2015 -0700
+++ b/src/share/vm/compiler/oopMap.cpp	Wed Apr 15 11:03:04 2015 -0700
@@ -388,68 +388,71 @@
       do {
         omv = oms.current();
         oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map);
-        if ( loc != NULL ) {
-          oop *base_loc    = fr->oopmapreg_to_location(omv.content_reg(), reg_map);
-          oop *derived_loc = loc;
-          oop val = *base_loc;
-          if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) {
-            // Ignore NULL oops and decoded NULL narrow oops which
-            // equal to Universe::narrow_oop_base when a narrow oop
-            // implicit null check is used in compiled code.
-            // The narrow_oop_base could be NULL or be the address
-            // of the page below heap depending on compressed oops mode.
-          } else
-            derived_oop_fn(base_loc, derived_loc);
+        guarantee(loc != NULL, "missing saved register");
+        oop *base_loc    = fr->oopmapreg_to_location(omv.content_reg(), reg_map);
+        oop *derived_loc = loc;
+        oop val = *base_loc;
+        if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) {
+          // Ignore NULL oops and decoded NULL narrow oops which
+          // equal to Universe::narrow_oop_base when a narrow oop
+          // implicit null check is used in compiled code.
+          // The narrow_oop_base could be NULL or be the address
+          // of the page below heap depending on compressed oops mode.
+        } else {
+          derived_oop_fn(base_loc, derived_loc);
         }
         oms.next();
       }  while (!oms.is_done());
     }
   }
 
-  // We want coop, value and oop oop_types
+  // We want narrowoop and oop oop_types
   int mask = OopMapValue::oop_value | OopMapValue::narrowoop_value;
   {
     for (OopMapStream oms(map,mask); !oms.is_done(); oms.next()) {
       omv = oms.current();
       oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map);
-      if ( loc != NULL ) {
-        if ( omv.type() == OopMapValue::oop_value ) {
-          oop val = *loc;
-          if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) {
-            // Ignore NULL oops and decoded NULL narrow oops which
-            // equal to Universe::narrow_oop_base when a narrow oop
-            // implicit null check is used in compiled code.
-            // The narrow_oop_base could be NULL or be the address
-            // of the page below heap depending on compressed oops mode.
-            continue;
-          }
+      // It should be an error if no location can be found for a
+      // register mentioned as contained an oop of some kind.  Maybe
+      // this was allowed previously because value_value items might
+      // be missing?
+      guarantee(loc != NULL, "missing saved register");
+      if ( omv.type() == OopMapValue::oop_value ) {
+        oop val = *loc;
+        if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) {
+          // Ignore NULL oops and decoded NULL narrow oops which
+          // equal to Universe::narrow_oop_base when a narrow oop
+          // implicit null check is used in compiled code.
+          // The narrow_oop_base could be NULL or be the address
+          // of the page below heap depending on compressed oops mode.
+          continue;
+        }
 #ifdef ASSERT
-          if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) ||
-             !Universe::heap()->is_in_or_null(*loc)) {
-            tty->print_cr("# Found non oop pointer.  Dumping state at failure");
-            // try to dump out some helpful debugging information
-            trace_codeblob_maps(fr, reg_map);
-            omv.print();
-            tty->print_cr("register r");
-            omv.reg()->print();
-            tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc);
-            // do the real assert.
-            assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer");
-          }
+        if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) ||
+            !Universe::heap()->is_in_or_null(*loc)) {
+          tty->print_cr("# Found non oop pointer.  Dumping state at failure");
+          // try to dump out some helpful debugging information
+          trace_codeblob_maps(fr, reg_map);
+          omv.print();
+          tty->print_cr("register r");
+          omv.reg()->print();
+          tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc);
+          // do the real assert.
+          assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer");
+        }
 #endif // ASSERT
-          oop_fn->do_oop(loc);
-        } else if ( omv.type() == OopMapValue::narrowoop_value ) {
-          narrowOop *nl = (narrowOop*)loc;
+        oop_fn->do_oop(loc);
+      } else if ( omv.type() == OopMapValue::narrowoop_value ) {
+        narrowOop *nl = (narrowOop*)loc;
 #ifndef VM_LITTLE_ENDIAN
-          if (!omv.reg()->is_stack()) {
-            // compressed oops in registers only take up 4 bytes of an
-            // 8 byte register but they are in the wrong part of the
-            // word so adjust loc to point at the right place.
-            nl = (narrowOop*)((address)nl + 4);
-          }
+        if (!omv.reg()->is_stack()) {
+          // compressed oops in registers only take up 4 bytes of an
+          // 8 byte register but they are in the wrong part of the
+          // word so adjust loc to point at the right place.
+          nl = (narrowOop*)((address)nl + 4);
+        }
 #endif
-          oop_fn->do_oop(nl);
-        }
+        oop_fn->do_oop(nl);
       }
     }
   }
--- a/src/share/vm/graal/graalEnv.cpp	Wed Apr 15 10:09:13 2015 -0700
+++ b/src/share/vm/graal/graalEnv.cpp	Wed Apr 15 11:03:04 2015 -0700
@@ -546,6 +546,12 @@
         }
       } else {
         nm->set_has_unsafe_access(has_unsafe_access);
+#ifdef TARGET_ARCH_x86
+        // It might be preferable to set this only for methods which
+        // use vector instructions but we currently don't track this
+        // and it probably wouldn't make much difference.
+        nm->set_has_wide_vectors(UseAVX >= 2);
+#endif
 
         // Record successful registration.
         // (Put nm into the task handle *before* publishing to the Java heap.)
--- a/src/share/vm/runtime/sharedRuntime.cpp	Wed Apr 15 10:09:13 2015 -0700
+++ b/src/share/vm/runtime/sharedRuntime.cpp	Wed Apr 15 11:03:04 2015 -0700
@@ -111,9 +111,14 @@
   _resolve_virtual_call_blob           = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_virtual_call_C),       "resolve_virtual_call");
   _resolve_static_call_blob            = generate_resolve_blob(CAST_FROM_FN_PTR(address, SharedRuntime::resolve_static_call_C),        "resolve_static_call");
 
+#if defined(COMPILER2) || defined(GRAAL)
+  // Vectors are generated only by C2 and Graal.
 #ifdef COMPILER2
-  // Vectors are generated only by C2.
-  if (is_wide_vector(MaxVectorSize)) {
+  bool support_wide = is_wide_vector(MaxVectorSize) || IS_GRAAL_DEFINED;
+#else
+  bool support_wide = true;
+#endif
+  if (support_wide) {
     _polling_page_vectors_safepoint_handler_blob = generate_handler_blob(CAST_FROM_FN_PTR(address, SafepointSynchronize::handle_polling_page_exception), POLL_AT_VECTOR_LOOP);
   }
 #endif // COMPILER2